Skip to content

Commit fd68a2b

Browse files
committed
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.
1 parent ca2dd12 commit fd68a2b

File tree

3 files changed

+339
-99
lines changed

3 files changed

+339
-99
lines changed

examples/auto/rust

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
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 for 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+
# # Space-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+
ngx_rust_prefix=lib
100+
ngx_rust_libext=.a
101+
102+
case "$NGX_MACHINE" in
103+
104+
amd64)
105+
RUST_TARGET_ARCH=x86_64
106+
;;
107+
108+
arm64)
109+
RUST_TARGET_ARCH=aarch64
110+
;;
111+
112+
i?86)
113+
RUST_TARGET_ARCH=i686
114+
;;
115+
116+
*)
117+
RUST_TARGET_ARCH=$NGX_MACHINE
118+
;;
119+
120+
esac
121+
122+
case "$NGX_PLATFORM" in
123+
124+
OpenBSD:*)
125+
# ld: error: undefined symbol: _Unwind_...
126+
RUST_LIBS="$RUST_LIBS -lutil"
127+
RUST_LIBS="$RUST_LIBS -lexecinfo"
128+
RUST_LIBS="$RUST_LIBS -lc++abi"
129+
;;
130+
131+
win32)
132+
case "$NGX_CC_NAME" in
133+
134+
msvc)
135+
ngx_rust_prefix=
136+
ngx_rust_libext=.lib
137+
138+
# as suggested by rustc --print native-static-libs,
139+
# excluding entries already present in CORE_LIBS
140+
RUST_LIBS="$RUST_LIBS bcrypt.lib" # ???
141+
RUST_LIBS="$RUST_LIBS ntdll.lib" # std::io, std::sys::pal::windows
142+
RUST_LIBS="$RUST_LIBS userenv.lib" # std::env::home_dir
143+
RUST_LIBS="$RUST_LIBS dbghelp.lib" # backtrace symbolization
144+
145+
RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-msvc
146+
;;
147+
148+
gcc | clang)
149+
RUST_LIBS="$RUST_LIBS -lbcrypt"
150+
RUST_LIBS="$RUST_LIBS -lntdll"
151+
RUST_LIBS="$RUST_LIBS -luserenv"
152+
RUST_LIBS="$RUST_LIBS -ldbghelp"
153+
# gnullvm on arm64?
154+
RUST_TARGET=$RUST_TARGET_ARCH-pc-windows-gnu
155+
;;
156+
157+
esac
158+
;;
159+
160+
esac
161+
162+
163+
# Prepare cargo configuration file
164+
165+
if [ "$NGX_DEBUG" = YES ]; then
166+
ngx_cargo_default_profile=ngx-debug
167+
else
168+
ngx_cargo_default_profile=ngx-release
169+
fi
170+
171+
ngx_cargo_config=$NGX_OBJS/.cargo/config.toml
172+
ngx_cargo_profile=${ngx_cargo_profile:-$ngx_cargo_default_profile}
173+
174+
mkdir -p "$NGX_OBJS/.cargo"
175+
176+
cat << END > "$ngx_cargo_config"
177+
178+
[profile.ngx-debug]
179+
inherits = "dev"
180+
181+
[profile.ngx-release]
182+
inherits = "release"
183+
lto = "thin"
184+
strip = "none"
185+
186+
# compatibility with LIBC=-MT set in auto/cc/msvc
187+
[target.aarch64-pc-windows-msvc]
188+
rustflags = ["-C", "target-feature=+crt-static"]
189+
190+
[target.i686-pc-windows-msvc]
191+
rustflags = ["-C", "target-feature=+crt-static"]
192+
193+
[target.x86_64-pc-windows-msvc]
194+
rustflags = ["-C", "target-feature=+crt-static"]
195+
196+
[env]
197+
NGINX_BUILD_DIR = { value = ".", force = true, relative = true }
198+
END
199+
200+
if [ "$NGX_PLATFORM" == win32 ] && command -v cygpath >/dev/null; then
201+
printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' \
202+
"$(cygpath -m "$PWD")"
203+
else
204+
printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' "$PWD"
205+
fi
206+
207+
208+
# Reconstructs path to a static lib built with cargo rustc,
209+
# relative to the --target-dir
210+
211+
ngx_rust_target_path () {
212+
ngx_rust_obj=$(echo "$ngx_rust_target_name" | tr - _)
213+
214+
if [ "$ngx_rust_target_type" = EXAMPLE ]; then
215+
ngx_rust_obj=examples/$ngx_rust_prefix$ngx_rust_obj$ngx_rust_libext
216+
else
217+
ngx_rust_obj=$ngx_rust_prefix$ngx_rust_obj$ngx_rust_libext
218+
fi
219+
220+
echo "${RUST_TARGET:+$RUST_TARGET/}$ngx_cargo_profile/$ngx_rust_obj"
221+
}
222+
223+
224+
# Registers a module in the buildsystem.
225+
# Expects two variables to be set:
226+
#
227+
# ngx_rust_target_type=LIB|EXAMPLE
228+
# ngx_rust_target_name=<library or example name[^1]>
229+
#
230+
# [^1]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-name-field)
231+
232+
ngx_rust_module () {
233+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
234+
ngx_rust_target_name=${ngx_rust_target_name:-ngx_module_name}
235+
ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path)
236+
237+
ngx_module_deps="$ngx_rust_obj $ngx_module_deps"
238+
ngx_module_libs="$ngx_rust_obj $ngx_module_libs $RUST_LIBS"
239+
240+
# Module deps are usually added to the object file targets, but we don't have any
241+
LINK_DEPS="$LINK_DEPS $ngx_rust_obj"
242+
243+
eval ${ngx_addon_id}_MODULES=\"\$${ngx_addon_id}_MODULES \
244+
$ngx_rust_target_type:$ngx_rust_target_name\"
245+
246+
if [ -n "$ngx_rust_target_features" ]; then
247+
eval ${ngx_addon_id}_FEATURES=\"\$${ngx_addon_id}_FEATURES \
248+
$ngx_rust_target_features\"
249+
fi
250+
251+
. auto/module
252+
}
253+
254+
255+
# Writes a Makefile fragment for all the modules configured for "ngx_addon_name"
256+
257+
ngx_rust_make_modules () {
258+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
259+
ngx_cargo_manifest=${ngx_cargo_manifest:-"$ngx_addon_dir/Cargo.toml"}
260+
261+
eval ngx_rust_features="\$${ngx_addon_id}_FEATURES"
262+
eval ngx_rust_modules="\$${ngx_addon_id}_MODULES"
263+
264+
for module in $ngx_rust_modules; do
265+
ngx_rust_target_type=${module%%:*}
266+
ngx_rust_target_name=${module#*:}
267+
268+
ngx_rust_make_module
269+
done
270+
}
271+
272+
273+
# Writes a Makefile fragment for a single module specified by
274+
# "ngx_addon_name", "ngx_rust_target_type" and "ngx_rust_target_name"
275+
276+
ngx_rust_make_module () {
277+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
278+
ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path)
279+
280+
ngx_rustc_module_opt=
281+
if [ "$ngx_rust_target_type" = EXAMPLE ]; then
282+
ngx_rustc_module_opt="--example $ngx_rust_target_name"
283+
fi
284+
285+
cat << END >> $NGX_MAKEFILE
286+
287+
# always run cargo instead of trying to track the source modifications
288+
.PHONY: $ngx_rust_obj
289+
290+
$ngx_rust_obj:
291+
$NGX_CARGO rustc \\
292+
--config $ngx_cargo_config \\
293+
--crate-type staticlib \\
294+
--manifest-path "$ngx_cargo_manifest" \\
295+
--no-default-features \\
296+
--profile $ngx_cargo_profile \\
297+
${RUST_TARGET:+--target $RUST_TARGET} \\
298+
--target-dir $NGX_OBJS/$ngx_addon_id \\
299+
--features "$ngx_rust_features" \\
300+
$ngx_rustc_module_opt $NGX_RUSTC_OPT
301+
302+
END
303+
}

0 commit comments

Comments
 (0)