Skip to content

Commit f0cae4e

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 925f5d7 commit f0cae4e

File tree

3 files changed

+343
-99
lines changed

3 files changed

+343
-99
lines changed

examples/auto/rust

+307
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
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+
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+
lto = "thin"
178+
strip = "none"
179+
180+
# compatibility with LIBC=-MT set in auto/cc/msvc
181+
[target.aarch64-pc-windows-msvc]
182+
rustflags = ["-C", "target-feature=+crt-static"]
183+
184+
[target.i686-pc-windows-msvc]
185+
rustflags = ["-C", "target-feature=+crt-static"]
186+
187+
[target.x86_64-pc-windows-msvc]
188+
rustflags = ["-C", "target-feature=+crt-static"]
189+
190+
[env]
191+
NGINX_BUILD_DIR = { value = ".", force = true, relative = true }
192+
END
193+
194+
if [ "$NGX_PLATFORM" = win32 ] && command -v cygpath >/dev/null; then
195+
printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' \
196+
"$(cygpath -m "$PWD")"
197+
else
198+
printf >> "$ngx_cargo_config" 'NGINX_SOURCE_DIR = "%s"\n' "$PWD"
199+
fi
200+
201+
202+
# Reconstructs path to a static lib built with cargo rustc,
203+
# relative to the --target-dir
204+
205+
ngx_rust_target_path () {
206+
ngx_rust_obj=$(echo "$ngx_rust_target_name" | tr - _)
207+
208+
case "$NGX_CC_NAME" in
209+
210+
msvc)
211+
ngx_rust_obj=${ngx_rust_obj}.lib
212+
;;
213+
214+
*)
215+
ngx_rust_obj=lib${ngx_rust_obj}.a
216+
;;
217+
218+
esac
219+
220+
if [ "$ngx_rust_target_type" = EXAMPLE ]; then
221+
ngx_rust_obj=examples/$ngx_rust_obj
222+
fi
223+
224+
echo "${RUST_TARGET:+$RUST_TARGET/}$ngx_cargo_profile/$ngx_rust_obj"
225+
}
226+
227+
228+
# Registers a module in the buildsystem.
229+
# Expects two variables to be set:
230+
#
231+
# ngx_rust_target_type=LIB|EXAMPLE
232+
# ngx_rust_target_name=<library or example name[^1]>
233+
#
234+
# [^1]: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-name-field)
235+
236+
ngx_rust_module () {
237+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
238+
ngx_rust_target_name=${ngx_rust_target_name:-ngx_module_name}
239+
ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path)
240+
241+
ngx_module_deps="$ngx_rust_obj $ngx_module_deps"
242+
ngx_module_libs="$ngx_rust_obj $ngx_module_libs $RUST_LIBS"
243+
244+
# Module deps are usually added to the object file targets, but we don't have any
245+
LINK_DEPS="$LINK_DEPS $ngx_rust_obj"
246+
247+
eval ${ngx_addon_id}_MODULES=\"\$${ngx_addon_id}_MODULES \
248+
$ngx_rust_target_type:$ngx_rust_target_name\"
249+
250+
if [ -n "$ngx_rust_target_features" ]; then
251+
eval ${ngx_addon_id}_FEATURES=\"\$${ngx_addon_id}_FEATURES \
252+
$ngx_rust_target_features\"
253+
fi
254+
255+
. auto/module
256+
}
257+
258+
259+
# Writes a Makefile fragment for all the modules configured for "ngx_addon_name"
260+
261+
ngx_rust_make_modules () {
262+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
263+
ngx_cargo_manifest=${ngx_cargo_manifest:-"$ngx_addon_dir/Cargo.toml"}
264+
265+
eval ngx_rust_features="\$${ngx_addon_id}_FEATURES"
266+
eval ngx_rust_modules="\$${ngx_addon_id}_MODULES"
267+
268+
for module in $ngx_rust_modules; do
269+
ngx_rust_target_type=${module%%:*}
270+
ngx_rust_target_name=${module#*:}
271+
272+
ngx_rust_make_module
273+
done
274+
}
275+
276+
277+
# Writes a Makefile fragment for a single module specified by
278+
# "ngx_addon_name", "ngx_rust_target_type" and "ngx_rust_target_name"
279+
280+
ngx_rust_make_module () {
281+
ngx_addon_id=$(echo "$ngx_addon_name" | sed -e 's/[^A-Za-z0-9_]/_/g')
282+
ngx_rust_obj=$NGX_OBJS/$ngx_addon_id/$(ngx_rust_target_path)
283+
284+
ngx_rustc_module_opt=
285+
if [ "$ngx_rust_target_type" = EXAMPLE ]; then
286+
ngx_rustc_module_opt="--example $ngx_rust_target_name"
287+
fi
288+
289+
cat << END >> $NGX_MAKEFILE
290+
291+
# always run cargo instead of trying to track the source modifications
292+
.PHONY: $ngx_rust_obj
293+
294+
$ngx_rust_obj:
295+
$NGX_CARGO rustc \\
296+
--config $ngx_cargo_config \\
297+
--crate-type staticlib \\
298+
--manifest-path "$ngx_cargo_manifest" \\
299+
--no-default-features \\
300+
--profile $ngx_cargo_profile \\
301+
${RUST_TARGET:+--target $RUST_TARGET} \\
302+
--target-dir $NGX_OBJS/$ngx_addon_id \\
303+
--features "$ngx_rust_features" \\
304+
$ngx_rustc_module_opt $NGX_RUSTC_OPT
305+
306+
END
307+
}

0 commit comments

Comments
 (0)