4848//! embed_resource::compile("checksums.rc", embed_resource::NONE).manifest_optional().unwrap();
4949//! // or
5050//! embed_resource::compile("checksums.rc", &["VERSION=000901"]).manifest_required().unwrap();
51+ //! // or
52+ //! embed_resource::compile("checksums.rc", embed_resource::ParamsMacrosAndIncludeDirs(
53+ //! &["VERSION=000901"], &["src/include"])).manifest_required().unwrap();
5154//! }
5255//! ```
5356//!
120123//! * Lars Strojny
121124//! * EvModder
122125
126+ #![ allow( private_bounds) ]
127+
123128
124129#[ cfg( any( not( target_os = "windows" ) , all( target_os = "windows" , target_env = "msvc" ) ) ) ]
125130extern crate cc;
@@ -155,12 +160,83 @@ use std::fmt::{self, Display};
155160use std:: path:: { Path , PathBuf } ;
156161
157162
158- /// Empty slice, properly-typed for [`compile()`] and `compile_for*()`'s macro list .
163+ /// Empty slice, properly-typed for [`compile()`] and `compile_for*()` to mean "no additional parameters" .
159164///
160165/// Rust helpfully forbids default type parameters on functions, so just passing `[]` doesn't work :)
161166pub const NONE : & [ & OsStr ] = & [ ] ;
162167
163168
169+ // This is all of the parameters and it's non-public:
170+ // the only way users can construct this is via From<Mi> (same as From<ParamsMacros>) and From<ParamsMacrosAndIncludeDirs>
171+ struct ArgumentBundle < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > , Is : AsRef < OsStr > , Ii : IntoIterator < Item = Is > > {
172+ macros : Mi ,
173+ include_dirs : Ii ,
174+ }
175+
176+ impl < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > From < Mi > for ArgumentBundle < Ms , Mi , & ' static & ' static OsStr , & ' static [ & ' static OsStr ] > {
177+ fn from ( macros : Mi ) -> Self {
178+ ParamsMacros ( macros) . into ( )
179+ }
180+ }
181+
182+ /// Give this to [`compile()`] or `compile_for*()` to add some macro definitions (`-D`/`/D`).
183+ ///
184+ /// Every value must be in the form `MACRO=value` or `MACRO`. An empty iterator is a no-op.
185+ pub struct ParamsMacros < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( pub Mi ) ;
186+ impl < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > From < ParamsMacros < Ms , Mi > > for ArgumentBundle < Ms , Mi , & ' static & ' static OsStr , & ' static [ & ' static OsStr ] > {
187+ fn from ( macros : ParamsMacros < Ms , Mi > ) -> Self {
188+ ParamsMacrosAndIncludeDirs ( macros. 0 , NONE ) . into ( )
189+ }
190+ }
191+
192+ /// Give this to [`compile()`] or `compile_for*()` to add some macro definitions (`-D`/`/D`) and include directories
193+ /// (`-I`/`/I`).
194+ ///
195+ /// Every macro value must be in the form `MACRO=value` or `MACRO`.
196+ ///
197+ /// Empty iterators are no-ops.
198+ pub struct ParamsMacrosAndIncludeDirs < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > , Is : AsRef < OsStr > , Ii : IntoIterator < Item = Is > > ( pub Mi , pub Ii ) ;
199+ impl < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > , Is : AsRef < OsStr > , Ii : IntoIterator < Item = Is > > From < ParamsMacrosAndIncludeDirs < Ms , Mi , Is , Ii > >
200+ for ArgumentBundle < Ms , Mi , Is , Ii > {
201+ fn from ( maid : ParamsMacrosAndIncludeDirs < Ms , Mi , Is , Ii > ) -> Self {
202+ Self {
203+ macros : maid. 0 ,
204+ include_dirs : maid. 1 ,
205+ }
206+ }
207+ }
208+
209+
210+ /// https://101010.pl/@nabijaczleweli/115226665478478763
211+ #[ cfg( test) ]
212+ #[ allow( dead_code) ]
213+ fn compat_3_0_5 ( ) {
214+ use std:: collections:: BTreeSet ;
215+
216+ // these spellings of the macros argument taken from GitHub "embed_resource::" search
217+ // and https://crates.io/crates/embed-resource/reverse_dependencies on 2025-09-18
218+ let _ = compile ( "" , std:: iter:: empty :: < & str > ( ) ) ;
219+ let _ = compile ( "" , None :: < & str > ) ;
220+ let marcos = & [ format ! ( "VERSION_PATCH={}" , env!( "CARGO_PKG_VERSION_PATCH" ) ) ] ;
221+ let _ = compile ( "" , marcos) ;
222+ let marcos = vec ! [ format!( "VERSION_PATCH={}" , env!( "CARGO_PKG_VERSION_PATCH" ) ) ] ;
223+ let _ = compile ( "" , marcos) ;
224+
225+ // these weren't
226+ let _ = compile ( "" , [ "" ] ) ;
227+ let _ = compile ( "" , & [ "" ] ) ;
228+ let _ = compile ( "" , vec ! [ "" ] ) ;
229+ let _ = compile ( "" , vec ! [ Path :: new( "gaming=baming" ) ] . into_iter ( ) . collect :: < BTreeSet < _ > > ( ) ) ;
230+ let _ = compile ( "" , vec ! [ Path :: new( "gaming=baming" ) . to_owned( ) ] . into_iter ( ) . collect :: < BTreeSet < _ > > ( ) ) ;
231+ let _ = compile ( "" , [ PathBuf :: from ( "gaming=baming" ) ] . iter ( ) ) ;
232+ let _ = compile ( "" , [ PathBuf :: from ( "gaming=baming" ) ] . iter ( ) . collect :: < BTreeSet < _ > > ( ) ) ;
233+
234+ // this is new
235+ let _ = compile ( "" , ParamsMacrosAndIncludeDirs ( NONE , NONE ) ) ;
236+ let _ = compile ( "" , ParamsMacrosAndIncludeDirs ( [ "" ] , [ "" ] ) ) ;
237+ }
238+
239+
164240/// Result of [`compile()`] and `compile_for*()`
165241///
166242/// Turn this into a `Result` with `manifest_optional()` if the manifest is nice, but isn't required, like when embedding an
@@ -246,7 +322,8 @@ macro_rules! try_compile_impl {
246322/// Since rustc 1.50.0, the resource is linked only to the binaries
247323/// (unless there are none, in which case it's also linked to the library).
248324///
249- /// `macros` are a list of macros to define, in standard `NAME`/`NAME=VALUE` format.
325+ /// `parameters` are a list of macros to define (directly or via [`ParamsMacros`]), in standard `NAME`/`NAME=VALUE` format,
326+ /// or [`ParamsMacrosAndIncludeDirs`].
250327///
251328/// # Examples
252329///
@@ -260,8 +337,15 @@ macro_rules! try_compile_impl {
260337/// embed_resource::compile("checksums.rc", embed_resource::NONE);
261338/// }
262339/// ```
263- pub fn compile < T : AsRef < Path > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , macros : Mi ) -> CompilationResult {
264- let ( prefix, out_dir, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
340+ pub fn compile < T : AsRef < Path > ,
341+ Ms : AsRef < OsStr > ,
342+ Mi : IntoIterator < Item = Ms > ,
343+ Is : AsRef < OsStr > ,
344+ Ii : IntoIterator < Item = Is > ,
345+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
346+ resource_file : T , parameters : P )
347+ -> CompilationResult {
348+ let ( prefix, out_dir, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
265349 let hasbins = fs:: read_to_string ( "Cargo.toml" )
266350 . unwrap_or_else ( |err| {
267351 eprintln ! ( "Couldn't read Cargo.toml: {}; assuming src/main.rs or S_ISDIR(src/bin/)" , err) ;
@@ -301,10 +385,17 @@ pub fn compile<T: AsRef<Path>, Ms: AsRef<OsStr>, Mi: IntoIterator<Item = Ms>>(re
301385/// embed_resource::compile_for("assets/uninstaller.rc", &["unins001"], embed_resource::NONE);
302386/// }
303387/// ```
304- pub fn compile_for < T : AsRef < Path > , J : Display , I : IntoIterator < Item = J > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , for_bins : I ,
305- macros : Mi )
306- -> CompilationResult {
307- let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
388+ pub fn compile_for < T : AsRef < Path > ,
389+ J : Display ,
390+ I : IntoIterator < Item = J > ,
391+ Ms : AsRef < OsStr > ,
392+ Mi : IntoIterator < Item = Ms > ,
393+ Is : AsRef < OsStr > ,
394+ Ii : IntoIterator < Item = Is > ,
395+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
396+ resource_file : T , for_bins : I , parameters : P )
397+ -> CompilationResult {
398+ let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
308399 for bin in for_bins {
309400 println ! ( "cargo:rustc-link-arg-bin={}={}" , bin, out_file) ;
310401 }
@@ -315,26 +406,47 @@ pub fn compile_for<T: AsRef<Path>, J: Display, I: IntoIterator<Item = J>, Ms: As
315406/// prefer [`compile_for_everything()`]).
316407///
317408/// Only available since rustc 1.60.0, does nothing before.
318- pub fn compile_for_tests < T : AsRef < Path > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , macros : Mi ) -> CompilationResult {
319- let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
409+ pub fn compile_for_tests < T : AsRef < Path > ,
410+ Ms : AsRef < OsStr > ,
411+ Mi : IntoIterator < Item = Ms > ,
412+ Is : AsRef < OsStr > ,
413+ Ii : IntoIterator < Item = Is > ,
414+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
415+ resource_file : T , parameters : P )
416+ -> CompilationResult {
417+ let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
320418 println ! ( "cargo:rustc-link-arg-tests={}" , out_file) ;
321419 CompilationResult :: Ok
322420}
323421
324422/// Likewise, but only link the resource to benchmarks.
325423///
326424/// Only available since rustc 1.60.0, does nothing before.
327- pub fn compile_for_benchmarks < T : AsRef < Path > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , macros : Mi ) -> CompilationResult {
328- let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
425+ pub fn compile_for_benchmarks < T : AsRef < Path > ,
426+ Ms : AsRef < OsStr > ,
427+ Mi : IntoIterator < Item = Ms > ,
428+ Is : AsRef < OsStr > ,
429+ Ii : IntoIterator < Item = Is > ,
430+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
431+ resource_file : T , parameters : P )
432+ -> CompilationResult {
433+ let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
329434 println ! ( "cargo:rustc-link-arg-benches={}" , out_file) ;
330435 CompilationResult :: Ok
331436}
332437
333438/// Likewise, but only link the resource to examples.
334439///
335440/// Only available since rustc 1.60.0, does nothing before.
336- pub fn compile_for_examples < T : AsRef < Path > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , macros : Mi ) -> CompilationResult {
337- let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
441+ pub fn compile_for_examples < T : AsRef < Path > ,
442+ Ms : AsRef < OsStr > ,
443+ Mi : IntoIterator < Item = Ms > ,
444+ Is : AsRef < OsStr > ,
445+ Ii : IntoIterator < Item = Is > ,
446+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
447+ resource_file : T , parameters : P )
448+ -> CompilationResult {
449+ let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
338450 println ! ( "cargo:rustc-link-arg-examples={}" , out_file) ;
339451 CompilationResult :: Ok
340452}
@@ -343,13 +455,22 @@ pub fn compile_for_examples<T: AsRef<Path>, Ms: AsRef<OsStr>, Mi: IntoIterator<I
343455/// benchmarks, &c.
344456///
345457/// Only available since rustc 1.50.0, does nothing before.
346- pub fn compile_for_everything < T : AsRef < Path > , Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : T , macros : Mi ) -> CompilationResult {
347- let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , macros) ) ;
458+ pub fn compile_for_everything < T : AsRef < Path > ,
459+ Ms : AsRef < OsStr > ,
460+ Mi : IntoIterator < Item = Ms > ,
461+ Is : AsRef < OsStr > ,
462+ Ii : IntoIterator < Item = Is > ,
463+ P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
464+ resource_file : T , parameters : P )
465+ -> CompilationResult {
466+ let ( _, _, out_file) = try_compile_impl ! ( compile_impl( resource_file. as_ref( ) , parameters. into( ) . macros) ) ;
348467 println ! ( "cargo:rustc-link-arg={}" , out_file) ;
349468 CompilationResult :: Ok
350469}
351470
352- fn compile_impl < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > > ( resource_file : & Path , macros : Mi ) -> Result < ( & str , String , String ) , CompilationResult > {
471+ fn compile_impl < Ms : AsRef < OsStr > , Mi : IntoIterator < Item = Ms > , Is : AsRef < OsStr > , Ii : IntoIterator < Item = Is > , P : Into < ArgumentBundle < Ms , Mi , Is , Ii > > > (
472+ resource_file : & Path , parameters : P )
473+ -> Result < ( & str , String , String ) , CompilationResult > {
353474 let mut comp = ResourceCompiler :: new ( ) ;
354475 if let Some ( missing) = comp. is_supported ( ) {
355476 if missing. is_empty ( ) {
@@ -361,7 +482,10 @@ fn compile_impl<Ms: AsRef<OsStr>, Mi: IntoIterator<Item = Ms>>(resource_file: &P
361482 let prefix = & resource_file. file_stem ( ) . expect ( "resource_file has no stem" ) . to_str ( ) . expect ( "resource_file's stem not UTF-8" ) ;
362483 let out_dir = env:: var ( "OUT_DIR" ) . expect ( "No OUT_DIR env var" ) ;
363484
364- let out_file = comp. compile_resource ( & out_dir, & prefix, resource_file. to_str ( ) . expect ( "resource_file not UTF-8" ) , macros)
485+ let out_file = comp. compile_resource ( & out_dir,
486+ & prefix,
487+ resource_file. to_str ( ) . expect ( "resource_file not UTF-8" ) ,
488+ parameters. into ( ) . macros )
365489 . map_err ( CompilationResult :: Failed ) ?;
366490 Ok ( ( prefix, out_dir, out_file) )
367491 }
0 commit comments