From 884c82991f4b3451e2aa3d0b93db91cfdeab560a Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 11 Dec 2024 13:22:15 -0800 Subject: [PATCH 1/5] fix(sys): work around missing UNC path support in MSVC `std::fs::canonicalize` always converts paths to UNC on Windows. However, a plenty of software lacks support for this naming convention, notably Microsoft's C/C++ Compiler. `dunce::canonicalize` is a commonly used solution that picks the most compatible path representation on Windows and calls `fs::canonicalize` on any other platform. --- Cargo.lock | 7 +++++++ nginx-sys/Cargo.toml | 1 + nginx-sys/build/main.rs | 11 +++++------ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a06b86..cd79846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,6 +245,12 @@ dependencies = [ "shared_child", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.13.0" @@ -520,6 +526,7 @@ dependencies = [ "bindgen", "cc", "duct", + "dunce", "flate2", "idna_adapter", "regex", diff --git a/nginx-sys/Cargo.toml b/nginx-sys/Cargo.toml index 28e7010..cfe918e 100644 --- a/nginx-sys/Cargo.toml +++ b/nginx-sys/Cargo.toml @@ -20,6 +20,7 @@ rust-version.workspace = true bindgen = "0.71" cc = "1.2.0" duct = { version = "0.13.7", optional = true } +dunce = "1.0.5" flate2 = { version = "1.0.28", optional = true } # Disable non-ASCII domain names support in ureq. We don't need it for any # of the 4 domains the buildscript interacts with. diff --git a/nginx-sys/build/main.rs b/nginx-sys/build/main.rs index d7661f5..d96b2f4 100644 --- a/nginx-sys/build/main.rs +++ b/nginx-sys/build/main.rs @@ -60,7 +60,7 @@ const NGX_CONF_OS: &[&str] = &[ /// NGINX in a subdirectory with the project. fn main() -> Result<(), Box> { let nginx_build_dir = match std::env::var("NGX_OBJS") { - Ok(v) => PathBuf::from(v).canonicalize()?, + Ok(v) => dunce::canonicalize(v)?, #[cfg(feature = "vendored")] Err(_) => vendored::build()?, #[cfg(not(feature = "vendored"))] @@ -170,10 +170,7 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec

Vec

