diff options
| author | Oskar Nyberg <oskar@mullvad.net> | 2021-04-21 13:37:54 +0200 |
|---|---|---|
| committer | Oskar Nyberg <oskar@mullvad.net> | 2021-04-21 13:37:54 +0200 |
| commit | fcf42ec680b78f5d432376763284298fb52c2d80 (patch) | |
| tree | a33a7a9a40442daf341e6106a6604af18ebe3b6b | |
| parent | 2d51a1a84f7ca914e6d157df0e2129af569b086f (diff) | |
| parent | 8400c4eb6baa3f09ea68ff8aab16b5e55efe7632 (diff) | |
| download | mullvadvpn-fcf42ec680b78f5d432376763284298fb52c2d80.tar.xz mullvadvpn-fcf42ec680b78f5d432376763284298fb52c2d80.zip | |
Merge branch 'cross-compile-for-m1'
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rwxr-xr-x | build.sh | 228 | ||||
| -rwxr-xr-x | env.sh | 31 | ||||
| -rw-r--r-- | gui/tasks/distribution.js | 57 | ||||
| -rwxr-xr-x | wireguard/build-wireguard-go.sh | 18 |
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. @@ -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: @@ -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..." @@ -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 } |
