Skip to content

Commit ac8be53

Browse files
Allow ::compile(..., ::ParamsMacrosAndIncludeDirs(&["macro", ...], &["includedir", ...])). Allow ::compile(..., ::ParamsMacros(&["macro", ...])) equivalent to without ParamsMacros
All old callers are still valid PMAID is a no-op for now, pending #80
1 parent 4bb24cc commit ac8be53

File tree

1 file changed

+142
-18
lines changed

1 file changed

+142
-18
lines changed

src/lib.rs

Lines changed: 142 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
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
//!
@@ -120,6 +123,8 @@
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")))]
125130
extern crate cc;
@@ -155,12 +160,83 @@ use std::fmt::{self, Display};
155160
use 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 :)
161166
pub 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

Comments
 (0)