summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--wireguard-go-rs/build.rs146
-rw-r--r--wireguard-go-rs/libwg/Android.mk4
-rwxr-xr-xwireguard-go-rs/libwg/build-android.sh63
3 files changed, 135 insertions, 78 deletions
diff --git a/wireguard-go-rs/build.rs b/wireguard-go-rs/build.rs
index 08905f5e16..29759417e9 100644
--- a/wireguard-go-rs/build.rs
+++ b/wireguard-go-rs/build.rs
@@ -1,4 +1,10 @@
-use std::{borrow::BorrowMut, env, path::PathBuf, process::Command, str};
+use std::{
+ borrow::BorrowMut,
+ env,
+ path::{Path, PathBuf},
+ process::Command,
+ str,
+};
use anyhow::{anyhow, bail, Context};
@@ -14,7 +20,7 @@ fn main() -> anyhow::Result<()> {
match target_os.as_str() {
"linux" => build_static_lib(Os::Linux, true)?,
"macos" => build_static_lib(Os::MacOs, true)?,
- "android" => build_android_dynamic_lib()?,
+ "android" => build_android_dynamic_lib(false)?,
// building wireguard-go-rs for windows is not implemented
_ => {}
}
@@ -34,6 +40,27 @@ enum Arch {
Arm64,
}
+#[derive(PartialEq, Eq, Clone, Copy)]
+enum AndroidTarget {
+ Aarch64, // "aarch64"
+ X86, // "x86_64"
+ Armv7, // "armv7"
+ I686, // "i686"
+}
+
+impl AndroidTarget {
+ fn from_str(input: &str) -> anyhow::Result<Self> {
+ use AndroidTarget::*;
+ match input {
+ "aarch64-linux-android" => Ok(Aarch64),
+ "x86_64-linux-android" => Ok(X86),
+ "armv7-linux-androideabi" => Ok(Armv7),
+ "i686-linux-android" => Ok(I686),
+ _ => bail!("{input} is not a supported android target!"),
+ }
+ }
+}
+
fn host_os() -> anyhow::Result<Os> {
// this ugliness is a limitation of rust, where we can't directly
// access the target triple of the build script.
@@ -134,26 +161,117 @@ fn build_static_lib(target_os: Os, daita: bool) -> anyhow::Result<()> {
Ok(())
}
-/// Compile libwg as a dynamic library for android and place it in `../build/lib/$TARGET`.
+/// Compile libwg as a dynamic library for android and place it in [`android_output_path`].
// NOTE: We use dynamic linking as Go cannot produce static binaries specifically for Android.
-fn build_android_dynamic_lib() -> anyhow::Result<()> {
- let target_triplet = env::var("TARGET").context("TARGET is not set")?;
+fn build_android_dynamic_lib(daita: bool) -> anyhow::Result<()> {
+ let out_dir = env::var("OUT_DIR").context("Missing OUT_DIR")?;
+ let target_triple = env::var("TARGET").context("Missing 'TARGET'")?;
+ let target = AndroidTarget::from_str(&target_triple)?;
+
+ // TODO: Since `libwg.so` is always copied to `android_output_path`, this rerun-directive will
+ // always trigger cargo to rebuild this crate. Some mechanism to detected changes to `android_output_path`
+ // is needed, because some external program may clean it at any time (e.g. gradle).
+ println!(
+ "cargo::rerun-if-changed={}",
+ android_output_path(target)?.display()
+ );
- exec(Command::new("./libwg/build-android.sh"))?;
+ // Before calling `canonicalize`, the directory we're referring to actually has to exist.
+ std::fs::create_dir_all("../build")?;
+ let tmp_build_dir = Path::new("../build").canonicalize()?;
+ let go_path = tmp_build_dir.join("android-go-path");
+ // Invoke the Makefile in wireguard-go-rs/libwg
+ let mut build_command = Command::new("make");
+ build_command
+ .args(["-C", "./libwg"])
+ .args(["-f", "Android.mk"]);
+ // Set up the correct Android toolchain for building libwg
+ build_command
+ .env("ANDROID_C_COMPILER", android_c_compiler(target)?)
+ .env("ANDROID_ABI", android_abi(target))
+ .env("ANDROID_ARCH_NAME", android_arch_name(target))
+ .env("GOPATH", &go_path)
+ // Note: -w -s results in a stripped binary
+ .env("LDFLAGS", format!("-L{out_dir} -w -s"));
- // Tell linker to check `base`/$TARGET for the dynamic library.
- let lib_dir = manifest_dir()?.join("../build/lib").join(target_triplet);
- println!("cargo::rustc-link-search={}", lib_dir.display());
+ exec(build_command)?;
+
+ // Move the resulting binary to the path where the Android project expects it to be
+ let binary = Path::new(&out_dir).join("libwg.so");
+ let android_output_path = android_output_path(target)?;
+ let output = android_output_path.join("libwg.so");
+ android_move_binary(&binary, &output)?;
+
+ // Tell linker to check android_output_path for the dynamic library.
+ println!("cargo::rustc-link-search={}", android_output_path.display());
println!("cargo::rustc-link-lib=dylib=wg");
+ // If daita is enabled, also enable the corresponding rust feature flag
+ if daita {
+ println!(r#"cargo::rustc-cfg=daita"#);
+ }
+
Ok(())
}
-/// Get the directory containing `Cargo.toml`
-fn manifest_dir() -> anyhow::Result<PathBuf> {
- env::var("CARGO_MANIFEST_DIR")
- .map(PathBuf::from)
- .context("CARGO_MANIFEST_DIR env var not set")
+/// Copy `binary` to `output`.
+///
+/// Note: This function will create the parent directory/directories to `output` if necessary.
+fn android_move_binary(binary: &Path, output: &Path) -> anyhow::Result<()> {
+ let parent_of_output = output.parent().context(format!(
+ "Could not find parent directory of {}",
+ output.display()
+ ))?;
+ std::fs::create_dir_all(parent_of_output)?;
+
+ let mut move_command = Command::new("mv");
+ move_command
+ .arg(binary.to_str().unwrap())
+ .arg(output.to_str().unwrap());
+
+ exec(&mut move_command)?;
+
+ Ok(())
+}
+
+fn android_c_compiler(target: AndroidTarget) -> anyhow::Result<PathBuf> {
+ let toolchain = env::var("NDK_TOOLCHAIN_DIR").context("Missing 'NDK_TOOLCHAIN_DIR")?;
+ let ccompiler = match target {
+ AndroidTarget::Aarch64 => "aarch64-linux-android26-clang",
+ AndroidTarget::X86 => "x86_64-linux-android26-clang",
+ AndroidTarget::Armv7 => "armv7a-linux-androideabi26-clang",
+ AndroidTarget::I686 => "i686-linux-android26-clang",
+ };
+ let compiler = Path::new(&toolchain).join(ccompiler);
+ Ok(compiler)
+}
+
+fn android_abi(target: AndroidTarget) -> String {
+ match target {
+ AndroidTarget::Aarch64 => "arm64-v8a",
+ AndroidTarget::X86 => "x86_64",
+ AndroidTarget::Armv7 => "armeabi-v7a",
+ AndroidTarget::I686 => "x86",
+ }
+ .to_string()
+}
+
+fn android_arch_name(target: AndroidTarget) -> String {
+ match target {
+ AndroidTarget::Aarch64 => "arm64",
+ AndroidTarget::X86 => "x86_64",
+ AndroidTarget::Armv7 => "arm",
+ AndroidTarget::I686 => "x86",
+ }
+ .to_string()
+}
+
+// Returns the path where the Android project expects Rust binaries to be
+fn android_output_path(target: AndroidTarget) -> anyhow::Result<PathBuf> {
+ let relative_output_path = Path::new("../android/app/build/extraJni").join(android_abi(target));
+ std::fs::create_dir_all(relative_output_path.clone())?;
+ let output_path = relative_output_path.canonicalize()?;
+ Ok(output_path)
}
/// Execute a command, assert that it succeeds, and return stdout as a string.
diff --git a/wireguard-go-rs/libwg/Android.mk b/wireguard-go-rs/libwg/Android.mk
index acf2f6fe88..9cb87b2471 100644
--- a/wireguard-go-rs/libwg/Android.mk
+++ b/wireguard-go-rs/libwg/Android.mk
@@ -2,7 +2,9 @@
#
# Copyright © 2017-2019 WireGuard LLC. All Rights Reserved.
-DESTDIR ?= $(CURDIR)/../../build/lib/$(RUST_TARGET_TRIPLE)
+DESTDIR ?= $(OUT_DIR)
+CARGO_TARGET_DIR ?=
+TARGET ?=
NDK_GO_ARCH_MAP_x86 := 386
NDK_GO_ARCH_MAP_x86_64 := amd64
diff --git a/wireguard-go-rs/libwg/build-android.sh b/wireguard-go-rs/libwg/build-android.sh
deleted file mode 100755
index 0c2336185a..0000000000
--- a/wireguard-go-rs/libwg/build-android.sh
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env bash
-
-set -eu
-
-# Ensure we are in the correct directory for the execution of this script
-script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-cd "$script_dir"
-
-# Keep a GOPATH in the build directory to maintain a cache of downloaded libraries
-export GOPATH=$script_dir/../../build/android-go-path/
-mkdir -p "$GOPATH"
-
-ANDROID_STRIP_TOOL="${NDK_TOOLCHAIN_DIR}/llvm-strip"
-
-for arch in ${ARCHITECTURES:-armv7 aarch64 x86_64 i686}; do
- case "$arch" in
- "aarch64")
- export ANDROID_C_COMPILER="${NDK_TOOLCHAIN_DIR}/aarch64-linux-android26-clang"
- export RUST_TARGET_TRIPLE="aarch64-linux-android"
- export ANDROID_ABI="arm64-v8a"
- export ANDROID_ARCH_NAME="arm64"
- ;;
- "x86_64")
- export ANDROID_C_COMPILER="${NDK_TOOLCHAIN_DIR}/x86_64-linux-android26-clang"
- export RUST_TARGET_TRIPLE="x86_64-linux-android"
- export ANDROID_ABI="x86_64"
- export ANDROID_ARCH_NAME="x86_64"
- ;;
- "armv7")
- export ANDROID_C_COMPILER="${NDK_TOOLCHAIN_DIR}/armv7a-linux-androideabi26-clang"
- export RUST_TARGET_TRIPLE="armv7-linux-androideabi"
- export ANDROID_ABI="armeabi-v7a"
- export ANDROID_ARCH_NAME="arm"
- ;;
- "i686")
- export ANDROID_C_COMPILER="${NDK_TOOLCHAIN_DIR}/i686-linux-android26-clang"
- export RUST_TARGET_TRIPLE="i686-linux-android"
- export ANDROID_ABI="x86"
- export ANDROID_ARCH_NAME="x86"
- ;;
- esac
-
- # Build Wireguard-Go
- pwd
- make -f Android.mk clean
- make -f Android.mk
-
- # Strip and copy the library to `android/build/extraJni/$ANDROID_ABI` to be able to build the APK
- UNSTRIPPED_LIB_PATH="../../build/lib/$RUST_TARGET_TRIPLE/libwg.so"
- STRIPPED_LIB_PATH="../../android/app/build/extraJni/$ANDROID_ABI/libwg.so"
-
- # Create the directories with RWX permissions for all users so that the build server can clean
- # the directories afterwards
- (umask ugo=rwx; mkdir -p "$(dirname "$STRIPPED_LIB_PATH")")
-
- $ANDROID_STRIP_TOOL --strip-unneeded --strip-debug -o "$STRIPPED_LIB_PATH" "$UNSTRIPPED_LIB_PATH"
-
- # Set permissions so that the build server can clean the outputs afterwards
- chmod 777 "$STRIPPED_LIB_PATH"
-done
-
-# ensure `git clean -fd` does not require root permissions
-find "$GOPATH" -exec chmod +rw {} \;