-
Notifications
You must be signed in to change notification settings - Fork 13.7k
compiler: Add Windows resources to rustc-main and rustc_driver #146018
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lambdageek
wants to merge
7
commits into
rust-lang:master
Choose a base branch
from
lambdageek:add-winres-version
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+260
−8
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f0ddbf2
compiler: Add Windows resources to rustc-main and rustc_driver
lambdageek 6886e5b
update bootstrap insta snapshot
lambdageek a21db62
don't put version into ProductDescription
lambdageek 93b57b8
fixup comment
lambdageek 037c462
invert .expect() messages
lambdageek 1cf405c
cleanup and document VersionInfoFileType enum
lambdageek a299d5f
reorder the numeric version construction
lambdageek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use std::{env, path}; | ||
|
||
use rustc_windows_rc::{VersionInfoFileType, compile_windows_resource_file}; | ||
|
||
fn main() { | ||
let target_os = env::var("CARGO_CFG_TARGET_OS"); | ||
let target_env = env::var("CARGO_CFG_TARGET_ENV"); | ||
if Ok("windows") == target_os.as_deref() && Ok("msvc") == target_env.as_deref() { | ||
set_windows_dll_options(); | ||
} else { | ||
// Avoid rerunning the build script every time. | ||
println!("cargo:rerun-if-changed=build.rs"); | ||
} | ||
} | ||
|
||
fn set_windows_dll_options() { | ||
let stem = path::PathBuf::from("rustc_driver_resource"); | ||
let file_description = "rustc_driver"; | ||
let res_file = compile_windows_resource_file(&stem, file_description, VersionInfoFileType::Dll); | ||
println!("cargo:rustc-link-arg={}", res_file.display()); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "rustc_windows_rc" | ||
version = "0.0.0" | ||
edition = "2024" | ||
|
||
[dependencies] | ||
#tidy-alphabetical-start | ||
# `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version | ||
# per crate", so if you change this, you need to also change it in `rustc_llvm` and `rustc_codegen_ssa`. | ||
cc = "=1.2.16" | ||
#tidy-alphabetical-end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// A template for the rustc_driver and rustc Windows resource files. | ||
// This file is processed by the build script to produce rustc.rc and rustc_driver.rc | ||
// with the appropriate version information filled in. | ||
|
||
// All the strings are in UTF-8 | ||
#pragma code_page(65001) | ||
|
||
#define RUSTC_FILEDESCRIPTION_STR "@RUSTC_FILEDESCRIPTION_STR@" | ||
#define RUSTC_FILETYPE @RUSTC_FILETYPE@ | ||
#define RUSTC_FILEVERSION_QUAD @RUSTC_FILEVERSION_QUAD@ | ||
#define RUSTC_FILEVERSION_STR "@RUSTC_FILEVERSION_STR@" | ||
|
||
#define RUSTC_PRODUCTNAME_STR "@RUSTC_PRODUCTNAME_STR@" | ||
#define RUSTC_PRODUCTVERSION_QUAD @RUSTC_PRODUCTVERSION_QUAD@ | ||
#define RUSTC_PRODUCTVERSION_STR "@RUSTC_PRODUCTVERSION_STR@" | ||
|
||
|
||
1 VERSIONINFO | ||
FILEVERSION RUSTC_FILEVERSION_QUAD | ||
PRODUCTVERSION RUSTC_PRODUCTVERSION_QUAD | ||
FILEOS 0x00040004 | ||
FILETYPE RUSTC_FILETYPE | ||
FILESUBTYPE 0 | ||
FILEFLAGSMASK 0x3f | ||
FILEFLAGS 0x0 | ||
{ | ||
BLOCK "StringFileInfo" | ||
{ | ||
BLOCK "000004b0" | ||
{ | ||
VALUE "FileDescription", RUSTC_FILEDESCRIPTION_STR | ||
VALUE "FileVersion", RUSTC_FILEVERSION_STR | ||
VALUE "ProductVersion", RUSTC_PRODUCTVERSION_STR | ||
VALUE "ProductName", RUSTC_PRODUCTNAME_STR | ||
} | ||
} | ||
BLOCK "VarFileInfo" { | ||
VALUE "Translation", 0x0, 0x04b0 | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
//! A build script dependency to create a Windows resource file for the compiler | ||
//! | ||
//! Uses values from the `CFG_VERSION` and `CFG_RELEASE` environment variables | ||
//! to set the product and file version information in the Windows resource file. | ||
use std::{env, ffi, fs, path, process}; | ||
|
||
use cc::windows_registry; | ||
|
||
/// The template for the Windows resource file. | ||
const RESOURCE_TEMPLATE: &str = include_str!("../rustc.rc.in"); | ||
|
||
/// A subset of the possible values for the `FILETYPE` field in a Windows resource file | ||
/// | ||
/// See the `dwFileType` member of [VS_FIXEDFILEINFO](https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo#members) | ||
#[derive(Debug, Clone, Copy)] | ||
#[repr(u32)] | ||
pub enum VersionInfoFileType { | ||
/// `VFT_APP` - The file is an application. | ||
App = 0x00000001, | ||
/// `VFT_DLL` - The file is a dynamic link library. | ||
Dll = 0x00000002, | ||
} | ||
|
||
/// Create and compile a Windows resource file with the product and file version information for the rust compiler. | ||
/// | ||
/// Returns the path to the compiled resource file | ||
/// | ||
/// Does not emit any cargo directives, the caller is responsible for that. | ||
pub fn compile_windows_resource_file( | ||
file_stem: &path::Path, | ||
file_description: &str, | ||
filetype: VersionInfoFileType, | ||
) -> path::PathBuf { | ||
let mut resources_dir = path::PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
resources_dir.push("resources"); | ||
fs::create_dir_all(&resources_dir).unwrap(); | ||
|
||
let resource_compiler = | ||
find_resource_compiler(&env::var("CARGO_CFG_TARGET_ARCH").unwrap()).expect("found rc.exe"); | ||
|
||
let mut resource_script = RESOURCE_TEMPLATE.to_string(); | ||
|
||
// Set the string product and file version to the same thing as `rustc --version` | ||
let descriptive_version = env::var("CFG_VERSION").unwrap_or("unknown".to_string()); | ||
|
||
// Set the product name to "Rust Compiler" or "Rust Compiler (nightly)" etc | ||
let product_name = product_name(env::var("CFG_RELEASE_CHANNEL").unwrap()); | ||
|
||
// For the numeric version we need `major,minor,patch,build`. | ||
// Extract them from `CFG_RELEASE` which is "major.minor.patch" and a "-dev", "-nightly" or similar suffix | ||
let cfg_release = env::var("CFG_RELEASE").unwrap(); | ||
// remove the suffix, if present and parse into [`ResourceVersion`] | ||
let version = parse_version(cfg_release.split("-").next().unwrap_or("0.0.0")) | ||
.expect("valid CFG_RELEASE version"); | ||
|
||
resource_script = resource_script | ||
.replace("@RUSTC_FILEDESCRIPTION_STR@", file_description) | ||
.replace("@RUSTC_FILETYPE@", &format!("{}", filetype as u32)) | ||
.replace("@RUSTC_FILEVERSION_QUAD@", &version.to_quad_string()) | ||
.replace("@RUSTC_FILEVERSION_STR@", &descriptive_version) | ||
.replace("@RUSTC_PRODUCTNAME_STR@", &product_name) | ||
.replace("@RUSTC_PRODUCTVERSION_QUAD@", &version.to_quad_string()) | ||
.replace("@RUSTC_PRODUCTVERSION_STR@", &descriptive_version); | ||
|
||
let rc_path = resources_dir.join(file_stem.with_extension("rc")); | ||
fs::write(&rc_path, resource_script) | ||
.unwrap_or_else(|_| panic!("failed to write resource file {}", rc_path.display())); | ||
|
||
let res_path = resources_dir.join(file_stem.with_extension("res")); | ||
|
||
let status = process::Command::new(resource_compiler) | ||
.arg("/fo") | ||
.arg(&res_path) | ||
.arg(&rc_path) | ||
.status() | ||
.expect("can execute resource compiler"); | ||
assert!(status.success(), "rc.exe failed with status {}", status); | ||
assert!( | ||
res_path.try_exists().unwrap_or(false), | ||
"resource file {} was not created", | ||
res_path.display() | ||
); | ||
res_path | ||
} | ||
|
||
fn product_name(channel: String) -> String { | ||
format!( | ||
"Rust Compiler{}", | ||
if channel == "stable" { "".to_string() } else { format!(" ({})", channel) } | ||
) | ||
} | ||
|
||
/// Windows resources store versions as four 16-bit integers. | ||
struct ResourceVersion { | ||
major: u16, | ||
minor: u16, | ||
patch: u16, | ||
build: u16, | ||
} | ||
|
||
impl ResourceVersion { | ||
/// Format the version as a comma-separated string of four integers | ||
/// as expected by Windows resource scripts for the `FILEVERSION` and `PRODUCTVERSION` fields. | ||
fn to_quad_string(&self) -> String { | ||
format!("{},{},{},{}", self.major, self.minor, self.patch, self.build) | ||
} | ||
} | ||
|
||
/// Parse a string in the format "major.minor.patch" into a [`ResourceVersion`]. | ||
/// The build is set to 0. | ||
/// Returns `None` if the version string is not in the expected format. | ||
fn parse_version(version: &str) -> Option<ResourceVersion> { | ||
let mut parts = version.split('.'); | ||
let major = parts.next()?.parse::<u16>().ok()?; | ||
let minor = parts.next()?.parse::<u16>().ok()?; | ||
let patch = parts.next()?.parse::<u16>().ok()?; | ||
if parts.next().is_some() { | ||
None | ||
} else { | ||
Some(ResourceVersion { major, minor, patch, build: 0 }) | ||
} | ||
} | ||
|
||
/// Find the Windows SDK resource compiler `rc.exe` for the given architecture or target triple. | ||
/// Returns `None` if the tool could not be found. | ||
fn find_resource_compiler(arch_or_target: &str) -> Option<path::PathBuf> { | ||
find_windows_sdk_tool(arch_or_target, "rc.exe") | ||
} | ||
|
||
/// Find a Windows SDK tool for the given architecture or target triple. | ||
/// Returns `None` if the tool could not be found. | ||
fn find_windows_sdk_tool(arch_or_target: &str, tool_name: &str) -> Option<path::PathBuf> { | ||
// windows_registry::find_tool can only find MSVC tools, not Windows SDK tools, but | ||
// cc does include the Windows SDK tools in the PATH environment of MSVC tools. | ||
|
||
let msvc_linker = windows_registry::find_tool(arch_or_target, "link.exe")?; | ||
let path = &msvc_linker.env().iter().find(|(k, _)| k == "PATH")?.1; | ||
find_tool_in_path(tool_name, path) | ||
} | ||
|
||
/// Find a tool in the directories in a given PATH-like string. | ||
fn find_tool_in_path<P: AsRef<ffi::OsStr>>(tool_name: &str, path: P) -> Option<path::PathBuf> { | ||
env::split_paths(path.as_ref()).find_map(|p| { | ||
let tool_path = p.join(tool_name); | ||
if tool_path.try_exists().unwrap_or(false) { Some(tool_path) } else { None } | ||
}) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.