@@ -9,7 +9,7 @@ use std::path::{Path, PathBuf};
99#[ cfg( feature = "vendored" ) ]
1010mod vendored;
1111
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 "] ;
1313
1414/// The feature flags set by the nginx configuration script.
1515///
@@ -54,34 +54,113 @@ const NGX_CONF_OS: &[&str] = &[
5454 "darwin" , "freebsd" , "gnu_hurd" , "hpux" , "linux" , "solaris" , "tru64" , "win32" ,
5555] ;
5656
57+ type BoxError = Box < dyn StdError > ;
58+
5759/// Function invoked when `cargo build` is executed.
5860/// This function will download NGINX and all supporting dependencies, verify their integrity,
5961/// extract them, execute autoconf `configure` for NGINX, compile NGINX and finally install
6062/// 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 > {
6964 // Hint cargo to rebuild if any of the these environment variables values change
7065 // because they will trigger a recompilation of NGINX with different parameters
7166 for var in ENV_VARS_TRIGGERING_RECOMPILE {
7267 println ! ( "cargo:rerun-if-env-changed={var}" ) ;
7368 }
7469 println ! ( "cargo:rerun-if-changed=build/main.rs" ) ;
7570 println ! ( "cargo:rerun-if-changed=build/wrapper.h" ) ;
71+
72+ let nginx = NginxSource :: from_env ( ) ;
7673 // Read autoconf generated makefile for NGINX and generate Rust bindings based on its includes
77- generate_binding ( nginx_build_dir ) ;
74+ generate_binding ( & nginx ) ;
7875 Ok ( ( ) )
7976}
8077
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+
81151/// 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 ( ) ;
85164 let clang_args: Vec < String > = includes
86165 . iter ( )
87166 . map ( |path| format ! ( "-I{}" , path. to_string_lossy( ) ) )
@@ -166,25 +245,7 @@ fn parse_includes_from_makefile(nginx_autoconf_makefile_path: &PathBuf) -> Vec<P
166245 }
167246 }
168247
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 ( )
188249}
189250
190251/// Collect info about the nginx configuration and expose it to the dependents via
0 commit comments