Compare commits

...

9 Commits

Author SHA1 Message Date
spectrum 07b43df2bf Address remaining macOS recipe review comments 2026-05-29 18:34:22 +03:00
spectrum 0a85137d37 Disable Xcode signing for non-NE macOS 2026-05-29 16:31:11 +03:00
spectrum 9b8b716479 Isolate awg-go universal builds 2026-05-29 15:31:39 +03:00
spectrum c9befdfaad Address macOS build review comments 2026-05-29 13:56:19 +03:00
spectrum 6e7925b534 Sign macOS OpenVPN helper script 2026-05-26 15:59:39 +03:00
spectrum cbecca407c Fix macOS universal recipe builds 2026-05-26 15:50:10 +03:00
Yaroslav Gurov 01227fbd72 feat: rework amnezia-xray-bindings for multiarch 2026-05-26 15:27:02 +03:00
Yaroslav Gurov ca54ddcc83 chore: remove parallel thingy from CI/CD 2026-05-26 15:27:02 +03:00
spectrum c62cdf810a Build macOS prebuilts for arm64 and x86_64 2026-05-26 15:27:02 +03:00
5 changed files with 184 additions and 45 deletions
+4
View File
@@ -240,6 +240,10 @@ install(SCRIPT ${QT_DEPLOY_SCRIPT}
if (APPLE AND NOT IOS AND NOT MACOS_NE) if (APPLE AND NOT IOS AND NOT MACOS_NE)
list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/macos/update-resolv-conf.sh") list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/macos/update-resolv-conf.sh")
set_target_properties(${PROJECT} PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO"
XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO"
)
endif() endif()
if (LINUX AND NOT ANDROID) if (LINUX AND NOT ANDROID)
list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/linux/update-resolv-conf.sh") list(APPEND OVPN_SCRIPTS "${CMAKE_SOURCE_DIR}/deploy/data/linux/update-resolv-conf.sh")
+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()
+71 -20
View File
@@ -1,16 +1,27 @@
from conan import ConanFile from conan import ConanFile
from conan.tools.files import get, copy, collect_libs, chdir, rename from conan.tools.files import get, copy, collect_libs, chdir, rename, mkdir
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.apple import XCRun, is_apple_os
from conan.tools.apple.apple import _to_apple_arch
import os import os
import shlex
from pathlib import Path
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"
_arch_map = {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}
@property @property
def _goos(self): def _goos(self):
return { return {
@@ -19,15 +30,15 @@ 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 _archs(self):
return { return str(self.settings.arch).split("|")
"x86": "386",
"x86_64": "amd64", @property
"armv8": "arm64" def _is_multiarch(self):
}.get(str(self.settings.arch)) return len(self._archs) > 1
@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,34 +65,72 @@ 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(arch in self._arch_map for arch in self._archs):
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}"
) )
if self._is_multiarch and not is_apple_os(self):
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} does not support multiarch builds"
)
def source(self): def source(self):
get(self, "https://github.com/amnezia-vpn/amnezia-xray-bindings/archive/v1.1.0.zip", get(self, "https://github.com/amnezia-vpn/amnezia-xray-bindings/archive/v1.1.0.zip",
sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True) sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True)
def generate(self): def generate(self):
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
tc.apple_arch_flag = None
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) env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOARCH", self._goarch) env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
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")
self._ldflags = tc.ldflags
self._cflags = tc.cflags
tc.generate(env) tc.generate(env)
def build(self): def build(self):
with chdir(self, self.source_folder): with chdir(self, self.source_folder):
autotools = Autotools(self) for arch in self._archs:
autotools.make() cflags = list(self._cflags)
ldflags = list(self._ldflags)
if is_apple_os(self):
cflags.append(f"-arch {_to_apple_arch(arch)}")
ldflags.append(f"-arch {_to_apple_arch(arch)}")
autotools = Autotools(self)
autotools.make(args=[
f"BUILD_DIR={os.path.join('build', arch)}",
f"ARCH={self._arch_map.get(arch)}",
f"CGO_CFLAGS={shlex.quote(' '.join(cflags))}",
f"CGO_LDFLAGS={shlex.quote(' '.join(ldflags))}"
])
if is_apple_os(self) and self._is_multiarch:
merged_dir = os.path.join(self.source_folder, "merged")
archives = sorted(
str(path) for path in Path(self.source_folder).glob("build/*/*.a")
)
if not archives:
raise ConanInvalidConfiguration(
f"{self.name} v{self.version} did not produce archives for {self.settings.arch}"
)
output = os.path.join(merged_dir, Path(archives[0]).name)
mkdir(self, merged_dir)
lipo = XCRun(self).find('lipo')
self.run("{} -create -output {} {}".format(
shlex.quote(lipo),
shlex.quote(output),
" ".join(shlex.quote(archive) for archive in archives)
))
def _rename_header(self): def _rename_header(self):
if not self._is_windows: if not self._is_windows:
@@ -99,10 +148,12 @@ class AmneziaXrayBindings(ConanFile):
os.rename(src, dst) os.rename(src, dst)
def package(self): def package(self):
copy(self, "*.h", src=self.build_folder, dst=os.path.join(self.package_folder, "include")) header_src = os.path.join(self.source_folder, "build", self._archs[0])
copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) lib_src = os.path.join(self.source_folder, "merged") if self._is_multiarch else header_src
copy(self, "*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib")) copy(self, "*.h", src=header_src, dst=os.path.join(self.package_folder, "include"), keep_path=False)
copy(self, "*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin")) copy(self, "*.a", src=lib_src, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.lib", src=lib_src, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.dll", src=lib_src, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
self._rename_header() self._rename_header()
def package_info(self): def package_info(self):
+58 -9
View File
@@ -1,16 +1,20 @@
from conan import ConanFile from conan import ConanFile
from conan.errors import ConanInvalidConfiguration 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, chdir
from conan.tools.apple import XCRun
from conan.tools.gnu import Autotools, AutotoolsToolchain from conan.tools.gnu import Autotools, AutotoolsToolchain
import os import os
import shlex
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 +25,29 @@ 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
def layout(self): def layout(self):
basic_layout(self, build_folder=".") basic_layout(self, build_folder=".")
@@ -35,7 +56,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 (len(self._archs) > 1 and not self._is_universal_macos):
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}"
) )
@@ -48,20 +69,48 @@ class AwgGo(ConanFile):
def generate(self): def generate(self):
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
env = tc.environment() env = tc.environment()
env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
env.define("GOTELEMETRY", "off")
env.define("GOOS", self._goos) env.define("GOOS", self._goos)
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):
at = Autotools(self) outputs = []
at.make() with chdir(self, self.source_folder):
for goarch in self._goarchs:
arch_destdir = os.path.join(self.build_folder, f"build-{goarch}")
at = Autotools(self)
at.make("clean")
at.make("install", args=[
f"DESTDIR={shlex.quote(arch_destdir)}",
"BINDIR=",
f"GOARCH={goarch}",
])
output_path = os.path.join(arch_destdir, self._binary_name)
arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}")
os.rename(output_path, arch_output_path)
outputs.append(arch_output_path)
output = os.path.join(self.build_folder, self._binary_name)
if self._is_universal_macos:
lipo = XCRun(self).find("lipo")
self.run("{} -create {} -output {}".format(
shlex.quote(lipo),
" ".join(shlex.quote(output) for output in outputs),
shlex.quote(output)
))
return
os.rename(outputs[0], output)
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")
+50 -15
View File
@@ -2,16 +2,24 @@ from conan import ConanFile
from conan.tools.layout import basic_layout 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.apple import XCRun
from conan.tools.gnu import Autotools, AutotoolsToolchain from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import Environment
import os import os
import shlex
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"
_arch_map = {
"x86": "386",
"x86_64": "amd64",
"armv8": "arm64"
}
@property @property
def _goos(self): def _goos(self):
@@ -22,17 +30,21 @@ class Tun2Socks(ConanFile):
}.get(str(self.settings.os)) }.get(str(self.settings.os))
@property @property
def _goarch(self): def _archs(self):
return { return str(self.settings.arch).split("|")
"x86": "386",
"x86_64": "amd64", @property
"armv8": "arm64" def _goarchs(self):
}.get(str(self.settings.arch)) 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 @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 +53,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 (len(self._archs) > 1 and not self._is_universal_macos):
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}"
) )
@@ -66,23 +78,46 @@ class Tun2Socks(ConanFile):
def generate(self): def generate(self):
tc = AutotoolsToolchain(self) tc = AutotoolsToolchain(self)
env = tc.environment() env = tc.environment()
env.define("GOPATH", os.path.join(self.build_folder, "gopath"))
env.define("GOMODCACHE", os.path.join(self.build_folder, "gopath", "pkg", "mod"))
env.define("GOCACHE", os.path.join(self.build_folder, "gocache"))
env.define("GOTELEMETRY", "off")
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)
tc.generate(env) tc.generate(env)
def build(self): def build(self):
outputs = []
with chdir(self, self.source_folder): with chdir(self, self.source_folder):
at = Autotools(self) for goarch in self._goarchs:
at.make("tun2socks") target = f"{self._goos}-{goarch}"
at = Autotools(self)
at.make(target)
output_ext = ".exe" if self._goos == "windows" else ""
output_path = os.path.join(self.source_folder, "build", f"{self._binary_name}-{target}{output_ext}")
arch_output_path = os.path.join(self.build_folder, f"{self._binary_name}-{goarch}")
os.rename(output_path, arch_output_path)
outputs.append(arch_output_path)
output = os.path.join(self.build_folder, self._binary_name)
if self._is_universal_macos:
lipo = XCRun(self).find("lipo")
self.run("{} -create {} -output {}".format(
shlex.quote(lipo),
" ".join(shlex.quote(output) for output in outputs),
shlex.quote(output)
))
return
os.rename(outputs[0], output)
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