, _>>() + .expect("canonicalize include paths") } /// Collect info about the nginx configuration and expose it to the dependents via From 7eaa9084e0fa8ea639649d01c1c91a5708600ad1 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 1 Jan 2025 03:52:21 -0800 Subject: [PATCH 2/5] feat(sys): accept `NGINX_SOURCE_DIR` along with `NGX_OBJS` Previously, we assumed that the source directory is a parent of `NGX_OBJS`. This isn't true, `--builddir` can point to an absolute path, and source directory can be read-only. Specifying an explicit source path and resolving includes agains it fixes the build for such configurations. --- nginx-sys/build/main.rs | 125 ++++++++++++++++++++++++++++++---------- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/nginx-sys/build/main.rs b/nginx-sys/build/main.rs index d96b2f4..e9aea72 100644 --- a/nginx-sys/build/main.rs +++ b/nginx-sys/build/main.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; #[cfg(feature = "vendored")] mod vendored; -const ENV_VARS_TRIGGERING_RECOMPILE: [&str; 2] = ["OUT_DIR", "NGX_OBJS"]; +const ENV_VARS_TRIGGERING_RECOMPILE: &[&str] = &["OUT_DIR", "NGX_OBJS", "NGINX_SOURCE_DIR"]; /// The feature flags set by the nginx configuration script. /// @@ -54,18 +54,13 @@ const NGX_CONF_OS: &[&str] = &[ "darwin", "freebsd", "gnu_hurd", "hpux", "linux", "solaris", "tru64", "win32", ]; +type BoxError = Box; + /// Function invoked when `cargo build` is executed. /// This function will download NGINX and all supporting dependencies, verify their integrity, /// extract them, execute autoconf `configure` for NGINX, compile NGINX and finally install /// NGINX in a subdirectory with the project. -fn main() -> Result<(), Box> { - let nginx_build_dir = match std::env::var("NGX_OBJS") { - Ok(v) => dunce::canonicalize(v)?, - #[cfg(feature = "vendored")] - Err(_) => vendored::build()?, - #[cfg(not(feature = "vendored"))] - Err(_) => panic!("\"nginx-sys/vendored\" feature is disabled and NGX_OBJS is not specified"), - }; +fn main() -> Result<(), BoxError> { // Hint cargo to rebuild if any of the these environment variables values change // because they will trigger a recompilation of NGINX with different parameters for var in ENV_VARS_TRIGGERING_RECOMPILE { @@ -73,15 +68,99 @@ fn main() -> Result<(), Box> { } println!("cargo:rerun-if-changed=build/main.rs"); println!("cargo:rerun-if-changed=build/wrapper.h"); + + let nginx = NginxSource::from_env(); // Read autoconf generated makefile for NGINX and generate Rust bindings based on its includes - generate_binding(nginx_build_dir); + generate_binding(&nginx); Ok(()) } +pub struct NginxSource { + source_dir: PathBuf, + build_dir: PathBuf, +} + +impl NginxSource { + pub fn new(source_dir: impl AsRef, build_dir: impl AsRef) -> Self { + let source_dir = NginxSource::check_source_dir(source_dir).expect("source directory"); + let build_dir = NginxSource::check_build_dir(build_dir).expect("build directory"); + + Self { source_dir, build_dir } + } + + pub fn from_env() -> Self { + match (env::var_os("NGINX_SOURCE_DIR"), env::var_os("NGX_OBJS")) { + (Some(source_dir), Some(build_dir)) => NginxSource::new(source_dir, build_dir), + (Some(source_dir), None) => Self::from_source_dir(source_dir), + (None, Some(build_dir)) => Self::from_build_dir(build_dir), + _ => Self::from_vendored(), + } + } + + pub fn from_source_dir(source_dir: impl AsRef) -> Self { + let build_dir = source_dir.as_ref().join("objs"); + + // todo!("Build from source"); + + Self::new(source_dir, build_dir) + } + + pub fn from_build_dir(build_dir: impl AsRef) -> Self { + let source_dir = build_dir.as_ref().parent().expect("source directory").to_owned(); + Self::new(source_dir, build_dir) + } + + #[cfg(feature = "vendored")] + pub fn from_vendored() -> Self { + let build_dir = vendored::build().expect("vendored build"); + let source_dir = build_dir.parent().expect("source directory").to_path_buf(); + + Self { source_dir, build_dir } + } + + #[cfg(not(feature = "vendored"))] + pub fn from_vendored() -> Self { + panic!("\"nginx-sys/vendored\" feature is disabled and neither NGINX_SOURCE_DIR nor NGX_OBJS is set"); + } + + fn check_source_dir(source_dir: impl AsRef) -> Result { + match dunce::canonicalize(&source_dir) { + Ok(path) if path.join("src/core/nginx.h").is_file() => Ok(path), + Err(err) => Err(format!("Invalid nginx source directory: {:?}. {}", source_dir.as_ref(), err).into()), + _ => Err(format!( + "Invalid nginx source directory: {:?}. NGINX_SOURCE_DIR is not specified or contains invalid value.", + source_dir.as_ref() + ) + .into()), + } + } + + fn check_build_dir(build_dir: impl AsRef) -> Result { + match dunce::canonicalize(&build_dir) { + Ok(path) if path.join("ngx_auto_config.h").is_file() => Ok(path), + Err(err) => Err(format!("Invalid nginx build directory: {:?}. {}", build_dir.as_ref(), err).into()), + _ => Err(format!( + "Invalid NGINX build directory: {:?}. NGX_OBJS is not specified or contains invalid value.", + build_dir.as_ref() + ) + .into()), + } + } +} + /// Generates Rust bindings for NGINX -fn generate_binding(nginx_build_dir: PathBuf) { - let autoconf_makefile_path = nginx_build_dir.join("Makefile"); - let includes = parse_includes_from_makefile(&autoconf_makefile_path); +fn generate_binding(nginx: &NginxSource) { + let autoconf_makefile_path = nginx.build_dir.join("Makefile"); + let includes: Vec<_> = parse_includes_from_makefile(&autoconf_makefile_path) + .into_iter() + .map(|path| { + if path.is_absolute() { + path + } else { + nginx.source_dir.join(path) + } + }) + .collect(); let clang_args: Vec = includes .iter() .map(|path| format!("-I{}", path.to_string_lossy())) @@ -166,25 +245,7 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec

