link_args-0.6.0/.cargo_vcs_info.json0000644000000001120000000000000130010ustar { "git": { "sha1": "400d5aa863be65e7b0c582955bbaa1a4f49f0156" } } link_args-0.6.0/.gitignore000064400000000000000000000000230000000000000135400ustar 00000000000000/target Cargo.lock link_args-0.6.0/Cargo.lock0000644000000002140000000000000107570ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "link_args" version = "0.6.0" link_args-0.6.0/Cargo.toml0000644000000017500000000000000110100ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "link_args" version = "0.6.0" authors = ["Chris Denton "] exclude = ["examples/*"] description = "Allows setting linker arugments at compile time without a build script. Currently only supports Windows MSVC toolchains." keywords = ["windows", "msvc", "link"] categories = ["development-tools::build-utils", "no-std"] license = "MIT OR Apache-2.0 OR Zlib" repository = "https://github.com/ChrisDenton/link_args" link_args-0.6.0/Cargo.toml.orig000064400000000000000000000007630000000000000144520ustar 00000000000000[package] name = "link_args" description = """\ Allows setting linker arugments at compile time without a build script. \ Currently only supports Windows MSVC toolchains.\ """ version = "0.6.0" authors = ["Chris Denton "] edition = "2018" license = "MIT OR Apache-2.0 OR Zlib" repository = "https://github.com/ChrisDenton/link_args" keywords = ["windows", "msvc", "link"] categories = ["development-tools::build-utils", "no-std"] exclude = [ "examples/*" ] link_args-0.6.0/Readme.md000064400000000000000000000007020000000000000132730ustar 00000000000000Allows setting linker arugments at compile time without a build script. Currently only supports Windows MSVC toolchains. Minimum Rust version: 1.51 # Usage Add this to your `Cargo.toml`: ```toml [dependencies] link_args = "0.6" ``` # Examples ## Set the stack size ```rust // Reserve 8 MiB for the stack. link_args::windows_msvc::stack_size!(0x800000); ``` ## Add a library ```rust link_args::windows_msvc::default_lib!("kernel32.lib"); ``` link_args-0.6.0/src/lib.rs000064400000000000000000000045660000000000000134730ustar 00000000000000#![no_std] //! Allows setting linker arugments at compile time without a build script. //! Currently only supports Windows MSVC toolchains. //! //! # Usage //! //! Add this to your `Cargo.toml`: //! ```toml //! [dependencies] //! link_args = "0.6" //! ``` //! //! # Examples //! //! Put these examples at the root of your `main.rs` or `lib.rs`. //! //! ## Set the size of the stack //! //! Reserve 8 MiB (8,388,608 bytes) of virtual memory for the stack. This should //! only be set for crates that produce a `.exe` or `.dll` binary. //! //! ```rust //! link_args::windows::stack_size!(0x800000); //! ``` //! //! ## Add a default library //! //! Add "kernel32.lib" to the libraries that are serached for symbols. //! //! ```rust //! link_args::windows::default_lib!("kernel32.lib"); //! ``` //! //! ## Use the `windows!` macro //! //! The [`windows!`] macro lets you set multiple arguments at once. //! //! ```rust //! link_args::windows! { //! stack_size(0x800000); //! default_lib("kernel32.lib"); //! } //! ``` //! //! If you use unsafe linker arguments the you must mark the whole block as //! `unsafe`. //! //! ```rust //! // Only set these in release mode. //! #[cfg(not(debug_assertions))] //! link_args::windows! { //! // Some of these linker args are unsafe so we have to use //! // an `unsafe` block. //! unsafe { //! // Link the ucrt dynamically and vcruntime statically. //! default_lib("ucrt", "libvcruntime", "libcmt"); //! // Disable the other C runtime libraries. //! no_default_lib( //! "libvcruntimed.lib", "vcruntime.lib", "vcruntimed.lib", //! "libcmtd.lib", "msvcrt.lib", "msvcrtd.lib", //! "libucrt.lib", "libucrtd.lib", "ucrtd.lib", //! ); //! } //! } //! ``` //! //! //! mod msvc_impl; /// Set linker arguments for the Windows toolchain pub mod windows { #[doc(inline)] pub use crate::windows_raw as raw; #[doc(inline)] pub use crate::windows_msvc_stack_size as stack_size; #[doc(inline)] pub use crate::windows_msvc_default_lib as default_lib; /// Helpers for constructing MSVC linker arguments. pub mod msvc { // These are mostly exported so I can use links. pub use crate::msvc_impl::LinkArgs; pub use crate::msvc_impl::ArgSize; } } link_args-0.6.0/src/msvc_impl/buffer.rs000064400000000000000000000052140000000000000161560ustar 00000000000000/// Helps to construct a list of argumets for the MSVC linker. /// Arguments are in the form: /// /// `/DIRECTIVE:value` /// /// Or: /// /// `/DIRECTIVE:value1,value2` /// /// Multiple arguments are seperated by a space: /// /// `/DIRECTIVE:value /DIRECTIVE:value1,value2` pub struct Buffer { pub buffer: [u8; CAPACITY], pub len: usize, } #[allow(unused)] impl Buffer { pub const fn new() -> Self { Self { buffer: [0; CAPACITY], len: 0, } } pub const fn push_directive(self, argument: &str) -> Self { self .push( b"/") .push(argument.as_bytes()) } pub const fn push_value(self, value: &str) -> Self { self .push(b":") .push(value.as_bytes()) } /// Turns u32's into a string such as `0x44332211`. /// Then pushes them as values. pub const fn push_values_hex(mut self, values: &[u32]) -> Self { if values.len() == 0 { return self; } let mut index = 0; self = self.push(b":"); while index < values.len() - 1 { let hex = to_hex_u32(values[index]); self = self.push(&hex).push(b","); index += 1; } self.push(&to_hex_u32(values[index])) } pub const fn push_value_hex(self, value: u32) -> Self { let hex = to_hex_u32(value); self .push(b":") .push(&hex) } pub const fn push_value_quoted(self, value: &str) -> Self { if !has_quote(value.as_bytes()) { self .push(b":\"") .push(value.as_bytes()) .push(b"\"") } else { self } } pub const fn push_seperator(self) -> Self { self.push(b" ") } pub const fn push(mut self, src: &[u8]) -> Self { let offset = self.len; while self.len - offset < src.len() { self.buffer[self.len] = src[self.len - offset]; self.len += 1; } self } } pub const fn has_quote(s: &[u8]) -> bool { let mut index = 0; while index < s.len() { if s[index] == b'"' { return true; } index += 1; } false } pub const fn to_hex_u32(val: u32) -> [u8; 10] { let mut val = val; let mut bytes = *b"0x00000000"; let lookup = [ b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f', ]; let mut index = bytes.len() - 1; while index > 1 { bytes[index] = lookup[(val & 0xf) as usize]; val >>= 4; index -= 1; } bytes } link_args-0.6.0/src/msvc_impl/macros.rs000064400000000000000000000172040000000000000161730ustar 00000000000000/// Embeds raw linker arguments for Windows targets. /// /// Many arguments that work on the command line will not work here. See /// [`LinkArgs::raw`](crate::windows::msvc::LinkArgs::raw) for more information. /// /// # Example /// /// ```rust /// link_args::windows::raw!(unsafe "/STACK:0x800000 /ENTRY:mainCRTStartup"); /// ``` #[macro_export] macro_rules! windows_raw { (unsafe $raw_args:expr) => { #[cfg(windows)] const _:() = { enum ns {} impl ns { const raw_args: &'static [u8] = $raw_args.as_bytes(); const args: [u8; ns::raw_args.len()+1] = { let mut bytes = [0; ns::raw_args.len() + 1]; let mut index = 0; while index < ns::raw_args.len() { bytes[index] = ns::raw_args[index]; index += 1; } bytes[index] = b' '; bytes }; } $crate::impl_msvc_bytes!( ns::args.len(), ns::args ); }; }; } /// Turn the given bytes into a linker directive without any processing. /// /// This will not check for errors such as invalid arguments. /// The bytes should end with a space (` `) otherwise to seperate it from any /// further arguments that may be added. #[doc(hidden)] #[macro_export] macro_rules! impl_msvc_bytes { ($size:expr, $bytes:expr) => { const _: () = { // This cfg restraint can be loosend if we support another target_env. #[cfg(all(windows, target_env = "msvc"))] #[link_section = ".drectve"] #[used] static DIRECTIVE: [u8; $size] = $bytes; }; }; } /// Set how much virtual memory is avaliable for the stack. /// /// You can also optionally allocate physical memory upfront. Be aware that /// Rust's `std::thread` can and will override these settings for all but the /// main thread. /// /// # Examples /// /// Reserve 8 MiB of virtual memory for the stack. /// /// ```rust /// link_args::windows::stack_size!(0x800000); /// ``` /// /// Reserve 8 MiB for the stack and allocate 4 MiB as soon as the program starts. /// /// ```rust /// link_args::windows::stack_size!(0x800000, 0x400000); /// ``` #[macro_export] macro_rules! windows_msvc_stack_size { ($reserve:expr) => { const _: () = { $crate::impl_msvc_bytes!( $crate::windows::msvc::ArgSize::STACK_SIZE, $crate::windows::msvc::LinkArgs::new().stack_size($reserve).into_array() ); }; }; ($reserve:expr, $commit:expr) => { const _: () = { $crate::impl_msvc_bytes!( $crate::windows::msvc::ArgSize::STACK_SIZE_WITH_COMMIT, $crate::windows::msvc::LinkArgs::new().stack_size_with_commit($reserve, $commit).into_array() ); }; }; } /// Adds one or more default libraries. /// /// Default libraries will be used to find symbols when they are not found in /// libraries specified on the command line. #[macro_export] macro_rules! windows_msvc_default_lib { ($($lib:expr),+) => { $crate::impl_msvc_bytes!( $crate::impl_msvc_arg_size!(default_lib($($lib),+)), $crate::impl_msvc_args!($crate::windows::msvc::LinkArgs::new(), default_lib($($lib),+)).into_array() ); }; } /// Set a group of arguments for the Windows linker. /// /// The following safe arguments can be set: /// /// * [`stack_size`](crate::windows::msvc::LinkArgs::stack_size) /// * [`default_lib`](crate::windows::msvc::LinkArgs::default_lib) /// /// The following unsafe arguments can be set: /// /// * [`no_default_lib`](crate::windows::msvc::LinkArgs::no_default_lib) /// * [`disable_all_default_libs`](crate::windows::msvc::LinkArgs::disable_all_default_libs) /// * [`raw`](crate::windows::msvc::LinkArgs::raw) /// /// # Examples /// /// # Safe arguments /// /// ```rust /// link_args::windows! { /// stack_size(0x80000); /// default_lib("kernel32.lib", "Shell32.lib"); /// } /// ``` /// /// # Unsafe arguments /// /// ```no_run /// link_args::windows! { /// unsafe { /// // Prevent some libraries being used unless they specified on the /// // comamnd line. /// no_default_lib("kernel32.lib", "Shell32.lib"); /// // This makes the above line redundant. /// disable_all_default_libs(); /// // Set the entry point. /// raw("/ENTRY:mainCRTStartup"); /// } /// } /// ``` #[macro_export] macro_rules! windows { (unsafe { $($tt:tt( $($expr:expr),* $(,)? ));+; }) => { #[cfg(target_env="msvc")] const _: () = { use $crate::{impl_msvc_arg_size, impl_msvc_args, impl_msvc_bytes, windows::msvc::LinkArgs}; enum ns {} impl ns { const SIZE: usize = 0$(+ impl_msvc_arg_size!($tt($($expr),*)))+; #[allow(unused_unsafe)] const BUFFER: LinkArgs::<{ns::SIZE}> = unsafe { let mut buf = LinkArgs::new(); $( buf = impl_msvc_args!(buf, $tt($($expr),*)); )+ buf }; } impl_msvc_bytes!(ns::SIZE, ns::BUFFER.into_array()); }; }; ($($tt:tt( $($expr:expr),* $(,)? ));+;) => { #[cfg(target_env="msvc")] const _: () = { use $crate::{impl_msvc_arg_size, impl_msvc_args, impl_msvc_bytes, windows::msvc::LinkArgs}; enum ns {} impl ns { const SIZE: usize = 0$(+ impl_msvc_arg_size!($tt($($expr),*)))+; const BUFFER: LinkArgs::<{ns::SIZE}> = { let mut buf = LinkArgs::new(); $( buf = impl_msvc_args!(buf, $tt($($expr),*)); )+ buf }; } impl_msvc_bytes!(ns::SIZE, ns::BUFFER.into_array()); }; }; } /// Build the linker arguments using a macro. #[doc(hidden)] #[macro_export] macro_rules! impl_msvc_args { // These are (probably) safe. ($args:expr, stack_size($reserve:expr)) => { $args.stack_size($reserve) }; ($args:expr, stack_size($reserve:expr, $commit:expr)) => { $args.stack_size_with_commit($reserve, $commit) }; ($args:expr, default_lib($($lib:expr),+)) => { $args $( .default_lib($lib) )+ }; // These are unsafe ($args:expr, no_default_lib($($lib:expr),+)) => { $args $( .no_default_lib($lib) )+ }; ($args:expr, disable_all_default_libs()) => { $args.disable_all_default_libs() }; ($args:expr, raw($raw:expr)) => { $args.raw($raw) }; } /// Calculate the size of linker arguments using a macro. #[doc(hidden)] #[macro_export] macro_rules! impl_msvc_arg_size { // These are (probably) safe. (stack_size($reserve:expr)) => { $crate::windows::msvc::ArgSize::STACK_SIZE }; (stack_size($reserve:expr, $commit:expr)) => { $crate::windows::msvc::ArgSize::STACK_SIZE_WITH_COMMIT }; (default_lib($($lib:expr),+)) => { 0$( +$crate::windows::msvc::ArgSize::default_lib($lib) )+ }; // These are unsafe. (no_default_lib($($lib:expr),+)) => { 0$( +$crate::windows::msvc::ArgSize::no_default_lib($lib) )+ }; (disable_all_default_libs()) => { $crate::windows::msvc::ArgSize::DISABLE_ALL_DEFAULT_LIBS }; (raw($lib:expr)) => { $lib.len() + 1 }; } link_args-0.6.0/src/msvc_impl.rs000064400000000000000000000141200000000000000147010ustar 00000000000000mod buffer; mod macros; use buffer::Buffer; /// Constants and functions to help to calculate the byte length of an argument. pub struct ArgSize; impl ArgSize { /// The size of `STACK` directive with a `reserve` value. pub const STACK_SIZE: usize = "/STACK:0x00000000 ".len(); /// The size of `STACK` directive with `reserve` and `commit` values. pub const STACK_SIZE_WITH_COMMIT: usize = "/STACK:0x00000000,0x00000000 ".len(); /// The size of the `NODEFAULTLIB` directive without any values. pub const DISABLE_ALL_DEFAULT_LIBS: usize = "/NODEFAULTLIB ".len(); /// The size of the `DEFAULTLIB` directive. pub const fn default_lib(lib: &str) -> usize { "/DEFAULTLIB: \"\"".len() + lib.len() } /// The size of the `NODEFAULTLIB` directive with a value. pub const fn no_default_lib(lib: &str) -> usize { "/NODEFAULTLIB: \"\"".len() + lib.len() } } /// Helps to construct MSVC linker arguments. pub struct LinkArgs { buffer: Buffer:: } impl LinkArgs { /// The `STACK` directive. /// /// `reserve` is the number of bytes of virtual memory to reserve for the /// stack. pub const fn stack_size(mut self, reserve: u32) -> Self { self.buffer = self.buffer .push_directive("STACK") .push_value_hex(reserve) .push_seperator(); self } /// The `STACK` directive with explicit commit value. /// /// `reserve` is the number of bytes of virtual memory to reserve for the /// stack. `commit` is the number of byte of physical memory to allocate for /// the stack when the program starts. pub const fn stack_size_with_commit(mut self, reserve: u32, commit: u32) -> Self { self.buffer = self.buffer .push_directive("STACK") .push_values_hex(&[reserve, commit]) .push_seperator(); self } /// The `DEFAULTLIB` directive. Adds a library to use. /// /// Libraries specified on the command line will override default libraries if /// there is a conflict. pub const fn default_lib(mut self, lib: &str) -> Self { self.buffer = self.buffer .push_directive("DEFAULTLIB") .push_value_quoted(lib) .push_seperator(); self } /// The `NODEFAULTLIB` directive. Prevents a default library from being used. /// /// Overrides `default_lib`. Libraries specified on the command line will /// bypass `no_default_lib`. /// /// This can be unsafe if used with `default_lib` to replace symbols. /// /// # Examples /// /// Prevent kernel32 from being linked. /// /// ```rust /// # #[cfg(not(debug_assertions))] /// link_args::windows::no_default_lib!("kernel32"); /// ``` pub const unsafe fn no_default_lib(mut self, lib: &str) -> Self { self.buffer = self.buffer .push_directive("NODEFAULTLIB") .push_value_quoted(lib) .push_seperator(); self } /// The `NODEFAULTLIB` directive wihout arguments. Prevent any default lib /// from being used. /// /// Completely disables any and all use of `default_lib`. This is safe /// because if a symbol is unavaliable the program will fail to compile. pub const fn disable_all_default_libs(mut self) -> Self { self.buffer = self.buffer.push_directive("NODEFAULTLIB").push_seperator(); self } /// One or more raw arguments, seperated by a space. /// /// Many arguments that work on the command line will not work here. /// /// # Examples /// /// ## The `windows!` macro. /// /// ```rust /// link_args::windows!{ /// unsafe { /// raw("/ENTRY:mainCRTStartup /STACK:0x800000"); /// } /// } /// ``` /// /// ## The `windows::raw!` macro. /// /// ```rust /// link_args::windows::raw!(unsafe "/ENTRY:mainCRTStartup /STACK:0x800000"); /// ``` /// /// # Possible arguments /// /// * [/DEFAULTLIB](https://docs.microsoft.com/en-us/cpp/build/reference/defaultlib-specify-default-library?view=msvc-160) /// * [/NODEFAULTLIB](https://docs.microsoft.com/en-us/cpp/build/reference/nodefaultlib-ignore-libraries?view=msvc-160) /// * [/STACK](https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-160) /// * [/HEAP](https://docs.microsoft.com/en-us/cpp/build/reference/heap-set-heap-size?view=msvc-160) /// * [/SUBSYSTEM](https://docs.microsoft.com/en-us/cpp/build/reference/subsystem-specify-subsystem?view=msvc-160) /// * [/EXPORT](https://docs.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-160) /// * [/INCLUDE](https://docs.microsoft.com/en-us/cpp/build/reference/include-force-symbol-references?view=msvc-160) /// * [/MANIFESTDEPENDENCY](https://docs.microsoft.com/en-us/cpp/build/reference/manifestdependency-specify-manifest-dependencies?view=msvc-160) /// * [/MERGE](https://docs.microsoft.com/en-us/cpp/build/reference/merge-combine-sections?view=msvc-160) /// * [/SECTION](https://docs.microsoft.com/en-us/cpp/build/reference/section-specify-section-attributes?view=msvc-160) /// * [/ENTRY](https://docs.microsoft.com/en-us/cpp/build/reference/entry-entry-point-symbol?view=msvc-160) /// /// # Limitations /// /// Different versions of the MSVC linker may support (or not support) different /// embeded arguments. Unsupported arguments or values may be silently ignored /// by the linker. pub const unsafe fn raw(mut self, raw: &str) -> Self { self.buffer = self.buffer.push(raw.as_bytes()).push_seperator(); self } /// Create an empty argument list with the `CAPACITY` of the type. pub const fn new() -> Self { Self { buffer: Buffer::new() } } /// Get the length in bytes. pub const fn len(&self) -> usize { self.buffer.len } /// Consume the `LinkArgs` and return its byte buffer. pub const fn into_array(self) -> [u8; CAPACITY] { self.buffer.buffer } }