mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
build: make conan tvOS pipeline build
build: make tvOS awg prebuilt explicit docs: make Apple TV build manual portable
This commit is contained in:
340
apple-tv-build.md
Normal file
340
apple-tv-build.md
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
# AmneziaVPN Apple TV Build
|
||||||
|
|
||||||
|
This document describes how to build the current branch for Apple TV from the repository root.
|
||||||
|
|
||||||
|
The pipeline is:
|
||||||
|
|
||||||
|
1. Use a separately built static Qt 6.9.2 for `tvOS`.
|
||||||
|
2. Let Conan build/provide C/C++ dependencies.
|
||||||
|
3. Generate an Xcode project with `qt-cmake`.
|
||||||
|
4. Build the `.app` and embedded Network Extension with `xcodebuild`.
|
||||||
|
|
||||||
|
Important:
|
||||||
|
|
||||||
|
- Run the project commands from the repository root.
|
||||||
|
- This is a device build for `appletvos`, not a simulator build.
|
||||||
|
- `xcodebuild build` produces `.app`.
|
||||||
|
- `.ipa` is produced later via `archive` and `-exportArchive`.
|
||||||
|
- The current tvOS Network Extension scope is WireGuard-only.
|
||||||
|
- The temporary tvOS WireGuard bridge prebuilt is opt-in. The Conan recipe does not contain machine-specific fallback paths.
|
||||||
|
- Do not initialize or update submodules just for this build. If a clean checkout has empty `client/3rd` folders, pass `AMNEZIA_THIRDPARTY_ROOT` to an already initialized read-only `client/3rd` tree.
|
||||||
|
|
||||||
|
## 1. Environment
|
||||||
|
|
||||||
|
Set these paths for your machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export REPO_ROOT="$PWD"
|
||||||
|
export QT_DESKTOP_PREFIX="$HOME/Qt/6.9.2/macos"
|
||||||
|
export QT_TVOS_SRC="$HOME/Qt_tv/qt-6.9.2-tvos-src"
|
||||||
|
export QT_TVOS_PREFIX="$HOME/Qt_tv/6.9.2/tvos-device"
|
||||||
|
export BUILD_DIR="$REPO_ROOT/build-tvos-device-conan"
|
||||||
|
```
|
||||||
|
|
||||||
|
If this checkout does not have initialized `client/3rd` sources, point CMake at an initialized tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export AMNEZIA_THIRDPARTY_ROOT="/path/to/initialized/amnezia/client/3rd"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using a temporary prebuilt tvOS WireGuard bridge, point Conan at it explicitly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export AMNEZIA_TVOS_AWG_PREBUILT_DIR="/path/to/WireGuardKitGo-appletvos"
|
||||||
|
export AMNEZIA_TVOS_AWG_VERSION_HEADER_DIR="/path/to/directory/with/wireguard-go-version.h"
|
||||||
|
```
|
||||||
|
|
||||||
|
`AMNEZIA_TVOS_AWG_PREBUILT_DIR` must contain `libwg-go.a`.
|
||||||
|
|
||||||
|
`AMNEZIA_TVOS_AWG_VERSION_HEADER_DIR` is optional when `wireguard-go-version.h` lives in the same directory as `libwg-go.a`.
|
||||||
|
|
||||||
|
If the env vars are not set, the recipe uses the normal source build path. Rebuilding and publishing the tvOS WireGuard bridge through the registry is a separate task.
|
||||||
|
|
||||||
|
## 2. Required Local Tools
|
||||||
|
|
||||||
|
Conan must be available:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv tool install conan
|
||||||
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
conan --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Validated version:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Conan version 2.27.1
|
||||||
|
```
|
||||||
|
|
||||||
|
The build uses Xcode's AppleTVOS SDK:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcrun --sdk appletvos --show-sdk-path
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Prepare Qt Sources
|
||||||
|
|
||||||
|
Do not edit the installed Qt sources in place. Copy them into a separate tvOS fork:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p "$HOME/Qt_tv"
|
||||||
|
rsync -a "$HOME/Qt/6.9.2/Src/" "$QT_TVOS_SRC/"
|
||||||
|
```
|
||||||
|
|
||||||
|
Recommended for reproducibility:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "$QT_TVOS_SRC"
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "Qt 6.9.2 source snapshot"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. Apply the Qt tvOS Patchset
|
||||||
|
|
||||||
|
Apply the local Qt tvOS patchset to `$QT_TVOS_SRC`.
|
||||||
|
|
||||||
|
If you need to recreate the patchset from a fresh copy, compare these files against `$HOME/Qt/6.9.2/Src` and reapply the same changes:
|
||||||
|
|
||||||
|
- `qtbase/cmake/QtBaseGlobalTargets.cmake`
|
||||||
|
- `qtbase/cmake/QtBaseHelpers.cmake`
|
||||||
|
- `qtbase/cmake/QtBuildPathsHelpers.cmake`
|
||||||
|
- `qtbase/cmake/QtMkspecHelpers.cmake`
|
||||||
|
- `qtbase/cmake/QtConfig.cmake.in`
|
||||||
|
- `qtbase/mkspecs/unsupported/macx-tvos-clang/qplatformdefs.h`
|
||||||
|
- `qtbase/src/corelib/CMakeLists.txt`
|
||||||
|
- `qtbase/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm`
|
||||||
|
- `qtbase/src/gui/CMakeLists.txt`
|
||||||
|
- `qtbase/src/widgets/CMakeLists.txt`
|
||||||
|
- `qtbase/src/network/kernel/qnetworkproxy_darwin.cpp`
|
||||||
|
- `qtbase/src/testlib/qtestcrashhandler.cpp`
|
||||||
|
- `qtbase/src/plugins/platforms/ios/qiosapplicationdelegate.mm`
|
||||||
|
- `qtbase/src/plugins/platforms/ios/qiosscreen.mm`
|
||||||
|
- `qtbase/src/plugins/platforms/ios/qiostheme.mm`
|
||||||
|
- `qtbase/src/plugins/platforms/ios/quiview.mm`
|
||||||
|
- `qtbase/src/plugins/platforms/ios/qiosclipboard.mm`
|
||||||
|
|
||||||
|
Recommended after patching:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C "$QT_TVOS_SRC" diff > "$HOME/Qt_tv/qt-6.9.2-tvos.patch"
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use `QT_APPLE_SDK=appletvos`. The working path is `CMAKE_SYSTEM_NAME=tvOS` with `CMAKE_OSX_SYSROOT=appletvos`.
|
||||||
|
|
||||||
|
## 5. Build Qt 6.9.2 for Apple TV
|
||||||
|
|
||||||
|
Only the modules required by this project are built.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /private/tmp/qt6.9.2-tvos-device-build
|
||||||
|
cd /private/tmp/qt6.9.2-tvos-device-build
|
||||||
|
|
||||||
|
"$QT_TVOS_SRC/configure" \
|
||||||
|
-release -static -appstore-compliant \
|
||||||
|
-nomake tests -nomake examples \
|
||||||
|
-submodules qtbase,qtdeclarative,qtshadertools,qtremoteobjects,qtsvg,qt5compat,qttools \
|
||||||
|
-qt-host-path "$QT_DESKTOP_PREFIX" \
|
||||||
|
-prefix "$QT_TVOS_PREFIX" \
|
||||||
|
-- \
|
||||||
|
-G Ninja \
|
||||||
|
-DQT_QMAKE_TARGET_MKSPEC=macx-tvos-clang \
|
||||||
|
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||||
|
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=17.0 \
|
||||||
|
-DBUILD_SHARED_LIBS=OFF \
|
||||||
|
-DQT_NO_APPLE_SDK_MAX_VERSION_CHECK=ON
|
||||||
|
|
||||||
|
cmake --build . --parallel 8
|
||||||
|
cmake --install .
|
||||||
|
```
|
||||||
|
|
||||||
|
Sanity checks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
"$QT_TVOS_PREFIX/bin/qt-cmake" --version
|
||||||
|
"$QT_TVOS_PREFIX/bin/qmake" -query QMAKE_XSPEC
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected `QMAKE_XSPEC`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
macx-tvos-clang
|
||||||
|
```
|
||||||
|
|
||||||
|
Return to the repository root after building Qt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Conan Dependency Behavior
|
||||||
|
|
||||||
|
For `CMAKE_SYSTEM_NAME=tvOS`, the project-level Conan graph is intentionally reduced:
|
||||||
|
|
||||||
|
- included: `awg-apple/2.0.1`
|
||||||
|
- included: `libssh/0.11.3@amnezia`
|
||||||
|
- included: `openssl/3.6.1` with `no_apps=True`
|
||||||
|
- excluded: `openvpnadapter`
|
||||||
|
- excluded: `hev-socks5-tunnel`
|
||||||
|
|
||||||
|
This keeps the current Apple TV target in the same practical scope as before: app plus WireGuard-only Network Extension.
|
||||||
|
|
||||||
|
`libssh` is built with `WITH_EXEC=OFF` on tvOS because tvOS does not provide `fork()` or `execv()`.
|
||||||
|
|
||||||
|
## 7. Configure the Project
|
||||||
|
|
||||||
|
From the repository root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd "$REPO_ROOT"
|
||||||
|
|
||||||
|
"$QT_TVOS_PREFIX/bin/qt-cmake" \
|
||||||
|
-B"$BUILD_DIR" \
|
||||||
|
-GXcode \
|
||||||
|
-DQT_HOST_PATH="$QT_DESKTOP_PREFIX" \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||||
|
-DCMAKE_OSX_SYSROOT=appletvos
|
||||||
|
```
|
||||||
|
|
||||||
|
If you need to provide an external initialized `client/3rd` tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
"$QT_TVOS_PREFIX/bin/qt-cmake" \
|
||||||
|
-B"$BUILD_DIR" \
|
||||||
|
-GXcode \
|
||||||
|
-DQT_HOST_PATH="$QT_DESKTOP_PREFIX" \
|
||||||
|
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||||
|
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||||
|
-DAMNEZIA_THIRDPARTY_ROOT="$AMNEZIA_THIRDPARTY_ROOT"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected non-fatal configure warnings:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Warning: plug-in QIOSIntegrationPlugin is not known to the current Qt installation.
|
||||||
|
Warning: plug-in QJpegPlugin is not known to the current Qt installation.
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
In this repo those warnings are tolerated because `client/cmake/ios.cmake` also links the static plugin targets explicitly when available.
|
||||||
|
|
||||||
|
## 8. Build the Apple TV App
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcodebuild -quiet \
|
||||||
|
-project "$BUILD_DIR/AmneziaVPN.xcodeproj" \
|
||||||
|
-scheme AmneziaVPN \
|
||||||
|
-configuration RelWithDebInfo \
|
||||||
|
-sdk appletvos \
|
||||||
|
CODE_SIGNING_ALLOWED=NO \
|
||||||
|
build
|
||||||
|
```
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
|
||||||
|
- `$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app`
|
||||||
|
- `$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex`
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
file "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/AmneziaVPN"
|
||||||
|
file "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/AmneziaVPNNetworkExtension"
|
||||||
|
lipo -info "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/AmneziaVPN"
|
||||||
|
lipo -info "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/AmneziaVPNNetworkExtension"
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Mach-O 64-bit executable arm64
|
||||||
|
Non-fat file: ... is architecture: arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
Useful plist checks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
plutil -p "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/Info.plist" | rg 'CFBundleIdentifier|DTPlatformName|UIDeviceFamily|MinimumOSVersion' -C 1
|
||||||
|
plutil -p "$BUILD_DIR/client/RelWithDebInfo-appletvos/AmneziaVPN.app/PlugIns/AmneziaVPNNetworkExtension.appex/Info.plist" | rg 'CFBundleIdentifier|NSExtension|DTPlatformName|MinimumOSVersion' -C 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
|
||||||
|
- `DTPlatformName => appletvos`
|
||||||
|
- `UIDeviceFamily => 3`
|
||||||
|
- `MinimumOSVersion => 17.0`
|
||||||
|
- extension point `com.apple.networkextension.packet-tunnel`
|
||||||
|
|
||||||
|
## 9. `.app` vs `.ipa`
|
||||||
|
|
||||||
|
This is the normal sequence:
|
||||||
|
|
||||||
|
1. `xcodebuild build` -> `.app`
|
||||||
|
2. `xcodebuild archive` -> `.xcarchive`
|
||||||
|
3. `xcodebuild -exportArchive` -> `.ipa`
|
||||||
|
|
||||||
|
So seeing `.app` after a successful `build` is correct.
|
||||||
|
|
||||||
|
## 10. Optional Archive and Export
|
||||||
|
|
||||||
|
The commands below are the next step for packaging, but signing and provisioning must be configured first.
|
||||||
|
|
||||||
|
Archive:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcodebuild \
|
||||||
|
-project "$BUILD_DIR/AmneziaVPN.xcodeproj" \
|
||||||
|
-scheme AmneziaVPN \
|
||||||
|
-configuration RelWithDebInfo \
|
||||||
|
-sdk appletvos \
|
||||||
|
-archivePath "$BUILD_DIR/AmneziaVPN-tvos.xcarchive" \
|
||||||
|
archive
|
||||||
|
```
|
||||||
|
|
||||||
|
Export:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xcodebuild -exportArchive \
|
||||||
|
-archivePath "$BUILD_DIR/AmneziaVPN-tvos.xcarchive" \
|
||||||
|
-exportPath "$BUILD_DIR/export-tvos" \
|
||||||
|
-exportOptionsPlist /absolute/path/to/ExportOptions.plist
|
||||||
|
```
|
||||||
|
|
||||||
|
The resulting `.ipa` should appear under:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$BUILD_DIR/export-tvos
|
||||||
|
```
|
||||||
|
|
||||||
|
## 11. Known Non-Fatal Warnings
|
||||||
|
|
||||||
|
The validated `xcodebuild` still prints warnings that do not break the build:
|
||||||
|
|
||||||
|
- missing Swift search path under the active Xcode Metal toolchain
|
||||||
|
- `SDKROOT[sdk=...]` target-level warnings generated by Xcode project export
|
||||||
|
- Swift conditional compilation flag warnings such as `GROUP_ID="..."`
|
||||||
|
- asset catalog warnings because the current icon set is still iOS-shaped, not a full tvOS Top Shelf asset set
|
||||||
|
- Go/WireGuard umbrella-header warnings from the temporary local `libwg-go.a` bridge
|
||||||
|
- deprecated libssh SCP API warnings in existing app code
|
||||||
|
- `qt_import_plugins()` warnings shown during configure
|
||||||
|
|
||||||
|
If the static platform plugin is not linked correctly, the typical failure is:
|
||||||
|
|
||||||
|
- `_OBJC_CLASS_$_QIOSApplicationDelegate`
|
||||||
|
- `_qt_main_wrapper`
|
||||||
|
|
||||||
|
Those are cleanup tasks, not blockers for the current build proof.
|
||||||
|
|
||||||
|
## 12. Fast Rebuild Checklist
|
||||||
|
|
||||||
|
If everything is already built once:
|
||||||
|
|
||||||
|
1. Reuse `$QT_TVOS_PREFIX`
|
||||||
|
2. Reuse Conan cache under `$HOME/.conan2`
|
||||||
|
3. Reuse or pass an initialized `AMNEZIA_THIRDPARTY_ROOT`
|
||||||
|
4. Re-run `qt-cmake` into `$BUILD_DIR`
|
||||||
|
5. Re-run `xcodebuild -quiet ... build`
|
||||||
@@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.25.0 FATAL_ERROR)
|
|||||||
set(PROJECT AmneziaVPN)
|
set(PROJECT AmneziaVPN)
|
||||||
project(${PROJECT})
|
project(${PROJECT})
|
||||||
|
|
||||||
|
set(AMNEZIA_THIRDPARTY_ROOT "${CMAKE_CURRENT_LIST_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||||
|
get_filename_component(AMNEZIA_THIRDPARTY_CLIENT_ROOT "${AMNEZIA_THIRDPARTY_ROOT}/.." ABSOLUTE)
|
||||||
|
|
||||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen")
|
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Autogen")
|
||||||
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Autogen")
|
||||||
@@ -108,6 +111,7 @@ include_directories(
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/../ipc
|
${CMAKE_CURRENT_LIST_DIR}/../ipc
|
||||||
${CMAKE_CURRENT_LIST_DIR}/../common/logger
|
${CMAKE_CURRENT_LIST_DIR}/../common/logger
|
||||||
${CMAKE_CURRENT_LIST_DIR}
|
${CMAKE_CURRENT_LIST_DIR}
|
||||||
|
${AMNEZIA_THIRDPARTY_CLIENT_ROOT}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -209,26 +213,28 @@ else()
|
|||||||
qt_finalize_target(${PROJECT})
|
qt_finalize_target(${PROJECT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(TARGETS ${PROJECT}
|
if(NOT IOS AND NOT CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
install(TARGETS ${PROJECT}
|
||||||
COMPONENT AmneziaVPN
|
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
)
|
COMPONENT AmneziaVPN
|
||||||
install(FILES $<TARGET_RUNTIME_DLLS:${PROJECT}>
|
)
|
||||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
install(FILES $<TARGET_RUNTIME_DLLS:${PROJECT}>
|
||||||
COMPONENT AmneziaVPN
|
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
)
|
COMPONENT AmneziaVPN
|
||||||
|
)
|
||||||
|
|
||||||
set(deploy_tool_options "")
|
set(deploy_tool_options "")
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(deploy_tool_options "--force-openssl --force")
|
set(deploy_tool_options "--force-openssl --force")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
qt_generate_deploy_qml_app_script(
|
||||||
|
TARGET ${PROJECT}
|
||||||
|
OUTPUT_SCRIPT QT_DEPLOY_SCRIPT
|
||||||
|
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||||
|
DEPLOY_TOOL_OPTIONS ${deploy_tool_options}
|
||||||
|
)
|
||||||
|
install(SCRIPT ${QT_DEPLOY_SCRIPT}
|
||||||
|
COMPONENT AmneziaVPN
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt_generate_deploy_qml_app_script(
|
|
||||||
TARGET ${PROJECT}
|
|
||||||
OUTPUT_SCRIPT QT_DEPLOY_SCRIPT
|
|
||||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
|
||||||
DEPLOY_TOOL_OPTIONS ${deploy_tool_options}
|
|
||||||
)
|
|
||||||
install(SCRIPT ${QT_DEPLOY_SCRIPT}
|
|
||||||
COMPONENT AmneziaVPN
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
|
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Modules;${CMAKE_MODULE_PATH}")
|
||||||
|
|
||||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/SortFilterProxyModel)
|
add_subdirectory(${AMNEZIA_THIRDPARTY_ROOT}/SortFilterProxyModel ${CMAKE_CURRENT_BINARY_DIR}/3rd/SortFilterProxyModel)
|
||||||
set(LIBS ${LIBS} SortFilterProxyModel)
|
set(LIBS ${LIBS} SortFilterProxyModel)
|
||||||
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
include(${CLIENT_ROOT_DIR}/cmake/QSimpleCrypto.cmake)
|
||||||
|
|
||||||
include(${CLIENT_ROOT_DIR}/3rd/qrcodegen/qrcodegen.cmake)
|
include(${AMNEZIA_THIRDPARTY_ROOT}/qrcodegen/qrcodegen.cmake)
|
||||||
|
|
||||||
add_compile_definitions(_WINSOCKAPI_)
|
add_compile_definitions(_WINSOCKAPI_)
|
||||||
|
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_WITH_QT6 ON)
|
set(BUILD_WITH_QT6 ON)
|
||||||
add_subdirectory(${CLIENT_ROOT_DIR}/3rd/qtkeychain EXCLUDE_FROM_ALL)
|
add_subdirectory(${AMNEZIA_THIRDPARTY_ROOT}/qtkeychain ${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
# Use qtgamepad from amnezia-vpn/qtgamepad repository
|
# Use qtgamepad from amnezia-vpn/qtgamepad repository
|
||||||
@@ -36,8 +37,8 @@ endif()
|
|||||||
set(LIBS ${LIBS} qt6keychain)
|
set(LIBS ${LIBS} qt6keychain)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src/include
|
${AMNEZIA_THIRDPARTY_ROOT}/QSimpleCrypto/src/include
|
||||||
${CLIENT_ROOT_DIR}/3rd/qtkeychain/qtkeychain
|
${AMNEZIA_THIRDPARTY_ROOT}/qtkeychain/qtkeychain
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
${CMAKE_CURRENT_BINARY_DIR}/3rd/qtkeychain
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)
|
||||||
set(QSIMPLECRYPTO_DIR ${CLIENT_ROOT_DIR}/3rd/QSimpleCrypto/src)
|
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||||
|
set(QSIMPLECRYPTO_DIR ${AMNEZIA_THIRDPARTY_ROOT}/QSimpleCrypto/src)
|
||||||
|
|
||||||
include_directories(${QSIMPLECRYPTO_DIR})
|
include_directories(${QSIMPLECRYPTO_DIR})
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,8 @@ if(AMNEZIA_IOS_APPLETV)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(WG_APPLE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd/amneziawg-apple/Sources)
|
set(AMNEZIA_THIRDPARTY_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||||
|
set(WG_APPLE_SOURCE_DIR ${AMNEZIA_THIRDPARTY_ROOT}/amneziawg-apple/Sources)
|
||||||
|
|
||||||
target_sources(${PROJECT} PRIVATE
|
target_sources(${PROJECT} PRIVATE
|
||||||
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift
|
# ${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/iosvpnprotocol.swift
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
enable_language(Swift)
|
enable_language(Swift)
|
||||||
|
|
||||||
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
set(CLIENT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||||
|
set(AMNEZIA_THIRDPARTY_ROOT "${CLIENT_ROOT_DIR}/3rd" CACHE PATH "Path to Amnezia client/3rd sources")
|
||||||
set(AMNEZIA_IOS_APPLETV ${AMNEZIA_IOS_ENABLE_APPLETV_TARGET})
|
set(AMNEZIA_IOS_APPLETV ${AMNEZIA_IOS_ENABLE_APPLETV_TARGET})
|
||||||
|
|
||||||
if(AMNEZIA_IOS_APPLETV)
|
if(AMNEZIA_IOS_APPLETV)
|
||||||
@@ -94,7 +95,7 @@ endif()
|
|||||||
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
target_compile_options(networkextension PRIVATE -DGROUP_ID=\"${BUILD_IOS_GROUP_IDENTIFIER}\")
|
||||||
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
|
target_compile_options(networkextension PRIVATE -DNETWORK_EXTENSION=1)
|
||||||
|
|
||||||
set(WG_APPLE_SOURCE_DIR ${CLIENT_ROOT_DIR}/3rd/amneziawg-apple/Sources)
|
set(WG_APPLE_SOURCE_DIR ${AMNEZIA_THIRDPARTY_ROOT}/amneziawg-apple/Sources)
|
||||||
|
|
||||||
set(NE_COMMON_SOURCES
|
set(NE_COMMON_SOURCES
|
||||||
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
|
${CLIENT_ROOT_DIR}/platforms/ios/NELogController.swift
|
||||||
|
|||||||
6
client/platforms/ios/tvos_cgo_stubs.c
Normal file
6
client/platforms/ios/tvos_cgo_stubs.c
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*
|
||||||
|
* tvOS does not export these iOS runtime helpers used by Go cgo archives.
|
||||||
|
* WireGuardKitGo references them indirectly; provide no-op stubs for tvOS.
|
||||||
|
*/
|
||||||
|
void darwin_arm_init_mach_exception_handler(void) {}
|
||||||
|
void darwin_arm_init_thread_exception_port(void) {}
|
||||||
@@ -1,11 +1,21 @@
|
|||||||
if(APPLE)
|
if(APPLE)
|
||||||
get_property(generator_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
get_property(generator_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||||
if (generator_is_multi_config)
|
if (generator_is_multi_config)
|
||||||
set(CONAN_INSTALL_BUILD_CONFIGURATIONS Release Debug MinSizeRel RelWithDebInfo)
|
if(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||||
|
set(CONAN_INSTALL_BUILD_CONFIGURATIONS RelWithDebInfo)
|
||||||
|
else()
|
||||||
|
set(CONAN_INSTALL_BUILD_CONFIGURATIONS Release Debug MinSizeRel RelWithDebInfo)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "" FORCE)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "" FORCE)
|
||||||
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
|
||||||
|
set(CONAN_INSTALL_ARGS "--build=missing;-o;openssl/3.6.1:no_apps=True" CACHE STRING "" FORCE)
|
||||||
|
set(AMNEZIA_IOS_ENABLE_APPLETV_TARGET ON CACHE BOOL "" FORCE)
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "17.0" CACHE STRING "" FORCE)
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "" FORCE)
|
||||||
elseif(MACOS_NE)
|
elseif(MACOS_NE)
|
||||||
set(CONAN_INSTALL_ARGS "--build=missing;-o=&:macos_ne=True" CACHE STRING "" FORCE)
|
set(CONAN_INSTALL_ARGS "--build=missing;-o=&:macos_ne=True" CACHE STRING "" FORCE)
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0" CACHE STRING "" FORCE)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class AmneziaVPN(ConanFile):
|
|||||||
def requirements(self):
|
def requirements(self):
|
||||||
os = str(self.settings.os)
|
os = str(self.settings.os)
|
||||||
|
|
||||||
has_ne = os == "iOS" or (os == "Macos" and self.options.macos_ne)
|
has_ne = os in ["iOS", "tvOS"] or (os == "Macos" and self.options.macos_ne)
|
||||||
has_service = os == "Windows" or os == "Linux" or (os == "Macos" and not has_ne)
|
has_service = os == "Windows" or os == "Linux" or (os == "Macos" and not has_ne)
|
||||||
|
|
||||||
if has_service:
|
if has_service:
|
||||||
@@ -33,8 +33,9 @@ class AmneziaVPN(ConanFile):
|
|||||||
|
|
||||||
if has_ne:
|
if has_ne:
|
||||||
self.requires("awg-apple/2.0.1")
|
self.requires("awg-apple/2.0.1")
|
||||||
self.requires("hev-socks5-tunnel/2.14.4", options={"as_framework": True})
|
if os != "tvOS":
|
||||||
self.requires("openvpnadapter/1.0.0")
|
self.requires("hev-socks5-tunnel/2.14.4", options={"as_framework": True})
|
||||||
|
self.requires("openvpnadapter/1.0.0")
|
||||||
|
|
||||||
if os == "Android":
|
if os == "Android":
|
||||||
self.requires("amnezia-libxray/1.0.0")
|
self.requires("amnezia-libxray/1.0.0")
|
||||||
@@ -42,4 +43,4 @@ class AmneziaVPN(ConanFile):
|
|||||||
self.requires("openvpn-pt-android/1.0.0")
|
self.requires("openvpn-pt-android/1.0.0")
|
||||||
|
|
||||||
self.requires("libssh/0.11.3@amnezia")
|
self.requires("libssh/0.11.3@amnezia")
|
||||||
self.requires("openssl/3.6.1")
|
self.requires("openssl/3.6.1", options={"no_apps": os == "tvOS"}, force=os == "tvOS")
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
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, collect_libs
|
from conan.tools.files import get, copy, collect_libs, replace_in_file
|
||||||
from conan.tools.apple import is_apple_os
|
from conan.tools.apple import is_apple_os
|
||||||
from conan.tools.gnu import AutotoolsToolchain, Autotools
|
from conan.tools.gnu import AutotoolsToolchain, Autotools
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
TVOS_PREBUILT_DIR_ENV = "AMNEZIA_TVOS_AWG_PREBUILT_DIR"
|
||||||
|
TVOS_VERSION_HEADER_DIR_ENV = "AMNEZIA_TVOS_AWG_VERSION_HEADER_DIR"
|
||||||
|
|
||||||
|
|
||||||
class AwgApple(ConanFile):
|
class AwgApple(ConanFile):
|
||||||
name = "awg-apple"
|
name = "awg-apple"
|
||||||
@@ -18,6 +23,10 @@ class AwgApple(ConanFile):
|
|||||||
"as_framework": False
|
"as_framework": False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _is_tvos(self):
|
||||||
|
return str(self.settings.os) == "tvOS"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _goarch(self):
|
def _goarch(self):
|
||||||
arch_map = {
|
arch_map = {
|
||||||
@@ -27,9 +36,6 @@ class AwgApple(ConanFile):
|
|||||||
archs = str(self.settings.arch).split("|")
|
archs = str(self.settings.arch).split("|")
|
||||||
return " ".join(arch_map.get(arch, arch) for arch in archs)
|
return " ".join(arch_map.get(arch, arch) for arch in archs)
|
||||||
|
|
||||||
def build_requirements(self):
|
|
||||||
self.tool_requires("go/1.26.0")
|
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
basic_layout(self, build_folder=os.path.join(self.folders.source, "Sources/WireGuardKitGo"))
|
basic_layout(self, build_folder=os.path.join(self.folders.source, "Sources/WireGuardKitGo"))
|
||||||
|
|
||||||
@@ -44,16 +50,96 @@ class AwgApple(ConanFile):
|
|||||||
sha256="9fe4f8cfbb6a751558b54b7979db3a5ea46e49731912aae99f093e84a1433e97", strip_root=True
|
sha256="9fe4f8cfbb6a751558b54b7979db3a5ea46e49731912aae99f093e84a1433e97", strip_root=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _go_env(self):
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["GOTOOLCHAIN"] = "local"
|
||||||
|
return env
|
||||||
|
|
||||||
|
def _go_root(self):
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(
|
||||||
|
["go", "env", "GOROOT"],
|
||||||
|
text=True,
|
||||||
|
env=self._go_env(),
|
||||||
|
cwd="/",
|
||||||
|
).strip()
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError) as error:
|
||||||
|
raise ConanInvalidConfiguration(
|
||||||
|
"Go is required to build awg-apple. Install Go or provide a tvOS "
|
||||||
|
f"prebuilt bridge through {TVOS_PREBUILT_DIR_ENV}."
|
||||||
|
) from error
|
||||||
|
|
||||||
|
def _env_path(self, name):
|
||||||
|
value = os.environ.get(name)
|
||||||
|
if not value:
|
||||||
|
return None
|
||||||
|
return os.path.abspath(os.path.expanduser(value))
|
||||||
|
|
||||||
|
def _uses_tvos_prebuilt_bridge(self):
|
||||||
|
return self._is_tvos and self._env_path(TVOS_PREBUILT_DIR_ENV) is not None
|
||||||
|
|
||||||
|
def _make_args(self):
|
||||||
|
if self._uses_tvos_prebuilt_bridge():
|
||||||
|
return []
|
||||||
|
|
||||||
|
sdk = self.settings.get_safe("os.sdk", "macosx")
|
||||||
|
args = [
|
||||||
|
f"ARCHS={self._goarch}",
|
||||||
|
f"PLATFORM_NAME={sdk}",
|
||||||
|
f"REAL_GOROOT={self._go_root()}",
|
||||||
|
"GOTOOLCHAIN=local",
|
||||||
|
]
|
||||||
|
if self._is_tvos:
|
||||||
|
args.extend([
|
||||||
|
"GOOS_appletvos=ios",
|
||||||
|
"GOFLAGS=-tags=netgo",
|
||||||
|
"DEPLOYMENT_TARGET_CLANG_FLAG_NAME=mtvos-version-min",
|
||||||
|
"DEPLOYMENT_TARGET_CLANG_ENV_NAME=TVOS_DEPLOYMENT_TARGET",
|
||||||
|
f"TVOS_DEPLOYMENT_TARGET={self.settings.os.version}",
|
||||||
|
])
|
||||||
|
return args
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
tc = AutotoolsToolchain(self)
|
tc = AutotoolsToolchain(self)
|
||||||
sdk = self.settings.get_safe("os.sdk", "macosx")
|
tc.make_args = self._make_args()
|
||||||
tc.make_args = [
|
|
||||||
f"ARCHS={self._goarch}",
|
|
||||||
f"PLATFORM_NAME={sdk}"
|
|
||||||
]
|
|
||||||
tc.generate()
|
tc.generate()
|
||||||
|
|
||||||
|
def _copy_tvos_prebuilt_bridge(self):
|
||||||
|
prebuilt_dir = self._env_path(TVOS_PREBUILT_DIR_ENV)
|
||||||
|
if not prebuilt_dir:
|
||||||
|
return False
|
||||||
|
|
||||||
|
lib_path = os.path.join(prebuilt_dir, "libwg-go.a")
|
||||||
|
if not os.path.isfile(lib_path):
|
||||||
|
raise ConanInvalidConfiguration(
|
||||||
|
f"{TVOS_PREBUILT_DIR_ENV} is set to '{prebuilt_dir}', but libwg-go.a was not found there."
|
||||||
|
)
|
||||||
|
|
||||||
|
header_dir = self._env_path(TVOS_VERSION_HEADER_DIR_ENV) or prebuilt_dir
|
||||||
|
header_path = os.path.join(header_dir, "wireguard-go-version.h")
|
||||||
|
if not os.path.isfile(header_path):
|
||||||
|
raise ConanInvalidConfiguration(
|
||||||
|
f"wireguard-go-version.h was not found in '{header_dir}'. Set "
|
||||||
|
f"{TVOS_VERSION_HEADER_DIR_ENV} if the header lives outside {TVOS_PREBUILT_DIR_ENV}."
|
||||||
|
)
|
||||||
|
|
||||||
|
self.output.warning(
|
||||||
|
f"Using explicit tvOS WireGuard bridge from {TVOS_PREBUILT_DIR_ENV}={prebuilt_dir}"
|
||||||
|
)
|
||||||
|
out_dir = os.path.join(self.build_folder, "out")
|
||||||
|
copy(self, "libwg-go.a", src=prebuilt_dir, dst=out_dir)
|
||||||
|
copy(self, "wireguard-go-version.h", src=header_dir, dst=out_dir)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _patch_tvos_go_version_for_local_toolchain(self):
|
||||||
|
replace_in_file(self, os.path.join(self.build_folder, "go.mod"), "go 1.26", "go 1.25")
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
|
if self._is_tvos:
|
||||||
|
if self._copy_tvos_prebuilt_bridge():
|
||||||
|
return
|
||||||
|
self._patch_tvos_go_version_for_local_toolchain()
|
||||||
|
|
||||||
autotools = Autotools(self)
|
autotools = Autotools(self)
|
||||||
autotools.make()
|
autotools.make()
|
||||||
autotools.make("version-header")
|
autotools.make("version-header")
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ class LibSSHRecipe(ConanFile):
|
|||||||
tc.cache_variables["WITH_MBEDTLS"] = self.options.crypto_backend == "mbedtls"
|
tc.cache_variables["WITH_MBEDTLS"] = self.options.crypto_backend == "mbedtls"
|
||||||
tc.cache_variables["WITH_NACL"] = False
|
tc.cache_variables["WITH_NACL"] = False
|
||||||
tc.cache_variables["WITH_SYMBOL_VERSIONING"] = self.options.get_safe("with_symbol_versioning", True)
|
tc.cache_variables["WITH_SYMBOL_VERSIONING"] = self.options.get_safe("with_symbol_versioning", True)
|
||||||
|
if self.settings.os == "tvOS":
|
||||||
|
tc.cache_variables["WITH_EXEC"] = False
|
||||||
tc.variables["WITH_ZLIB"] = self.options.with_zlib
|
tc.variables["WITH_ZLIB"] = self.options.with_zlib
|
||||||
if is_msvc(self):
|
if is_msvc(self):
|
||||||
tc.cache_variables["USE_MSVC_RUNTIME_LIBRARY_DLL"] = not is_msvc_static_runtime(self)
|
tc.cache_variables["USE_MSVC_RUNTIME_LIBRARY_DLL"] = not is_msvc_static_runtime(self)
|
||||||
|
|||||||
Reference in New Issue
Block a user