Build macOS prebuilts for arm64 and x86_64

This commit is contained in:
spectrum
2026-05-12 00:56:34 +03:00
parent c714d98bd1
commit c62cdf810a
5 changed files with 265 additions and 27 deletions
+1
View File
@@ -408,6 +408,7 @@ jobs:
if: needs.Detect-Changes.outputs.recipes_changed == 'true' if: needs.Detect-Changes.outputs.recipes_changed == 'true'
strategy: strategy:
max-parallel: 1
matrix: matrix:
xcode-version: [16.2, 16.4, 26.4] xcode-version: [16.2, 16.4, 26.4]
include: include:
+1 -1
View File
@@ -12,7 +12,7 @@ if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
else() else()
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE) 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()
endif() endif()
+117 -10
View File
@@ -3,13 +3,17 @@ from conan.tools.files import get, copy, collect_libs, chdir, rename
from conan.tools.layout import basic_layout from conan.tools.layout import basic_layout
from conan.errors import ConanInvalidConfiguration from conan.errors import ConanInvalidConfiguration
from conan.tools.gnu import Autotools, AutotoolsToolchain from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import VirtualBuildEnv
import os import os
import shlex
class AmneziaXrayBindings(ConanFile): class AmneziaXrayBindings(ConanFile):
name = "amnezia-xray-bindings" name = "amnezia-xray-bindings"
version = "1.1.0" version = "1.1.0"
settings = "os", "arch", "compiler" settings = "os", "arch", "compiler"
_lib_name = "libamnezia_xray.a"
@property @property
def _goos(self): def _goos(self):
@@ -19,15 +23,108 @@ class AmneziaXrayBindings(ConanFile):
"Macos": "darwin", "Macos": "darwin",
"Windows": "windows" "Windows": "windows"
}.get(str(self.settings.os)) }.get(str(self.settings.os))
@property @property
def _goarch(self): def _arch_map(self):
return { return {
"x86": "386", "x86": "386",
"x86_64": "amd64", "x86_64": "amd64",
"armv8": "arm64" "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 @property
def _is_windows(self): def _is_windows(self):
return str(self.settings.os).startswith("Windows") return str(self.settings.os).startswith("Windows")
@@ -54,7 +151,7 @@ class AmneziaXrayBindings(ConanFile):
self.tool_requires("mingw-builds/15.1.0") self.tool_requires("mingw-builds/15.1.0")
def validate(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( raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" 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) sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True)
def generate(self): def generate(self):
VirtualBuildEnv(self).generate()
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
tc.make_args = [ tc.make_args = [
"LIB_ARC=libamnezia_xray.a" "LIB_ARC=libamnezia_xray.a"
] ]
env = tc.environment() env = tc.environment()
env.define("ARCH", self._goarch) self._define_go_cache_env(env)
env.define("GOARCH", self._goarch) 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("GOOS", self._goos)
env.define("CGO_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags)
if self._is_windows: if self._is_windows:
env.define("OS", "windows") env.define("OS", "windows")
tc.generate(env) tc.generate(env)
def build(self): def build(self):
if self._is_universal_macos:
self._build_universal_macos()
return
with chdir(self, self.source_folder): with chdir(self, self.source_folder):
autotools = Autotools(self) autotools = Autotools(self)
autotools.make() autotools.make()
@@ -100,7 +204,10 @@ class AmneziaXrayBindings(ConanFile):
def package(self): def package(self):
copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include")) 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, "*.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")) copy(self, "*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"))
self._rename_header() self._rename_header()
+69 -6
View File
@@ -3,14 +3,17 @@ from conan.errors import ConanInvalidConfiguration
from conan.tools.layout import basic_layout from conan.tools.layout import basic_layout
from conan.tools.files import get, copy from conan.tools.files import get, copy
from conan.tools.gnu import Autotools, AutotoolsToolchain from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import VirtualBuildEnv
import os import os
class AwgGo(ConanFile): class AwgGo(ConanFile):
name = "awg-go" name = "awg-go"
version = "0.2.16" version = "0.2.16"
package_type = "application" package_type = "application"
settings = "os", "arch" settings = "os", "arch"
_binary_name = "amneziawg-go"
@property @property
def _goos(self): def _goos(self):
@@ -21,12 +24,65 @@ class AwgGo(ConanFile):
}.get(str(self.settings.os)) }.get(str(self.settings.os))
@property @property
def _goarch(self): def _arch_map(self):
return { return {
"x86": "386", "x86": "386",
"x86_64": "amd64", "x86_64": "amd64",
"armv8": "arm64" "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): def layout(self):
basic_layout(self, build_folder=".") basic_layout(self, build_folder=".")
@@ -35,7 +91,7 @@ class AwgGo(ConanFile):
self.tool_requires("go/1.26.0") self.tool_requires("go/1.26.0")
def validate(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( raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" 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): def generate(self):
VirtualBuildEnv(self).generate()
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
env = tc.environment() env = tc.environment()
self._define_go_cache_env(env)
env.define("GOOS", self._goos) 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_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags) env.define("CGO_CFLAGS", tc.cflags)
tc.generate(env) tc.generate(env)
def build(self): def build(self):
if self._is_universal_macos:
self._build_universal_macos()
return
at = Autotools(self) at = Autotools(self)
at.make() at.make()
def package(self): 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): def package_info(self):
self.cpp_info.exe = True 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") self.cpp_info.set_property("cmake_target_name", "amnezia::awg-go")
+77 -10
View File
@@ -3,15 +3,17 @@ from conan.tools.layout import basic_layout
from conan.tools.files import get, copy, chdir from conan.tools.files import get, copy, chdir
from conan.errors import ConanInvalidConfiguration from conan.errors import ConanInvalidConfiguration
from conan.tools.gnu import Autotools, AutotoolsToolchain from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import Environment from conan.tools.env import VirtualBuildEnv
import os import os
class Tun2Socks(ConanFile): class Tun2Socks(ConanFile):
name = "tun2socks" name = "tun2socks"
version = "2.6.0" version = "2.6.0"
package_type = "application" package_type = "application"
settings = "os", "arch" settings = "os", "arch"
_binary_name = "tun2socks"
@property @property
def _goos(self): def _goos(self):
@@ -22,17 +24,75 @@ class Tun2Socks(ConanFile):
}.get(str(self.settings.os)) }.get(str(self.settings.os))
@property @property
def _goarch(self): def _arch_map(self):
return { return {
"x86": "386", "x86": "386",
"x86_64": "amd64", "x86_64": "amd64",
"armv8": "arm64" "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 @property
def _is_windows(self): def _is_windows(self):
return str(self.settings.get_safe("os")).startswith("Windows") return str(self.settings.get_safe("os")).startswith("Windows")
@property @property
def _ext(self): def _ext(self):
return ".exe" if self._is_windows else "" return ".exe" if self._is_windows else ""
@@ -41,7 +101,7 @@ class Tun2Socks(ConanFile):
basic_layout(self) basic_layout(self)
def validate(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( raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support {self.settings.os} {self.settings.arch}" 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): def generate(self):
VirtualBuildEnv(self).generate()
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
env = tc.environment() env = tc.environment()
self._define_go_cache_env(env)
env.define("LDFLAGS", "") env.define("LDFLAGS", "")
env.define("CGO_LDFLAGS", tc.ldflags) env.define("CGO_LDFLAGS", tc.ldflags)
env.define("CGO_CFLAGS", tc.cflags) env.define("CGO_CFLAGS", tc.cflags)
env.define("GOOS", self._goos) env.define("GOOS", self._goos)
env.define("GOARCH", self._goarch) if not self._is_universal_macos:
env.define("GOARCH", self._goarch)
tc.generate(env) tc.generate(env)
def build(self): def build(self):
if self._is_universal_macos:
self._build_universal_macos()
return
with chdir(self, self.source_folder): with chdir(self, self.source_folder):
at = Autotools(self) at = Autotools(self)
at.make("tun2socks") at.make(self._binary_name)
def package(self): 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: if self._is_windows:
with chdir(self, self.package_folder): 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): def package_info(self):
self.cpp_info.exe = True self.cpp_info.exe = True