|
| 1 | +#!/bin/sh |
| 2 | +# |
| 3 | +# Copyright 2025 Nginx, Inc. |
| 4 | +# |
| 5 | +# Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | +# you may not use this file except in compliance with the License. |
| 7 | +# You may obtain a copy of the License at |
| 8 | +# |
| 9 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +# |
| 11 | +# Unless required by applicable law or agreed to in writing, software |
| 12 | +# distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +# See the License for the specific language governing permissions and |
| 15 | +# limitations under the License. |
| 16 | +# |
| 17 | +# |
| 18 | +# Utility library for integration of ngx-rust modules into the NGINX build |
| 19 | +# configuration. |
| 20 | +# |
| 21 | +# Usage: |
| 22 | +# |
| 23 | +# In "config", |
| 24 | +# |
| 25 | +# ```sh |
| 26 | +# . $ngx_addon_dir/auto/rust |
| 27 | +# |
| 28 | +# # ngx_addon_name determines the build directory and should be set before |
| 29 | +# # any modules are defined |
| 30 | +# |
| 31 | +# ngx_addon_name="example" |
| 32 | +# |
| 33 | +# if [ $HTTP = YES ]; then |
| 34 | +# # Regular NGINX module options, |
| 35 | +# # http://nginx.org/en/docs/dev/development_guide.html#adding_new_modules |
| 36 | +# |
| 37 | +# ngx_module_type=HTTP |
| 38 | +# # Should match the "ngx_module_t" static name(s) exported from the Rust code |
| 39 | +# ngx_module_name=ngx_http_example_module |
| 40 | +# ngx_module_incs= |
| 41 | +# ngx_module_deps= |
| 42 | +# ngx_module_libs= |
| 43 | +# |
| 44 | +# # Options specific to ngx-rust modules |
| 45 | +# |
| 46 | +# # Target type: LIB or EXAMPLE |
| 47 | +# ngx_rust_target_type=LIB |
| 48 | +# |
| 49 | +# # Target name: crate name, lib.name or example.name |
| 50 | +# ngx_rust_target_name=example |
| 51 | +# |
| 52 | +# # Whitespace-separated list of cargo features. |
| 53 | +# # "default" should be specified explicitly if required. |
| 54 | +# ngx_rust_target_features= |
| 55 | +# |
| 56 | +# ngx_rust_module |
| 57 | +# fi |
| 58 | +# ``` |
| 59 | +# |
| 60 | +# In "config.make", |
| 61 | +# |
| 62 | +# ```sh |
| 63 | +# ngx_addon_name="example" |
| 64 | +# ngx_cargo_manifest=$ngx_addon_dir/Cargo.toml |
| 65 | +# |
| 66 | +# # generate Makefile section for all the modules configured earlier |
| 67 | +# |
| 68 | +# ngx_rust_make_modules |
| 69 | +# ``` |
| 70 | + |
| 71 | +# Prevent duplicate invocation unless it is a newer library version |
| 72 | +if [ "${NGX_RUST_AUTO_VER:-0}" -ge 1 ]; then |
| 73 | + return |
| 74 | +fi |
| 75 | + |
| 76 | +NGX_RUST_AUTO_VER=1 |
| 77 | + |
| 78 | +echo $ngx_n "checking for Rust toolchain ...$ngx_c" |
| 79 | + |
| 80 | +NGX_CARGO=${NGX_CARGO:-cargo} |
| 81 | + |
| 82 | +NGX_RUST_VER=$($NGX_CARGO version 2>&1 \ |
| 83 | + | grep 'cargo 1\.[0-9][0-9]*\.[0-9]*' 2>&1 \ |
| 84 | + | sed -e 's/^.* \(1\.[0-9][0-9]*\.[0-9][0.9]*.*\)/\1/') |
| 85 | + |
| 86 | +NGX_RUST_VERSION=${NGX_RUST_VER%% *} |
| 87 | + |
| 88 | +if [ -z "$NGX_RUST_VERSION" ]; then |
| 89 | + echo " not found" |
| 90 | + echo |
| 91 | + echo $0: error: cargo binary $NGX_CARGO is not found |
| 92 | + echo |
| 93 | + exit 1 |
| 94 | +fi |
| 95 | + |
| 96 | +echo " found" |
| 97 | +echo " + Rust version: $NGX_RUST_VER" |
| 98 | + |
| 99 | +case "$NGX_MACHINE" in |
| 100 | + |
| 101 | + amd64) |
| 102 | + RUST_TARGET_ARCH=x86_64 |
| 103 | + ;; |
| 104 | + |
| 105 | + arm64) |
| 106 | + RUST_TARGET_ARCH=aarch64 |
| 107 | + ;; |
| 108 | + |
| 109 | + i?86) |
| 110 | + RUST_TARGET_ARCH=i686 |
| 111 | + ;; |
| 112 | + |
| 113 | + *) |
| 114 | + RUST_TARGET_ARCH=$NGX_MACHINE |
| 115 | + ;; |
| 116 | + |
| 117 | +esac |
| 118 | + |
| 119 | +case "$NGX_PLATFORM" in |
| 120 | + |
| 121 | + OpenBSD:*) |
| 122 | + # ld: error: undefined symbol: _Unwind_... |
| 123 | + RUST_LIBS="$RUST_LIBS -lutil" |
| 124 | + RUST_LIBS="$RUST_LIBS -lexecinfo" |
| 125 | + RUST_LIBS="$RUST_LIBS -lc++abi" |
| 126 | + ;; |
| 127 | + |
| 128 | + win32) |
| 129 | + case "$NGX_CC_NAME" in |
| 130 | + |
| 131 | + msvc) |
| 132 | + # as suggested by rustc --print native-static-libs, |
| 133 | + # excluding entries already present in CORE_LIBS |
| 134 | + RUST_LIBS="$RUST_LIBS bcrypt.lib" # ??? |
| 135 | + RUST_LIBS="$RUST_LIBS ntdll.lib" # std::io, std::sys::pal::windows |
| 136 | + RUST_LIBS="$RUST_LIBS userenv.lib" # std::env::home_dir |
| 137 | + RUST_LIBS="$RUST_LIBS dbghelp.lib" # backtrace symbolization |
| 138 | + |
| 139 | + RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-msvc |
| 140 | + ;; |
| 141 | + |
| 142 | + gcc | clang) |
| 143 | + RUST_LIBS="$RUST_LIBS -lbcrypt" |
| 144 | + RUST_LIBS="$RUST_LIBS -lntdll" |
| 145 | + RUST_LIBS="$RUST_LIBS -luserenv" |
| 146 | + RUST_LIBS="$RUST_LIBS -ldbghelp" |
| 147 | + # gnullvm on arm64? |
| 148 | + RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-gnu |
| 149 | + ;; |
| 150 | + |
| 151 | + esac |
| 152 | + ;; |
| 153 | + |
| 154 | +esac |
| 155 | + |
| 156 | + |
| 157 | +# Prepare cargo configuration file |
| 158 | + |
| 159 | +if [ "$NGX_DEBUG" = YES ]; then |
| 160 | + ngx_cargo_default_profile=ngx-debug |
| 161 | +else |
| 162 | + ngx_cargo_default_profile=ngx-release |
| 163 | +fi |
| 164 | + |
| 165 | +ngx_cargo_config=$NGX_OBJS/.cargo/config.toml |
| 166 | +ngx_cargo_profile=${ngx_cargo_profile:-$ngx_cargo_default_profile} |
| 167 | + |
| 168 | +mkdir -p "$NGX_OBJS/.cargo" |
| 169 | + |
| 170 | +cat << END > "$ngx_cargo_config" |
| 171 | +
|
| 172 | +[profile.ngx-debug] |
| 173 | +inherits = "dev" |
| 174 | +
|
| 175 | +[profile.ngx-release] |
| 176 | +inherits = "release" |
| 177 | +strip = "none" |
| 178 | +
|
| 179 | +# compatibility with LIBC=-MT set in auto/cc/msvc |
| 180 | +[target.aarch64-pc-windows-msvc] |
| 181 | +rustflags = ["-C", "target-feature=+crt-static"] |
| 182 | +
|
| 183 | +[target.i686-pc-windows-msvc] |
| 184 | +rustflags = ["-C", "target-feature=+crt-static"] |
| 185 | +
|
| 186 | +[target.x86_64-pc-windows-msvc] |
| 187 | +rustflags = ["-C", "target-feature=+crt-static"] |
| 188 | +
|
| 189 | +[env] |
| 190 | +NGINX_BUILD_DIR = { value = ".", force = true, relative = true } |
| 191 | +END |
| 192 | + |
| 193 | +if [ "$NGX_PLATFORM" = win32 ] && command -v cygpath >/dev/null; then |
| 194 | + printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' \ |
| 195 | + "$(cygpath -m "$PWD")" |
| 196 | +else |
| 197 | + printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' "$PWD" |
| 198 | +fi |
| 199 | + |
| 200 | + |
| 201 | +# Reconstructs path to a static lib built with cargo rustc, |
| 202 | +# relative to the --target-dir |
| 203 | + |
| 204 | +ngx_rust_target_path () { |
| 205 | + ngx_rust_obj=$(echo "$ngx_rust_target_name" | tr - _) |
| 206 | + |
| 207 | + case "$NGX_CC_NAME" in |
| 208 | + |
| 209 | + msvc) |
| 210 | + ngx_rust_obj=${ngx_rust_obj}.lib |
| 211 | + ;; |
| 212 | + |
| 213 | + *) |
| 214 | + ngx_rust_obj=lib${ngx_rust_obj}.a |
| 215 | + ;; |
| 216 | + |
| 217 | + esac |
| 218 | + |
| 219 | + if [ "$ngx_rust_target_type" = EXAMPLE ]; then |
| 220 | + ngx_rust_obj=examples/$ngx_rust_obj |
| 221 | + fi |
| 222 | + |
| 223 | + echo "${RUST_TARGET:+$RUST_TARGET/}$ngx_cargo_profile/$ngx_rust_obj" |
| 224 | +} |
| 225 | + |
| 226 | + |
| 227 | +# Registers a module in the buildsystem. |
| 228 | +# In addition to the regular auto/module parameters, the following variables |
| 229 | +# are expected to be set: |
| 230 | +# |
| 231 | +# ngx_rust_target_type=LIB|EXAMPLE |
| 232 | +# ngx_rust_target_name=<library or example name[^1]> |
| 233 | +# ngx_rust_target_features=<list of cargo features> |
| 234 | +# |
| 235 | +# [^1]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-name-field) |
| 236 | + |
| 237 | +ngx_rust_module () { |
| 238 | + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') |
| 239 | + ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path) |
| 240 | + |
| 241 | + ngx_module_deps_saved=$ngx_module_deps |
| 242 | + ngx_module_deps="$ngx_rust_obj $ngx_module_deps" |
| 243 | + |
| 244 | + ngx_module_libs_saved=$ngx_module_libs |
| 245 | + ngx_module_libs="$ngx_rust_obj $ngx_module_libs $RUST_LIBS" |
| 246 | + |
| 247 | + # Module deps are usually added to the object file targets, but we don't have any |
| 248 | + LINK_DEPS="$LINK_DEPS $ngx_rust_obj" |
| 249 | + |
| 250 | + eval ${ngx_addon_id}_MODULES=\"\$${ngx_addon_id}_MODULES \ |
| 251 | + $ngx_rust_target_type:$ngx_rust_target_name\" |
| 252 | + |
| 253 | + if [ -n "$ngx_rust_target_features" ]; then |
| 254 | + eval ${ngx_addon_id}_FEATURES=\"\$${ngx_addon_id}_FEATURES \ |
| 255 | + $ngx_rust_target_features\" |
| 256 | + fi |
| 257 | + |
| 258 | + . auto/module |
| 259 | + |
| 260 | + ngx_module_deps=$ngx_module_deps_saved |
| 261 | + ngx_module_libs=$ngx_module_libs_saved |
| 262 | +} |
| 263 | + |
| 264 | + |
| 265 | +# Writes a Makefile fragment for all the modules configured for "ngx_addon_name" |
| 266 | + |
| 267 | +ngx_rust_make_modules () { |
| 268 | + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') |
| 269 | + ngx_cargo_manifest=${ngx_cargo_manifest:-"$ngx_addon_dir/Cargo.toml"} |
| 270 | + |
| 271 | + eval ngx_rust_features="\$${ngx_addon_id}_FEATURES" |
| 272 | + eval ngx_rust_modules="\$${ngx_addon_id}_MODULES" |
| 273 | + |
| 274 | + for module in $ngx_rust_modules; do |
| 275 | + ngx_rust_target_type=${module%%:*} |
| 276 | + ngx_rust_target_name=${module#*:} |
| 277 | + |
| 278 | + ngx_rust_make_module |
| 279 | + done |
| 280 | +} |
| 281 | + |
| 282 | + |
| 283 | +# Writes a Makefile fragment for a single module specified by |
| 284 | +# "ngx_addon_name", "ngx_rust_target_type" and "ngx_rust_target_name" |
| 285 | + |
| 286 | +ngx_rust_make_module () { |
| 287 | + ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g') |
| 288 | + ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path) |
| 289 | + |
| 290 | + ngx_rustc_module_opt= |
| 291 | + if [ "$ngx_rust_target_type" = EXAMPLE ]; then |
| 292 | + ngx_rustc_module_opt="--example $ngx_rust_target_name" |
| 293 | + fi |
| 294 | + |
| 295 | + cat << END >> $NGX_MAKEFILE |
| 296 | +
|
| 297 | +# always run cargo instead of trying to track the source modifications |
| 298 | +.PHONY: $ngx_rust_obj |
| 299 | +
|
| 300 | +$ngx_rust_obj: |
| 301 | + $NGX_CARGO rustc \\ |
| 302 | + --config $ngx_cargo_config \\ |
| 303 | + --crate-type staticlib \\ |
| 304 | + --manifest-path "$ngx_cargo_manifest" \\ |
| 305 | + --no-default-features \\ |
| 306 | + --profile $ngx_cargo_profile \\ |
| 307 | + ${RUST_TARGET:+--target $RUST_TARGET} \\ |
| 308 | + --target-dir $NGX_OBJS/$ngx_addon_id \\ |
| 309 | + --features "$ngx_rust_features" \\ |
| 310 | + $ngx_rustc_module_opt $NGX_RUSTC_OPT |
| 311 | +
|
| 312 | +END |
| 313 | +} |
0 commit comments