summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2021-04-21 13:37:54 +0200
committerOskar Nyberg <oskar@mullvad.net>2021-04-21 13:37:54 +0200
commitfcf42ec680b78f5d432376763284298fb52c2d80 (patch)
treea33a7a9a40442daf341e6106a6604af18ebe3b6b
parent2d51a1a84f7ca914e6d157df0e2129af569b086f (diff)
parent8400c4eb6baa3f09ea68ff8aab16b5e55efe7632 (diff)
downloadmullvadvpn-fcf42ec680b78f5d432376763284298fb52c2d80.tar.xz
mullvadvpn-fcf42ec680b78f5d432376763284298fb52c2d80.zip
Merge branch 'cross-compile-for-m1'
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG.md1
-rw-r--r--README.md7
-rwxr-xr-xbuild.sh228
-rwxr-xr-xenv.sh31
-rw-r--r--gui/tasks/distribution.js57
-rwxr-xr-xwireguard/build-wireguard-go.sh18
7 files changed, 239 insertions, 105 deletions
diff --git a/.gitignore b/.gitignore
index 3cbba48396..21f8064886 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,8 @@
/dist-assets/sslocal
/dist-assets/sslocal.exe
/dist-assets/shell-completions/
+/dist-assets/aarch64-apple-darwin/
+/dist-assets/x86_64-apple-darwin/
/windows/**/bin/
/windows/**/*.user
/android/keystore.properties
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 44a33c985d..05728b97e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,6 +27,7 @@ Line wrap the file at 100 chars. Th
- When `MULLVAD_MANAGEMENT_SOCKET_GROUP` is set, only allow the specified group to access the
management interface UDS socket. This means that only users in that group can use the CLI and GUI.
- Support WireGuard over TCP for custom VPN relays in the CLI.
+- Make app native on Apple Silicon.
### Changed
- Upgrade OpenVPN from 2.5.0 to 2.5.1.
diff --git a/README.md b/README.md
index 6d3c970c82..8e142454bb 100644
--- a/README.md
+++ b/README.md
@@ -296,7 +296,12 @@ This should produce an installer exe, pkg or rpm+deb file in the `dist/` directo
Building this requires at least 1GB of memory.
-#### Apple ARM64 (aka Apple Silicon)
+#### macOS
+
+By default a universal app is built on macOS. To build specifically for x86_64 or ARM64 add
+`--target x86_64-apple-darwin` or `--target aarch64-apple-darwin`.
+
+##### Apple ARM64 (aka Apple Silicon)
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:
diff --git a/build.sh b/build.sh
index 897d8f769c..83afe6a940 100755
--- a/build.sh
+++ b/build.sh
@@ -15,15 +15,34 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
RUSTC_VERSION=$(rustc +stable --version)
PRODUCT_VERSION=$(node -p "require('./gui/package.json').version" | sed -Ee 's/\.0//g')
-CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-"$SCRIPT_DIR/target"}
+CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-"target"}
CARGO_ARGS=()
NPM_PACK_ARGS=()
-source env.sh
+BUILD_MODE="release"
+while [[ "$#" -gt 0 ]]; do
+ case $1 in
+ --dev-build) BUILD_MODE="dev" ;;
+ --target)
+ TARGET=("$2")
+ shift
+ ;;
+ *)
+ echo "Unknown parameter: $1"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+if [[ "$(uname -s)" == "Darwin" && -z ${TARGET:-""} ]]; then
+ echo "Defaulting to universal macOS target since no target was provided"
+ TARGET=(x86_64-apple-darwin aarch64-apple-darwin)
+ NPM_PACK_ARGS+=(--universal)
+fi
-if [[ "${1:-""}" != "--dev-build" ]]; then
- BUILD_MODE="release"
+if [[ "$BUILD_MODE" == "release" ]]; then
if [[ $(git diff --shortstat 2> /dev/null | tail -n1) != "" ]]; then
echo "Dirty working directory!"
echo "You should only build releases in clean working directories in order to make it"
@@ -57,7 +76,6 @@ if [[ "${1:-""}" != "--dev-build" ]]; then
export CSC_IDENTITY_AUTO_DISCOVERY=false
fi
else
- BUILD_MODE="dev"
NPM_PACK_ARGS+=(--no-compression)
echo "!! Development build. Not for general distribution !!"
unset CSC_LINK CSC_KEY_PASSWORD
@@ -78,8 +96,52 @@ else
CARGO_ARGS+=(--locked)
fi
+if [[ "${TARGET:-""}" == "aarch64-apple-darwin" ]]; then
+ NPM_PACK_ARGS+=(--arm64)
+fi
+
+if [[ ("$(uname -s)" == "Darwin") ]]; then
+ BINARIES=(
+ mullvad-daemon
+ mullvad
+ mullvad-problem-report
+ libtalpid_openvpn_plugin.dylib
+ mullvad-setup
+ )
+elif [[ ("$(uname -s)" == "Linux") ]]; then
+ BINARIES=(
+ mullvad-daemon
+ mullvad
+ mullvad-problem-report
+ libtalpid_openvpn_plugin.so
+ mullvad-setup
+ mullvad-exclude
+ )
+elif [[ ("$(uname -s)" == "MINGW"*) ]]; then
+ BINARIES=(
+ mullvad-daemon.exe
+ mullvad.exe
+ mullvad-problem-report.exe
+ talpid_openvpn_plugin.dll
+ mullvad-setup.exe
+ )
+fi
+
+function restore_metadata_backups() {
+ pushd "$SCRIPT_DIR"
+ echo "Restoring version metadata files..."
+ ./version-metadata.sh restore-backup --desktop
+ mv Cargo.lock.bak Cargo.lock || true
+ popd
+}
+trap 'restore_metadata_backups' EXIT
+
+echo "Updating version in metadata files..."
+cp Cargo.lock Cargo.lock.bak
+./version-metadata.sh inject "$PRODUCT_VERSION" --desktop
+
function sign_win() {
- NUM_RETRIES=3
+ local NUM_RETRIES=3
for binary in "$@"; do
# Try multiple times in case the timestamp server cannot
@@ -105,96 +167,99 @@ function sign_win() {
return 0
}
-echo "Building Mullvad VPN $PRODUCT_VERSION"
+function build() {
+ local current_target=${1:-""}
+ local for_target_string=""
+ if [[ -n $current_target ]]; then
+ for_target_string=" for $current_target"
+ fi
-function restore_metadata_backups() {
- pushd "$SCRIPT_DIR"
- echo "Restoring version metadata files..."
- ./version-metadata.sh restore-backup --desktop
- mv Cargo.lock.bak Cargo.lock || true
- popd
-}
-trap 'restore_metadata_backups' EXIT
+ echo "Building Mullvad VPN $PRODUCT_VERSION$for_target_string"
-echo "Updating version in metadata files..."
-cp Cargo.lock Cargo.lock.bak
-./version-metadata.sh inject "$PRODUCT_VERSION" --desktop
+ ################################################################################
+ # Compile and link all binaries.
+ ################################################################################
+ if [[ "$(uname -s)" == "MINGW"* ]]; then
+ CPP_BUILD_MODES="Release" ./build_windows_modules.sh "$@"
+ fi
-################################################################################
-# Compile and link all binaries.
-################################################################################
+ ################################################################################
+ # Compile wireguard-go
+ ################################################################################
-if [[ "$(uname -s)" == "MINGW"* ]]; then
- CPP_BUILD_MODES="Release" ./build_windows_modules.sh "$@"
-fi
+ ./wireguard/build-wireguard-go.sh "$current_target"
-################################################################################
-# Compile wireguard-go
-################################################################################
-./wireguard/build-wireguard-go.sh
+ export MULLVAD_ADD_MANIFEST="1"
+
+ echo "Building Rust code in release mode using $RUSTC_VERSION$for_target_string..."
-export MULLVAD_ADD_MANIFEST="1"
+ CARGO_TARGET_ARG=()
+ if [[ -n $current_target ]]; then
+ CARGO_TARGET_ARG+=(--target="$current_target")
+ fi
+
+ cargo +stable build "${CARGO_TARGET_ARG[@]}" "${CARGO_ARGS[@]}" --release
-echo "Building Rust code in release mode using $RUSTC_VERSION..."
+ ################################################################################
+ # Move binaries to correct locations in dist-assets
+ ################################################################################
-cargo +stable build "${CARGO_ARGS[@]}" --release
+ for binary in ${BINARIES[*]}; do
+ if [[ -n $current_target ]]; then
+ SRC="$CARGO_TARGET_DIR/$current_target/release/$binary"
+ else
+ SRC="$CARGO_TARGET_DIR/release/$binary"
+ fi
+ if [[ "$(uname -s)" == "Darwin" ]]; then
+ # To make it easier to package universal builds on macOS the binaries are located in a
+ # directory with the name of the target triple.
+ DST_DIR="dist-assets/$current_target"
+ DST="$DST_DIR/$binary"
+ mkdir -p "$DST_DIR"
+ else
+ DST="dist-assets/$binary"
+ fi
+
+ if [[ "$BUILD_MODE" == "release" && "$(uname -s)" == "MINGW"* ]]; then
+ sign_win "$SRC"
+ fi
+
+ if [[ "$(uname -s)" == "MINGW"* || "$binary" == *.dylib ]]; then
+ echo "Copying $SRC => $DST"
+ cp "$SRC" "$DST"
+ else
+ echo "Stripping $SRC => $DST"
+ strip "$SRC" -o "$DST"
+ fi
+ done
+}
+
+function buildTargets() {
+ if [[ -n ${TARGET:-""} ]]; then
+ for t in ${TARGET[*]}; do
+ source env.sh "$t"
+ build "$t"
+ done
+ else
+ source env.sh
+ build
+ fi
+}
if [[ "$(uname -s)" == "Darwin" || "$(uname -s)" == "Linux" ]]; then
- mkdir -p "$SCRIPT_DIR/dist-assets/shell-completions"
+ mkdir -p "dist-assets/shell-completions"
for sh in bash zsh fish; do
echo "Generating shell completion script for $sh..."
cargo +stable run --bin mullvad "${CARGO_ARGS[@]}" --release -- shell-completions "$sh" \
- "$SCRIPT_DIR/dist-assets/shell-completions/"
+ "dist-assets/shell-completions/"
done
fi
-################################################################################
-# Other work to prepare the release.
-################################################################################
-
-if [[ ("$(uname -s)" == "Darwin") ]]; then
- binaries=(
- mullvad-daemon
- mullvad
- mullvad-problem-report
- libtalpid_openvpn_plugin.dylib
- mullvad-setup
- )
-elif [[ ("$(uname -s)" == "Linux") ]]; then
- binaries=(
- mullvad-daemon
- mullvad
- mullvad-problem-report
- libtalpid_openvpn_plugin.so
- mullvad-setup
- mullvad-exclude
- )
-elif [[ ("$(uname -s)" == "MINGW"*) ]]; then
- binaries=(
- mullvad-daemon.exe
- mullvad.exe
- mullvad-problem-report.exe
- talpid_openvpn_plugin.dll
- mullvad-setup.exe
- )
-fi
-for binary in ${binaries[*]}; do
- SRC="$CARGO_TARGET_DIR/release/$binary"
- DST="$SCRIPT_DIR/dist-assets/$binary"
-
- if [[ "$BUILD_MODE" == "release" && "$(uname -s)" == "MINGW"* ]]; then
- sign_win "$SRC"
- fi
+./update-relays.sh
+./update-api-address.sh
- if [[ "$(uname -s)" == "MINGW"* || "$binary" == *.dylib ]]; then
- echo "Copying $SRC => $DST"
- cp "$SRC" "$DST"
- else
- echo "Stripping $SRC => $DST"
- strip "$SRC" -o "$DST"
- fi
-done
+buildTargets
if [[ "$BUILD_MODE" == "release" && "$(uname -s)" == "MINGW"* ]]; then
signdep=(
@@ -208,12 +273,7 @@ if [[ "$BUILD_MODE" == "release" && "$(uname -s)" == "MINGW"* ]]; then
sign_win "${signdep[@]}"
fi
-
-./update-relays.sh
-./update-api-address.sh
-
-
-pushd "$SCRIPT_DIR/gui"
+pushd gui
echo "Installing JavaScript dependencies..."
diff --git a/env.sh b/env.sh
index a1b9ae59ef..7143760a21 100755
--- a/env.sh
+++ b/env.sh
@@ -6,28 +6,43 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
case "$(uname -s)" in
Linux*)
- TARGET="x86_64-unknown-linux-gnu"
+ HOST="x86_64-unknown-linux-gnu"
;;
Darwin*)
- TARGET="x86_64-apple-darwin"
+ arch="$(uname -m)"
+ if [[ ("${arch}" == "arm64") ]]; then
+ arch="aarch64"
+ fi
+ HOST="${arch}-apple-darwin"
;;
MINGW*|MSYS_NT*)
- TARGET="x86_64-pc-windows-msvc"
+ HOST="x86_64-pc-windows-msvc"
;;
esac
-case "$TARGET" in
+ENV_TARGET=${1:-$HOST}
+
+case "$ENV_TARGET" in
*linux*)
- export LIBMNL_LIB_DIR="$SCRIPT_DIR/dist-assets/binaries/$TARGET"
- export LIBNFTNL_LIB_DIR="$SCRIPT_DIR/dist-assets/binaries/$TARGET"
+ export LIBMNL_LIB_DIR="$SCRIPT_DIR/dist-assets/binaries/$ENV_TARGET"
+ export LIBNFTNL_LIB_DIR="$SCRIPT_DIR/dist-assets/binaries/$ENV_TARGET"
;;
- *darwin*)
+ x86_64-*-darwin*)
export MACOSX_DEPLOYMENT_TARGET="10.7"
;;
+ aarch64-*-darwin*)
+ export MACOSX_DEPLOYMENT_TARGET="11.0"
+
+ if [[ $HOST != "$ENV_TARGET" ]]; then
+ # Required for building daemon
+ SDKROOT=$(xcrun --show-sdk-path)
+ export SDKROOT
+ fi
+ ;;
*windows*)
;;
*)
- echo "Unknown target \"$TARGET\"" >&2
+ echo "Unknown target \"$ENV_TARGET\"" >&2
exit 1
;;
esac
diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js
index e70ba6ab37..f3e9b1a07d 100644
--- a/gui/tasks/distribution.js
+++ b/gui/tasks/distribution.js
@@ -5,8 +5,11 @@ const parseSemver = require('semver/functions/parse');
const { notarize } = require('electron-notarize');
const { version } = require('../package.json');
-const compression = process.argv.indexOf('--no-compression') !== -1 ? 'store' : 'normal';
-const noAppleNotarization = process.argv.indexOf('--no-apple-notarization') !== -1;
+const compression = process.argv.includes('--no-compression') ? 'store' : 'normal';
+const noAppleNotarization = process.argv.includes('--no-apple-notarization');
+
+const arm64 = process.argv.includes('--arm64');
+const universal = process.argv.includes('--universal');
const config = {
appId: 'net.mullvad.vpn',
@@ -44,7 +47,10 @@ const config = {
],
mac: {
- target: 'pkg',
+ target: {
+ target: 'pkg',
+ arch: getMacArch(),
+ },
artifactName: 'MullvadVPN-${version}.${ext}',
category: 'public.app-category.tools',
extendInfo: {
@@ -52,13 +58,16 @@ const config = {
NSUserNotificationAlertStyle: 'alert',
},
extraResources: [
- { from: distAssets('mullvad'), to: '.' },
- { from: distAssets('mullvad-problem-report'), to: '.' },
- { from: distAssets('mullvad-daemon'), to: '.' },
- { from: distAssets('mullvad-setup'), to: '.' },
- { from: distAssets('libtalpid_openvpn_plugin.dylib'), to: '.' },
- { from: distAssets('binaries/x86_64-apple-darwin/openvpn'), to: '.' },
- { from: distAssets('binaries/x86_64-apple-darwin/sslocal'), to: '.' },
+ { from: distAssets(path.join('${env.TARGET_TRIPLE}', 'mullvad')), to: '.' },
+ { from: distAssets(path.join('${env.TARGET_TRIPLE}', 'mullvad-problem-report')), to: '.' },
+ { from: distAssets(path.join('${env.TARGET_TRIPLE}', 'mullvad-daemon')), to: '.' },
+ { from: distAssets(path.join('${env.TARGET_TRIPLE}', 'mullvad-setup')), to: '.' },
+ {
+ from: distAssets(path.join('${env.TARGET_TRIPLE}', 'libtalpid_openvpn_plugin.dylib')),
+ to: '.',
+ },
+ { from: distAssets(path.join('binaries', '${env.TARGET_TRIPLE}', 'openvpn')), to: '.' },
+ { from: distAssets(path.join('binaries', '${env.TARGET_TRIPLE}', 'sslocal')), to: '.' },
{ from: distAssets('uninstall_macos.sh'), to: './uninstall.sh' },
{ from: distAssets('shell-completions/_mullvad'), to: '.' },
{ from: distAssets('shell-completions/mullvad.fish'), to: '.' },
@@ -195,7 +204,24 @@ function packMac() {
config: {
...config,
asarUnpack: ['**/*.node'],
+ beforeBuild: (options) => {
+ switch (options.arch) {
+ case 'x64':
+ process.env.TARGET_TRIPLE = 'x86_64-apple-darwin';
+ break;
+ case 'arm64':
+ process.env.TARGET_TRIPLE = 'aarch64-apple-darwin';
+ break;
+ default:
+ delete process.env.TARGET_TRIPLE;
+ break;
+ }
+
+ return true;
+ },
afterPack: (context) => {
+ delete process.env.TARGET_TRIPLE;
+
appOutDir = context.appOutDir;
return Promise.resolve();
},
@@ -254,6 +280,17 @@ function root(relativePath) {
return path.join(path.resolve(__dirname, '../../'), relativePath);
}
+function getMacArch() {
+ if (universal) {
+ return 'universal';
+ } else if (arm64) {
+ return 'arm64';
+ } else {
+ // Not specifying an arch makes Electron builder build for the arch it's running on.
+ return undefined;
+ }
+}
+
// Replace '-' between components with a tilde to make the version comparison understand that
// YYYY.NN > YYYY.NN-betaN > YYYY.NN-betaN-dev-HHHHHH.
function getDebVersion() {
diff --git a/wireguard/build-wireguard-go.sh b/wireguard/build-wireguard-go.sh
index 67748dd811..0b63cc3f43 100755
--- a/wireguard/build-wireguard-go.sh
+++ b/wireguard/build-wireguard-go.sh
@@ -86,8 +86,22 @@ 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"
+ fi
+
pushd libwg
- target_triple_dir="../../build/lib/$(unix_target_triple)"
+ target_triple_dir="../../build/lib/$1"
+
mkdir -p $target_triple_dir
go build -v -o $target_triple_dir/libwg.a -buildmode c-archive
popd
@@ -116,7 +130,7 @@ function build_wireguard_go {
local platform="$(uname -s)";
case "$platform" in
- Linux*|Darwin*) build_unix $platform;;
+ Linux*|Darwin*) build_unix ${1:-$(unix_target_triple)};;
MINGW*|MSYS_NT*) build_windows;;
esac
}