Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion cmake/CPack.cmake
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
6 changes: 6 additions & 0 deletions cmake/conan_provider.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions cmake/recipes_bootstrap.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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}
)
Expand Down
11 changes: 10 additions & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -43,5 +49,8 @@ def requirements(self):

# 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")
9 changes: 8 additions & 1 deletion deploy/build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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 (
Expand Down
Binary file not shown.
115 changes: 115 additions & 0 deletions recipes/_helpers/cgo_cc.py
Original file line number Diff line number Diff line change
@@ -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())
Loading
Loading