• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kivy / python-for-android / 14561414518

20 Apr 2025 04:39PM UTC coverage: 58.861% (-0.3%) from 59.204%
14561414518

Pull #3136

github

web-flow
Merge bce0f1307 into f491c6eb2
Pull Request #3136: scipy: update to v1.15.2

1059 of 2398 branches covered (44.16%)

Branch coverage included in aggregate %.

72 of 221 new or added lines in 9 files covered. (32.58%)

4 existing lines in 3 files now uncovered.

4979 of 7860 relevant lines covered (63.35%)

2.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.03
/pythonforandroid/recipes/fortran/__init__.py
1
import os
4✔
2
import subprocess
4✔
3
import shutil
4✔
4
import sh
4✔
5
from pathlib import Path
4✔
6
from os.path import join
4✔
7
from pythonforandroid.recipe import Recipe
4✔
8
from pythonforandroid.recommendations import read_ndk_version
4✔
9
from pythonforandroid.logger import info, shprint, info_main
4✔
10
from pythonforandroid.util import ensure_dir
4✔
11
import hashlib
4✔
12

13
FLANG_FILES = {
4✔
14
    "package-flang-aarch64.tar.bz2": "775f362c758abe8d3173edc7be9ced3730ff14c64d44743017c3af7ceb0a6610",
15
    "package-flang-host.tar.bz2": "04fe24d67ee7eb5a4223299c610013585e75c56467e4b185ed929a3d17e3d077",
16
    "package-flang-x86_64.tar.bz2": "2061a0e3179f4afa55516ce3858582d25ea7b108ff762d9fb4ec8a03b49b36d2",
17
    "package-install.tar.bz2": "d37dc6a58b495807f015c7fec08a57ff95d52ad0d0553cbf573b0215d8a1707c",
18
}
19

20

21
class GFortranRecipe(Recipe):
4✔
22
    # flang support in NDK by @termux (on github)
23
    name = "fortran"
4✔
24
    toolchain_ver = 0
4✔
25
    url = "https://github.com/termux/ndk-toolchain-clang-with-flang/releases/download/"
4✔
26

27
    def match_sha256(self, file_path, expected_hash):
4✔
NEW
28
        sha256 = hashlib.sha256()
×
NEW
29
        with open(file_path, "rb") as f:
×
NEW
30
            for chunk in iter(lambda: f.read(8192), b""):
×
NEW
31
                sha256.update(chunk)
×
NEW
32
        file_hash = sha256.hexdigest()
×
NEW
33
        return file_hash == expected_hash
×
34

35
    @property
4✔
36
    def ndk_version(self):
4✔
NEW
37
        ndk_version = read_ndk_version(self.ctx.ndk_dir)
×
NEW
38
        minor_to_letter = {0: ""}
×
NEW
39
        minor_to_letter.update(
×
40
            {n + 1: chr(i) for n, i in enumerate(range(ord("b"), ord("b") + 25))}
41
        )
NEW
42
        return f"{ndk_version.major}{minor_to_letter[ndk_version.minor]}"
×
43

44
    def get_cache_dir(self):
4✔
NEW
45
        dir_name = self.get_dir_name()
×
NEW
46
        return join(self.ctx.build_dir, "other_builds", dir_name)
×
47

48
    def get_fortran_dir(self):
4✔
NEW
49
        toolchain_name = f"android-r{self.ndk_version}-api-{self.ctx.ndk_api}"
×
NEW
50
        return join(
×
51
            self.get_cache_dir(), f"{toolchain_name}-flang-v{self.toolchain_ver}"
52
        )
53

54
    def get_incomplete_files(self):
4✔
NEW
55
        incomplete_files = []
×
NEW
56
        cache_dir = self.get_cache_dir()
×
NEW
57
        for file, sha256sum in FLANG_FILES.items():
×
NEW
58
            _file = join(cache_dir, file)
×
NEW
59
            if not (os.path.exists(_file) and self.match_sha256(_file, sha256sum)):
×
NEW
60
                incomplete_files.append(file)
×
NEW
61
        return incomplete_files
×
62

63
    def download_if_necessary(self):
4✔
NEW
64
        assert self.ndk_version == "27c"
×
NEW
65
        if len(self.get_incomplete_files()) == 0:
×
NEW
66
            return
×
NEW
67
        self.download()
×
68

69
    def download(self):
4✔
NEW
70
        cache_dir = self.get_cache_dir()
×
NEW
71
        ensure_dir(cache_dir)
×
NEW
72
        for file in self.get_incomplete_files():
×
NEW
73
            _file = join(cache_dir, file)
×
NEW
74
            if os.path.exists(_file):
×
NEW
75
                os.remove(_file)
×
NEW
76
            self.download_file(f"{self.url}r{join(self.ndk_version, file)}", _file)
×
77

78
    def extract_tar(self, file_path: Path, dest: Path, strip=1):
4✔
NEW
79
        shprint(
×
80
            sh.tar,
81
            "xf",
82
            str(file_path),
83
            "--strip-components",
84
            str(strip),
85
            "-C",
86
            str(dest) if dest else ".",
87
        )
