#!/usr/bin/python3 import os import sys import platform import argparse def build_architecture(arch, output, output_dir): os.environ["GOARCH"] = arch os.system(f"go build -buildmode=c-shared -o {output}") # 检查生成的头文件 headers = [f for f in os.listdir(output_dir) if f.endswith(".h") and "libclash" in f] if not headers: raise FileNotFoundError(f"No header file generated for architecture: {arch}") # 重命名第一个找到的头文件为 libclash.h for header in headers: old_path = os.path.join(output_dir, header) new_path = os.path.join(output_dir, "libclash.h") if old_path != new_path: os.rename(old_path, new_path) print(f"[info] Renamed {header} to libclash.h") break # 只需要处理一次 def clean_up_dynamic_libs(output_dir, output_x86_64, output_arm64): # 删除多余的动态库,确保只保留 libclash.dylib files_to_delete = [output_x86_64, output_arm64] for lib_file in files_to_delete: if os.path.exists(lib_file): os.remove(lib_file) print(f"[info] Deleted extra dynamic library: {lib_file}") def clean_up_headers(output_dir): # 删除多余的头文件,确保只有 libclash.h 存在 headers = [f for f in os.listdir(output_dir) if f.endswith(".h") and f != "libclash.h"] for header in headers: header_path = os.path.join(output_dir, header) os.remove(header_path) print(f"[info] Deleted extra header file: {header_path}") def package_universal_binary(output_x86_64, output_arm64, final_output, output_dir): # 确保生成的二进制文件存在 print(f"[info] Checking {output_x86_64} and {output_arm64} for packaging...") if not os.path.exists(output_x86_64): raise FileNotFoundError(f"File not found: {output_x86_64}") if not os.path.exists(output_arm64): raise FileNotFoundError(f"File not found: {output_arm64}") # 使用 lipo 将 x86_64 和 arm64 合并为通用二进制文件 print("[info] Creating universal binary for macOS...") os.system(f"lipo -create -output {final_output} {output_x86_64} {output_arm64}") if not os.path.exists(final_output): raise FileNotFoundError(f"Failed to create universal binary: {final_output}") print(f"[info] Universal binary created: {final_output}") # 清理多余的动态库 clean_up_dynamic_libs(output_dir, output_x86_64, output_arm64) # 清理并重命名头文件为 libclash.h clean_up_headers(output_dir) def build(target): os.chdir("core") os.environ["CGO_ENABLED"] = "1" output_base = "../libclash/libclash" output_dir = "../libclash" # 根据平台设置动态库文件扩展名 if sys.platform == 'win32': output_x86_64 = output_base + ".dll" final_output = output_x86_64 elif sys.platform == "darwin": output_x86_64 = output_base + "_x86_64.dylib" output_arm64 = output_base + "_arm64.dylib" final_output = output_base + ".dylib" else: output_x86_64 = output_base + "_x86_64.so" output_arm64 = output_base + "_arm64.so" final_output = output_base + ".so" if sys.platform == 'win32': # Windows 平台仅编译 x86_64 版本 print("[info] Compiling x86_64 target for Windows...") build_architecture("amd64", output_x86_64, output_dir) elif sys.platform == "darwin": # macOS 平台编译 x86_64 和 arm64,并合并为通用二进制 print("[info] Compiling x86_64 target for macOS...") build_architecture("amd64", output_x86_64, output_dir) print("[info] Compiling arm64 target for macOS...") build_architecture("arm64", output_arm64, output_dir) # 在 build 阶段也执行 lipo 合并并清理 package_universal_binary(output_x86_64, output_arm64, final_output, output_dir) else: # Linux 平台分别编译 x86_64 和 arm64,不合并为通用二进制 print("[info] Compiling x86_64 target for Linux...") build_architecture("amd64", output_x86_64, output_dir) print("[info] Compiling arm64 target for Linux...") build_architecture("arm64", output_arm64, output_dir) os.chdir("..") def run_flutter_distributor(): print("[info] Running flutter_distributor for packaging...") # 使用 flutter_distributor 打包 Flutter 项目 os.system("flutter_distributor package --skip-clean --platform all") def package(): if sys.platform == "darwin": # 打包 macOS 的通用二进制(通过 lipo 合并) output_base = "../libclash/libclash" output_x86_64 = output_base + "_x86_64.dylib" output_arm64 = output_base + "_arm64.dylib" final_output = output_base + ".dylib" output_dir = "../libclash" package_universal_binary(output_x86_64, output_arm64, final_output, output_dir) # 执行 flutter_distributor 进行打包 run_flutter_distributor() def main(): parser = argparse.ArgumentParser(description="Build and package libclash dynamic libraries.") parser.add_argument("action", choices=["build", "package"], help="Specify whether to build or package.") args = parser.parse_args() if args.action == "build": build("build") elif args.action == "package": build("package") # 在打包时也先进行构建 package() if __name__ == "__main__": main()