diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-08-23 13:40:14 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-08-23 13:40:14 +0200 |
| commit | 7dc36e0fb75403c634c2c90c52e710ce2115248c (patch) | |
| tree | 42671cabd83517a9be84422e321d935356a4c115 | |
| parent | e7c9140c4c2555affdd4ed879cd1a3593bdea7cf (diff) | |
| parent | 2b6855070649663dbb66107660085e3e1994f8c9 (diff) | |
| download | mullvadvpn-7dc36e0fb75403c634c2c90c52e710ce2115248c.tar.xz mullvadvpn-7dc36e0fb75403c634c2c90c52e710ce2115248c.zip | |
Merge branch 'linux-aarch64-build'
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | README.md | 60 | ||||
| -rwxr-xr-x | build.sh | 20 | ||||
| m--------- | dist-assets/binaries | 0 | ||||
| -rwxr-xr-x | env.sh | 3 | ||||
| -rwxr-xr-x | gui/scripts/build-proto.sh | 9 | ||||
| -rw-r--r-- | gui/tasks/distribution.js | 72 | ||||
| -rwxr-xr-x | wireguard/build-wireguard-go.sh | 33 |
8 files changed, 160 insertions, 38 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b06412661..327cbd5a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ Line wrap the file at 100 chars. Th #### Linux - GUI: Add electron flags to run Wayland native if in a compositor/desktop known to work well +- Add support for Linux ARM64. ### Changed - Reject invalid WireGuard ports in the CLI. @@ -147,6 +147,35 @@ sudo dnf install dbus-devel sudo dnf install rpm-build ``` +### Cross-compiling for Linux ARM64 + +By default, the app will build for the host platform. It is also possible to cross-compile the app +for ARM64 on x64. + +#### Debian + +```bash +# As root +dpkg --add-architecture arm64 && \ + apt update && \ + apt install libdbus-1-dev:arm64 gcc-aarch64-linux-gnu +``` + +```bash +rustup target add aarch64-unknown-linux-gnu +``` + +To make sure the right linker and libraries are used, add the following to `~/.cargo/config.toml`: + +``` +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" + +[target.aarch64-unknown-linux-gnu.dbus] +rustc-link-search = ["/usr/aarch64-linux-gnu/lib"] +rustc-link-lib = ["dbus-1"] +``` + ### Android These instructions are for building the app for Android **under Linux**. @@ -317,16 +346,27 @@ Building this requires at least 1GB of memory. By default, `build.sh` produces a pkg for your current architecture only. To build a universal app that works on both Intel and Apple Silicon macs, build with `--universal`. -##### Apple ARM64 (aka Apple Silicon) +#### Linux ARM64 + +To cross-compile for ARM64 rather than the current architecture, set the `TARGETS` environment +variable to `aarch64-unknown-linux-gnu`: + +```bash +TARGETS="aarch64-unknown-linux-gnu" ./build.sh +``` + +##### ARM64 Due to inability to build the management interface proto files on ARM64 (see -[this](https://github.com/grpc/grpc-node/issues/1497) issue) the Apple ARM64 build must be done in 2 stages: +[this](https://github.com/grpc/grpc-node/issues/1497) issue), building on ARM64 must be done in +2 stages: 1. Build management interface proto files on a non-ARM64 platform -2. Use the built proto files during the main build by setting the `MANAGEMENT_INTERFACE_PROTO_BUILD_DIR` - environment variable to the path the proto files +2. Use the built proto files during the main build by setting the + `MANAGEMENT_INTERFACE_PROTO_BUILD_DIR` environment variable to the path the proto files -To build the management interface proto files there is a script (execute it on a non-ARM64 platform): +To build the management interface proto files there is a script (execute it on a non-ARM64 +platform): ```bash cd gui/scripts @@ -334,11 +374,11 @@ npm ci ./build-proto.sh ``` -After that copy the files from `gui/src/main/management_interface/` and `gui/build/src/main/management_interface/` -directories into a single directory on your Apple Silicon Mac, and set the value of -`MANAGEMENT_INTERFACE_PROTO_BUILD_DIR` to that directory while running the main build. +After that copy the files from `gui/src/main/management_interface/` and +`gui/build/src/main/management_interface/` directories into a single directory, and set the value +of `MANAGEMENT_INTERFACE_PROTO_BUILD_DIR` to that directory while running the main build. -Install `protobuf` by running: +Install `protobuf`. On macOS, this can be done using Homebrew: ```bash brew install protobuf @@ -351,6 +391,8 @@ directory, the build command will look as follows: MANAGEMENT_INTERFACE_PROTO_BUILD_DIR=/tmp/management_interface_proto ./build.sh --dev-build ``` +On Linux, you may also have to specify `USE_SYSTEM_FPM=true` to generate the deb/rpm packages. + If you want to build each component individually, or run in development mode, read the following sections. @@ -65,7 +65,16 @@ fi CARGO_ARGS=() NPM_PACK_ARGS=() +if [[ -n ${TARGETS:-""} ]]; then + NPM_PACK_ARGS+=(--targets "${TARGETS[*]}") +fi + if [[ "$UNIVERSAL" == "true" ]]; then + if [[ -n ${TARGETS:-""} ]]; then + log_error "'TARGETS' and '--universal' cannot be specified simultaneously." + exit 1 + fi + TARGETS=(x86_64-apple-darwin aarch64-apple-darwin) NPM_PACK_ARGS+=(--universal) fi @@ -197,8 +206,13 @@ function sign_win { function build { local current_target=${1:-""} local for_target_string="" + local stripbin="strip" if [[ -n $current_target ]]; then for_target_string=" for $current_target" + + if [[ "$current_target" == "aarch64-unknown-linux-gnu" && "$(uname -m)" != "aarch64" ]]; then + stripbin="aarch64-linux-gnu-strip" + fi fi ################################################################################ @@ -255,8 +269,8 @@ function build { if [[ -n $current_target ]]; then local cargo_output_dir="$CARGO_TARGET_DIR/$current_target/$RUST_BUILD_MODE" - # To make it easier to package universal builds on macOS the binaries are located in a - # directory with the name of the target triple. + # To make it easier to package multiple targets, the binaries are + # located in a directory with the name of the target triple. local destination_dir="dist-assets/$current_target" mkdir -p "$destination_dir" else @@ -273,7 +287,7 @@ function build { cp "$source" "$destination" else log_info "Stripping $source => $destination" - strip "$source" -o "$destination" + "${stripbin}" "$source" -o "$destination" fi if [[ "$SIGN" == "true" && "$(uname -s)" == "MINGW"* ]]; then diff --git a/dist-assets/binaries b/dist-assets/binaries -Subproject 1c5f5202fc522ecbf9d5e972ed70df5cbb71cf6 +Subproject 4ccf373118861377c0a6fe10de50eeab7650ab5 @@ -6,7 +6,8 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" case "$(uname -s)" in Linux*) - HOST="x86_64-unknown-linux-gnu" + arch="$(uname -m)" + HOST="${arch}-unknown-linux-gnu" ;; Darwin*) arch="$(uname -m)" diff --git a/gui/scripts/build-proto.sh b/gui/scripts/build-proto.sh index f2ee78e3af..5f8724a68c 100755 --- a/gui/scripts/build-proto.sh +++ b/gui/scripts/build-proto.sh @@ -5,7 +5,8 @@ set -eu SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$SCRIPT_DIR" -PLATFORM="$(uname -s)-$(uname -m)" +ARCH="$(uname -m)" +PLATFORM="$(uname -s)-${ARCH}" MANAGEMENT_INTERFACE_PROTO_BUILD_DIR=${MANAGEMENT_INTERFACE_PROTO_BUILD_DIR:-} NODE_MODULES_DIR="$(cd ../node_modules/.bin && pwd)" PROTO_DIR="../../mullvad-management-interface/proto" @@ -21,14 +22,14 @@ fi mkdir -p $DESTINATION_DIR mkdir -p $TYPES_DESTINATION_DIR -if [[ "${PLATFORM}" == "Darwin-arm64" ]]; then +if [[ "${ARCH,,}" == "arm64" || "${ARCH,,}" == "aarch64" ]]; then if [[ -n "${MANAGEMENT_INTERFACE_PROTO_BUILD_DIR}" ]]; then cp $MANAGEMENT_INTERFACE_PROTO_BUILD_DIR/*.js $DESTINATION_DIR cp $MANAGEMENT_INTERFACE_PROTO_BUILD_DIR/*.ts $TYPES_DESTINATION_DIR else - >&2 echo "Building management interface proto files on Apple Silicon is not supported" + >&2 echo "Building management interface proto files on aarch64 is not supported" >&2 echo "(see https://github.com/grpc/grpc-node/issues/1497)." - >&2 echo "Please build the proto files on another platform using build_mi_proto.sh script," + >&2 echo "Please build the proto files on another platform using build-proto.sh script," >&2 echo "and set MANAGEMENT_INTERFACE_PROTO_BUILD_DIR environment variable to the directory of the build." exit 1 fi diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js index cee853748a..8fde833d4f 100644 --- a/gui/tasks/distribution.js +++ b/gui/tasks/distribution.js @@ -12,6 +12,13 @@ const noAppleNotarization = process.argv.includes('--no-apple-notarization'); const universal = process.argv.includes('--universal'); const release = process.argv.includes('--release'); +const targetsIndex = process.argv.indexOf('--targets'); +let targets = null; + +if (targetsIndex !== -1) { + targets = process.argv[targetsIndex + 1]; +} + const config = { appId: 'net.mullvad.vpn', copyright: 'Mullvad VPN AB', @@ -147,17 +154,26 @@ const config = { }, linux: { - target: ['deb', 'rpm'], + target: [ + { + target: 'deb', + arch: getLinuxTargetArch(), + }, + { + target: 'rpm', + arch: getLinuxTargetArch(), + }, + ], artifactName: 'MullvadVPN-${version}_${arch}.${ext}', category: 'Network', icon: distAssets('icon.icns'), extraFiles: [{ from: distAssets('linux/mullvad-gui-launcher.sh'), to: '.' }], extraResources: [ - { from: distAssets('mullvad-problem-report'), to: '.' }, - { from: distAssets('mullvad-daemon'), to: '.' }, - { from: distAssets('mullvad-setup'), to: '.' }, - { from: distAssets('libtalpid_openvpn_plugin.so'), to: '.' }, - { from: distAssets('binaries/x86_64-unknown-linux-gnu/openvpn'), to: '.' }, + { from: distAssets(path.join(getLinuxTargetSubdir(), 'mullvad-problem-report')), to: '.' }, + { from: distAssets(path.join(getLinuxTargetSubdir(), 'mullvad-daemon')), to: '.' }, + { from: distAssets(path.join(getLinuxTargetSubdir(), 'mullvad-setup')), to: '.' }, + { from: distAssets(path.join(getLinuxTargetSubdir(), 'libtalpid_openvpn_plugin.so')), to: '.' }, + { from: distAssets(path.join('binaries', '${env.TARGET_TRIPLE}', 'openvpn')), to: '.' }, { from: distAssets('linux/mullvad-daemon.service'), to: '.' }, ], }, @@ -173,8 +189,8 @@ const config = { distAssets('linux/before-remove.sh'), '--config-files', '/opt/Mullvad VPN/resources/mullvad-daemon.service', - distAssets('mullvad') + '=/usr/bin/', - distAssets('mullvad-exclude') + '=/usr/bin/', + distAssets(path.join(getLinuxTargetSubdir(), 'mullvad')) + '=/usr/bin/', + distAssets(path.join(getLinuxTargetSubdir(), 'mullvad-exclude')) + '=/usr/bin/', distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report', distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad', @@ -196,8 +212,8 @@ const config = { distAssets('linux/post-transaction.sh'), '--config-files', '/opt/Mullvad VPN/resources/mullvad-daemon.service', - distAssets('mullvad') + '=/usr/bin/', - distAssets('mullvad-exclude') + '=/usr/bin/', + distAssets(path.join(getLinuxTargetSubdir(), 'mullvad')) + '=/usr/bin/', + distAssets(path.join(getLinuxTargetSubdir(), 'mullvad-exclude')) + '=/usr/bin/', distAssets('linux/problem-report-link') + '=/usr/bin/mullvad-problem-report', distAssets('shell-completions/mullvad.bash') + '=/usr/share/bash-completion/completions/mullvad', @@ -304,6 +320,21 @@ function packLinux() { targets: builder.Platform.LINUX.createTarget(), config: { ...config, + beforeBuild: (options) => { + switch (options.arch) { + case 'x64': + process.env.TARGET_TRIPLE = 'x86_64-unknown-linux-gnu'; + break; + case 'arm64': + process.env.TARGET_TRIPLE = 'aarch64-unknown-linux-gnu'; + break; + default: + delete process.env.TARGET_TRIPLE; + break; + } + + return true; + }, afterPack: async (context) => { config.afterPack?.(context); @@ -328,6 +359,27 @@ function root(relativePath) { return path.join(path.resolve(__dirname, '../../'), relativePath); } +function getLinuxTargetArch() { + if (targets) { + if (targets === 'aarch64-unknown-linux-gnu') { + return 'arm64'; + } + throw new Error(`Invalid or unknown target (only one may be specified)`); + } + // Use host architecture. + return undefined; +} + +function getLinuxTargetSubdir() { + if (targets) { + if (targets === 'aarch64-unknown-linux-gnu') { + return targets; + } + throw new Error(`Invalid or unknown target (only one may be specified)`); + } + return ''; +} + function getMacArch() { if (universal) { return 'universal'; diff --git a/wireguard/build-wireguard-go.sh b/wireguard/build-wireguard-go.sh index 33330c9298..0374a82892 100755 --- a/wireguard/build-wireguard-go.sh +++ b/wireguard/build-wireguard-go.sh @@ -70,7 +70,8 @@ function build_windows { function unix_target_triple { local platform="$(uname -s)" if [[ ("${platform}" == "Linux") ]]; then - echo "x86_64-unknown-linux-gnu" + local arch="$(uname -m)" + echo "${arch}-unknown-linux-gnu" elif [[ ("${platform}" == "Darwin") ]]; then local arch="$(uname -m)" if [[ ("${arch}" == "arm64") ]]; then @@ -87,16 +88,26 @@ function unix_target_triple { function build_unix { echo "Building wireguard-go for $1" - # Flags for cross compiling for M1 macs - if [[ "$(unix_target_triple)" != "$1" && "$1" == "aarch64-apple-darwin" ]]; then - export CGO_ENABLED=1 - export GOOS=darwin - export GOARCH=arm64 - export CC="$(xcrun -sdk $SDKROOT --find clang) -arch $GOARCH -isysroot $SDKROOT" - export CFLAGS="-isysroot $SDKROOT -arch $GOARCH -I$SDKROOT/usr/include" - export LD_LIBRARY_PATH="$SDKROOT/usr/lib" - export CGO_CFLAGS="-isysroot $SDKROOT -arch $GOARCH" - export CGO_LDFLAGS="-isysroot $SDKROOT -arch $GOARCH" + # Flags for cross compiling + if [[ "$(unix_target_triple)" != "$1" ]]; then + # Linux arm + if [[ "$1" == "aarch64-unknown-linux-gnu" ]]; then + export CGO_ENABLED=1 + export GOARCH=arm64 + export CC=aarch64-linux-gnu-gcc + fi + + # Apple silicon + if [[ "$1" == "aarch64-apple-darwin" ]]; then + export CGO_ENABLED=1 + export GOOS=darwin + export GOARCH=arm64 + export CC="$(xcrun -sdk $SDKROOT --find clang) -arch $GOARCH -isysroot $SDKROOT" + export CFLAGS="-isysroot $SDKROOT -arch $GOARCH -I$SDKROOT/usr/include" + export LD_LIBRARY_PATH="$SDKROOT/usr/lib" + export CGO_CFLAGS="-isysroot $SDKROOT -arch $GOARCH" + export CGO_LDFLAGS="-isysroot $SDKROOT -arch $GOARCH" + fi fi pushd libwg |