88

89
    def create_flang_wrapper(self, path: Path, target: str):
4✔
NEW
90
        script = f"""#!/usr/bin/env bash
×
91
if [ "$1" != "-cpp" ] && [ "$1" != "-fc1" ]; then
92
  `dirname $0`/flang-new --target={target}{self.ctx.ndk_api} -D__ANDROID_API__={self.ctx.ndk_api} "$@"
93
else
94
  `dirname $0`/flang-new "$@"
95
fi
96
"""
NEW
97
        path.write_text(script)
×
NEW
98
        path.chmod(0o755)
×
99

100
    def unpack(self, arch):
4✔
NEW
101
        info_main("Unpacking fortran")
×
102

NEW
103
        flang_folder = self.get_fortran_dir()
×
NEW
104
        if os.path.exists(flang_folder):
×
NEW
105
            info("{} is already unpacked, skipping".format(self.name))
×
NEW
106
            return
×
107

NEW
108
        toolchain_path = Path(
×
109
            join(self.ctx.ndk_dir, "toolchains/llvm/prebuilt/linux-x86_64")
110
        )
NEW
111
        cache_dir = Path(os.path.abspath(self.get_cache_dir()))
×
112

113
        # clean tmp folder
NEW
114
        tmp_folder = Path(os.path.abspath(f"{flang_folder}-tmp"))
×
NEW
115
        shutil.rmtree(tmp_folder, ignore_errors=True)
×
NEW
116
        tmp_folder.mkdir(parents=True)
×
NEW
117
        os.chdir(tmp_folder)
×
118

NEW
119
        self.extract_tar(cache_dir / "package-install.tar.bz2", None, strip=4)
×
NEW
120
        self.extract_tar(cache_dir / "package-flang-host.tar.bz2", None)
×
121

NEW
122
        sysroot_path = tmp_folder / "sysroot"
×
NEW
123
        shutil.copytree(toolchain_path / "sysroot", sysroot_path)
×
124

NEW
125
        self.extract_tar(
×
126
            cache_dir / "package-flang-aarch64.tar.bz2",
127
            sysroot_path / "usr/lib/aarch64-linux-android",
128
        )
NEW
129
        self.extract_tar(
×
130
            cache_dir / "package-flang-x86_64.tar.bz2",
131
            sysroot_path / "usr/lib/x86_64-linux-android",
132
        )
133

134
        # Fix lib/clang paths
NEW
135
        version_output = subprocess.check_output(
×
136
            [str(tmp_folder / "bin/clang"), "--version"], text=True
137
        )
NEW
138
        clang_version = next(
×
139
            (line for line in version_output.splitlines() if "clang version" in line),
140
            "",
141
        )
NEW
142
        major_ver = clang_version.split("clang version ")[-1].split(".")[0]
×
143

NEW
144
        lib_path = tmp_folder / f"lib/clang/{major_ver}/lib"
×
NEW
145
        src_lib_path = toolchain_path / f"lib/clang/{major_ver}/lib"
×
NEW
146
        shutil.rmtree(lib_path, ignore_errors=True)
×
NEW
147
        lib_path.mkdir(parents=True)
×
148

NEW
149
        for item in src_lib_path.iterdir():
×
NEW
150
            shprint(sh.cp, "-r", str(item), str(lib_path))
×
151

152
        # Create flang wrappers
NEW
153
        targets = [
×
154
            "aarch64-linux-android",
155
            "armv7a-linux-androideabi",
156
            "i686-linux-android",
157
            "x86_64-linux-android",
158
        ]
159

NEW
160
        for target in targets:
×
NEW
161
            wrapper_path = tmp_folder / f"bin/{target}-flang"
×
NEW
162
            self.create_flang_wrapper(wrapper_path, target)
×
NEW
163
            shutil.copy(
×
164
                wrapper_path, tmp_folder / f"bin/{target}{self.ctx.ndk_api}-flang"
165
            )
166

NEW
167
        tmp_folder.rename(flang_folder)
×
168

169
    @property
4✔
170
    def bin_path(self):
4✔
NEW
171
        return f"{self.get_fortran_dir()}/bin"
×
172

173
    def get_host_platform(self, arch):
4✔
NEW
174
        return {
×
175
            "arm64-v8a": "aarch64-linux-android",
176
            "armeabi-v7a": "armv7a-linux-androideabi",
177
            "x86_64": "x86_64-linux-android",
178
            "x86": "i686-linux-android",
179
        }[arch]
180

181
    def get_fortran_bin(self, arch):
4✔
NEW
182
        return join(self.bin_path, f"{self.get_host_platform(arch)}-flang")
×
183

184
    def get_fortran_flags(self, arch):
4✔
NEW
185
        return f"--target={self.get_host_platform(arch)}{self.ctx.ndk_api} -D__ANDROID_API__={self.ctx.ndk_api}"
×
186

187

188
recipe = GFortranRecipe()
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc