diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt index 4111d8c67..a0ea1823f 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/tasks/MagiskInstaller.kt @@ -134,10 +134,12 @@ abstract class MagiskInstallImpl protected constructor( val abi32 = Const.CPU_ABI_32 if (Process.is64Bit() && abi32 != null) { - val magisk32 = File(installDir, "magisk32") val entry = zf.getEntry("lib/$abi32/libmagisk.so") - zf.getInputStream(entry).writeTo(magisk32) - magisk32.setExecutable(true) + if (entry != null) { + val magisk32 = File(installDir, "magisk32") + zf.getInputStream(entry).writeTo(magisk32) + magisk32.setExecutable(true) + } } } } else { diff --git a/build.py b/build.py index 918ae393b..988462b9b 100755 --- a/build.py +++ b/build.py @@ -5,6 +5,7 @@ import lzma import multiprocessing import os import platform +import re import shutil import stat import subprocess @@ -51,7 +52,7 @@ if is_windows: # We can't do ANSI color codes in terminal on Windows without colorama no_color = True -# Environment checks +# Environment checks and detection if not sys.version_info >= (3, 8): error("Requires Python 3.8+") @@ -73,18 +74,19 @@ if shutil.which("ccache") is not None: cpu_count = multiprocessing.cpu_count() os_name = platform.system().lower() -archs = ["armeabi-v7a", "x86", "arm64-v8a", "x86_64", "riscv64"] -triples = [ - "armv7a-linux-androideabi", - "i686-linux-android", - "aarch64-linux-android", - "x86_64-linux-android", - "riscv64-linux-android", -] +# Common constants +support_abis = { + "armeabi-v7a": "thumbv7neon-linux-androideabi", + "x86": "i686-linux-android", + "arm64-v8a": "aarch64-linux-android", + "x86_64": "x86_64-linux-android", + "riscv64": "riscv64-linux-android", +} default_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"} support_targets = default_targets | {"resetprop"} rust_targets = {"magisk", "magiskinit", "magiskboot", "magiskpolicy"} +# Common paths ndk_root = sdk_path / "ndk" ndk_path = ndk_root / "magisk" ndk_build = ndk_path / "ndk-build" @@ -97,8 +99,8 @@ native_gen_path = Path("native", "out", "generated").resolve() # Global vars config = {} -STDOUT = None -build_tools = None +args = {} +build_abis = {} def mv(source: Path, target: Path): @@ -137,12 +139,16 @@ def rm_on_error(func, path, _): def rm_rf(path: Path): vprint(f"rm -rf {path}") - shutil.rmtree(path, ignore_errors=False, onerror=rm_on_error) + if sys.version_info >= (3, 12): + shutil.rmtree(path, ignore_errors=False, onexc=rm_on_error) + else: + shutil.rmtree(path, ignore_errors=False, onerror=rm_on_error) def execv(cmds: list, env=None): + out = None if args.force_out or args.verbose > 0 else subprocess.DEVNULL # Use shell on Windows to support PATHEXT - return subprocess.run(cmds, stdout=STDOUT, env=env, shell=is_windows) + return subprocess.run(cmds, stdout=out, env=env, shell=is_windows) def cmd_out(cmds: list, env=None): @@ -172,10 +178,11 @@ def parse_props(file): prop = line.split("=") if len(prop) != 2: continue + key = prop[0].strip(" \t\r\n") value = prop[1].strip(" \t\r\n") - if len(value) == 0: + if not key or not value: continue - props[prop[0].strip(" \t\r\n")] = value + props[key] = value return props @@ -204,10 +211,18 @@ def load_config(args): error('Config error: "versionCode" is required to be an integer') config["outdir"] = Path(config["outdir"]) - config["outdir"].mkdir(mode=0o755, parents=True, exist_ok=True) - global STDOUT - STDOUT = None if args.verbose > 0 else subprocess.DEVNULL + + if "abiList" in config: + abiList = re.split("\\s*,\\s*", config["abiList"]) + archs = set(abiList) & support_abis.keys() + else: + archs = {"armeabi-v7a", "x86", "arm64-v8a", "x86_64"} + + triples = map(support_abis.get, archs) + + global build_abis + build_abis = dict(zip(archs, triples)) def clean_elf(): @@ -238,6 +253,7 @@ def run_ndk_build(args, cmds: list): os.chdir("native") cmds.append("NDK_PROJECT_PATH=.") cmds.append("NDK_APPLICATION_MK=src/Application.mk") + cmds.append(f"APP_ABI={' '.join(build_abis.keys())}") cmds.append(f"-j{cpu_count}") if args.verbose > 1: cmds.append("V=1") @@ -248,12 +264,13 @@ def run_ndk_build(args, cmds: list): error("Build binary failed!") os.chdir("..") - for arch in archs: + for arch in support_abis.keys(): arch_dir = Path("native", "libs", arch) - out_dir = Path("native", "out", arch) - for source in arch_dir.iterdir(): - target = out_dir / source.name - mv(source, target) + if arch_dir.exists(): + out_dir = Path("native", "out", arch) + for source in arch_dir.iterdir(): + target = out_dir / source.name + mv(source, target) def build_cpp_src(args, targets: set): @@ -332,11 +349,8 @@ def build_rust_src(args, targets: set): cmds.append("--target") cmds.append("") - for arch, triple in zip(archs, triples): - rust_triple = ( - "thumbv7neon-linux-androideabi" if triple.startswith("armv7") else triple - ) - cmds[-1] = rust_triple + for arch, triple in build_abis.items(): + cmds[-1] = triple for tgt in targets: cmds[2] = tgt @@ -347,16 +361,15 @@ def build_rust_src(args, targets: set): arch_out = native_out / arch arch_out.mkdir(mode=0o755, exist_ok=True) for tgt in targets: - source = Path("target", rust_triple, rust_out, f"lib{tgt}.a") + source = Path("target", triple, rust_out, f"lib{tgt}.a") target = arch_out / f"lib{tgt}-rs.a" mv(source, target) os.chdir(Path("..", "..")) -def run_cargo_cmd(args): - global STDOUT - STDOUT = None +def cargo_cli(args): + args.force_out = True if len(args.commands) >= 1 and args.commands[0] == "--": args.commands = args.commands[1:] os.chdir(Path("native", "src")) @@ -677,9 +690,11 @@ binary_parser.add_argument( ) binary_parser.set_defaults(func=build_binary) -cargo_parser = subparsers.add_parser("cargo", help="run cargo with proper environment") +cargo_parser = subparsers.add_parser( + "cargo", help="call 'cargo' commands against the project" +) cargo_parser.add_argument("commands", nargs=argparse.REMAINDER) -cargo_parser.set_defaults(func=run_cargo_cmd) +cargo_parser.set_defaults(func=cargo_cli) rustup_parser = subparsers.add_parser("rustup", help="setup rustup wrapper") rustup_parser.add_argument("wrapper_dir", help="path to setup rustup wrapper binaries") @@ -722,6 +737,7 @@ if len(sys.argv) == 1: args = parser.parse_args() load_config(args) +vars(args)["force_out"] = False # Call corresponding functions args.func(args) diff --git a/buildSrc/src/main/java/Plugin.kt b/buildSrc/src/main/java/Plugin.kt index 780d82bc0..a793437e2 100644 --- a/buildSrc/src/main/java/Plugin.kt +++ b/buildSrc/src/main/java/Plugin.kt @@ -8,6 +8,8 @@ import java.util.Properties private val props = Properties() private var commitHash = "" +private val supportAbis = setOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64", "riscv64") +private val defaultAbis = setOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64") object Config { operator fun get(key: String): String? { @@ -20,6 +22,10 @@ object Config { val version: String get() = get("version") ?: commitHash val versionCode: Int get() = get("magisk.versionCode")!!.toInt() val stubVersion: String get() = get("magisk.stubVersion")!! + val abiList: Set get() { + val abiList = get("abiList") ?: return defaultAbis + return abiList.split(Regex("\\s*,\\s*")).toSet() intersect supportAbis + } } class MagiskPlugin : Plugin { diff --git a/buildSrc/src/main/java/Setup.kt b/buildSrc/src/main/java/Setup.kt index 407072738..a2e7bdaa0 100644 --- a/buildSrc/src/main/java/Setup.kt +++ b/buildSrc/src/main/java/Setup.kt @@ -121,9 +121,11 @@ const val BUSYBOX_ZIP_CHECKSUM = fun Project.setupCoreLib() { setupCommon() + val abiList = Config.abiList + val syncLibs by tasks.registering(Sync::class) { into("src/main/jniLibs") - for (abi in arrayOf("armeabi-v7a", "x86", "arm64-v8a", "x86_64", "riscv64")) { + for (abi in abiList) { into(abi) { from(rootProject.file("native/out/$abi")) { include("magiskboot", "magiskinit", "magiskpolicy", "magisk", "libinit-ld.so") @@ -132,7 +134,7 @@ fun Project.setupCoreLib() { } } onlyIf { - if (inputs.sourceFiles.files.size != 25) + if (inputs.sourceFiles.files.size != abiList.size * 5) throw StopExecutionException("Please build binaries first! (./build.py binary)") true } @@ -158,6 +160,7 @@ fun Project.setupCoreLib() { } } from(zipTree(bb)) + include(abiList.map { "$it/libbusybox.so" }) into("src/main/jniLibs") } diff --git a/config.prop.sample b/config.prop.sample index a69a25e34..c17e17366 100644 --- a/config.prop.sample +++ b/config.prop.sample @@ -9,6 +9,10 @@ version=string # Output path. Default: out outdir=string +# List of ABIs to build, separated with ',' +# Default: armeabi-v7a,x86,arm64-v8a,x86_64 +abiList=[string] + ##################################################### # Signing configs for signing zips and APKs # These 4 variables has to be either all set or not diff --git a/native/src/Application.mk b/native/src/Application.mk index 3e58fd1ae..82f8c272d 100644 --- a/native/src/Application.mk +++ b/native/src/Application.mk @@ -1,5 +1,4 @@ APP_BUILD_SCRIPT := src/Android.mk -APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 riscv64 APP_CFLAGS := -Wall -Oz -fomit-frame-pointer APP_CPPFLAGS := -std=c++23 APP_STL := none diff --git a/native/src/Cargo.toml b/native/src/Cargo.toml index de4b5cc14..e7425afff 100644 --- a/native/src/Cargo.toml +++ b/native/src/Cargo.toml @@ -63,6 +63,6 @@ panic = "abort" [profile.release] opt-level = "z" -lto = true +lto = "fat" codegen-units = 1 panic = "abort"