diff --git a/cmake/platform_settings.cmake b/cmake/platform_settings.cmake index f561d5574..a9351aa4a 100644 --- a/cmake/platform_settings.cmake +++ b/cmake/platform_settings.cmake @@ -12,7 +12,7 @@ if(APPLE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) else() set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE) - set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE) + set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) endif() endif() diff --git a/recipes/amnezia-xray-bindings/conanfile.py b/recipes/amnezia-xray-bindings/conanfile.py index fb7d6a53b..3c903d167 100644 --- a/recipes/amnezia-xray-bindings/conanfile.py +++ b/recipes/amnezia-xray-bindings/conanfile.py @@ -3,13 +3,17 @@ from conan.tools.files import get, copy, collect_libs, chdir, rename from conan.tools.layout import basic_layout from conan.errors import ConanInvalidConfiguration from conan.tools.gnu import Autotools, AutotoolsToolchain +from conan.tools.env import VirtualBuildEnv import os +import shlex + class AmneziaXrayBindings(ConanFile): name = "amnezia-xray-bindings" version = "1.1.0" settings = "os", "arch", "compiler" + _lib_name = "libamnezia_xray.a" @property def _goos(self): @@ -19,15 +23,108 @@ class AmneziaXrayBindings(ConanFile): "Macos": "darwin", "Windows": "windows" }.get(str(self.settings.os)) - + @property - def _goarch(self): + def _arch_map(self): return { "x86": "386", "x86_64": "amd64", "armv8": "arm64" - }.get(str(self.settings.arch)) - + } + + @property + def _apple_arch_map(self): + return { + "x86_64": "x86_64", + "armv8": "arm64", + } + + @property + def _archs(self): + return str(self.settings.arch).split("|") + + @property + def _goarch(self): + goarchs = [self._arch_map.get(arch) for arch in self._archs] + return goarchs[0] if len(goarchs) == 1 else None + + @property + def _goarchs(self): + return [self._arch_map.get(arch) for arch in self._archs] + + @property + def _is_universal_macos(self): + return str(self.settings.os) == "Macos" and len(self._archs) > 1 + + @property + def _is_unsupported_multi_arch(self): + return len(self._archs) > 1 and not self._is_universal_macos + + def _go_cache_vars(self): + return { + "GOPATH": os.path.join(self.build_folder, "gopath"), + "GOMODCACHE": os.path.join(self.build_folder, "gopath", "pkg", "mod"), + "GOCACHE": os.path.join(self.build_folder, "gocache"), + "GOTELEMETRY": "off", + } + + def _define_go_cache_env(self, env): + for name, value in self._go_cache_vars().items(): + env.define(name, value) + + def _go_cache_make_args(self): + return [f"{name}={value}" for name, value in self._go_cache_vars().items()] + + def _non_arch_flags(self, flags): + tokens = [] + for flag in flags: + tokens.extend(shlex.split(flag)) + + result = [] + skip_next = False + for flag in tokens: + if skip_next: + skip_next = False + elif flag == "-arch": + skip_next = True + else: + result.append(flag) + return result + + def _cgo_flags(self, arch, flags): + return " ".join(["-arch", self._apple_arch_map[arch]] + self._non_arch_flags(flags)) + + def _make_var(self, name, value): + return f"{name}={shlex.quote(value)}" + + def _go_arch_make_args(self, arch, goarch): + tc = AutotoolsToolchain(self) + return self._go_cache_make_args() + [ + f"GOOS={self._goos}", + f"GOARCH={goarch}", + f"ARCH={goarch}", + self._make_var("CGO_CFLAGS", self._cgo_flags(arch, tc.cflags)), + self._make_var("CGO_LDFLAGS", self._cgo_flags(arch, tc.ldflags)), + ] + + def _build_go_arch(self, arch, goarch): + with chdir(self, self.source_folder): + autotools = Autotools(self) + autotools.make(args=self._go_arch_make_args(arch, goarch)) + + output_path = os.path.join(self.build_folder, self._lib_name) + if not os.path.exists(output_path): + output_path = os.path.join(self.source_folder, self._lib_name) + + arch_output_path = os.path.join(self.build_folder, f"libamnezia_xray-{goarch}.a") + os.rename(output_path, arch_output_path) + return arch_output_path + + def _build_universal_macos(self): + outputs = [self._build_go_arch(arch, goarch) for arch, goarch in zip(self._archs, self._goarchs)] + universal_output = os.path.join(self.build_folder, self._lib_name) + self.run(f"lipo -create {' '.join(outputs)} -output {universal_output}") + @property def _is_windows(self): return str(self.settings.os).startswith("Windows") @@ -54,7 +151,7 @@ class AmneziaXrayBindings(ConanFile): self.tool_requires("mingw-builds/15.1.0") def validate(self): - if not self._goos or not self._goarch: + if not self._goos or not all(self._goarchs) or self._is_unsupported_multi_arch: raise ConanInvalidConfiguration( f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" ) @@ -64,21 +161,28 @@ class AmneziaXrayBindings(ConanFile): sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True) def generate(self): + VirtualBuildEnv(self).generate() tc = AutotoolsToolchain(self) tc.make_args = [ "LIB_ARC=libamnezia_xray.a" ] env = tc.environment() - env.define("ARCH", self._goarch) - env.define("GOARCH", self._goarch) + self._define_go_cache_env(env) + if not self._is_universal_macos: + env.define("ARCH", self._goarch) + env.define("GOARCH", self._goarch) + env.define("CGO_LDFLAGS", tc.ldflags) + env.define("CGO_CFLAGS", tc.cflags) env.define("GOOS", self._goos) - env.define("CGO_LDFLAGS", tc.ldflags) - env.define("CGO_CFLAGS", tc.cflags) if self._is_windows: env.define("OS", "windows") tc.generate(env) def build(self): + if self._is_universal_macos: + self._build_universal_macos() + return + with chdir(self, self.source_folder): autotools = Autotools(self) autotools.make() @@ -100,7 +204,10 @@ class AmneziaXrayBindings(ConanFile): def package(self): copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include")) - copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) + if self._is_universal_macos: + copy(self, self._lib_name, src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) + else: + copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) copy(self, "*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) copy(self, "*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin")) self._rename_header() diff --git a/recipes/awg-go/conanfile.py b/recipes/awg-go/conanfile.py index ae39623e6..ac2804533 100644 --- a/recipes/awg-go/conanfile.py +++ b/recipes/awg-go/conanfile.py @@ -3,14 +3,17 @@ from conan.errors import ConanInvalidConfiguration from conan.tools.layout import basic_layout from conan.tools.files import get, copy from conan.tools.gnu import Autotools, AutotoolsToolchain +from conan.tools.env import VirtualBuildEnv import os + class AwgGo(ConanFile): name = "awg-go" version = "0.2.16" package_type = "application" settings = "os", "arch" + _binary_name = "amneziawg-go" @property def _goos(self): @@ -21,12 +24,65 @@ class AwgGo(ConanFile): }.get(str(self.settings.os)) @property - def _goarch(self): + def _arch_map(self): return { "x86": "386", "x86_64": "amd64", "armv8": "arm64" - }.get(str(self.settings.arch)) + } + + @property + def _archs(self): + return str(self.settings.arch).split("|") + + @property + def _goarch(self): + goarchs = [self._arch_map.get(arch) for arch in self._archs] + return goarchs[0] if len(goarchs) == 1 else None + + @property + def _goarchs(self): + return [self._arch_map.get(arch) for arch in self._archs] + + @property + def _is_universal_macos(self): + return str(self.settings.os) == "Macos" and len(self._archs) > 1 + + @property + def _is_unsupported_multi_arch(self): + return len(self._archs) > 1 and not self._is_universal_macos + + def _go_cache_vars(self): + return { + "GOPATH": os.path.join(self.build_folder, "gopath"), + "GOMODCACHE": os.path.join(self.build_folder, "gopath", "pkg", "mod"), + "GOCACHE": os.path.join(self.build_folder, "gocache"), + "GOTELEMETRY": "off", + } + + def _define_go_cache_env(self, env): + for name, value in self._go_cache_vars().items(): + env.define(name, value) + + def _go_arch_make_args(self, goarch): + return [f"{name}={value}" for name, value in self._go_cache_vars().items()] + [ + f"GOOS={self._goos}", + f"GOARCH={goarch}", + ] + + def _build_go_arch(self, goarch): + autotools = Autotools(self) + autotools.make(args=self._go_arch_make_args(goarch)) + + output_path = os.path.join(self.build_folder, self._binary_name) + arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}") + os.rename(output_path, arch_output_path) + return arch_output_path + + def _build_universal_macos(self): + outputs = [self._build_go_arch(goarch) for goarch in self._goarchs] + universal_output = os.path.join(self.build_folder, self._binary_name) + self.run(f"lipo -create {' '.join(outputs)} -output {universal_output}") def layout(self): basic_layout(self, build_folder=".") @@ -35,7 +91,7 @@ class AwgGo(ConanFile): self.tool_requires("go/1.26.0") def validate(self): - if not self._goos or not self._goarch: + if not self._goos or not all(self._goarchs) or self._is_unsupported_multi_arch: raise ConanInvalidConfiguration( f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" ) @@ -46,22 +102,29 @@ class AwgGo(ConanFile): ) def generate(self): + VirtualBuildEnv(self).generate() tc = AutotoolsToolchain(self) env = tc.environment() + self._define_go_cache_env(env) env.define("GOOS", self._goos) - env.define("GOARCH", self._goarch) + if not self._is_universal_macos: + env.define("GOARCH", self._goarch) env.define("CGO_LDFLAGS", tc.ldflags) env.define("CGO_CFLAGS", tc.cflags) tc.generate(env) def build(self): + if self._is_universal_macos: + self._build_universal_macos() + return + at = Autotools(self) at.make() def package(self): - copy(self, "amneziawg-go", src=self.build_folder, dst=self.package_folder) + copy(self, self._binary_name, src=self.build_folder, dst=self.package_folder) def package_info(self): self.cpp_info.exe = True - self.cpp_info.location = os.path.join(self.package_folder, "amneziawg-go") + self.cpp_info.location = os.path.join(self.package_folder, self._binary_name) self.cpp_info.set_property("cmake_target_name", "amnezia::awg-go") diff --git a/recipes/tun2socks/conanfile.py b/recipes/tun2socks/conanfile.py index 417bcfd10..4df179922 100644 --- a/recipes/tun2socks/conanfile.py +++ b/recipes/tun2socks/conanfile.py @@ -3,15 +3,17 @@ from conan.tools.layout import basic_layout from conan.tools.files import get, copy, chdir from conan.errors import ConanInvalidConfiguration from conan.tools.gnu import Autotools, AutotoolsToolchain -from conan.tools.env import Environment +from conan.tools.env import VirtualBuildEnv import os + class Tun2Socks(ConanFile): name = "tun2socks" version = "2.6.0" package_type = "application" settings = "os", "arch" + _binary_name = "tun2socks" @property def _goos(self): @@ -22,17 +24,75 @@ class Tun2Socks(ConanFile): }.get(str(self.settings.os)) @property - def _goarch(self): + def _arch_map(self): return { "x86": "386", "x86_64": "amd64", "armv8": "arm64" - }.get(str(self.settings.arch)) - + } + + @property + def _archs(self): + return str(self.settings.arch).split("|") + + @property + def _goarch(self): + goarchs = [self._arch_map.get(arch) for arch in self._archs] + return goarchs[0] if len(goarchs) == 1 else None + + @property + def _goarchs(self): + return [self._arch_map.get(arch) for arch in self._archs] + + @property + def _is_universal_macos(self): + return str(self.settings.os) == "Macos" and len(self._archs) > 1 + + @property + def _is_unsupported_multi_arch(self): + return len(self._archs) > 1 and not self._is_universal_macos + + def _go_cache_vars(self): + return { + "GOPATH": os.path.join(self.build_folder, "gopath"), + "GOMODCACHE": os.path.join(self.build_folder, "gopath", "pkg", "mod"), + "GOCACHE": os.path.join(self.build_folder, "gocache"), + "GOTELEMETRY": "off", + } + + def _define_go_cache_env(self, env): + for name, value in self._go_cache_vars().items(): + env.define(name, value) + + def _go_arch_make_args(self, goarch): + return [f"{name}={value}" for name, value in self._go_cache_vars().items()] + [ + "LDFLAGS=", + f"GOOS={self._goos}", + f"GOARCH={goarch}", + ] + + def _build_go_arch(self, goarch): + with chdir(self, self.source_folder): + autotools = Autotools(self) + autotools.make(self._binary_name, args=self._go_arch_make_args(goarch)) + + output_path = os.path.join(self.build_folder, self._binary_name) + if not os.path.exists(output_path): + output_path = os.path.join(self.source_folder, self._binary_name) + + arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}") + os.rename(output_path, arch_output_path) + return arch_output_path + + def _build_universal_macos(self): + outputs = [self._build_go_arch(goarch) for goarch in self._goarchs] + universal_output = os.path.join(self.build_folder, self._binary_name) + self.run(f"lipo -create {' '.join(outputs)} -output {universal_output}") + @property def _is_windows(self): return str(self.settings.get_safe("os")).startswith("Windows") - + @property def _ext(self): return ".exe" if self._is_windows else "" @@ -41,7 +101,7 @@ class Tun2Socks(ConanFile): basic_layout(self) def validate(self): - if not self._goos or not self._goarch: + if not self._goos or not all(self._goarchs) or self._is_unsupported_multi_arch: raise ConanInvalidConfiguration( f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" ) @@ -64,25 +124,32 @@ class Tun2Socks(ConanFile): ) def generate(self): + VirtualBuildEnv(self).generate() tc = AutotoolsToolchain(self) env = tc.environment() + self._define_go_cache_env(env) env.define("LDFLAGS", "") env.define("CGO_LDFLAGS", tc.ldflags) env.define("CGO_CFLAGS", tc.cflags) env.define("GOOS", self._goos) - env.define("GOARCH", self._goarch) + if not self._is_universal_macos: + env.define("GOARCH", self._goarch) tc.generate(env) def build(self): + if self._is_universal_macos: + self._build_universal_macos() + return + with chdir(self, self.source_folder): at = Autotools(self) - at.make("tun2socks") + at.make(self._binary_name) def package(self): - copy(self, "tun2socks", src=self.build_folder, dst=self.package_folder) + copy(self, self._binary_name, src=self.build_folder, dst=self.package_folder) if self._is_windows: with chdir(self, self.package_folder): - os.rename(src="tun2socks", dst="tun2socks.exe") + os.rename(src=self._binary_name, dst=f"{self._binary_name}.exe") def package_info(self): self.cpp_info.exe = True