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