Compare commits

...

18 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
Yaroslav Gurov c714d98bd1 chore: extend prebuilts support for MacOS NE by clang 21+ (#2633)
* chore: extend prebuilts support for MacOS NE by clang 21+

* chore: trigger prebuilts on workflow file changes
2026-05-25 22:05:56 +08:00
vkamn 4787f3915b chore: defines for update controller (#2634) 2026-05-21 20:40:04 +08:00
Yaroslav Gurov 7a383116b2 fix: force os.sdk to empty on Darwin (#2632) 2026-05-21 18:56:53 +08:00
Yaroslav Gurov d3de5f0f48 fix(conan): openvpn support in MSVC+Ninja setup (#2616) 2026-05-21 18:09:52 +08:00
vkamn 8749d683e3 chore: minor fixes (#2630) 2026-05-21 11:38:41 +08:00
vkamn 9de9d082bc chore: bump version (#2629) 2026-05-21 10:41:25 +08:00
Yaroslav Gurov a4233fef41 fix: add ssh init and finalize for statically-linked libssh (#2627) 2026-05-21 10:19:08 +08:00
Yaroslav Gurov 4890dd1d74 chore: compare changes against base branch of the PR (#2626) 2026-05-20 21:26:41 +08:00
Yaroslav Gurov 564630827e сhore: apple ci cd macos versions (#2625)
* chore(ci/cd): use macos-26 for xcode>26.4

* chore(ci/cd): bump conan version

* chore(conan): remove redundant VirtualBuildEnv
2026-05-20 21:19:56 +08:00
17 changed files with 321 additions and 86 deletions
+30 -19
View File
@@ -18,11 +18,11 @@ jobs:
- uses: dorny/paths-filter@v3 - uses: dorny/paths-filter@v3
id: filter id: filter
with: with:
base: ${{ github.event.before }}
filters: | filters: |
recipes: recipes:
- 'recipes/**' - 'recipes/**'
- 'conanfile.py' - 'conanfile.py'
- '.github/workflows/deploy.yml'
Bake-Prebuilts-Linux: Bake-Prebuilts-Linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -40,7 +40,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build dependencies' - name: 'Build dependencies'
shell: bash shell: bash
@@ -100,7 +100,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Install system packages' - name: 'Install system packages'
run: sudo apt-get install libxkbcommon-x11-0 libsecret-1-dev run: sudo apt-get install libxkbcommon-x11-0 libsecret-1-dev
@@ -151,7 +151,7 @@ jobs:
- uses: ilammy/msvc-dev-cmd@v1 - uses: ilammy/msvc-dev-cmd@v1
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build dependencies' - name: 'Build dependencies'
run: cmake -S . -B build -G "Visual Studio 17 2022" -DPREBUILTS_ONLY=1 run: cmake -S . -B build -G "Visual Studio 17 2022" -DPREBUILTS_ONLY=1
@@ -233,7 +233,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build project' - name: 'Build project'
shell: cmd shell: cmd
@@ -260,13 +260,17 @@ jobs:
# ------------------------------------------------------ # ------------------------------------------------------
Bake-Prebuilts-iOS: Bake-Prebuilts-iOS:
runs-on: macos-latest
needs: Detect-Changes needs: Detect-Changes
if: needs.Detect-Changes.outputs.recipes_changed == 'true' if: needs.Detect-Changes.outputs.recipes_changed == 'true'
strategy: strategy:
matrix: matrix:
xcode-version: [26.0, 26.4] xcode-version: [26.0, 26.4]
include:
- xcode-version: 26.4
os: macos-26
runs-on: ${{ matrix.os || 'macos-latest' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -283,7 +287,7 @@ jobs:
xcode-version: ${{ matrix.xcode-version }} xcode-version: ${{ matrix.xcode-version }}
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build dependencies' - name: 'Build dependencies'
run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1 -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1 -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos
@@ -350,7 +354,7 @@ jobs:
- name: 'Setup xcode' - name: 'Setup xcode'
uses: maxim-lobanov/setup-xcode@v1 uses: maxim-lobanov/setup-xcode@v1
with: with:
xcode-version: '26.4' xcode-version: '26.0'
- name: 'Install desktop Qt' - name: 'Install desktop Qt'
uses: jurplel/install-qt-action@v3 uses: jurplel/install-qt-action@v3
@@ -382,7 +386,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install deps' - name: 'Install deps'
run: pip install "conan==2.26.2" jsonschema jinja2 run: pip install "conan==2.28.0" jsonschema jinja2
- name: 'Build project' - name: 'Build project'
env: env:
@@ -400,14 +404,17 @@ jobs:
# ------------------------------------------------------ # ------------------------------------------------------
Bake-Prebuilts-MacOS: Bake-Prebuilts-MacOS:
runs-on: macos-latest
needs: Detect-Changes needs: Detect-Changes
if: needs.Detect-Changes.outputs.recipes_changed == 'true' if: needs.Detect-Changes.outputs.recipes_changed == 'true'
strategy: strategy:
matrix: matrix:
xcode-version: [16.2, 16.4, 26.4] xcode-version: [16.2, 16.4, 26.4]
include:
- xcode-version: 26.4
os: macos-26
runs-on: ${{ matrix.os || 'macos-latest' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -424,7 +431,7 @@ jobs:
xcode-version: ${{ matrix.xcode-version }} xcode-version: ${{ matrix.xcode-version }}
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build dependencies' - name: 'Build dependencies'
run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1 run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1
@@ -510,7 +517,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build project' - name: 'Build project'
env: env:
@@ -533,13 +540,17 @@ jobs:
# ------------------------------------------------------ # ------------------------------------------------------
Bake-Prebuilts-MacOS-NE: Bake-Prebuilts-MacOS-NE:
runs-on: macos-latest
needs: Detect-Changes needs: Detect-Changes
if: needs.Detect-Changes.outputs.recipes_changed == 'true' if: needs.Detect-Changes.outputs.recipes_changed == 'true'
strategy: strategy:
matrix: matrix:
xcode-version: [16.2, 16.4] xcode-version: [16.2, 16.4, 26.4]
include:
- xcode-version: 26.4
os: macos-26
runs-on: ${{ matrix.os || 'macos-latest' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -556,7 +567,7 @@ jobs:
xcode-version: ${{ matrix.xcode-version }} xcode-version: ${{ matrix.xcode-version }}
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build dependencies' - name: 'Build dependencies'
run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1 -DMACOS_NE=TRUE run: cmake -S . -B build -G Xcode -DPREBUILTS_ONLY=1 -DMACOS_NE=TRUE
@@ -645,7 +656,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Build project' - name: 'Build project'
run: | run: |
@@ -681,7 +692,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Setup Android SDK' - name: 'Setup Android SDK'
uses: android-actions/setup-android@v4 uses: android-actions/setup-android@v4
@@ -818,7 +829,7 @@ jobs:
python-version: 3.14 python-version: 3.14
- name: 'Install conan' - name: 'Install conan'
run: pip install "conan==2.26.2" run: pip install "conan==2.28.0"
- name: 'Decode keystore secret to file' - name: 'Decode keystore secret to file'
env: env:
+1 -1
View File
@@ -4,7 +4,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(PROJECT AmneziaVPN) set(PROJECT AmneziaVPN)
set(AMNEZIAVPN_VERSION 4.8.9.0) set(AMNEZIAVPN_VERSION 4.9.0.0)
set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE) set(QT_CREATOR_SKIP_PACKAGE_MANAGER_SETUP ON CACHE BOOL "" FORCE)
set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES set(CMAKE_PROJECT_TOP_LEVEL_INCLUDES
+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")
@@ -460,6 +460,7 @@ ErrorCode SubscriptionController::updateServiceFromGateway(const QString &server
if (apiV2->nameOverriddenByUser) { if (apiV2->nameOverriddenByUser) {
newApiV2->name = apiV2->name; newApiV2->name = apiV2->name;
newApiV2->displayName = apiV2->displayName;
newApiV2->nameOverriddenByUser = true; newApiV2->nameOverriddenByUser = true;
} }
@@ -44,6 +44,7 @@ bool ServersController::renameServer(const QString &serverId, const QString &nam
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId); auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
if (!cfg.has_value()) return false; if (!cfg.has_value()) return false;
cfg->description = name; cfg->description = name;
cfg->displayName = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind); m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true; return true;
} }
@@ -51,6 +52,7 @@ bool ServersController::renameServer(const QString &serverId, const QString &nam
auto cfg = m_serversRepository->selfHostedUserConfig(serverId); auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
if (!cfg.has_value()) return false; if (!cfg.has_value()) return false;
cfg->description = name; cfg->description = name;
cfg->displayName = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind); m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true; return true;
} }
@@ -58,6 +60,7 @@ bool ServersController::renameServer(const QString &serverId, const QString &nam
auto cfg = m_serversRepository->nativeConfig(serverId); auto cfg = m_serversRepository->nativeConfig(serverId);
if (!cfg.has_value()) return false; if (!cfg.has_value()) return false;
cfg->description = name; cfg->description = name;
cfg->displayName = name;
m_serversRepository->editServer(serverId, cfg->toJson(), kind); m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true; return true;
} }
@@ -67,6 +70,7 @@ bool ServersController::renameServer(const QString &serverId, const QString &nam
auto cfg = m_serversRepository->apiV2Config(serverId); auto cfg = m_serversRepository->apiV2Config(serverId);
if (!cfg.has_value()) return false; if (!cfg.has_value()) return false;
cfg->name = name; cfg->name = name;
cfg->displayName = name;
cfg->nameOverriddenByUser = true; cfg->nameOverriddenByUser = true;
m_serversRepository->editServer(serverId, cfg->toJson(), kind); m_serversRepository->editServer(serverId, cfg->toJson(), kind);
return true; return true;
+8 -16
View File
@@ -23,7 +23,7 @@ namespace
#if defined(Q_OS_WINDOWS) #if defined(Q_OS_WINDOWS)
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_windows_x64.exe"); const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_windows_x64.exe");
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN_installer.exe"; const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN_installer.exe";
#elif defined(Q_OS_MACOS) #elif defined(Q_OS_MACOS) && !defined(MACOS_NE)
const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_macos_x64.pkg"); const QLatin1String kInstallerRemoteFileNamePattern("AmneziaVPN_%1_macos_x64.pkg");
const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.pkg"; const QString kInstallerLocalPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/AmneziaVPN.pkg";
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
@@ -184,7 +184,7 @@ void UpdateController::setupNetworkErrorHandling(QNetworkReply* reply, const QSt
logger.error() << QString("Network error occurred while fetching %1: %2 %3") logger.error() << QString("Network error occurred while fetching %1: %2 %3")
.arg(operation, reply->errorString(), QString::number(error)); .arg(operation, reply->errorString(), QString::number(error));
}); });
QObject::connect(reply, &QNetworkReply::sslErrors, [operation](const QList<QSslError> &errors) { QObject::connect(reply, &QNetworkReply::sslErrors, [operation](const QList<QSslError> &errors) {
QStringList errorStrings; QStringList errorStrings;
for (const QSslError &err : errors) { for (const QSslError &err : errors) {
@@ -196,21 +196,13 @@ void UpdateController::setupNetworkErrorHandling(QNetworkReply* reply, const QSt
void UpdateController::handleNetworkError(QNetworkReply* reply, const QString& operation) void UpdateController::handleNetworkError(QNetworkReply* reply, const QString& operation)
{ {
if (reply->error() == QNetworkReply::NetworkError::OperationCanceledError logger.error() << "Network error code:" << QString::number(static_cast<int>(reply->error()));
|| reply->error() == QNetworkReply::NetworkError::TimeoutError) { logger.error() << "HTTP status:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
logger.error() << errorString(ErrorCode::ApiConfigTimeoutError);
} else {
QString err = reply->errorString();
logger.error() << "Network error code:" << QString::number(static_cast<int>(reply->error()));
logger.error() << "Error message:" << err;
logger.error() << "HTTP status:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
logger.error() << errorString(ErrorCode::ApiConfigDownloadError);
}
} }
QString UpdateController::composeDownloadUrl() const QString UpdateController::composeDownloadUrl() const
{ {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
const QString fileName = QString(kInstallerRemoteFileNamePattern).arg(m_version); const QString fileName = QString(kInstallerRemoteFileNamePattern).arg(m_version);
return m_baseUrl + "/" + fileName; return m_baseUrl + "/" + fileName;
#else #else
@@ -220,7 +212,7 @@ QString UpdateController::composeDownloadUrl() const
void UpdateController::runInstaller() void UpdateController::runInstaller()
{ {
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
if (m_downloadUrl.isEmpty()) { if (m_downloadUrl.isEmpty()) {
logger.error() << "Download URL is empty"; logger.error() << "Download URL is empty";
return; return;
@@ -252,7 +244,7 @@ void UpdateController::runInstaller()
#if defined(Q_OS_WINDOWS) #if defined(Q_OS_WINDOWS)
runWindowsInstaller(kInstallerLocalPath); runWindowsInstaller(kInstallerLocalPath);
#elif defined(Q_OS_MACOS) #elif defined(Q_OS_MACOS) && !defined(MACOS_NE)
runMacInstaller(kInstallerLocalPath); runMacInstaller(kInstallerLocalPath);
#elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) #elif defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
runLinuxInstaller(kInstallerLocalPath); runLinuxInstaller(kInstallerLocalPath);
@@ -292,7 +284,7 @@ int UpdateController::runWindowsInstaller(const QString &installerPath)
} }
#endif #endif
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS) && !defined(MACOS_NE)
int UpdateController::runMacInstaller(const QString &installerPath) int UpdateController::runMacInstaller(const QString &installerPath)
{ {
// Create temporary directory for extraction // Create temporary directory for extraction
+6 -2
View File
@@ -1,13 +1,12 @@
#include <QDebug> #include <QDebug>
#include <QTimer> #include <QTimer>
#include <libssh/libssh.h>
#include "amneziaApplication.h" #include "amneziaApplication.h"
#include "core/utils/osSignalHandler.h" #include "core/utils/osSignalHandler.h"
#include "core/utils/migrations.h" #include "core/utils/migrations.h"
#include "version.h" #include "version.h"
#include <QTimer>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include "Windows.h" #include "Windows.h"
#endif #endif
@@ -47,6 +46,11 @@ int main(int argc, char *argv[])
AmneziaApplication app(argc, argv); AmneziaApplication app(argc, argv);
OsSignalHandler::setup(); OsSignalHandler::setup();
ssh_init();
QObject::connect(&app, &QCoreApplication::aboutToQuit, []() {
ssh_finalize();
});
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE) #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) && !defined(MACOS_NE)
if (isAnotherInstanceRunning()) { if (isAnotherInstanceRunning()) {
QTimer::singleShot(1000, &app, [&]() { app.quit(); }); QTimer::singleShot(1000, &app, [&]() { app.quit(); });
+4
View File
@@ -84,6 +84,10 @@ function(detect_os os os_api_level os_sdk os_subsystem os_version)
set(_os_sdk "watch${apple_platform_suffix}") set(_os_sdk "watch${apple_platform_suffix}")
endif() endif()
endif() endif()
# Macos does not support os.sdk
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(_os_sdk "")
endif()
if(DEFINED os_sdk) if(DEFINED os_sdk)
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}") message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
set(${os_sdk} ${_os_sdk} PARENT_SCOPE) set(${os_sdk} ${_os_sdk} PARENT_SCOPE)
+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()
+1 -2
View File
@@ -2,7 +2,7 @@ from conan import ConanFile
from conan.tools.files import get, copy from conan.tools.files import get, copy
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.env import VirtualBuildEnv, Environment from conan.tools.env import Environment
import os import os
import stat import stat
@@ -34,7 +34,6 @@ class AmneziaLibxray(ConanFile):
) )
def generate(self): def generate(self):
VirtualBuildEnv(self).generate()
env = Environment() env = Environment()
ndk_path_str = self.conf.get("tools.android:ndk_path") ndk_path_str = self.conf.get("tools.android:ndk_path")
if ndk_path_str: if ndk_path_str:
+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")
+4
View File
@@ -0,0 +1,4 @@
patches:
"2.7.0":
- patch_file: "patches/0001-carefully-handle-CMAKE_GENERATOR_PLATFORM.patch"
- patch_file: "patches/0002-explicitly-pass-unicode-everywhere.patch"
+3 -1
View File
@@ -1,5 +1,5 @@
from conan import ConanFile from conan import ConanFile
from conan.tools.files import get, copy, replace_in_file from conan.tools.files import get, copy, replace_in_file, apply_conandata_patches, export_conandata_patches
from conan.tools.gnu import Autotools, AutotoolsToolchain, AutotoolsDeps, PkgConfigDeps from conan.tools.gnu import Autotools, AutotoolsToolchain, AutotoolsDeps, PkgConfigDeps
from conan.tools.layout import basic_layout from conan.tools.layout import basic_layout
from conan.tools.cmake import cmake_layout, CMakeToolchain, CMake, CMakeDeps from conan.tools.cmake import cmake_layout, CMakeToolchain, CMake, CMakeDeps
@@ -17,6 +17,7 @@ class Openvpn(ConanFile):
return str(self.settings.os).startswith("Windows") return str(self.settings.os).startswith("Windows")
def export_sources(self): def export_sources(self):
export_conandata_patches(self)
copy(self, "*applink.c", src=self.recipe_folder, dst=self.export_sources_folder) copy(self, "*applink.c", src=self.recipe_folder, dst=self.export_sources_folder)
def layout(self): def layout(self):
@@ -84,6 +85,7 @@ class Openvpn(ConanFile):
deps.generate() deps.generate()
def build(self): def build(self):
apply_conandata_patches(self)
if self._is_windows: if self._is_windows:
cmake = CMake(self) cmake = CMake(self)
cmake.configure() cmake.configure()
@@ -0,0 +1,25 @@
From 693bee38daaec5962ea3f0939c71e869f202c08a Mon Sep 17 00:00:00 2001
From: Yaroslav Gurov <ygurov@proton.me>
Date: Mon, 18 May 2026 16:58:00 +0200
Subject: [PATCH] carefully handle CMAKE_GENERATOR_PLATFORM
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 198c98ff..7341db70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,7 +108,7 @@ if (MSVC)
"$<$<CONFIG:Release>:/OPT:REF>"
"$<$<CONFIG:Release>:/OPT:ICF>"
)
- if (${CMAKE_GENERATOR_PLATFORM} STREQUAL "x64" OR ${CMAKE_GENERATOR_PLATFORM} STREQUAL "x86")
+ if ("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64" OR "${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x86")
add_link_options("$<$<CONFIG:Release>:/CETCOMPAT>")
endif()
else ()
--
2.46.0.windows.1
@@ -0,0 +1,50 @@
From 9a42a0350abaa1a329ad56e40b1900ef78183323 Mon Sep 17 00:00:00 2001
From: Yaroslav Gurov <ygurov@proton.me>
Date: Mon, 18 May 2026 18:05:09 +0200
Subject: [PATCH] explicitly pass unicode everywhere
---
src/openvpnmsica/CMakeLists.txt | 1 +
src/openvpnserv/CMakeLists.txt | 1 +
src/tapctl/CMakeLists.txt | 1 +
3 files changed, 3 insertions(+)
diff --git a/src/openvpnmsica/CMakeLists.txt b/src/openvpnmsica/CMakeLists.txt
index 9126b80f..23f979d6 100644
--- a/src/openvpnmsica/CMakeLists.txt
+++ b/src/openvpnmsica/CMakeLists.txt
@@ -22,6 +22,7 @@ target_sources(openvpnmsica PRIVATE
openvpnmsica_resources.rc
)
target_compile_options(openvpnmsica PRIVATE
+ -DUNICODE
-D_UNICODE
-UNTDDI_VERSION
-D_WIN32_WINNT=_WIN32_WINNT_VISTA
diff --git a/src/openvpnserv/CMakeLists.txt b/src/openvpnserv/CMakeLists.txt
index fc153822..b3a0cff1 100644
--- a/src/openvpnserv/CMakeLists.txt
+++ b/src/openvpnserv/CMakeLists.txt
@@ -19,6 +19,7 @@ function(add_common_options target)
${MC_GEN_DIR}
)
target_compile_options(${target} PRIVATE
+ -DUNICODE
-D_UNICODE
-UNTDDI_VERSION
-D_WIN32_WINNT=_WIN32_WINNT_VISTA
diff --git a/src/tapctl/CMakeLists.txt b/src/tapctl/CMakeLists.txt
index 97702c01..81da46b8 100644
--- a/src/tapctl/CMakeLists.txt
+++ b/src/tapctl/CMakeLists.txt
@@ -19,6 +19,7 @@ target_sources(tapctl PRIVATE
tapctl_resources.rc
)
target_compile_options(tapctl PRIVATE
+ -DUNICODE
-D_UNICODE
-UNTDDI_VERSION
-D_WIN32_WINNT=_WIN32_WINNT_VISTA
--
2.46.0.windows.1
+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