mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-06-15 14:53:11 +03:00
Compare commits
1 Commits
fix/killsw
...
feat/add_s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42cd079017 |
@@ -1,7 +1,13 @@
|
||||
set(CPACK_PACKAGE_VENDOR AmneziaVPN)
|
||||
set(CPACK_PACKAGE_VERSION ${AMNEZIAVPN_VERSION})
|
||||
if(WIN32)
|
||||
set(CPACK_PACKAGE_FILE_NAME "AmneziaVPN_${AMNEZIAVPN_VERSION}_windows_x64")
|
||||
if(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64"
|
||||
OR CMAKE_CXX_COMPILER_ARCHITECTURE_ID MATCHES "ARM64|arm64")
|
||||
set(_amnezia_win_arch arm64)
|
||||
else()
|
||||
set(_amnezia_win_arch x64)
|
||||
endif()
|
||||
set(CPACK_PACKAGE_FILE_NAME "AmneziaVPN_${AMNEZIAVPN_VERSION}_windows_${_amnezia_win_arch}")
|
||||
elseif(APPLE AND NOT IOS AND NOT MACOS_NE)
|
||||
set(CPACK_PACKAGE_FILE_NAME "AmneziaVPN_${AMNEZIAVPN_VERSION}_macos_x64")
|
||||
elseif(LINUX AND NOT ANDROID)
|
||||
|
||||
@@ -431,6 +431,12 @@ function(detect_host_profile output_file)
|
||||
string(APPEND profile "build_type=${build_type}\n")
|
||||
endif()
|
||||
|
||||
# OpenSSL ASM on Windows/ARM64 needs clang-cl; disable ASM when building from CMake-Conan.
|
||||
if(os STREQUAL "Windows" AND arch STREQUAL "armv8")
|
||||
string(APPEND profile "\n[options]\n")
|
||||
string(APPEND profile "openssl/*:no_asm=True\n")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED output_file)
|
||||
set(file_name "${CMAKE_BINARY_DIR}/profile")
|
||||
else()
|
||||
|
||||
@@ -7,6 +7,10 @@ find_program(CONAN_COMMAND "conan" REQUIRED
|
||||
file(GLOB_RECURSE LOCAL_RECIPES "${CMAKE_SOURCE_DIR}/recipes/*/conanfile.py")
|
||||
foreach(RECIPE ${LOCAL_RECIPES})
|
||||
get_filename_component(RECIPE_DIR ${RECIPE} DIRECTORY)
|
||||
get_filename_component(RECIPE_NAME ${RECIPE_DIR} NAME)
|
||||
if(RECIPE_NAME MATCHES "^[-_]")
|
||||
continue()
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${CONAN_COMMAND} export ${RECIPE_DIR}
|
||||
)
|
||||
|
||||
11
conanfile.py
11
conanfile.py
@@ -11,6 +11,12 @@ class AmneziaVPN(ConanFile):
|
||||
"macos_ne": False
|
||||
}
|
||||
|
||||
def configure(self):
|
||||
# OpenSSL 3.x ASM on Windows/ARM64 needs clang-cl (VS "C++ Clang tools").
|
||||
# Without it, nmake fails on *.asm; pure C build is fine for the client.
|
||||
if str(self.settings.os) == "Windows" and str(self.settings.arch) == "armv8":
|
||||
self.options["openssl/*"].no_asm = True
|
||||
|
||||
def requirements(self):
|
||||
os = str(self.settings.os)
|
||||
|
||||
@@ -43,5 +49,8 @@ class AmneziaVPN(ConanFile):
|
||||
|
||||
# expicitly use libssh@amnezia to prevent it from being downloaded from conan-center
|
||||
self.requires("libssh/0.11.3@amnezia")
|
||||
self.requires("openssl/3.6.1")
|
||||
if str(self.settings.os) == "Windows" and str(self.settings.arch) == "armv8":
|
||||
self.requires("openssl/3.6.1", options={"no_asm": True})
|
||||
else:
|
||||
self.requires("openssl/3.6.1")
|
||||
self.requires("zlib/1.3.2")
|
||||
|
||||
@@ -22,11 +22,13 @@ if /i "%ARCH%" == "x64" set "ARCH=amd64"
|
||||
if /i "%ARCH%" == "amd64" (
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "_vcvars_arg=amd64"
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "x86" set "_vcvars_arg=x86_amd64"
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "ARM64" set "_vcvars_arg=arm64_x64"
|
||||
set "_qt_postfix_arg=64"
|
||||
)
|
||||
if /i "%ARCH%" == "arm64" (
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "AMD64" set "_vcvars_arg=amd64_arm64"
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "x86" set "_vcvars_arg=x86_arm64"
|
||||
if /i "%PROCESSOR_ARCHITECTURE%" == "ARM64" set "_vcvars_arg=arm64"
|
||||
set "_qt_postfix_arg=arm64"
|
||||
)
|
||||
if not defined _vcvars_arg (
|
||||
@@ -94,8 +96,13 @@ if exist "%VCVARS_PATH%" (
|
||||
)
|
||||
|
||||
:: build project and installers
|
||||
if /i "%_qt_postfix_arg%" == "arm64" (
|
||||
set "_cmake_arch=-A ARM64"
|
||||
) else (
|
||||
set "_cmake_arch=-A x64"
|
||||
)
|
||||
@echo on
|
||||
cmake -S "%PROJECT_DIR%" -B "%BUILD_DIR%" -DCMAKE_BUILD_TYPE=Release "-DCMAKE_PREFIX_PATH=%QT_ROOT_PATH%\msvc2022_%_qt_postfix_arg%" "-DCMAKE_VS_GLOBALS=UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true" || goto :fail
|
||||
cmake -S "%PROJECT_DIR%" -B "%BUILD_DIR%" -DCMAKE_BUILD_TYPE=Release %_cmake_arch% "-DCMAKE_PREFIX_PATH=%QT_ROOT_PATH%\msvc2022_%_qt_postfix_arg%" "-DCMAKE_VS_GLOBALS=UseMultiToolTask=true;EnforceProcessCountAcrossBuilds=true" || goto :fail
|
||||
cmake --build "%BUILD_DIR%" --config Release -- /m || goto :fail
|
||||
@echo off
|
||||
for %%I in (%ARG_BUILD_INSTALLERS%) do (
|
||||
|
||||
BIN
recipes/_helpers/__pycache__/windows_cgo.cpython-312.pyc
Normal file
BIN
recipes/_helpers/__pycache__/windows_cgo.cpython-312.pyc
Normal file
Binary file not shown.
115
recipes/_helpers/cgo_cc.py
Normal file
115
recipes/_helpers/cgo_cc.py
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CGO compiler shim: clang-cl if present, otherwise MSVC cl with GCC-flag filtering."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def _vs_install() -> str | None:
|
||||
pf = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(pf, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
return None
|
||||
r = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return None
|
||||
return r.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _find_clang_cl() -> str | None:
|
||||
install = _vs_install()
|
||||
if not install:
|
||||
return None
|
||||
llvm = os.path.join(install, "VC", "Tools", "Llvm")
|
||||
if not os.path.isdir(llvm):
|
||||
return None
|
||||
preferred: list[str] = []
|
||||
fallback: list[str] = []
|
||||
for root, _, files in os.walk(llvm):
|
||||
if "clang-cl.exe" not in files:
|
||||
continue
|
||||
path = os.path.join(root, "clang-cl.exe")
|
||||
if "arm64" in root.lower():
|
||||
preferred.append(path)
|
||||
else:
|
||||
fallback.append(path)
|
||||
if preferred:
|
||||
return preferred[0]
|
||||
if fallback:
|
||||
return fallback[0]
|
||||
direct = os.path.join(llvm, "bin", "clang-cl.exe")
|
||||
return direct if os.path.isfile(direct) else None
|
||||
|
||||
|
||||
def _gcc_args_to_msvc(args: list[str]) -> list[str]:
|
||||
out: list[str] = []
|
||||
i = 0
|
||||
while i < len(args):
|
||||
a = args[i]
|
||||
if a == "-x" and i + 1 < len(args):
|
||||
i += 2
|
||||
continue
|
||||
if a == "-o" and i + 1 < len(args):
|
||||
obj = args[i + 1]
|
||||
if obj.endswith((".o", ".obj")):
|
||||
out.append("/Fo" + obj)
|
||||
else:
|
||||
out.append("/Fe" + obj)
|
||||
i += 2
|
||||
continue
|
||||
if a.startswith("-W") or a.startswith("-f") or a.startswith("-d"):
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-m") or a.startswith("-std=") or a in ("-pthread",):
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O2":
|
||||
out.append("/O2")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O0":
|
||||
out.append("/Od")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-g":
|
||||
out.append("/Zi")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-c":
|
||||
out.append("/c")
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-D"):
|
||||
out.append("/D" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-I"):
|
||||
out.append("/I" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if not a.startswith("-"):
|
||||
out.append(a)
|
||||
i += 1
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = sys.argv[1:]
|
||||
clang = _find_clang_cl()
|
||||
if clang:
|
||||
return subprocess.call([clang, *args])
|
||||
|
||||
msvc = _gcc_args_to_msvc(args)
|
||||
return subprocess.call(["cl", *msvc])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
198
recipes/_helpers/windows_cgo.py
Normal file
198
recipes/_helpers/windows_cgo.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""Windows CGO helpers: llvm-mingw for ARM64, MinGW via Conan for x86_64."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
# https://github.com/mstorsjo/llvm-mingw/releases
|
||||
LLVM_MINGW_VERSION = "20260519"
|
||||
LLVM_MINGW_URL = (
|
||||
f"https://github.com/mstorsjo/llvm-mingw/releases/download/"
|
||||
f"{LLVM_MINGW_VERSION}/llvm-mingw-{LLVM_MINGW_VERSION}-ucrt-aarch64.zip"
|
||||
)
|
||||
LLVM_MINGW_SHA256 = "7bb5e3c9964dc29555cababb55e69eea02a51e98e1240eb9513e6540c7bae0ea"
|
||||
|
||||
|
||||
def is_windows_arm64(conanfile) -> bool:
|
||||
return (
|
||||
str(conanfile.settings.get_safe("os", "")).startswith("Windows")
|
||||
and str(conanfile.settings.arch) == "armv8"
|
||||
)
|
||||
|
||||
|
||||
def msvc_machine(arch: str) -> str:
|
||||
return {"x86_64": "X64", "armv8": "ARM64", "x86": "X86"}.get(arch, "ARM64")
|
||||
|
||||
|
||||
def go_tool_exe(conanfile) -> str:
|
||||
go = conanfile.dependencies.build["go"]
|
||||
return os.path.join(go.package_folder, "bin", "go.exe")
|
||||
|
||||
|
||||
def _vs_install_path(conanfile) -> str:
|
||||
program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(program_files_x86, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
raise RuntimeError(f"{conanfile}: vswhere.exe not found at {vswhere}")
|
||||
|
||||
completed = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0 or not completed.stdout.strip():
|
||||
raise RuntimeError(
|
||||
f"{conanfile}: vswhere failed ({completed.returncode}): "
|
||||
f"{completed.stderr or completed.stdout}"
|
||||
)
|
||||
return completed.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _vcvars_ver_flag(conanfile) -> str:
|
||||
version = str(conanfile.settings.get_safe("compiler.version", ""))
|
||||
if not version:
|
||||
return ""
|
||||
minor = {"192": "14.2", "193": "14.3", "194": "14.4", "195": "14.5"}
|
||||
ver = minor.get(version)
|
||||
return f" -vcvars_ver={ver}" if ver else ""
|
||||
|
||||
|
||||
def _vcvars_arch_arg(target_arch: str) -> str:
|
||||
import platform
|
||||
|
||||
host = platform.machine().lower()
|
||||
host_is_arm = host in ("arm64", "aarch64")
|
||||
|
||||
if target_arch == "armv8":
|
||||
return "arm64" if host_is_arm else "amd64_arm64"
|
||||
if target_arch == "x86_64":
|
||||
if host_is_arm:
|
||||
return "arm64_x64"
|
||||
return "amd64" if host in ("amd64", "x86_64") else "x86_amd64"
|
||||
return "arm64" if host_is_arm else "amd64"
|
||||
|
||||
|
||||
def msvc_vcvars_cmd(conanfile) -> str:
|
||||
target_arch = str(conanfile.settings.arch)
|
||||
install_path = _vs_install_path(conanfile)
|
||||
vcvarsall = os.path.join(install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat")
|
||||
arch_arg = _vcvars_arch_arg(target_arch)
|
||||
ver_flag = _vcvars_ver_flag(conanfile)
|
||||
return f'call "{vcvarsall}" {arch_arg}{ver_flag}'
|
||||
|
||||
|
||||
def _find_llvm_mingw_toolchain(root_dir: str) -> tuple[str, str]:
|
||||
gcc_names = (
|
||||
"aarch64-w64-windows-gnu-gcc.exe",
|
||||
"aarch64-w64-mingw32-gcc.exe",
|
||||
)
|
||||
for gcc_name in gcc_names:
|
||||
for root, _, files in os.walk(root_dir):
|
||||
if gcc_name in files:
|
||||
bindir = os.path.join(root, "")
|
||||
return os.path.join(root, gcc_name), bindir
|
||||
|
||||
for root, _, files in os.walk(root_dir):
|
||||
for fname in files:
|
||||
if fname.endswith("-gcc.exe") and "aarch64" in fname:
|
||||
return os.path.join(root, fname), root
|
||||
raise RuntimeError(f"llvm-mingw gcc not found under {root_dir}")
|
||||
|
||||
|
||||
def ensure_llvm_mingw(conanfile) -> tuple[str, str]:
|
||||
"""Download and extract llvm-mingw (UCRT, aarch64). Returns (gcc.exe, bin_dir)."""
|
||||
from conan.tools.files import download, unzip
|
||||
|
||||
dest = os.path.join(conanfile.build_folder, "llvm-mingw")
|
||||
ready = os.path.join(dest, ".extracted")
|
||||
if not os.path.isfile(ready):
|
||||
zip_path = os.path.join(conanfile.build_folder, "llvm-mingw.zip")
|
||||
conanfile.output.info(f"Downloading llvm-mingw {LLVM_MINGW_VERSION} for Windows ARM64 CGO")
|
||||
download(conanfile, LLVM_MINGW_URL, zip_path, sha256=LLVM_MINGW_SHA256)
|
||||
unzip(conanfile, zip_path, dest)
|
||||
with open(ready, "w", encoding="ascii") as marker:
|
||||
marker.write(LLVM_MINGW_VERSION)
|
||||
|
||||
gcc, bindir = _find_llvm_mingw_toolchain(dest)
|
||||
conanfile.output.info(f"CGO compiler: {gcc}")
|
||||
return gcc, bindir
|
||||
|
||||
|
||||
def run_llvm_mingw_go_build(
|
||||
conanfile,
|
||||
src: str,
|
||||
out: str,
|
||||
goarch: str,
|
||||
*,
|
||||
goarm=None,
|
||||
extra_args="-ldflags=-w -buildmode=c-shared",
|
||||
) -> None:
|
||||
"""Build c-shared with llvm-mingw GCC (same approach as other Go Windows/arm64 projects)."""
|
||||
gcc, bindir = ensure_llvm_mingw(conanfile)
|
||||
go = go_tool_exe(conanfile)
|
||||
goarm_set = f"&& set GOARM={goarm}" if goarm else ""
|
||||
bindir_q = bindir.replace('"', '""')
|
||||
gcc_q = gcc.replace('"', '""')
|
||||
conanfile.run(
|
||||
f'set "PATH={bindir_q};%PATH%"&& set CGO_ENABLED=1&& set GOOS=windows&& set GOARCH={goarch}{goarm_set}&& '
|
||||
f'set "CC={gcc_q}"&& set "CXX={gcc_q}"&& '
|
||||
f'"{go}" build -C "{src}" {extra_args} -o "{out}" .',
|
||||
)
|
||||
|
||||
|
||||
def ensure_msvc_import_lib(
|
||||
conanfile,
|
||||
build_dir: str,
|
||||
dll_name: str,
|
||||
base_name: str,
|
||||
) -> None:
|
||||
"""MSVC import library for linking the DLL from the main app (MSVC/Qt)."""
|
||||
lib_path = os.path.join(build_dir, f"{base_name}.lib")
|
||||
if os.path.isfile(lib_path):
|
||||
return
|
||||
|
||||
dll_path = os.path.join(build_dir, dll_name)
|
||||
if not os.path.isfile(dll_path):
|
||||
raise RuntimeError(f"{conanfile}: DLL not found: {dll_path}")
|
||||
|
||||
machine = msvc_machine(str(conanfile.settings.arch))
|
||||
def_path = os.path.join(build_dir, f"{base_name}.def")
|
||||
exports_txt = os.path.join(build_dir, f"{base_name}.exports.txt")
|
||||
vc = msvc_vcvars_cmd(conanfile)
|
||||
|
||||
conanfile.run(f'{vc} && dumpbin /nologo /exports "{dll_path}" > "{exports_txt}"')
|
||||
|
||||
with open(exports_txt, encoding="utf-8", errors="replace") as exports_file:
|
||||
text = exports_file.read()
|
||||
|
||||
exports = []
|
||||
in_table = False
|
||||
for line in text.splitlines():
|
||||
if "ordinal hint RVA" in line:
|
||||
in_table = True
|
||||
continue
|
||||
if not in_table:
|
||||
continue
|
||||
match = re.match(r"\s+\d+\s+[0-9A-Fa-f]+\s+[0-9A-Fa-f]+\s+(\S+)", line)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
if name != "[noname]":
|
||||
exports.append(name)
|
||||
|
||||
if not exports:
|
||||
raise RuntimeError(f"{conanfile}: No exports found in {dll_path}")
|
||||
|
||||
with open(def_path, "w", encoding="ascii") as def_file:
|
||||
def_file.write(f"LIBRARY {base_name}\nEXPORTS\n")
|
||||
for symbol in exports:
|
||||
def_file.write(f" {symbol}\n")
|
||||
|
||||
conanfile.run(
|
||||
f'{vc} && lib /nologo /def:"{def_path}" /out:"{lib_path}" /machine:{machine}',
|
||||
)
|
||||
|
||||
try:
|
||||
os.remove(exports_txt)
|
||||
except OSError:
|
||||
pass
|
||||
115
recipes/amnezia-xray-bindings/cgo_cc.py
Normal file
115
recipes/amnezia-xray-bindings/cgo_cc.py
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CGO compiler shim: clang-cl if present, otherwise MSVC cl with GCC-flag filtering."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def _vs_install() -> str | None:
|
||||
pf = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(pf, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
return None
|
||||
r = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return None
|
||||
return r.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _find_clang_cl() -> str | None:
|
||||
install = _vs_install()
|
||||
if not install:
|
||||
return None
|
||||
llvm = os.path.join(install, "VC", "Tools", "Llvm")
|
||||
if not os.path.isdir(llvm):
|
||||
return None
|
||||
preferred: list[str] = []
|
||||
fallback: list[str] = []
|
||||
for root, _, files in os.walk(llvm):
|
||||
if "clang-cl.exe" not in files:
|
||||
continue
|
||||
path = os.path.join(root, "clang-cl.exe")
|
||||
if "arm64" in root.lower():
|
||||
preferred.append(path)
|
||||
else:
|
||||
fallback.append(path)
|
||||
if preferred:
|
||||
return preferred[0]
|
||||
if fallback:
|
||||
return fallback[0]
|
||||
direct = os.path.join(llvm, "bin", "clang-cl.exe")
|
||||
return direct if os.path.isfile(direct) else None
|
||||
|
||||
|
||||
def _gcc_args_to_msvc(args: list[str]) -> list[str]:
|
||||
out: list[str] = []
|
||||
i = 0
|
||||
while i < len(args):
|
||||
a = args[i]
|
||||
if a == "-x" and i + 1 < len(args):
|
||||
i += 2
|
||||
continue
|
||||
if a == "-o" and i + 1 < len(args):
|
||||
obj = args[i + 1]
|
||||
if obj.endswith((".o", ".obj")):
|
||||
out.append("/Fo" + obj)
|
||||
else:
|
||||
out.append("/Fe" + obj)
|
||||
i += 2
|
||||
continue
|
||||
if a.startswith("-W") or a.startswith("-f") or a.startswith("-d"):
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-m") or a.startswith("-std=") or a in ("-pthread",):
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O2":
|
||||
out.append("/O2")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O0":
|
||||
out.append("/Od")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-g":
|
||||
out.append("/Zi")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-c":
|
||||
out.append("/c")
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-D"):
|
||||
out.append("/D" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-I"):
|
||||
out.append("/I" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if not a.startswith("-"):
|
||||
out.append(a)
|
||||
i += 1
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = sys.argv[1:]
|
||||
clang = _find_clang_cl()
|
||||
if clang:
|
||||
return subprocess.call([clang, *args])
|
||||
|
||||
msvc = _gcc_args_to_msvc(args)
|
||||
return subprocess.call(["cl", *msvc])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
37
recipes/amnezia-xray-bindings/cgo_cl_shim.cmd
Normal file
37
recipes/amnezia-xray-bindings/cgo_cl_shim.cmd
Normal file
@@ -0,0 +1,37 @@
|
||||
@echo off
|
||||
REM CGO driver for MSVC cl: drop GCC-only flags (-Werror, -f*, -d*, -m*, etc.).
|
||||
setlocal EnableDelayedExpansion
|
||||
set "_args="
|
||||
:argloop
|
||||
if "%~1"=="" goto invoke
|
||||
set "_a=%~1"
|
||||
if /i "!_a!"=="-Werror" goto next
|
||||
if /i "!_a!"=="-Wall" goto next
|
||||
if /i "!_a!"=="-Wno-error" goto next
|
||||
if "!_a:~0,2!"=="-W" goto next
|
||||
if "!_a:~0,2!"=="-f" goto next
|
||||
if "!_a:~0,2!"=="-d" goto next
|
||||
if "!_a:~0,2!"=="-m" goto next
|
||||
if "!_a:~0,5!"=="-std=" goto next
|
||||
if /i "!_a!"=="-pthread" goto next
|
||||
if /i "!_a!"=="-O2" (set "_args=!_args! /O2") & goto next
|
||||
if /i "!_a!"=="-O0" (set "_args=!_args! /Od") & goto next
|
||||
if /i "!_a!"=="-g" (set "_args=!_args! /Zi") & goto next
|
||||
if /i "!_a!"=="-c" (set "_args=!_args! /c") & goto next
|
||||
if /i "!_a!"=="-x" (shift & goto next)
|
||||
if /i "%~1"=="c" goto next
|
||||
if "!_a:~0,2!"=="-D" (set "_args=!_args! /D!_a:~2!") & goto next
|
||||
if "!_a:~0,2!"=="-I" (set "_args=!_args! /I!_a:~2!") & goto next
|
||||
if /i "!_a!"=="-o" (
|
||||
set "_o=%~2"
|
||||
if /i "!_o:~-2!"==".o" set "_args=!_args! /Fo!_o!"
|
||||
shift
|
||||
goto next
|
||||
)
|
||||
if not "!_a:~0,1!"=="-" set "_args=!_args! "!_a!""
|
||||
:next
|
||||
shift
|
||||
goto argloop
|
||||
:invoke
|
||||
cl !_args!
|
||||
exit /b !ERRORLEVEL!
|
||||
@@ -3,13 +3,23 @@ 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 sys
|
||||
|
||||
_recipe_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if _recipe_dir not in sys.path:
|
||||
sys.path.insert(0, _recipe_dir)
|
||||
|
||||
from windows_cgo import ensure_msvc_import_lib, is_windows_arm64, run_llvm_mingw_go_build
|
||||
|
||||
|
||||
class AmneziaXrayBindings(ConanFile):
|
||||
name = "amnezia-xray-bindings"
|
||||
version = "1.1.0"
|
||||
settings = "os", "arch", "compiler"
|
||||
exports = "windows_cgo.py"
|
||||
|
||||
@property
|
||||
def _goos(self):
|
||||
@@ -19,7 +29,7 @@ class AmneziaXrayBindings(ConanFile):
|
||||
"Macos": "darwin",
|
||||
"Windows": "windows"
|
||||
}.get(str(self.settings.os))
|
||||
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
return {
|
||||
@@ -27,19 +37,23 @@ class AmneziaXrayBindings(ConanFile):
|
||||
"x86_64": "amd64",
|
||||
"armv8": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
|
||||
@property
|
||||
def _is_windows(self):
|
||||
return str(self.settings.os).startswith("Windows")
|
||||
|
||||
@property
|
||||
def _windows_arm64(self):
|
||||
return is_windows_arm64(self)
|
||||
|
||||
def config_options(self):
|
||||
self.package_type = "shared-library" if self._is_windows else "static-library"
|
||||
|
||||
def configure(self):
|
||||
self.settings.rm_safe("compiler.libcxx")
|
||||
self.settings.rm_safe("compiler.cppstd")
|
||||
if self._is_windows:
|
||||
# mingw-builds is being used on Windows
|
||||
# Keep compiler settings on Windows ARM64 so VCVars can expose cl/link to CGO.
|
||||
if self._is_windows and str(self.settings.arch) != "armv8":
|
||||
del self.settings.compiler
|
||||
|
||||
def layout(self):
|
||||
@@ -47,10 +61,8 @@ class AmneziaXrayBindings(ConanFile):
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("go/1.26.0")
|
||||
if self._is_windows:
|
||||
self.win_bash = True
|
||||
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
|
||||
self.tool_requires("msys2/cci.latest")
|
||||
if self._is_windows and not self._windows_arm64:
|
||||
# x86/x64: MinGW gendef + dlltool for import libraries.
|
||||
self.tool_requires("mingw-builds/15.1.0")
|
||||
|
||||
def validate(self):
|
||||
@@ -64,33 +76,86 @@ class AmneziaXrayBindings(ConanFile):
|
||||
sha256="6ea768ec7002cedd422a39aea17704b888acaf794432aa5937cfc92fb6d80eb5", strip_root=True)
|
||||
|
||||
def generate(self):
|
||||
# Go + (MinGW or MSVC) on PATH for all Windows/Linux variants.
|
||||
VirtualBuildEnv(self).generate()
|
||||
|
||||
if self._is_windows and self._windows_arm64:
|
||||
# MSVC CGO: activate vcvars only in build() (see run_msvc_go_build).
|
||||
return
|
||||
|
||||
tc = AutotoolsToolchain(self)
|
||||
tc.make_args = [
|
||||
"LIB_ARC=libamnezia_xray.a"
|
||||
]
|
||||
if not self._is_windows:
|
||||
tc.make_args = [
|
||||
"LIB_ARC=libamnezia_xray.a"
|
||||
]
|
||||
env = tc.environment()
|
||||
env.define("ARCH", self._goarch)
|
||||
env.define("GOARCH", self._goarch)
|
||||
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")
|
||||
env.define("CGO_ENABLED", "1")
|
||||
env.define("CGO_LDFLAGS", tc.ldflags)
|
||||
env.define("CGO_CFLAGS", tc.cflags)
|
||||
else:
|
||||
env.define("CGO_LDFLAGS", tc.ldflags)
|
||||
env.define("CGO_CFLAGS", tc.cflags)
|
||||
tc.generate(env)
|
||||
|
||||
def build(self):
|
||||
if self._is_windows:
|
||||
self._build_windows_native()
|
||||
return
|
||||
with chdir(self, self.source_folder):
|
||||
autotools = Autotools(self)
|
||||
autotools.make()
|
||||
|
||||
@property
|
||||
def _windows_artifact_dir(self):
|
||||
"""Keep Windows outputs under build_folder (not source_folder/llvm-mingw tree)."""
|
||||
return os.path.join(self.build_folder, "build")
|
||||
|
||||
def _build_windows_native(self):
|
||||
"""
|
||||
Windows: c-shared DLL. x86_64 uses MinGW gendef + dlltool; ARM64 uses llvm-mingw CGO.
|
||||
"""
|
||||
src = self.source_folder
|
||||
bdir = self._windows_artifact_dir
|
||||
os.makedirs(bdir, exist_ok=True)
|
||||
dll_name = "amnezia_xray.dll"
|
||||
dll_path = os.path.join(bdir, dll_name)
|
||||
|
||||
if self._windows_arm64:
|
||||
run_llvm_mingw_go_build(self, src, dll_path, self._goarch)
|
||||
ensure_msvc_import_lib(self, bdir, dll_name, "amnezia_xray")
|
||||
else:
|
||||
self.run(
|
||||
f'cd /d "{src}" && go build -ldflags=-w -o "{dll_path}" -buildmode=c-shared .',
|
||||
env="conanbuild",
|
||||
)
|
||||
if not self._windows_arm64:
|
||||
self.run(
|
||||
f'cd /d "{bdir}" && gendef {dll_name}',
|
||||
env="conanbuild",
|
||||
)
|
||||
self.run(
|
||||
f'cd /d "{bdir}" && dlltool -d amnezia_xray.def -l amnezia_xray.lib -D {dll_name}',
|
||||
env="conanbuild",
|
||||
)
|
||||
|
||||
def_path = os.path.join(bdir, "amnezia_xray.def")
|
||||
try:
|
||||
if os.path.isfile(def_path):
|
||||
os.remove(def_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _rename_header(self):
|
||||
if not self._is_windows:
|
||||
rename(self, os.path.join(self.package_folder, "include", "libamnezia_xray.h"),
|
||||
os.path.join(self.package_folder, "include", "amnezia_xray.h"))
|
||||
os.path.join(self.package_folder, "include", "amnezia_xray.h"))
|
||||
|
||||
def _rename_libs(self):
|
||||
# workaround of bad naming strategy in amnezia-xray-bindings
|
||||
# TODO: change it and kick out the code below
|
||||
lib_dir = os.path.join(self.package_folder, "lib")
|
||||
for fname in os.listdir(lib_dir):
|
||||
if not fname.startswith("lib"):
|
||||
@@ -99,12 +164,23 @@ class AmneziaXrayBindings(ConanFile):
|
||||
os.rename(src, dst)
|
||||
|
||||
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"))
|
||||
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"))
|
||||
if self._is_windows:
|
||||
art = self._windows_artifact_dir
|
||||
else:
|
||||
art = os.path.join(self.build_folder, "build")
|
||||
if not os.path.isdir(art):
|
||||
art = self.build_folder
|
||||
copy(self, "*.h", src=art, dst=os.path.join(self.package_folder, "include"), keep_path=False)
|
||||
copy(self, "*.a", src=art, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
|
||||
copy(self, "*.lib", src=art, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
|
||||
copy(self, "*.dll", src=art, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
|
||||
self._rename_header()
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.set_property("cmake_target_name", "amnezia::xray-bindings")
|
||||
self.cpp_info.libs = collect_libs(self)
|
||||
if self._is_windows:
|
||||
self.cpp_info.libs = ["amnezia_xray"]
|
||||
self.cpp_info.libdirs = ["lib"]
|
||||
self.cpp_info.bindirs = ["bin"]
|
||||
else:
|
||||
self.cpp_info.libs = collect_libs(self)
|
||||
|
||||
198
recipes/amnezia-xray-bindings/windows_cgo.py
Normal file
198
recipes/amnezia-xray-bindings/windows_cgo.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""Windows CGO helpers: llvm-mingw for ARM64, MinGW via Conan for x86_64."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
# https://github.com/mstorsjo/llvm-mingw/releases
|
||||
LLVM_MINGW_VERSION = "20260519"
|
||||
LLVM_MINGW_URL = (
|
||||
f"https://github.com/mstorsjo/llvm-mingw/releases/download/"
|
||||
f"{LLVM_MINGW_VERSION}/llvm-mingw-{LLVM_MINGW_VERSION}-ucrt-aarch64.zip"
|
||||
)
|
||||
LLVM_MINGW_SHA256 = "7bb5e3c9964dc29555cababb55e69eea02a51e98e1240eb9513e6540c7bae0ea"
|
||||
|
||||
|
||||
def is_windows_arm64(conanfile) -> bool:
|
||||
return (
|
||||
str(conanfile.settings.get_safe("os", "")).startswith("Windows")
|
||||
and str(conanfile.settings.arch) == "armv8"
|
||||
)
|
||||
|
||||
|
||||
def msvc_machine(arch: str) -> str:
|
||||
return {"x86_64": "X64", "armv8": "ARM64", "x86": "X86"}.get(arch, "ARM64")
|
||||
|
||||
|
||||
def go_tool_exe(conanfile) -> str:
|
||||
go = conanfile.dependencies.build["go"]
|
||||
return os.path.join(go.package_folder, "bin", "go.exe")
|
||||
|
||||
|
||||
def _vs_install_path(conanfile) -> str:
|
||||
program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(program_files_x86, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
raise RuntimeError(f"{conanfile}: vswhere.exe not found at {vswhere}")
|
||||
|
||||
completed = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0 or not completed.stdout.strip():
|
||||
raise RuntimeError(
|
||||
f"{conanfile}: vswhere failed ({completed.returncode}): "
|
||||
f"{completed.stderr or completed.stdout}"
|
||||
)
|
||||
return completed.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _vcvars_ver_flag(conanfile) -> str:
|
||||
version = str(conanfile.settings.get_safe("compiler.version", ""))
|
||||
if not version:
|
||||
return ""
|
||||
minor = {"192": "14.2", "193": "14.3", "194": "14.4", "195": "14.5"}
|
||||
ver = minor.get(version)
|
||||
return f" -vcvars_ver={ver}" if ver else ""
|
||||
|
||||
|
||||
def _vcvars_arch_arg(target_arch: str) -> str:
|
||||
import platform
|
||||
|
||||
host = platform.machine().lower()
|
||||
host_is_arm = host in ("arm64", "aarch64")
|
||||
|
||||
if target_arch == "armv8":
|
||||
return "arm64" if host_is_arm else "amd64_arm64"
|
||||
if target_arch == "x86_64":
|
||||
if host_is_arm:
|
||||
return "arm64_x64"
|
||||
return "amd64" if host in ("amd64", "x86_64") else "x86_amd64"
|
||||
return "arm64" if host_is_arm else "amd64"
|
||||
|
||||
|
||||
def msvc_vcvars_cmd(conanfile) -> str:
|
||||
target_arch = str(conanfile.settings.arch)
|
||||
install_path = _vs_install_path(conanfile)
|
||||
vcvarsall = os.path.join(install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat")
|
||||
arch_arg = _vcvars_arch_arg(target_arch)
|
||||
ver_flag = _vcvars_ver_flag(conanfile)
|
||||
return f'call "{vcvarsall}" {arch_arg}{ver_flag}'
|
||||
|
||||
|
||||
def _find_llvm_mingw_toolchain(root_dir: str) -> tuple[str, str]:
|
||||
gcc_names = (
|
||||
"aarch64-w64-windows-gnu-gcc.exe",
|
||||
"aarch64-w64-mingw32-gcc.exe",
|
||||
)
|
||||
for gcc_name in gcc_names:
|
||||
for root, _, files in os.walk(root_dir):
|
||||
if gcc_name in files:
|
||||
bindir = os.path.join(root, "")
|
||||
return os.path.join(root, gcc_name), bindir
|
||||
|
||||
for root, _, files in os.walk(root_dir):
|
||||
for fname in files:
|
||||
if fname.endswith("-gcc.exe") and "aarch64" in fname:
|
||||
return os.path.join(root, fname), root
|
||||
raise RuntimeError(f"llvm-mingw gcc not found under {root_dir}")
|
||||
|
||||
|
||||
def ensure_llvm_mingw(conanfile) -> tuple[str, str]:
|
||||
"""Download and extract llvm-mingw (UCRT, aarch64). Returns (gcc.exe, bin_dir)."""
|
||||
from conan.tools.files import download, unzip
|
||||
|
||||
dest = os.path.join(conanfile.build_folder, "llvm-mingw")
|
||||
ready = os.path.join(dest, ".extracted")
|
||||
if not os.path.isfile(ready):
|
||||
zip_path = os.path.join(conanfile.build_folder, "llvm-mingw.zip")
|
||||
conanfile.output.info(f"Downloading llvm-mingw {LLVM_MINGW_VERSION} for Windows ARM64 CGO")
|
||||
download(conanfile, LLVM_MINGW_URL, zip_path, sha256=LLVM_MINGW_SHA256)
|
||||
unzip(conanfile, zip_path, dest)
|
||||
with open(ready, "w", encoding="ascii") as marker:
|
||||
marker.write(LLVM_MINGW_VERSION)
|
||||
|
||||
gcc, bindir = _find_llvm_mingw_toolchain(dest)
|
||||
conanfile.output.info(f"CGO compiler: {gcc}")
|
||||
return gcc, bindir
|
||||
|
||||
|
||||
def run_llvm_mingw_go_build(
|
||||
conanfile,
|
||||
src: str,
|
||||
out: str,
|
||||
goarch: str,
|
||||
*,
|
||||
goarm=None,
|
||||
extra_args="-ldflags=-w -buildmode=c-shared",
|
||||
) -> None:
|
||||
"""Build c-shared with llvm-mingw GCC (same approach as other Go Windows/arm64 projects)."""
|
||||
gcc, bindir = ensure_llvm_mingw(conanfile)
|
||||
go = go_tool_exe(conanfile)
|
||||
goarm_set = f"&& set GOARM={goarm}" if goarm else ""
|
||||
bindir_q = bindir.replace('"', '""')
|
||||
gcc_q = gcc.replace('"', '""')
|
||||
conanfile.run(
|
||||
f'set "PATH={bindir_q};%PATH%"&& set CGO_ENABLED=1&& set GOOS=windows&& set GOARCH={goarch}{goarm_set}&& '
|
||||
f'set "CC={gcc_q}"&& set "CXX={gcc_q}"&& '
|
||||
f'"{go}" build -C "{src}" {extra_args} -o "{out}" .',
|
||||
)
|
||||
|
||||
|
||||
def ensure_msvc_import_lib(
|
||||
conanfile,
|
||||
build_dir: str,
|
||||
dll_name: str,
|
||||
base_name: str,
|
||||
) -> None:
|
||||
"""MSVC import library for linking the DLL from the main app (MSVC/Qt)."""
|
||||
lib_path = os.path.join(build_dir, f"{base_name}.lib")
|
||||
if os.path.isfile(lib_path):
|
||||
return
|
||||
|
||||
dll_path = os.path.join(build_dir, dll_name)
|
||||
if not os.path.isfile(dll_path):
|
||||
raise RuntimeError(f"{conanfile}: DLL not found: {dll_path}")
|
||||
|
||||
machine = msvc_machine(str(conanfile.settings.arch))
|
||||
def_path = os.path.join(build_dir, f"{base_name}.def")
|
||||
exports_txt = os.path.join(build_dir, f"{base_name}.exports.txt")
|
||||
vc = msvc_vcvars_cmd(conanfile)
|
||||
|
||||
conanfile.run(f'{vc} && dumpbin /nologo /exports "{dll_path}" > "{exports_txt}"')
|
||||
|
||||
with open(exports_txt, encoding="utf-8", errors="replace") as exports_file:
|
||||
text = exports_file.read()
|
||||
|
||||
exports = []
|
||||
in_table = False
|
||||
for line in text.splitlines():
|
||||
if "ordinal hint RVA" in line:
|
||||
in_table = True
|
||||
continue
|
||||
if not in_table:
|
||||
continue
|
||||
match = re.match(r"\s+\d+\s+[0-9A-Fa-f]+\s+[0-9A-Fa-f]+\s+(\S+)", line)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
if name != "[noname]":
|
||||
exports.append(name)
|
||||
|
||||
if not exports:
|
||||
raise RuntimeError(f"{conanfile}: No exports found in {dll_path}")
|
||||
|
||||
with open(def_path, "w", encoding="ascii") as def_file:
|
||||
def_file.write(f"LIBRARY {base_name}\nEXPORTS\n")
|
||||
for symbol in exports:
|
||||
def_file.write(f" {symbol}\n")
|
||||
|
||||
conanfile.run(
|
||||
f'{vc} && lib /nologo /def:"{def_path}" /out:"{lib_path}" /machine:{machine}',
|
||||
)
|
||||
|
||||
try:
|
||||
os.remove(exports_txt)
|
||||
except OSError:
|
||||
pass
|
||||
115
recipes/awg-windows/cgo_cc.py
Normal file
115
recipes/awg-windows/cgo_cc.py
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CGO compiler shim: clang-cl if present, otherwise MSVC cl with GCC-flag filtering."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def _vs_install() -> str | None:
|
||||
pf = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(pf, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
return None
|
||||
r = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if r.returncode != 0 or not r.stdout.strip():
|
||||
return None
|
||||
return r.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _find_clang_cl() -> str | None:
|
||||
install = _vs_install()
|
||||
if not install:
|
||||
return None
|
||||
llvm = os.path.join(install, "VC", "Tools", "Llvm")
|
||||
if not os.path.isdir(llvm):
|
||||
return None
|
||||
preferred: list[str] = []
|
||||
fallback: list[str] = []
|
||||
for root, _, files in os.walk(llvm):
|
||||
if "clang-cl.exe" not in files:
|
||||
continue
|
||||
path = os.path.join(root, "clang-cl.exe")
|
||||
if "arm64" in root.lower():
|
||||
preferred.append(path)
|
||||
else:
|
||||
fallback.append(path)
|
||||
if preferred:
|
||||
return preferred[0]
|
||||
if fallback:
|
||||
return fallback[0]
|
||||
direct = os.path.join(llvm, "bin", "clang-cl.exe")
|
||||
return direct if os.path.isfile(direct) else None
|
||||
|
||||
|
||||
def _gcc_args_to_msvc(args: list[str]) -> list[str]:
|
||||
out: list[str] = []
|
||||
i = 0
|
||||
while i < len(args):
|
||||
a = args[i]
|
||||
if a == "-x" and i + 1 < len(args):
|
||||
i += 2
|
||||
continue
|
||||
if a == "-o" and i + 1 < len(args):
|
||||
obj = args[i + 1]
|
||||
if obj.endswith((".o", ".obj")):
|
||||
out.append("/Fo" + obj)
|
||||
else:
|
||||
out.append("/Fe" + obj)
|
||||
i += 2
|
||||
continue
|
||||
if a.startswith("-W") or a.startswith("-f") or a.startswith("-d"):
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-m") or a.startswith("-std=") or a in ("-pthread",):
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O2":
|
||||
out.append("/O2")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-O0":
|
||||
out.append("/Od")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-g":
|
||||
out.append("/Zi")
|
||||
i += 1
|
||||
continue
|
||||
if a == "-c":
|
||||
out.append("/c")
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-D"):
|
||||
out.append("/D" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if a.startswith("-I"):
|
||||
out.append("/I" + a[2:])
|
||||
i += 1
|
||||
continue
|
||||
if not a.startswith("-"):
|
||||
out.append(a)
|
||||
i += 1
|
||||
return out
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = sys.argv[1:]
|
||||
clang = _find_clang_cl()
|
||||
if clang:
|
||||
return subprocess.call([clang, *args])
|
||||
|
||||
msvc = _gcc_args_to_msvc(args)
|
||||
return subprocess.call(["cl", *msvc])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
37
recipes/awg-windows/cgo_cl_shim.cmd
Normal file
37
recipes/awg-windows/cgo_cl_shim.cmd
Normal file
@@ -0,0 +1,37 @@
|
||||
@echo off
|
||||
REM CGO driver for MSVC cl: drop GCC-only flags (-Werror, -f*, -d*, -m*, etc.).
|
||||
setlocal EnableDelayedExpansion
|
||||
set "_args="
|
||||
:argloop
|
||||
if "%~1"=="" goto invoke
|
||||
set "_a=%~1"
|
||||
if /i "!_a!"=="-Werror" goto next
|
||||
if /i "!_a!"=="-Wall" goto next
|
||||
if /i "!_a!"=="-Wno-error" goto next
|
||||
if "!_a:~0,2!"=="-W" goto next
|
||||
if "!_a:~0,2!"=="-f" goto next
|
||||
if "!_a:~0,2!"=="-d" goto next
|
||||
if "!_a:~0,2!"=="-m" goto next
|
||||
if "!_a:~0,5!"=="-std=" goto next
|
||||
if /i "!_a!"=="-pthread" goto next
|
||||
if /i "!_a!"=="-O2" (set "_args=!_args! /O2") & goto next
|
||||
if /i "!_a!"=="-O0" (set "_args=!_args! /Od") & goto next
|
||||
if /i "!_a!"=="-g" (set "_args=!_args! /Zi") & goto next
|
||||
if /i "!_a!"=="-c" (set "_args=!_args! /c") & goto next
|
||||
if /i "!_a!"=="-x" (shift & goto next)
|
||||
if /i "%~1"=="c" goto next
|
||||
if "!_a:~0,2!"=="-D" (set "_args=!_args! /D!_a:~2!") & goto next
|
||||
if "!_a:~0,2!"=="-I" (set "_args=!_args! /I!_a:~2!") & goto next
|
||||
if /i "!_a!"=="-o" (
|
||||
set "_o=%~2"
|
||||
if /i "!_o:~-2!"==".o" set "_args=!_args! /Fo!_o!"
|
||||
shift
|
||||
goto next
|
||||
)
|
||||
if not "!_a:~0,1!"=="-" set "_args=!_args! "!_a!""
|
||||
:next
|
||||
shift
|
||||
goto argloop
|
||||
:invoke
|
||||
cl !_args!
|
||||
exit /b !ERRORLEVEL!
|
||||
@@ -3,13 +3,23 @@ from conan.tools.layout import basic_layout
|
||||
from conan.errors import ConanInvalidConfiguration
|
||||
from conan.tools.files import get, copy, chdir
|
||||
from conan.tools.gnu import AutotoolsToolchain
|
||||
from conan.tools.env import Environment, VirtualBuildEnv
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
_recipe_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
if _recipe_dir not in sys.path:
|
||||
sys.path.insert(0, _recipe_dir)
|
||||
|
||||
from windows_cgo import is_windows_arm64, run_llvm_mingw_go_build
|
||||
|
||||
|
||||
class AwgWindows(ConanFile):
|
||||
name = "awg-windows"
|
||||
version = "0.1.8"
|
||||
settings = "os", "arch"
|
||||
settings = "os", "arch", "compiler", "build_type"
|
||||
exports = "windows_cgo.py"
|
||||
|
||||
@property
|
||||
def _goarm(self):
|
||||
@@ -22,7 +32,7 @@ class AwgWindows(ConanFile):
|
||||
"armv7s": "7",
|
||||
"armv7k": "7",
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
|
||||
@property
|
||||
def _goarch(self):
|
||||
return {
|
||||
@@ -41,9 +51,18 @@ class AwgWindows(ConanFile):
|
||||
"arm64ec": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
@property
|
||||
def _windows_arm64(self):
|
||||
return is_windows_arm64(self)
|
||||
|
||||
def layout(self):
|
||||
basic_layout(self)
|
||||
|
||||
def configure(self):
|
||||
if not self._windows_arm64:
|
||||
self.settings.rm_safe("compiler")
|
||||
self.settings.rm_safe("build_type")
|
||||
|
||||
def validate(self):
|
||||
if not str(self.settings.os).startswith("Windows"):
|
||||
raise ConanInvalidConfiguration(
|
||||
@@ -55,7 +74,8 @@ class AwgWindows(ConanFile):
|
||||
)
|
||||
|
||||
def build_requirements(self):
|
||||
self.tool_requires("mingw-builds/15.1.0")
|
||||
if not self._windows_arm64:
|
||||
self.tool_requires("mingw-builds/15.1.0")
|
||||
self.tool_requires("go/1.26.0")
|
||||
|
||||
def requirements(self):
|
||||
@@ -64,8 +84,19 @@ class AwgWindows(ConanFile):
|
||||
def source(self):
|
||||
get(self, f"https://github.com/amnezia-vpn/amneziawg-windows/archive/refs/tags/v{self.version}.zip",
|
||||
sha256="1de472832b332515c96cdf14ea887edde42ed7ad173675280c51baa9a3ef62f2", strip_root=True)
|
||||
|
||||
|
||||
def generate(self):
|
||||
VirtualBuildEnv(self).generate()
|
||||
if self._windows_arm64:
|
||||
return
|
||||
|
||||
env = Environment()
|
||||
env.define("GOOS", "windows")
|
||||
if self._goarm:
|
||||
env.define("GOARM", self._goarm)
|
||||
env.define("GOARCH", self._goarch)
|
||||
env.define("CGO_ENABLED", "1")
|
||||
|
||||
tc = AutotoolsToolchain(self)
|
||||
tc.extra_cflags = [
|
||||
"-Wall",
|
||||
@@ -73,25 +104,36 @@ class AwgWindows(ConanFile):
|
||||
"-Wno-switch",
|
||||
"-DWINVER=0x0601"
|
||||
]
|
||||
tc.extra_ldflags = [
|
||||
tc.extra_ldflags = [
|
||||
"-Wl,--dynamicbase",
|
||||
"-Wl,--nxcompat",
|
||||
"-Wl,--export-all-symbols",
|
||||
"-Wl,--high-entropy-va"
|
||||
]
|
||||
env = tc.environment()
|
||||
env.define("GOOS", "windows")
|
||||
if self._goarm:
|
||||
env.define("GOARM", self._goarm)
|
||||
env.define("GOARCH", self._goarch)
|
||||
env.define("CGO_ENABLED", "1")
|
||||
env.define("CGO_LDFLAGS", tc.ldflags)
|
||||
env.define("CGO_CFLAGS", tc.cflags)
|
||||
tc.generate(env)
|
||||
|
||||
env.vars(self, scope="build").save_script("conanbuild")
|
||||
|
||||
def build(self):
|
||||
out_dll = os.path.join(self.build_folder, "tunnel.dll")
|
||||
if self._windows_arm64:
|
||||
run_llvm_mingw_go_build(
|
||||
self,
|
||||
self.source_folder,
|
||||
out_dll,
|
||||
self._goarch,
|
||||
goarm=self._goarm,
|
||||
extra_args='-buildmode c-shared -ldflags="-w -s" -trimpath -v',
|
||||
)
|
||||
return
|
||||
|
||||
with chdir(self, self.source_folder):
|
||||
self.run(f'go build -buildmode c-shared -ldflags="-w -s" -trimpath -v -o "{os.path.join(self.build_folder, "tunnel.dll")}"')
|
||||
self.run(
|
||||
f'go build -buildmode c-shared -ldflags="-w -s" -trimpath -v '
|
||||
f'-o "{out_dll}"',
|
||||
env="conanbuild",
|
||||
)
|
||||
|
||||
def package(self):
|
||||
copy(self, "tunnel.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"))
|
||||
|
||||
198
recipes/awg-windows/windows_cgo.py
Normal file
198
recipes/awg-windows/windows_cgo.py
Normal file
@@ -0,0 +1,198 @@
|
||||
"""Windows CGO helpers: llvm-mingw for ARM64, MinGW via Conan for x86_64."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
# https://github.com/mstorsjo/llvm-mingw/releases
|
||||
LLVM_MINGW_VERSION = "20260519"
|
||||
LLVM_MINGW_URL = (
|
||||
f"https://github.com/mstorsjo/llvm-mingw/releases/download/"
|
||||
f"{LLVM_MINGW_VERSION}/llvm-mingw-{LLVM_MINGW_VERSION}-ucrt-aarch64.zip"
|
||||
)
|
||||
LLVM_MINGW_SHA256 = "7bb5e3c9964dc29555cababb55e69eea02a51e98e1240eb9513e6540c7bae0ea"
|
||||
|
||||
|
||||
def is_windows_arm64(conanfile) -> bool:
|
||||
return (
|
||||
str(conanfile.settings.get_safe("os", "")).startswith("Windows")
|
||||
and str(conanfile.settings.arch) == "armv8"
|
||||
)
|
||||
|
||||
|
||||
def msvc_machine(arch: str) -> str:
|
||||
return {"x86_64": "X64", "armv8": "ARM64", "x86": "X86"}.get(arch, "ARM64")
|
||||
|
||||
|
||||
def go_tool_exe(conanfile) -> str:
|
||||
go = conanfile.dependencies.build["go"]
|
||||
return os.path.join(go.package_folder, "bin", "go.exe")
|
||||
|
||||
|
||||
def _vs_install_path(conanfile) -> str:
|
||||
program_files_x86 = os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")
|
||||
vswhere = os.path.join(program_files_x86, "Microsoft Visual Studio", "Installer", "vswhere.exe")
|
||||
if not os.path.isfile(vswhere):
|
||||
raise RuntimeError(f"{conanfile}: vswhere.exe not found at {vswhere}")
|
||||
|
||||
completed = subprocess.run(
|
||||
[vswhere, "-latest", "-products", "*", "-property", "installationPath"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if completed.returncode != 0 or not completed.stdout.strip():
|
||||
raise RuntimeError(
|
||||
f"{conanfile}: vswhere failed ({completed.returncode}): "
|
||||
f"{completed.stderr or completed.stdout}"
|
||||
)
|
||||
return completed.stdout.strip().splitlines()[0]
|
||||
|
||||
|
||||
def _vcvars_ver_flag(conanfile) -> str:
|
||||
version = str(conanfile.settings.get_safe("compiler.version", ""))
|
||||
if not version:
|
||||
return ""
|
||||
minor = {"192": "14.2", "193": "14.3", "194": "14.4", "195": "14.5"}
|
||||
ver = minor.get(version)
|
||||
return f" -vcvars_ver={ver}" if ver else ""
|
||||
|
||||
|
||||
def _vcvars_arch_arg(target_arch: str) -> str:
|
||||
import platform
|
||||
|
||||
host = platform.machine().lower()
|
||||
host_is_arm = host in ("arm64", "aarch64")
|
||||
|
||||
if target_arch == "armv8":
|
||||
return "arm64" if host_is_arm else "amd64_arm64"
|
||||
if target_arch == "x86_64":
|
||||
if host_is_arm:
|
||||
return "arm64_x64"
|
||||
return "amd64" if host in ("amd64", "x86_64") else "x86_amd64"
|
||||
return "arm64" if host_is_arm else "amd64"
|
||||
|
||||
|
||||
def msvc_vcvars_cmd(conanfile) -> str:
|
||||
target_arch = str(conanfile.settings.arch)
|
||||
install_path = _vs_install_path(conanfile)
|
||||
vcvarsall = os.path.join(install_path, "VC", "Auxiliary", "Build", "vcvarsall.bat")
|
||||
arch_arg = _vcvars_arch_arg(target_arch)
|
||||
ver_flag = _vcvars_ver_flag(conanfile)
|
||||
return f'call "{vcvarsall}" {arch_arg}{ver_flag}'
|
||||
|
||||
|
||||
def _find_llvm_mingw_toolchain(root_dir: str) -> tuple[str, str]:
|
||||
gcc_names = (
|
||||
"aarch64-w64-windows-gnu-gcc.exe",
|
||||
"aarch64-w64-mingw32-gcc.exe",
|
||||
)
|
||||
for gcc_name in gcc_names:
|
||||
for root, _, files in os.walk(root_dir):
|
||||
if gcc_name in files:
|
||||
bindir = os.path.join(root, "")
|
||||
return os.path.join(root, gcc_name), bindir
|
||||
|
||||
for root, _, files in os.walk(root_dir):
|
||||
for fname in files:
|
||||
if fname.endswith("-gcc.exe") and "aarch64" in fname:
|
||||
return os.path.join(root, fname), root
|
||||
raise RuntimeError(f"llvm-mingw gcc not found under {root_dir}")
|
||||
|
||||
|
||||
def ensure_llvm_mingw(conanfile) -> tuple[str, str]:
|
||||
"""Download and extract llvm-mingw (UCRT, aarch64). Returns (gcc.exe, bin_dir)."""
|
||||
from conan.tools.files import download, unzip
|
||||
|
||||
dest = os.path.join(conanfile.build_folder, "llvm-mingw")
|
||||
ready = os.path.join(dest, ".extracted")
|
||||
if not os.path.isfile(ready):
|
||||
zip_path = os.path.join(conanfile.build_folder, "llvm-mingw.zip")
|
||||
conanfile.output.info(f"Downloading llvm-mingw {LLVM_MINGW_VERSION} for Windows ARM64 CGO")
|
||||
download(conanfile, LLVM_MINGW_URL, zip_path, sha256=LLVM_MINGW_SHA256)
|
||||
unzip(conanfile, zip_path, dest)
|
||||
with open(ready, "w", encoding="ascii") as marker:
|
||||
marker.write(LLVM_MINGW_VERSION)
|
||||
|
||||
gcc, bindir = _find_llvm_mingw_toolchain(dest)
|
||||
conanfile.output.info(f"CGO compiler: {gcc}")
|
||||
return gcc, bindir
|
||||
|
||||
|
||||
def run_llvm_mingw_go_build(
|
||||
conanfile,
|
||||
src: str,
|
||||
out: str,
|
||||
goarch: str,
|
||||
*,
|
||||
goarm=None,
|
||||
extra_args="-ldflags=-w -buildmode=c-shared",
|
||||
) -> None:
|
||||
"""Build c-shared with llvm-mingw GCC (same approach as other Go Windows/arm64 projects)."""
|
||||
gcc, bindir = ensure_llvm_mingw(conanfile)
|
||||
go = go_tool_exe(conanfile)
|
||||
goarm_set = f"&& set GOARM={goarm}" if goarm else ""
|
||||
bindir_q = bindir.replace('"', '""')
|
||||
gcc_q = gcc.replace('"', '""')
|
||||
conanfile.run(
|
||||
f'set "PATH={bindir_q};%PATH%"&& set CGO_ENABLED=1&& set GOOS=windows&& set GOARCH={goarch}{goarm_set}&& '
|
||||
f'set "CC={gcc_q}"&& set "CXX={gcc_q}"&& '
|
||||
f'"{go}" build -C "{src}" {extra_args} -o "{out}" .',
|
||||
)
|
||||
|
||||
|
||||
def ensure_msvc_import_lib(
|
||||
conanfile,
|
||||
build_dir: str,
|
||||
dll_name: str,
|
||||
base_name: str,
|
||||
) -> None:
|
||||
"""MSVC import library for linking the DLL from the main app (MSVC/Qt)."""
|
||||
lib_path = os.path.join(build_dir, f"{base_name}.lib")
|
||||
if os.path.isfile(lib_path):
|
||||
return
|
||||
|
||||
dll_path = os.path.join(build_dir, dll_name)
|
||||
if not os.path.isfile(dll_path):
|
||||
raise RuntimeError(f"{conanfile}: DLL not found: {dll_path}")
|
||||
|
||||
machine = msvc_machine(str(conanfile.settings.arch))
|
||||
def_path = os.path.join(build_dir, f"{base_name}.def")
|
||||
exports_txt = os.path.join(build_dir, f"{base_name}.exports.txt")
|
||||
vc = msvc_vcvars_cmd(conanfile)
|
||||
|
||||
conanfile.run(f'{vc} && dumpbin /nologo /exports "{dll_path}" > "{exports_txt}"')
|
||||
|
||||
with open(exports_txt, encoding="utf-8", errors="replace") as exports_file:
|
||||
text = exports_file.read()
|
||||
|
||||
exports = []
|
||||
in_table = False
|
||||
for line in text.splitlines():
|
||||
if "ordinal hint RVA" in line:
|
||||
in_table = True
|
||||
continue
|
||||
if not in_table:
|
||||
continue
|
||||
match = re.match(r"\s+\d+\s+[0-9A-Fa-f]+\s+[0-9A-Fa-f]+\s+(\S+)", line)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
if name != "[noname]":
|
||||
exports.append(name)
|
||||
|
||||
if not exports:
|
||||
raise RuntimeError(f"{conanfile}: No exports found in {dll_path}")
|
||||
|
||||
with open(def_path, "w", encoding="ascii") as def_file:
|
||||
def_file.write(f"LIBRARY {base_name}\nEXPORTS\n")
|
||||
for symbol in exports:
|
||||
def_file.write(f" {symbol}\n")
|
||||
|
||||
conanfile.run(
|
||||
f'{vc} && lib /nologo /def:"{def_path}" /out:"{lib_path}" /machine:{machine}',
|
||||
)
|
||||
|
||||
try:
|
||||
os.remove(exports_txt)
|
||||
except OSError:
|
||||
pass
|
||||
@@ -23,4 +23,7 @@ sources:
|
||||
sha256: "50674f3d6a071fa1a4c1d76dc37fafa0330df87d84087a262fee020da5396b6b"
|
||||
x86_64:
|
||||
url: "https://go.dev/dl/go1.26.0.windows-amd64.zip"
|
||||
sha256: "9bbe0fc64236b2b51f6255c05c4232532b8ecc0e6d2e00950bd3021d8a4d07d4"
|
||||
sha256: "9bbe0fc64236b2b51f6255c05c4232532b8ecc0e6d2e00950bd3021d8a4d07d4"
|
||||
armv8:
|
||||
url: "https://go.dev/dl/go1.26.0.windows-arm64.zip"
|
||||
sha256: "73bdbb9f64aa152758024485c5243a1098182bb741fcc603b6fb664ee5e0fe35"
|
||||
@@ -45,6 +45,8 @@ class LibSSHRecipe(ConanFile):
|
||||
self.options.rm_safe("fPIC")
|
||||
self.settings.rm_safe("compiler.libcxx")
|
||||
self.settings.rm_safe("compiler.cppstd")
|
||||
if self.settings.os == "Windows" and str(self.settings.arch) == "armv8":
|
||||
self.options["openssl/*"].no_asm = True
|
||||
|
||||
def layout(self):
|
||||
cmake_layout(self, src_folder="src")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from conan import ConanFile
|
||||
from conan.tools.files import get, copy, replace_in_file, apply_conandata_patches, export_conandata_patches
|
||||
from conan.tools.files import get, copy, replace_in_file
|
||||
from conan.tools.gnu import Autotools, AutotoolsToolchain, AutotoolsDeps, PkgConfigDeps
|
||||
from conan.tools.layout import basic_layout
|
||||
from conan.tools.cmake import cmake_layout, CMakeToolchain, CMake, CMakeDeps
|
||||
@@ -17,7 +17,6 @@ class Openvpn(ConanFile):
|
||||
return str(self.settings.os).startswith("Windows")
|
||||
|
||||
def export_sources(self):
|
||||
export_conandata_patches(self)
|
||||
copy(self, "*applink.c", src=self.recipe_folder, dst=self.export_sources_folder)
|
||||
|
||||
def layout(self):
|
||||
@@ -37,7 +36,8 @@ class Openvpn(ConanFile):
|
||||
self.tool_requires("pkgconf/2.5.1")
|
||||
|
||||
def requirements(self):
|
||||
self.requires("openssl/3.6.1", visible=False)
|
||||
openssl_opts = {"no_asm": True} if self._is_windows and str(self.settings.arch) == "armv8" else {}
|
||||
self.requires("openssl/3.6.1", visible=False, options=openssl_opts)
|
||||
self.requires("lz4/1.10.0", visible=False)
|
||||
self.requires("lzo/2.10", visible=False)
|
||||
if self.settings.os == "Linux":
|
||||
@@ -52,10 +52,15 @@ class Openvpn(ConanFile):
|
||||
)
|
||||
|
||||
def _patch_sources(self):
|
||||
replace_in_file(self,
|
||||
os.path.join(self.source_folder, "CMakeLists.txt"),
|
||||
"/Qspectre",
|
||||
""
|
||||
cmakelists = os.path.join(self.source_folder, "CMakeLists.txt")
|
||||
replace_in_file(self, cmakelists, "/Qspectre", "")
|
||||
# Empty CMAKE_GENERATOR_PLATFORM (Ninja + MSVC) breaks
|
||||
# `if (${CMAKE_GENERATOR_PLATFORM} STREQUAL ...)` → invalid `if (STREQUAL ...)`.
|
||||
replace_in_file(
|
||||
self,
|
||||
cmakelists,
|
||||
'if (${CMAKE_GENERATOR_PLATFORM} STREQUAL "x64" OR ${CMAKE_GENERATOR_PLATFORM} STREQUAL "x86")',
|
||||
'if (CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x86" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")',
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
@@ -73,6 +78,8 @@ class Openvpn(ConanFile):
|
||||
tc.extra_cxxflags = [ f"-I{tap_include_path}", f"-I{applink_include_path}" ]
|
||||
tc.cache_variables["BUILD_TESTING"] = False
|
||||
tc.cache_variables["ENABLE_PKCS11"] = False
|
||||
# Upstream defaults USE_WERROR=ON → /WX on MSVC; breaks on newer toolchains (warnings from deps / OpenVPN).
|
||||
tc.cache_variables["USE_WERROR"] = False
|
||||
tc.generate()
|
||||
deps = CMakeDeps(self)
|
||||
deps.generate()
|
||||
@@ -85,7 +92,6 @@ class Openvpn(ConanFile):
|
||||
deps.generate()
|
||||
|
||||
def build(self):
|
||||
apply_conandata_patches(self)
|
||||
if self._is_windows:
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
|
||||
@@ -2,8 +2,7 @@ from conan import ConanFile
|
||||
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
|
||||
|
||||
@@ -28,11 +27,11 @@ class Tun2Socks(ConanFile):
|
||||
"x86_64": "amd64",
|
||||
"armv8": "arm64"
|
||||
}.get(str(self.settings.arch))
|
||||
|
||||
|
||||
@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 ""
|
||||
@@ -47,12 +46,8 @@ class Tun2Socks(ConanFile):
|
||||
)
|
||||
|
||||
def build_requirements(self):
|
||||
# Upstream Makefile: CGO_ENABLED=0 — pure Go; no MSYS2 / MinGW / make on Windows.
|
||||
self.tool_requires("go/1.26.0")
|
||||
if self._is_windows:
|
||||
self.win_bash = True
|
||||
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
|
||||
self.tool_requires("msys2/cci.latest")
|
||||
self.tool_requires("mingw-builds/15.1.0")
|
||||
|
||||
def requirements(self):
|
||||
if self._is_windows:
|
||||
@@ -64,25 +59,33 @@ class Tun2Socks(ConanFile):
|
||||
)
|
||||
|
||||
def generate(self):
|
||||
tc = AutotoolsToolchain(self)
|
||||
env = tc.environment()
|
||||
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)
|
||||
tc.generate(env)
|
||||
VirtualBuildEnv(self).generate()
|
||||
|
||||
def build(self):
|
||||
# Makefile default: BUILD_DIR=build, CGO_ENABLED=0, target tun2socks -> build/tun2socks(.exe)
|
||||
out_dir = os.path.join(self.source_folder, "build")
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
out_name = f"tun2socks{self._ext}"
|
||||
out_path = os.path.join(out_dir, out_name)
|
||||
goos = self._goos
|
||||
goarch = self._goarch
|
||||
with chdir(self, self.source_folder):
|
||||
at = Autotools(self)
|
||||
at.make("tun2socks")
|
||||
if self._is_windows:
|
||||
self.run(
|
||||
f'set "GOOS={goos}"&& set "GOARCH={goarch}"&& set "CGO_ENABLED=0"&& set "GO111MODULE=on"&& '
|
||||
f'go build -trimpath -ldflags="-w -s -buildid=" -o "{out_path}" .',
|
||||
env="conanbuild",
|
||||
)
|
||||
else:
|
||||
self.run(
|
||||
f'GOOS={goos} GOARCH={goarch} CGO_ENABLED=0 GO111MODULE=on '
|
||||
f'go build -trimpath -ldflags="-w -s -buildid=" -o "{out_path}" .',
|
||||
env="conanbuild",
|
||||
)
|
||||
|
||||
def package(self):
|
||||
copy(self, "tun2socks", 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")
|
||||
out_dir = os.path.join(self.source_folder, "build")
|
||||
copy(self, f"tun2socks{self._ext}", src=out_dir, dst=self.package_folder)
|
||||
|
||||
def package_info(self):
|
||||
self.cpp_info.exe = True
|
||||
|
||||
@@ -29,18 +29,33 @@ class WinSplitTunnel(ConanFile):
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} supports only Windows"
|
||||
)
|
||||
if not self._arch:
|
||||
raise ConanInvalidConfiguration(
|
||||
f"{self.name} v{self.version} does not support {self.settings.arch}"
|
||||
)
|
||||
|
||||
def _prebuilt_files(self):
|
||||
# Mullvad binaries per target triple (ff0e3746 pin in URL below).
|
||||
by_arch = {
|
||||
"x86_64": [
|
||||
("mullvad-split-tunnel.cat", "9bbd10b95a2cf2226b266a52077300c280f7782def69ebbeb892bb60505d9a5f"),
|
||||
("mullvad-split-tunnel.inf", "4ec3c2bdefc2a1df9e4e19cd4301b5774624ea07e61add588067b16f8925f5d7"),
|
||||
("mullvad-split-tunnel.pdb", "ee0e246b18a3bfecfc27104b40f9492ffd2b735582870fbd572f93d55e8e9eaa"),
|
||||
("mullvad-split-tunnel.sys", "4056b22d08115c1a83bc2cafa17de0bb17db3705eac382de77fd7935eeff7edb"),
|
||||
],
|
||||
"aarch64": [
|
||||
("mullvad-split-tunnel.cat", "d6c27e43b6aaca989d59ca63c5b53f1876d3dbe9a189d654ee0f49c5b37b8a44"),
|
||||
("mullvad-split-tunnel.inf", "acd2e65ea51ad2c76725c3a8f3afd65f0e5b2a7e1c5410371db67a3fb0f3cb72"),
|
||||
("mullvad-split-tunnel.pdb", "a10382fd0534aec18a998b0b6068a47a1111f42da196240ddf066f1cdb475d92"),
|
||||
("mullvad-split-tunnel.sys", "dd5befd1537e6f1e90fe2a0139c8d91deda41faaef84a234b780ffc49037b9be"),
|
||||
],
|
||||
}
|
||||
return by_arch[self._arch]
|
||||
|
||||
def build(self):
|
||||
url = f"https://raw.githubusercontent.com/mullvad/mullvadvpn-app-binaries/ff0e3746c89a04314377cffeb52faaa976413a69/{self._target}/split-tunnel"
|
||||
|
||||
files = [
|
||||
("mullvad-split-tunnel.cat", "9bbd10b95a2cf2226b266a52077300c280f7782def69ebbeb892bb60505d9a5f"),
|
||||
("mullvad-split-tunnel.inf", "4ec3c2bdefc2a1df9e4e19cd4301b5774624ea07e61add588067b16f8925f5d7"),
|
||||
("mullvad-split-tunnel.pdb", "ee0e246b18a3bfecfc27104b40f9492ffd2b735582870fbd572f93d55e8e9eaa"),
|
||||
("mullvad-split-tunnel.sys", "4056b22d08115c1a83bc2cafa17de0bb17db3705eac382de77fd7935eeff7edb"),
|
||||
]
|
||||
|
||||
for name, sha256 in files:
|
||||
for name, sha256 in self._prebuilt_files():
|
||||
download(self, f"{url}/{name}", os.path.join("prebuilt", name), sha256=sha256)
|
||||
|
||||
def package(self):
|
||||
|
||||
Reference in New Issue
Block a user