embed-resource

repository·master·Indexed 42 days ago

https://github.com/nabijaczleweli/rust-embed-resource

A Cargo build script library for the compilation and inclusion of Windows resources, such as .rc files and manifests, into Rust binaries. Version 3.0.11 provides tools for handling manifest requirements via .manifest_optional() and .manifest_required(), as well as functions to link resources to specific binaries, tests, benchmarks, or cdylibs.

Tokens
2.7K
Snippets
8
Records
11
Agent score
3%

What's inside embed-resource

  1. Quickstart: Compile and link Windows resources

    master

    In your build.rs script, use embed_resource::compile to process a resource file (.rc).

    Use .manifest_optional().unwrap() if the manifest is cosmetic (e.g., an icon). Use .manifest_required().unwrap() if the manifest is required for security or as an entry point.

    Arguments that look like &["string"] or embed_resource::NONE must satisfy IntoIterator<AsRef<OsStr>> (e.g., &[&str], Option<PathBuf>, or Vec<OsString>).

    extern crate embed_resource;
    
    fn main() {
        // Compile and link checksums.rc
        embed_resource::compile("checksums.rc", embed_resource::NONE).manifest_optional().unwrap();
    
        // Or, to select a resource file for each binary separately
        embed_resource::compile_for("assets/poke-a-mango.rc", &["poke-a-mango", "poke-a-mango-installer"], &["VERSION=\"0.5.0\""]).manifest_required().unwrap();
        embed_resource::compile_for("assets/uninstaller.rc", &["unins001"], embed_resource::NONE).manifest_required().unwrap();
    }
  2. Migrate from 2.x to 3.x

    master

    When upgrading to version 3.x, you must update your compile and compile_for calls. In 3.x, the CompilationResult is marked #[must_use].

    Every call must now explicitly handle the manifest requirement by appending either .manifest_optional().unwrap() or .manifest_required().unwrap(). In versions < 3.x, the library always behaved like .manifest_optional().unwrap().

  3. Configure cross-compilation for Windows

    master

    You can embed resources when targeting Windows from a non-Windows host.

    Tool Selection

    • For *-pc-windows-gnu targets: windres is attempted by default.
    • For *-pc-windows-msvc targets: llvm-rc is used.

    Overriding the Compiler

    You can override the default compiler by setting the following environment variables:

    • RC_$TARGET (e.g., RC_X86_64_PC_WINDOWS_MSVC)
    • RC_${TARGET//-/_}
    • RC
  4. Embed Windows resources in a Cargo build script

    master

    To embed Windows resources (like icons or manifests) into your application, use embed_resource within your build.rs file.

    1. Setup Cargo.toml

    Add embed-resource to your [build-dependencies]:

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

    2. Implement build.rs

    Use embed_resource::compile() to process your .rc file. You must decide if the resulting manifest is optional or required using .manifest_optional() or .manifest_required().

    • Use .manifest_optional() for cosmetic resources like icons.
    • Use .manifest_required() for critical resources like security settings or entry points.

    Note: In version 3.x, these methods are #[must_use], so you should call .unwrap() or handle the result to ensure compilation errors are caught.

    extern crate embed_resource;
    
    fn main() {
        // Basic usage with no extra parameters
        embed_resource::compile("checksums.rc", embed_resource::NONE).manifest_optional().unwrap();
    
        // Usage with macro definitions
        embed_resource::compile("checksums.rc", &["VERSION=000901"]).manifest_required().unwrap();
    
        // Usage with macros and include directories
        embed_resource::compile("checksums.rc", embed_resource::ParamsMacrosAndIncludeDirs(
            &["VERSION=000901"], 
            &["src/include"]
        )).manifest_required().unwrap();
    }
  5. Handle Cargo rerun-if-changed manually

    master

    Because the C preprocessor step used for manifests does not automatically generate cargo:rerun-if-changed annotations, Cargo may scan the entire build root by default. If this is too expensive, manually specify the dependency in your build.rs using println! before calling compile.

    println!("cargo:rerun-if-changed=app-name-manifest.rc");
    embed_resource::compile("app-name-manifest.rc", embed_resource::NONE).manifest_optional().unwrap();
  6. Embed a Windows Manifest to request Admin permissions

    master

    To embed a manifest that requests administrator privileges, follow these steps:

    1. Add embed-resource = "3.0" to [build-dependencies] in Cargo.toml.
    2. Create build.rs in your project root:
      extern crate embed_resource;
      fn main() {
          embed_resource::compile("app-name-manifest.rc", embed_resource::NONE).manifest_optional().unwrap();
      }
    3. Create app-name-manifest.rc in your project root:
      #define RT_MANIFEST 24
      1 RT_MANIFEST "app-name.exe.manifest"
    4. Create app-name.exe.manifest in your project root:
      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
          <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
              <security>
                  <requestedPrivileges>
                      <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
                  </requestedPrivileges>
              </security>
          </trustInfo>
      </assembly>
    5. Build your project.
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
            <security>
                <requestedPrivileges>
                    <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
                </requestedPrivileges>
            </security>
        </trustInfo>
    </assembly>
  7. Handle compilation results with CompilationResult

    master

    The compile() and compile_for*() functions return a CompilationResult. Because this type is #[must_use], you should always handle it to catch failures.

    Handling Manifest Requirements

    Use these methods to convert the result into a standard Result<(), CompilationResult> based on your needs:

    • .manifest_optional(): Returns Ok(()) if the build is for non-Windows, if compilation succeeded, or if it wasn't attempted. Returns Err only if compilation actually failed.
    • .manifest_required(): Returns Ok(()) if the build is for non-Windows or if compilation succeeded. Returns Err if compilation failed OR if it wasn't attempted (e.g., missing compiler).
  8. Link resources to specific binaries or artifacts

    master

    If you want to avoid linking the resource to every single artifact in your crate, use the specialized compile_for* functions. These are useful for large projects where you only want specific binaries to carry the Windows resources.

    Available Functions

    • compile_for(resource_file, for_bins, parameters): Links the resource to a specific list of binary names (available since rustc 1.55.0).
    • compile_for_tests(resource_file, parameters): Links to test binaries (available since rustc 1.60.0).
    • compile_for_benchmarks(resource_file, parameters): Links to benchmark binaries (available since rustc 1.60.0).
    • compile_for_examples(resource_file, parameters): Links to example binaries (available since rustc 1.60.0).
    • compile_for_cdylib(resource_file, parameters): Links to the cdylib (available since rustc 1.61.0).
    • compile_for_everything(resource_file, parameters): Links to every artifact (available since rustc 1.50.0).
    // Link to specific binaries
    embed_resource::compile_for(
        "assets/poke-a-mango.rc", 
        &["poke-a-mango", "poke-a-mango-installer"], 
        &["VERSION=\"0.5.0\""]
    );
    
    // Link to everything
    embed_resource::compile_for_everything("res.rc", embed_resource::NONE);
  9. Find Windows SDK tools

    master

    On Windows with MSVC, you may need to find specific tools like midl.exe to compile IDL files. embed_resource::find_windows_sdk_tool searches for these tools in Windows Kits and/or SDK directories.

    Note: This function returns None on non-MSVC targets.

    #[cfg(all(target_os = "windows", target_env = "msvc"))]
    {
        use std::env;
        use std::process::Command;
        use embed_resource::find_windows_sdk_tool;
    
        let midl = find_windows_sdk_tool("midl.exe").unwrap();
        // Use the found path to run a command...
    }
  10. Configure macro definitions and include directories

    master

    When calling compile() or compile_for*(), you can pass different parameter types to define macros (-D//D) or include directories (-I//I). Parameters must satisfy IntoIterator<AsRef<OsStr>> (e.g., &[&str], Vec<OsString>, etc.).

    Parameter Types

    • embed_resource::NONE: An empty slice used when no extra parameters are needed.
    • ParamsMacros: Provides only macro definitions. Format: "MACRO=value" or "MACRO".
    • ParamsIncludeDirs: Provides only include directories.
    • ParamsMacrosAndIncludeDirs: Provides both macros and include directories.
    // Example: Using ParamsIncludeDirs
    embed_resource::compile("res.rc", embed_resource::ParamsIncludeDirs(&["src/include"]));
    
    // Example: Using ParamsMacrosAndIncludeDirs
    embed_resource::compile("res.rc", embed_resource::ParamsMacrosAndIncludeDirs(
        &["DEBUG=1"], 
        &["include/path"]
    ));