summaryrefslogtreecommitdiffstats
path: root/third_party/rust/embed-manifest/src/lib.rs
blob: 6c60cdf5417f30dd2b2eb8594368ba49894d47e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! 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.
//!
//! [1]: https://doc.rust-lang.org/cargo/reference/build-scripts.html
//!
//! 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.
///
/// [tier1]: https://doc.rust-lang.org/nightly/rustc/platform-support.html
/// [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
/// [uac]: https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works#virtualization
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()
}