Crate embed_resource [] [src]

A Cargo build script library to handle compilation and inclusion of Windows resources in the most resilient fashion imaginable

Background

Including Windows resources seems very easy at first, despite the build scripts' abhorrent documentation: compile with windres, then make linkable with ar.

I was very happy with that solution until it was brought to my attention, that MSVC uses something different, and now either windres-ar combo or RC.EXE would be used, which was OK.

Later it transpired, that MSVC is even more incompatible with everything else by way of not having RC.EXE in $PATH (because it would only be reasonable to do so), so another MSVC artisan made the script find the most likely places for RC.EXE to be, and the script grew yet again, now standing at 100 lines and 3.2 kB.

After copying the build script in its entirety and realising how error-prone that was, then being nudged by Shepmaster to extract it to a crate, here we are.

Usage (overview)

Since the build script documentation is trash and build script handling is even more trash, we can't print a build script line to link to the compiled resource file. Instead, you need to use and extern block in your main.rs file like so:

#[cfg(target_os="windows")]
#[link(name="checksums-manifest", kind="static")]
extern "C" {}

// Your main() and w/e

Since the manifest is only generated on Windows, the cfg attribute takes care of that.

The name attribute argument is either:

  • The name of the crate + "-manifest" by default, or
  • The second argument to compile().

Usage (detailed)

For the purposes of the demonstration we will assume that the crate's name is "checksums" and that the resource file's name is "checksums.rc".

In Cargo.toml:

# The general section with crate name, license, etc.
build = "build.rs"

[build-dependencies]
embed-resource = "0.1"

In build.rs:

extern crate embed_resource;

fn main() {
    embed_resource::compile("checksums.rc", None, None);
}

In main.rs:

#[cfg(target_os="windows")]
#[link(name="checksums-manifest", kind="static")]
extern "C" {}

If, however, you want to use a different manifest link name (here: "chksum-rc"):

In build.rs:

extern crate embed_resource;

fn main() {
    embed_resource::compile("checksums.rc", Some("chksum-rc"), None);
}

In main.rs:

#[cfg(target_os="windows")]
#[link(name="chksum-rc", kind="static")]
extern "C" {}

If, for an unfathomable reason, you want to create the resource archive in a different location:

In build.rs:

extern crate embed_resource;

fn main() {
    embed_resource::compile("checksums.rc", None, Some("C:/Rast/build-files-output"));
}

I souldn't recommend this, but hey.

Credit

In chronological order:

@liigo -- persistency in pestering me and investigating problems where I have failed

@mzji -- MSVC lab rat

@TheCatPlusPlus -- knowledge and providing first iteration of manifest-embedding code

@azyobuzin -- providing code for finding places where RC.EXE could hide

Functions

compile

Compile the Windows resource file and update the cargo search path if we're on Windows.