@@ -9,7 +9,7 @@ use std::path::{Path, PathBuf};
9
9
#[ cfg( feature = "vendored" ) ]
10
10
mod vendored;
11
11
12
- const ENV_VARS_TRIGGERING_RECOMPILE : [ & str ; 2 ] = [ "OUT_DIR" , "NGX_OBJS" ] ;
12
+ const ENV_VARS_TRIGGERING_RECOMPILE : & [ & str ] = & [ "OUT_DIR" , "NGX_OBJS" , "NGINX_SOURCE_DIR "] ;
13
13
14
14
/// The feature flags set by the nginx configuration script.
15
15
///
@@ -54,34 +54,113 @@ const NGX_CONF_OS: &[&str] = &[
54
54
"darwin" , "freebsd" , "gnu_hurd" , "hpux" , "linux" , "solaris" , "tru64" , "win32" ,
55
55
] ;
56
56
57
+ type BoxError = Box < dyn StdError > ;
58
+
57
59
/// Function invoked when `cargo build` is executed.
58
60
/// This function will download NGINX and all supporting dependencies, verify their integrity,
59
61
/// extract them, execute autoconf `configure` for NGINX, compile NGINX and finally install
60
62
/// NGINX in a subdirectory with the project.
61
- fn main ( ) -> Result < ( ) , Box < dyn StdError > > {
62
- let nginx_build_dir = match std:: env:: var ( "NGX_OBJS" ) {
63
- Ok ( v) => dunce:: canonicalize ( v) ?,
64
- #[ cfg( feature = "vendored" ) ]
65
- Err ( _) => vendored:: build ( ) ?,
66
- #[ cfg( not( feature = "vendored" ) ) ]
67
- Err ( _) => panic ! ( "\" nginx-sys/vendored\" feature is disabled and NGX_OBJS is not specified" ) ,
68
- } ;
63
+ fn main ( ) -> Result < ( ) , BoxError > {
69
64
// Hint cargo to rebuild if any of the these environment variables values change
70
65
// because they will trigger a recompilation of NGINX with different parameters
71
66
for var in ENV_VARS_TRIGGERING_RECOMPILE {
72
67
println ! ( "cargo:rerun-if-env-changed={var}" ) ;
73
68
}
74
69
println ! ( "cargo:rerun-if-changed=build/main.rs" ) ;
75
70
println ! ( "cargo:rerun-if-changed=build/wrapper.h" ) ;
71
+
72
+ let nginx = NginxSource :: from_env ( ) ;
76
73
// Read autoconf generated makefile for NGINX and generate Rust bindings based on its includes
77
- generate_binding ( nginx_build_dir ) ;
74
+ generate_binding ( & nginx ) ;
78
75
Ok ( ( ) )
79
76
}
80
77
78
+ pub struct NginxSource {
79
+ source_dir : PathBuf ,
80
+ build_dir : PathBuf ,
81
+ }
82
+
83
+ impl NginxSource {
84
+ pub fn new ( source_dir : impl AsRef < Path > , build_dir : impl AsRef < Path > ) -> Self {
85
+ let source_dir = NginxSource :: check_source_dir ( source_dir) . expect ( "source directory" ) ;
86
+ let build_dir = NginxSource :: check_build_dir ( build_dir) . expect ( "build directory" ) ;
87
+
88
+ Self { source_dir, build_dir }
89
+ }
90
+
91
+ pub fn from_env ( ) -> Self {
92
+ match ( env:: var_os ( "NGINX_SOURCE_DIR" ) , env:: var_os ( "NGX_OBJS" ) ) {
93
+ ( Some ( source_dir) , Some ( build_dir) ) => NginxSource :: new ( source_dir, build_dir) ,
94
+ ( Some ( source_dir) , None ) => Self :: from_source_dir ( source_dir) ,
95
+ ( None , Some ( build_dir) ) => Self :: from_build_dir ( build_dir) ,
96
+ _ => Self :: from_vendored ( ) ,
97
+ }
98
+ }
99
+
100
+ pub fn from_source_dir ( source_dir : impl AsRef < Path > ) -> Self {
101
+ let build_dir = source_dir. as_ref ( ) . join ( "objs" ) ;
102
+
103
+ // todo!("Build from source");
104
+
105
+ Self :: new ( source_dir, build_dir)
106
+ }
107
+
108
+ pub fn from_build_dir ( build_dir : impl AsRef < Path > ) -> Self {
109
+ let source_dir = build_dir. as_ref ( ) . parent ( ) . expect ( "source directory" ) . to_owned ( ) ;
110
+ Self :: new ( source_dir, build_dir)
111
+ }
112
+
113
+ #[ cfg( feature = "vendored" ) ]
114
+ pub fn from_vendored ( ) -> Self {
115
+ let build_dir = vendored:: build ( ) . expect ( "vendored build" ) ;
116
+ let source_dir = build_dir. parent ( ) . expect ( "source directory" ) . to_path_buf ( ) ;
117
+
118
+ Self { source_dir, build_dir }
119
+ }
120
+
121
+ #[ cfg( not( feature = "vendored" ) ) ]
122
+ pub fn from_vendored ( ) -> Self {
123
+ panic ! ( "\" nginx-sys/vendored\" feature is disabled and neither NGINX_SOURCE_DIR nor NGX_OBJS is set" ) ;
124
+ }
125
+
126
+ fn check_source_dir ( source_dir : impl AsRef < Path > ) -> Result < PathBuf , BoxError > {
127
+ match dunce:: canonicalize ( & source_dir) {
128
+ Ok ( path) if path. join ( "src/core/nginx.h" ) . is_file ( ) => Ok ( path) ,
129
+ Err ( err) => Err ( format ! ( "Invalid nginx source directory: {:?}. {}" , source_dir. as_ref( ) , err) . into ( ) ) ,
130
+ _ => Err ( format ! (
131
+ "Invalid nginx source directory: {:?}. NGINX_SOURCE_DIR is not specified or contains invalid value." ,
132
+ source_dir. as_ref( )
133
+ )
134
+ . into ( ) ) ,
135
+ }
136
+ }
137
+
138
+ fn check_build_dir ( build_dir : impl AsRef < Path > ) -> Result < PathBuf , BoxError > {
139
+ match dunce:: canonicalize ( & build_dir) {
140
+ Ok ( path) if path. join ( "ngx_auto_config.h" ) . is_file ( ) => Ok ( path) ,
141
+ Err ( err) => Err ( format ! ( "Invalid nginx build directory: {:?}. {}" , build_dir. as_ref( ) , err) . into ( ) ) ,
142
+ _ => Err ( format ! (
143
+ "Invalid NGINX build directory: {:?}. NGX_OBJS is not specified or contains invalid value." ,
144
+ build_dir. as_ref( )
145
+ )
146
+ . into ( ) ) ,
147
+ }
148
+ }
149
+ }
150
+
81
151
/// Generates Rust bindings for NGINX
82
- fn generate_binding ( nginx_build_dir : PathBuf ) {
83
- let autoconf_makefile_path = nginx_build_dir. join ( "Makefile" ) ;
84
- let includes = parse_includes_from_makefile ( & autoconf_makefile_path) ;
152
+ fn generate_binding ( nginx : & NginxSource ) {
153
+ let autoconf_makefile_path = nginx. build_dir . join ( "Makefile" ) ;
154
+ let includes: Vec < _ > = parse_includes_from_makefile ( & autoconf_makefile_path)
155
+ . into_iter ( )
156
+ . map ( |path| {
157
+ if path. is_absolute ( ) {
158
+ path
159
+ } else {
160
+ nginx. source_dir . join ( path)
161
+ }
162
+ } )
163
+ . collect ( ) ;
85
164
let clang_args: Vec < String > = includes
86
165
. iter ( )
87
166
. map ( |path| format ! ( "-I{}" , path. to_string_lossy( ) ) )
@@ -166,25 +245,7 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec<P
166
245
}
167
246
}
168
247
169
- let makefile_dir = nginx_autoconf_makefile_path
170
- . parent ( )
171
- . expect ( "makefile path has no parent" )
172
- . parent ( )
173
- . expect ( "objs dir has no parent" ) ;
174
-
175
- includes
176
- . into_iter ( )
177
- . map ( PathBuf :: from)
178
- . map ( |path| {
179
- if path. is_absolute ( ) {
180
- path
181
- } else {
182
- makefile_dir. join ( path)
183
- }
184
- } )
185
- . map ( dunce:: canonicalize)
186
- . collect :: < Result < Vec < _ > , _ > > ( )
187
- . expect ( "canonicalize include paths" )
248
+ includes. into_iter ( ) . map ( PathBuf :: from) . collect ( )
188
249
}
189
250
190
251
/// Collect info about the nginx configuration and expose it to the dependents via
0 commit comments