summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2022-08-23 13:40:14 +0200
committerDavid Lönnhager <david.l@mullvad.net>2022-08-23 13:40:14 +0200
commit7dc36e0fb75403c634c2c90c52e710ce2115248c (patch)
tree42671cabd83517a9be84422e321d935356a4c115
parente7c9140c4c2555affdd4ed879cd1a3593bdea7cf (diff)
parent2b6855070649663dbb66107660085e3e1994f8c9 (diff)
downloadmullvadvpn-7dc36e0fb75403c634c2c90c52e710ce2115248c.tar.xz
mullvadvpn-7dc36e0fb75403c634c2c90c52e710ce2115248c.zip
Merge branch 'linux-aarch64-build'
-rw-r--r--CHANGELOG.md1
-rw-r--r--README.md60
-rwxr-xr-xbuild.sh20
m---------dist-assets/binaries0
-rwxr-xr-xenv.sh3
-rwxr-xr-xgui/scripts/build-proto.sh9
-rw-r--r--gui/tasks/distribution.js72
-rwxr-xr-xwireguard/build-wireguard-go.sh33
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.
diff --git a/README.md b/README.md
index 7ae4f631e3..72bb7c1703 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/build.sh b/build.sh
index 9f759ad4de..4eaa409cc7 100755
--- a/build.sh
+++ b/build.sh
@@ -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
diff --git a/env.sh b/env.sh
index 7143760a21..a952769ce6 100755
--- a/env.sh
+++ b/env.sh
@@ -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