, _>>() - .expect("canonicalize include paths") + includes.into_iter().map(PathBuf::from).collect() } /// Collect info about the nginx configuration and expose it to the dependents via From 925f5d7625c5bc7a7f5a3801948729bc385b255b Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 24 Jan 2025 23:42:36 -0800 Subject: [PATCH 3/5] refactor: rename `NGX_OBJS` to `NGINX_BUILD_DIR` The `NGX_OBJS` name was taken from the nginx buildsystem, but it is an internal detail there, so the name wasn't really meaningful. Now that we have `NGINX_SOURCE_DIR`, there's a benefit in more consistent naming. Technically, not a breaking change, as we haven't had a release with the old variable name. --- Cargo.toml | 5 +++-- README.md | 4 ++-- nginx-sys/build/main.rs | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c65d00a..d46cb3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,8 +36,9 @@ alloc = [] # Currently the only difference to `alloc` flag is `std::error::Error` implementation. std = ["alloc"] # Build our own copy of the NGINX by default. -# This could be disabled with `--no-default-features` to minimize the dependency tree -# when building against an existing copy of the NGINX with the NGX_OBJS variable. +# This could be disabled with `--no-default-features` to minimize the dependency +# tree when building against an existing copy of the NGINX with the +# NGINX_SOURCE_DIR/NGINX_BUILD_DIR variables. vendored = ["nginx-sys/vendored"] [badges] diff --git a/README.md b/README.md index e46afe6..43b6847 100644 --- a/README.md +++ b/README.md @@ -78,12 +78,12 @@ For example (all examples plus linux specific): ### Build with external NGINX source tree If you require a customized NGINX configuration, you can build a module against an existing pre-configured source tree. -To do that, you need to set the `NGX_OBJS` variable to an _absolute_ path of the NGINX build directory (`--builddir`, defaults to the `objs` in the source directory). +To do that, you need to set the `NGINX_BUILD_DIR` variable to an _absolute_ path of the NGINX build directory (`--builddir`, defaults to the `objs` in the source directory). Only the `./configure` step of the NGINX build is mandatory because bindings don't depend on any of the artifacts generated by `make`. ``` -NGX_OBJS=$PWD/../nginx/objs cargo build --package=examples --examples +NGINX_BUILD_DIR=$PWD/../nginx/objs cargo build --package=examples --examples ``` diff --git a/nginx-sys/build/main.rs b/nginx-sys/build/main.rs index e9aea72..e2a7378 100644 --- a/nginx-sys/build/main.rs +++ b/nginx-sys/build/main.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; #[cfg(feature = "vendored")] mod vendored; -const ENV_VARS_TRIGGERING_RECOMPILE: &[&str] = &["OUT_DIR", "NGX_OBJS", "NGINX_SOURCE_DIR"]; +const ENV_VARS_TRIGGERING_RECOMPILE: &[&str] = &["OUT_DIR", "NGINX_BUILD_DIR", "NGINX_SOURCE_DIR"]; /// The feature flags set by the nginx configuration script. /// @@ -89,7 +89,7 @@ impl NginxSource { } pub fn from_env() -> Self { - match (env::var_os("NGINX_SOURCE_DIR"), env::var_os("NGX_OBJS")) { + match (env::var_os("NGINX_SOURCE_DIR"), env::var_os("NGINX_BUILD_DIR")) { (Some(source_dir), Some(build_dir)) => NginxSource::new(source_dir, build_dir), (Some(source_dir), None) => Self::from_source_dir(source_dir), (None, Some(build_dir)) => Self::from_build_dir(build_dir), @@ -120,7 +120,7 @@ impl NginxSource { #[cfg(not(feature = "vendored"))] pub fn from_vendored() -> Self { - panic!("\"nginx-sys/vendored\" feature is disabled and neither NGINX_SOURCE_DIR nor NGX_OBJS is set"); + panic!("\"nginx-sys/vendored\" feature is disabled and neither NGINX_SOURCE_DIR nor NGINX_BUILD_DIR is set"); } fn check_source_dir(source_dir: impl AsRef) -> Result { @@ -140,7 +140,7 @@ impl NginxSource { Ok(path) if path.join("ngx_auto_config.h").is_file() => Ok(path), Err(err) => Err(format!("Invalid nginx build directory: {:?}. {}", build_dir.as_ref(), err).into()), _ => Err(format!( - "Invalid NGINX build directory: {:?}. NGX_OBJS is not specified or contains invalid value.", + "Invalid NGINX build directory: {:?}. NGINX_BUILD_DIR is not specified or contains invalid value.", build_dir.as_ref() ) .into()), From 0318404bc1fb1815458f5b5bff3f321b07c72cf0 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 10 Jan 2025 23:00:20 -0800 Subject: [PATCH 4/5] feat: library for nginx auto/configure integration A new file, `examples/auto/rust`, can be used in the module projects to simplify the build and hide most of the platform-specific details. `examples/config` and `examples/config.make` are reimplemented using the library. --- examples/auto/rust | 313 +++++++++++++++++++++++++++++++++++++++++++ examples/config | 98 +++++--------- examples/config.make | 35 +---- 3 files changed, 347 insertions(+), 99 deletions(-) create mode 100644 examples/auto/rust diff --git a/examples/auto/rust b/examples/auto/rust new file mode 100644 index 0000000..32aaeb0 --- /dev/null +++ b/examples/auto/rust @@ -0,0 +1,313 @@ +#!/bin/sh +# +# Copyright 2025 Nginx, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# Utility library for integration of ngx-rust modules into the NGINX build +# configuration. +# +# Usage: +# +# In "config", +# +# ```sh +# . $ngx_addon_dir/auto/rust +# +# # ngx_addon_name determines the build directory and should be set before +# # any modules are defined +# +# ngx_addon_name="example" +# +# if [ $HTTP = YES ]; then +# # Regular NGINX module options, +# # http://nginx.org/en/docs/dev/development_guide.html#adding_new_modules +# +# ngx_module_type=HTTP +# # Should match the "ngx_module_t" static name(s) exported from the Rust code +# ngx_module_name=ngx_http_example_module +# ngx_module_incs= +# ngx_module_deps= +# ngx_module_libs= +# +# # Options specific to ngx-rust modules +# +# # Target type: LIB or EXAMPLE +# ngx_rust_target_type=LIB +# +# # Target name: crate name, lib.name or example.name +# ngx_rust_target_name=example +# +# # Whitespace-separated list of cargo features. +# # "default" should be specified explicitly if required. +# ngx_rust_target_features= +# +# ngx_rust_module +# fi +# ``` +# +# In "config.make", +# +# ```sh +# ngx_addon_name="example" +# ngx_cargo_manifest=$ngx_addon_dir/Cargo.toml +# +# # generate Makefile section for all the modules configured earlier +# +# ngx_rust_make_modules +# ``` + +# Prevent duplicate invocation unless it is a newer library version +if [ "${NGX_RUST_AUTO_VER:-0}" -ge 1 ]; then + return +fi + +NGX_RUST_AUTO_VER=1 + +echo $ngx_n "checking for Rust toolchain ...$ngx_c" + +NGX_CARGO=${NGX_CARGO:-cargo} + +NGX_RUST_VER=$($NGX_CARGO version 2>&1 \ + | grep 'cargo 1\.[0-9][0-9]*\.[0-9]*' 2>&1 \ + | sed -e 's/^.* \(1\.[0-9][0-9]*\.[0-9][0.9]*.*\)/\1/') + +NGX_RUST_VERSION=${NGX_RUST_VER%% *} + +if [ -z "$NGX_RUST_VERSION" ]; then + echo " not found" + echo + echo $0: error: cargo binary $NGX_CARGO is not found + echo + exit 1 +fi + +echo " found" +echo " + Rust version: $NGX_RUST_VER" + +case "$NGX_MACHINE" in + + amd64) + RUST_TARGET_ARCH=x86_64 + ;; + + arm64) + RUST_TARGET_ARCH=aarch64 + ;; + + i?86) + RUST_TARGET_ARCH=i686 + ;; + + *) + RUST_TARGET_ARCH=$NGX_MACHINE + ;; + +esac + +case "$NGX_PLATFORM" in + + OpenBSD:*) + # ld: error: undefined symbol: _Unwind_... + RUST_LIBS="$RUST_LIBS -lutil" + RUST_LIBS="$RUST_LIBS -lexecinfo" + RUST_LIBS="$RUST_LIBS -lc++abi" + ;; + + win32) + case "$NGX_CC_NAME" in + + msvc) + # as suggested by rustc --print native-static-libs, + # excluding entries already present in CORE_LIBS + RUST_LIBS="$RUST_LIBS bcrypt.lib" # ??? + RUST_LIBS="$RUST_LIBS ntdll.lib" # std::io, std::sys::pal::windows + RUST_LIBS="$RUST_LIBS userenv.lib" # std::env::home_dir + RUST_LIBS="$RUST_LIBS dbghelp.lib" # backtrace symbolization + + RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-msvc + ;; + + gcc | clang) + RUST_LIBS="$RUST_LIBS -lbcrypt" + RUST_LIBS="$RUST_LIBS -lntdll" + RUST_LIBS="$RUST_LIBS -luserenv" + RUST_LIBS="$RUST_LIBS -ldbghelp" + # gnullvm on arm64? + RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-gnu + ;; + + esac + ;; + +esac + + +# Prepare cargo configuration file + +if [ "$NGX_DEBUG" = YES ]; then + ngx_cargo_default_profile=ngx-debug +else + ngx_cargo_default_profile=ngx-release +fi + +ngx_cargo_config=$NGX_OBJS/.cargo/config.toml +ngx_cargo_profile=${ngx_cargo_profile:-$ngx_cargo_default_profile} + +mkdir -p "$NGX_OBJS/.cargo" + +cat << END > "$ngx_cargo_config" + +[profile.ngx-debug] +inherits = "dev" + +[profile.ngx-release] +inherits = "release" +strip = "none" + +# compatibility with LIBC=-MT set in auto/cc/msvc +[target.aarch64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.i686-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] + +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-feature=+crt-static"] + +[env] +NGINX_BUILD_DIR = { value = ".", force = true, relative = true } +END + +if [ "$NGX_PLATFORM" = win32 ] && command -v cygpath >/dev/null; then + printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' \ + "$(cygpath -m "$PWD")" +else + printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' "$PWD" +fi + + +# Reconstructs path to a static lib built with cargo rustc, +# relative to the --target-dir + +ngx_rust_target_path () { + ngx_rust_obj=$(echo "$ngx_rust_target_name" | tr - _) + + case "$NGX_CC_NAME" in + + msvc) + ngx_rust_obj=${ngx_rust_obj}.lib + ;; + + *) + ngx_rust_obj=lib${ngx_rust_obj}.a + ;; + + esac + + if [ "$ngx_rust_target_type" = EXAMPLE ]; then + ngx_rust_obj=examples/$ngx_rust_obj + fi + + echo "${RUST_TARGET:+$RUST_TARGET/}$ngx_cargo_profile/$ngx_rust_obj" +} + + +# Registers a module in the buildsystem. +# In addition to the regular auto/module parameters, the following variables +# are expected to be set: +# +# ngx_rust_target_type=LIB|EXAMPLE +# ngx_rust_target_name= +# ngx_rust_target_features= +# +# [^1]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-name-field) + +ngx_rust_module () { + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') + ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path) + + ngx_module_deps_saved=$ngx_module_deps + ngx_module_deps="$ngx_rust_obj $ngx_module_deps" + + ngx_module_libs_saved=$ngx_module_libs + ngx_module_libs="$ngx_rust_obj $ngx_module_libs $RUST_LIBS" + + # Module deps are usually added to the object file targets, but we don't have any + LINK_DEPS="$LINK_DEPS $ngx_rust_obj" + + eval ${ngx_addon_id}_MODULES=\"\$${ngx_addon_id}_MODULES \ + $ngx_rust_target_type:$ngx_rust_target_name\" + + if [ -n "$ngx_rust_target_features" ]; then + eval ${ngx_addon_id}_FEATURES=\"\$${ngx_addon_id}_FEATURES \ + $ngx_rust_target_features\" + fi + + . auto/module + + ngx_module_deps=$ngx_module_deps_saved + ngx_module_libs=$ngx_module_libs_saved +} + + +# Writes a Makefile fragment for all the modules configured for "ngx_addon_name" + +ngx_rust_make_modules () { + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') + ngx_cargo_manifest=${ngx_cargo_manifest:-"$ngx_addon_dir/Cargo.toml"} + + eval ngx_rust_features="\$${ngx_addon_id}_FEATURES" + eval ngx_rust_modules="\$${ngx_addon_id}_MODULES" + + for module in $ngx_rust_modules; do + ngx_rust_target_type=${module%%:*} + ngx_rust_target_name=${module#*:} + + ngx_rust_make_module + done +} + + +# Writes a Makefile fragment for a single module specified by +# "ngx_addon_name", "ngx_rust_target_type" and "ngx_rust_target_name" + +ngx_rust_make_module () { + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') + ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path) + + ngx_rustc_module_opt= + if [ "$ngx_rust_target_type" = EXAMPLE ]; then + ngx_rustc_module_opt="--example $ngx_rust_target_name" + fi + + cat << END >> $NGX_MAKEFILE + +# always run cargo instead of trying to track the source modifications +.PHONY: $ngx_rust_obj + +$ngx_rust_obj: + $NGX_CARGO rustc \\ + --config $ngx_cargo_config \\ + --crate-type staticlib \\ + --manifest-path "$ngx_cargo_manifest" \\ + --no-default-features \\ + --profile $ngx_cargo_profile \\ + ${RUST_TARGET:+--target $RUST_TARGET} \\ + --target-dir $NGX_OBJS/$ngx_addon_id \\ + --features "$ngx_rust_features" \\ + $ngx_rustc_module_opt $NGX_RUSTC_OPT + +END +} diff --git a/examples/config b/examples/config index c3f4cd4..744825c 100644 --- a/examples/config +++ b/examples/config @@ -1,94 +1,58 @@ +# shellcheck source=auto/rust +. $ngx_addon_dir/auto/rust + +# ngx_addon_name determines the build directory and should be set before +# any modules are defined + ngx_addon_name=ngx_rust_examples -ngx_cargo_profile=ngx-module if [ $HTTP = YES ]; then ngx_module_type=HTTP + ngx_module_incs= + ngx_module_deps= + ngx_module_order= + + ngx_rust_target_type=EXAMPLE + ngx_rust_target_features= if [ "$ngx_module_link" = DYNAMIC ]; then ngx_module_name=ngx_http_async_module - ngx_module_lib=async - - ngx_module_lib=$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_module_lib.a - ngx_module_deps=$ngx_module_lib - ngx_module_libs="$ngx_module_lib -lm" - - # Module deps are usually added to the object file targets, but we don't have any - LINK_DEPS="$LINK_DEPS $ngx_module_lib" + ngx_module_libs="-lm" + ngx_rust_target_name=async - . auto/module + ngx_rust_module fi if :; then ngx_module_name=ngx_http_awssigv4_module - ngx_module_lib=awssig + ngx_module_libs="-lm" + ngx_rust_target_name=awssig - ngx_module_lib=$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_module_lib.a - ngx_module_deps=$ngx_module_lib - ngx_module_libs="$ngx_module_lib -lm" - - # Module deps are usually added to the object file targets, but we don't have any - LINK_DEPS="$LINK_DEPS $ngx_module_lib" - - . auto/module + ngx_rust_module fi if :; then ngx_module_name=ngx_http_curl_module - ngx_module_lib=curl - - ngx_module_lib=$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_module_lib.a - ngx_module_deps=$ngx_module_lib - ngx_module_libs=$ngx_module_lib - - # Module deps are usually added to the object file targets, but we don't have any - LINK_DEPS="$LINK_DEPS $ngx_module_lib" + ngx_module_libs= + ngx_rust_target_name=curl - . auto/module + ngx_rust_module fi - case "$NGX_PLATFORM" in - Linux:*) - ngx_module_name=ngx_http_orig_dst_module - ngx_module_lib=httporigdst - - ngx_module_lib=$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_module_lib.a - ngx_module_deps=$ngx_module_lib - ngx_module_libs=$ngx_module_lib - - # Module deps are usually added to the object file targets, but we don't have any - LINK_DEPS="$LINK_DEPS $ngx_module_lib" - - . auto/module - ;; - esac - if :; then ngx_module_name=ngx_http_upstream_custom_module - ngx_module_lib=upstream - - ngx_module_lib=$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_module_lib.a - ngx_module_deps=$ngx_module_lib - ngx_module_libs=$ngx_module_lib + ngx_module_libs= + ngx_rust_target_name=upstream - # Module deps are usually added to the object file targets, but we don't have any - LINK_DEPS="$LINK_DEPS $ngx_module_lib" - - . auto/module + ngx_rust_module fi -fi -# Write a cargo config with the $ngx_cargo_profile definition (optional) + if [ "$NGX_SYSTEM" = Linux ]; then + ngx_module_name=ngx_http_orig_dst_module + ngx_module_libs= + ngx_rust_target_name=httporigdst + ngx_rust_target_features=linux -if [ "$NGX_DEBUG" = YES ]; then - NGX_CARGO_PROFILE_BASE=dev -else - NGX_CARGO_PROFILE_BASE=release + ngx_rust_module + fi fi - -mkdir -p "$NGX_OBJS/.cargo" -cat > "$NGX_OBJS/.cargo/config.toml" << END - -[profile.$ngx_cargo_profile] -inherits = "$NGX_CARGO_PROFILE_BASE" - -END diff --git a/examples/config.make b/examples/config.make index fff246b..5e62127 100644 --- a/examples/config.make +++ b/examples/config.make @@ -1,35 +1,6 @@ ngx_addon_name=ngx_rust_examples -ngx_cargo_profile=ngx-module -ngx_cargo_manifest=$(realpath $ngx_addon_dir/Cargo.toml) -ngx_cargo_features= -ngx_rust_examples="async awssig curl upstream" +ngx_cargo_manifest=$ngx_addon_dir/Cargo.toml -case "$NGX_PLATFORM" in - Linux:*) - ngx_cargo_features="$ngx_cargo_features linux" - ngx_rust_examples="$ngx_rust_examples httporigdst" - ;; -esac +# generate Makefile section for all the modules configured earlier -for ngx_rust_example in $ngx_rust_examples -do - -cat << END >> $NGX_MAKEFILE - -# Always call cargo instead of tracking the source modifications -.PHONY: $NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_rust_example.a - -$NGX_OBJS/$ngx_addon_name/$ngx_cargo_profile/examples/lib$ngx_rust_example.a: - cd $NGX_OBJS && \\ - NGX_OBJS="\$\$PWD" cargo rustc \\ - --crate-type staticlib \\ - --example "$ngx_rust_example" \\ - --no-default-features \\ - --features "$ngx_cargo_features" \\ - --profile $ngx_cargo_profile \\ - --target-dir $ngx_addon_name \\ - --manifest-path $ngx_cargo_manifest - -END - -done +ngx_rust_make_modules From 8ff5f94bd095e06ee47a664dcea5a7d8466363df Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Sat, 25 Jan 2025 00:42:48 -0800 Subject: [PATCH 5/5] doc(sys): document `NGINX_SOURCE_DIR` and `NGINX_BUILD_DIR` --- nginx-sys/README.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/nginx-sys/README.md b/nginx-sys/README.md index 35fe7fb..73b1a69 100644 --- a/nginx-sys/README.md +++ b/nginx-sys/README.md @@ -12,11 +12,33 @@ Add `nginx-sys` as a dependency in your `Cargo.toml`: nginx-sys = "0.5.0" ``` +Set the path to your nginx sources and build directory using the +[environment variables](#input-variables), or enable the `nginx-sys/vendored` +feature to use a downloaded copy of the nginx sources. + +Note that it is recommended to use the exact source and `configure` arguments +of the nginx build you are planning to use in production. +`configure` arguments alter the APIs and the symbols visible to the Rust code, +and some OS distributions are known to ship nginx packages with API-breaking +patches applied. + ## Features - `vendored`: Enables the build scripts to download and build a copy of nginx source and link against it. - This feature is enabled by default. + +## Input variables + +`NGINX_SOURCE_DIR`, `NGINX_BUILD_DIR` control paths to an external nginx source +tree and a configured build directory. Normally, specifying either of these is +sufficient, as the build directory defaults to `objs` under the source dir. + +However, it's possible to set the latter to any valid path with +`configure --builddir=<...>`, and we need _both_ paths to support such +configuration. + +The variables above are optional, but take preference when the `vendored` crate +feature is enabled. ## Output variables