Revision control
Copy as Markdown
Other Tools
//! The `embed-manifest` crate provides a straightforward way to embed
//! a Windows manifest in an executable, whatever the build environment
//! and even when cross-compiling, without dependencies on external
//! tools from LLVM or MinGW.
//!
//! This should be called from a [build script][1], as shown below.
//!
//!
//! On MSVC targets, the manifest file is embedded in the executable by
//! instructing Cargo to pass `/MANIFEST` options to `LINK.EXE`. This
//! requires Cargo from Rust 1.56.
//!
//! On GNU targets, the manifest file is added as a resource in a COFF
//! object file, and Cargo is instructed to link this file into the
//! executable, also using functionality from Rust 1.56.
//!
//! # Usage
//!
//! This crate should be added to the `[build-dependencies]` section in
//! your executable’s `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! embed-manifest = "1.3.1"
//! ```
//!
//! In the same directory, create a `build.rs` file to call this crate’s
//! code when building for Windows, and to only run once:
//!
//! ```
//! use embed_manifest::{embed_manifest, new_manifest};
//!
//! fn main() {
//! # let tempdir = tempfile::tempdir().unwrap();
//! # std::env::set_var("OUT_DIR", tempdir.path());
//! # std::env::set_var("TARGET", "x86_64-pc-windows-gnu");
//! # std::env::set_var("CARGO_CFG_WINDOWS", "");
//! if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
//! embed_manifest(new_manifest("Contoso.Sample")).expect("unable to embed manifest file");
//! }
//! println!("cargo:rerun-if-changed=build.rs");
//! }
//! ```
//!
//! To customise the application manifest, use the methods on it to change things like
//! enabling the segment heap:
//!
//! ```
//! use embed_manifest::{embed_manifest, new_manifest, manifest::HeapType};
//!
//! fn main() {
//! # let tempdir = tempfile::tempdir().unwrap();
//! # std::env::set_var("OUT_DIR", tempdir.path());
//! # std::env::set_var("TARGET", "x86_64-pc-windows-gnu");
//! # std::env::set_var("CARGO_CFG_WINDOWS", "");
//! if std::env::var_os("CARGO_CFG_WINDOWS").is_some() {
//! embed_manifest(new_manifest("Contoso.Sample").heap_type(HeapType::SegmentHeap))
//! .expect("unable to embed manifest file");
//! }
//! println!("cargo:rerun-if-changed=build.rs");
//! }
//! ```
//!
//! or making it always use legacy single-byte API encoding and only declaring compatibility
//! up to Windows 8.1, without checking whether this is a Windows build:
//!
//! ```
//! use embed_manifest::{embed_manifest, new_manifest};
//! use embed_manifest::manifest::{ActiveCodePage::Legacy, SupportedOS::*};
//!
//! fn main() {
//! # let tempdir = tempfile::tempdir().unwrap();
//! # std::env::set_var("OUT_DIR", tempdir.path());
//! # std::env::set_var("TARGET", "x86_64-pc-windows-gnu");
//! let manifest = new_manifest("Contoso.Sample")
//! .active_code_page(Legacy)
//! .supported_os(Windows7..=Windows81);
//! embed_manifest(manifest).expect("unable to embed manifest file");
//! println!("cargo:rerun-if-changed=build.rs");
//! }
//! ```
#![allow(clippy::needless_doctest_main)]
pub use embed::error::Error;
pub use embed::{embed_manifest, embed_manifest_file};
use crate::manifest::ManifestBuilder;
mod embed;
pub mod manifest;
/// Creates a new [`ManifestBuilder`] with sensible defaults, allowing customisation
/// before the Windows application manifest XML is generated.
///
/// The initial values used by the manifest are:
/// - Version number from the `CARGO_PKG_VERSION_MAJOR`, `CARGO_PKG_VERSION_MINOR` and
/// `CARGO_PKG_VERSION_PATCH` environment variables. This can then be changed with
/// [`version()`][ManifestBuilder::version].
/// - A dependency on version 6 of the Common Controls so that message boxes and dialogs
/// will use the latest design, and have the best available support for high DPI displays.
/// This can be removed with
/// [`remove_dependency`][ManifestBuilder::remove_dependency].
/// - [Compatible with Windows from 7 to 11][ManifestBuilder::supported_os],
/// matching the Rust compiler [tier 1 targets][tier1].
/// - A “[maximum version tested][ManifestBuilder::max_version_tested]” of Windows 10
/// version 1903.
/// - An [active code page][ManifestBuilder::active_code_page] of UTF-8, so that
/// single-byte Windows APIs will generally interpret Rust strings correctly, starting
/// from Windows 10 version 1903.
/// - [Version 2 of per-monitor high DPI awareness][manifest::DpiAwareness::PerMonitorV2Only],
/// so that user interface elements can be scaled correctly by the application and
/// Common Controls from Windows 10 version 1703.
/// - [Long path awareness][ManifestBuilder::long_path_aware] from Windows 10 version
/// 1607 [when separately enabled][longpaths].
/// - [Printer driver isolation][ManifestBuilder::printer_driver_isolation] enabled
/// to improve reliability and security.
/// - An [execution level][ManifestBuilder::requested_execution_level] of “as invoker”
/// so that the UAC elevation dialog will never be displayed, regardless of the name
/// of the program, and [UAC Virtualisation][uac] is disabled in 32-bit programs.
///
/// [longpaths]: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd#enable-long-paths-in-windows-10-version-1607-and-later
pub fn new_manifest(name: &str) -> ManifestBuilder {
ManifestBuilder::new(name)
}
/// Creates a new [`ManifestBuilder`] without any settings, allowing creation of
/// a manifest with only desired content.
pub fn empty_manifest() -> ManifestBuilder {
ManifestBuilder::empty()
}