diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5e18096 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +* +!/docker/ +!/rust-toolchain.toml diff --git a/Cargo.lock b/Cargo.lock index 94ac7c5..fee6930 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "app-logging" +version = "0.0.0" +dependencies = [ + "env_logger", + "log", + "syslog", +] + [[package]] name = "bindgen" version = "0.69.4" @@ -161,9 +170,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c012a26a7f605efc424dd53697843a72be7dc86ad2d01f7814337794a12231d" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" dependencies = [ "anstream", "anstyle", @@ -229,9 +238,8 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" name = "hello_world" version = "1.0.0" dependencies = [ - "env_logger", + "app-logging", "log", - "syslog", ] [[package]] @@ -299,9 +307,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -335,10 +343,9 @@ dependencies = [ name = "licensekey_handler" version = "1.0.0" dependencies = [ - "env_logger", + "app-logging", "licensekey", "log", - "syslog", ] [[package]] @@ -349,9 +356,9 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "match_cfg" @@ -564,18 +571,18 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index b8a8ce3..9f298ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ syslog = "6.1.1" thiserror = "1.0.57" licensekey = { path = "crates/licensekey" } +app-logging = { path = "crates/app-logging" } [workspace.package] edition = "2021" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..788d448 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +ARG REPO=axisecp +ARG SDK=acap-native-sdk +ARG UBUNTU_VERSION=22.04 +ARG VERSION=1.14 +ARG BASE_IMAGE=debian:bookworm-20240423-slim + +FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 +FROM ${REPO}/${SDK}:${VERSION}-armv7hf-ubuntu${UBUNTU_VERSION} AS sdk-armv7hf +FROM ${BASE_IMAGE} + +COPY --from=sdk-aarch64 /opt/axis/acapsdk/axis-acap-manifest-tools /opt/axis/acapsdk/axis-acap-manifest-tools +COPY --from=sdk-aarch64 /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux /opt/axis/acapsdk/environment-setup-cortexa53-crypto-poky-linux +COPY --from=sdk-armv7hf /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi /opt/axis/acapsdk/environment-setup-cortexa9hf-neon-poky-linux-gnueabi +COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/aarch64 /opt/axis/acapsdk/sysroots/aarch64 +COPY --from=sdk-armv7hf /opt/axis/acapsdk/sysroots/armv7hf /opt/axis/acapsdk/sysroots/armv7hf +COPY --from=sdk-aarch64 /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux /opt/axis/acapsdk/sysroots/x86_64-pokysdk-linux + +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + clang \ + g++-aarch64-linux-gnu \ + g++-arm-linux-gnueabihf \ + pkg-config \ + python3-jsonschema \ + wget \ + && rm -rf /var/lib/apt/lists/* + +ENV RUSTUP_HOME=/usr/local/rustup \ + CARGO_HOME=/usr/local/cargo \ + PATH=/usr/local/cargo/bin:$PATH + +COPY docker/install_rust.sh rust-toolchain.toml ./ +RUN ./install_rust.sh \ + && rustup target add \ + aarch64-unknown-linux-gnu \ + thumbv7neon-unknown-linux-gnueabihf \ + && rm install_rust.sh rust-toolchain.toml + +ENV \ + SYSROOT_AARCH64=/opt/axis/acapsdk/sysroots/aarch64 \ + SYSROOT_ARMV7HF=/opt/axis/acapsdk/sysroots/armv7hf +# The above makes the below easier to read +ENV \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="aarch64-linux-gnu-gcc" \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_AARCH64}" \ + CC_aarch64_axis_linux_gnu="aarch64-linux-gnu-gcc" \ + CXX_aarch64_axis_linux_gnu="aarch64-linux-gnu-g++" \ + PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ + PKG_CONFIG_PATH_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}/usr/lib/pkgconfig:${SYSROOT_AARCH64}/usr/share/pkgconfig" \ + PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu="${SYSROOT_AARCH64}" \ + CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_LINKER="arm-linux-gnueabihf-gcc" \ + CARGO_TARGET_THUMBV7NEON_UNKNOWN_LINUX_GNUEABIHF_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_ARMV7HF}" \ + CC_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-gcc" \ + CXX_thumbv7neon_unknown_linux_gnueabihf="arm-linux-gnueabihf-g++" \ + PKG_CONFIG_LIBDIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ + PKG_CONFIG_PATH_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}/usr/lib/pkgconfig:${SYSROOT_ARMV7HF}/usr/share/pkgconfig" \ + PKG_CONFIG_SYSROOT_DIR_thumbv7neon_unknown_linux_gnueabihf="${SYSROOT_ARMV7HF}" \ No newline at end of file diff --git a/Makefile b/Makefile index 675873c..ede00ef 100644 --- a/Makefile +++ b/Makefile @@ -197,7 +197,26 @@ crates/%-sys/src/bindings.rs: FORCE # Use the `_envoy` file as a target because # * `.DELETE_ON_ERROR` does not work for directories, and # * the name of the `.eap` file is annoying to predict. +# When building for all targets using a single image we cannot rely on wildcard matching. +target/aarch64/$(PACKAGE)/_envoy: ENVIRONMENT_SETUP=environment-setup-cortexa53-crypto-poky-linux +target/armv7hf/$(PACKAGE)/_envoy: ENVIRONMENT_SETUP=environment-setup-cortexa9hf-neon-poky-linux-gnueabi target/%/$(PACKAGE)/_envoy: ARCH=$* +target/%/$(PACKAGE)/_envoy: target/%/$(PACKAGE)/$(PACKAGE) target/%/$(PACKAGE)/manifest.json target/%/$(PACKAGE)/LICENSE +ifeq (0, $(shell test -e /.dockerenv; echo $$?)) + . /opt/axis/acapsdk/$(ENVIRONMENT_SETUP) && cd $(@D) && acap-build --build no-build . +else + $(DOCKER_RUN) sh -c ". /opt/axis/acapsdk/environment-setup-* && acap-build --build no-build ." +endif + touch $@ + +target/%/$(PACKAGE)/manifest.json: apps/$(PACKAGE)/manifest.json + mkdir -p $(dir $@) + cp $< $@ + +target/%/$(PACKAGE)/LICENSE: apps/$(PACKAGE)/LICENSE + mkdir -p $(dir $@) + cp $< $@ + # The target triple and the name of the docker image do not match, so # at some point we need to map one to the other. It might as well be here. target/aarch64/$(PACKAGE)/_envoy: target/aarch64-unknown-linux-gnu/release/$(PACKAGE) @@ -212,5 +231,9 @@ target/%/$(PACKAGE)/_envoy: apps/$(PACKAGE)/manifest.json apps/$(PACKAGE)/LICENS # Always rebuild the executable because configuring accurate cache invalidation is annoying. target/%/release/$(PACKAGE): FORCE +ifeq (0, $(shell test -e /.dockerenv; echo $$?)) + cargo -v build --release --target $* --package $(PACKAGE) +else cross -v build --release --target $* --package $(PACKAGE) +endif touch $@ # This is a hack to make the `_envoy` target above always build diff --git a/README.md b/README.md index f1d3479..bb4e000 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,25 @@ _Easy and safe [ACAP] apps using [Rust]_ ## Quickstart guide +Build the `hello_world` example and create `.eap` files in the `target/acap/` directory like + +```sh +docker build --tag acap-rs . +docker run \ + --interactive \ + --rm \ + --tty \ + --user $(id -u):$(id -g) \ + --volume $(pwd):$(pwd) \ + --workdir $(pwd) \ + acap-rs \ + make build PACKAGE=hello_world +``` + +This works with any of the [example applications](#example-applications). + +## Advanced setup + Ensure global prerequisites are installed: * Docker @@ -22,15 +41,7 @@ source ./init_env.sh make sync_env ``` -Build the `hello_world` example and create `.eap` files in the `target/acap/` directory like - -```sh -PACKAGE=hello_world make build -``` - -This works with any of the [example applications](#example-applications). - -Other important workflows are documented in the [Makefile](./Makefile) and can be listed with `make help`. +Important workflows are documented in the [Makefile](./Makefile) and can now be listed with `make help`. ## Example applications diff --git a/apps/hello_world/Cargo.toml b/apps/hello_world/Cargo.toml index 13172ba..5cd09fc 100644 --- a/apps/hello_world/Cargo.toml +++ b/apps/hello_world/Cargo.toml @@ -5,5 +5,5 @@ edition.workspace = true [dependencies] log = { workspace = true } -env_logger = { workspace = true } -syslog = { workspace = true } + +app-logging = { workspace = true } diff --git a/apps/hello_world/src/main.rs b/apps/hello_world/src/main.rs index 18d9a12..4011eec 100644 --- a/apps/hello_world/src/main.rs +++ b/apps/hello_world/src/main.rs @@ -1,13 +1,11 @@ //! A simple hello world application //! -//! Uses some common logging crates to demonstrate +//! Uses some common app-logging crates to demonstrate //! 1. how to use them in an application, and //! 2. how to build and bundle them as an application. use log::info; -mod app_logging; - fn main() { app_logging::init_logger(); info!("Hello World!"); diff --git a/apps/licensekey_handler/Cargo.toml b/apps/licensekey_handler/Cargo.toml index 387c0d3..34a8f53 100644 --- a/apps/licensekey_handler/Cargo.toml +++ b/apps/licensekey_handler/Cargo.toml @@ -5,7 +5,6 @@ edition.workspace = true [dependencies] log = { workspace = true } -env_logger = { workspace = true } -syslog = { workspace = true } -licensekey = { workspace = true } \ No newline at end of file +licensekey = { workspace = true } +app-logging = { workspace = true } diff --git a/apps/licensekey_handler/src/app_logging.rs b/apps/licensekey_handler/src/app_logging.rs deleted file mode 100644 index edb8609..0000000 --- a/apps/licensekey_handler/src/app_logging.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Utilities for managing logging in an application. - -use std::env; -use std::io::IsTerminal; - -use log::debug; - -fn init_syslog() { - let formatter = syslog::Formatter3164::default(); - let logger = syslog::unix(formatter).unwrap(); - log::set_boxed_logger(Box::new(syslog::BasicLogger::new(logger))).unwrap(); - log::set_max_level(log::LevelFilter::Debug); -} - -/// Set up logging as appropriate for the environment, then run the provided function. -/// -/// If stdout is a terminal, write to stderr. -/// Otherwise, write to the system logger. -pub fn init_logger() { - // Using `su -pc "..."` just says the "Connection to ... closed", and - // I have not found another way to run as the SDK user over ssh and allocate a tty, so - // if we detect an `env_logger` configuration we write to stderr anyway. - if std::io::stdout().is_terminal() - || env::var_os("RUST_LOG").is_some() - || env::var_os("RUST_LOG_STYLE").is_some() - { - env_logger::init(); - } else { - init_syslog(); - } - debug!("Logging initialized"); -} diff --git a/apps/licensekey_handler/src/main.rs b/apps/licensekey_handler/src/main.rs index d0090cc..5a69d87 100644 --- a/apps/licensekey_handler/src/main.rs +++ b/apps/licensekey_handler/src/main.rs @@ -1,10 +1,11 @@ //! A simple example application demonstrating how the licensekey crate may be used -use log::{info, warn}; -use std::ffi::{CStr, CString}; -use std::os::unix::ffi::OsStrExt; +use std::{ + ffi::{CStr, CString}, + os::unix::ffi::OsStrExt, +}; -mod app_logging; +use log::{info, warn}; const APP_ID: i32 = 0; const MAJOR_VERSION: i32 = 1; diff --git a/crates/app-logging/Cargo.toml b/crates/app-logging/Cargo.toml new file mode 100644 index 0000000..aaa717b --- /dev/null +++ b/crates/app-logging/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "app-logging" +version = "0.0.0" +edition.workspace = true + +[dependencies] +log = { workspace = true } +env_logger = { workspace = true } +syslog = { workspace = true } \ No newline at end of file diff --git a/apps/hello_world/src/app_logging.rs b/crates/app-logging/src/lib.rs similarity index 82% rename from apps/hello_world/src/app_logging.rs rename to crates/app-logging/src/lib.rs index edb8609..af0f1e4 100644 --- a/apps/hello_world/src/app_logging.rs +++ b/crates/app-logging/src/lib.rs @@ -1,7 +1,6 @@ -//! Utilities for managing logging in an application. +//! Utilities for managing app-logging in an application. -use std::env; -use std::io::IsTerminal; +use std::{env, io::IsTerminal}; use log::debug; @@ -12,7 +11,7 @@ fn init_syslog() { log::set_max_level(log::LevelFilter::Debug); } -/// Set up logging as appropriate for the environment, then run the provided function. +/// Set up app-logging as appropriate for the environment, then run the provided function. /// /// If stdout is a terminal, write to stderr. /// Otherwise, write to the system logger. diff --git a/crates/licensekey/src/flex.rs b/crates/licensekey/src/flex.rs index b79c1e0..37cf9f8 100644 --- a/crates/licensekey/src/flex.rs +++ b/crates/licensekey/src/flex.rs @@ -123,10 +123,12 @@ pub fn licensekey_get_state_string(state_code: c_int) -> Option { #[cfg(not(target_arch = "x86_64"))] #[cfg(test)] mod tests { - use super::*; - use licensekey_sys::LicenseKeyState; use std::ffi::CString; + use licensekey_sys::LicenseKeyState; + + use super::*; + #[test] fn licensekey_verify_does_not_panic() { let app_name = CString::new("test_app").unwrap(); diff --git a/docker/install_rust.sh b/docker/install_rust.sh new file mode 100755 index 0000000..1bbbdb3 --- /dev/null +++ b/docker/install_rust.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh +set -eux +wget "https://static.rust-lang.org/rustup/archive/1.26.0/x86_64-unknown-linux-gnu/rustup-init" +echo "0b2f6c8f85a3d02fde2efc0ced4657869d73fccfce59defb4e8d29233116e6db rustup-init" | sha256sum -c - +chmod +x rustup-init + +./rustup-init \ + --default-host x86_64-unknown-linux-gnu \ + --default-toolchain $(grep "channel" rust-toolchain.toml | cut -d '"' -f 2) \ + --no-modify-path \ + --profile minimal \ + -y + +rm rustup-init +chmod -R a+w $RUSTUP_HOME $CARGO_HOME \ No newline at end of file