link_args/msvc_impl/macros.rs
1/// Embeds raw linker arguments for Windows targets.
2///
3/// Many arguments that work on the command line will not work here. See
4/// [`LinkArgs::raw`](crate::windows::msvc::LinkArgs::raw) for more information.
5///
6/// # Example
7///
8/// ```rust
9/// link_args::windows::raw!(unsafe "/STACK:0x800000 /ENTRY:mainCRTStartup");
10/// ```
11#[macro_export]
12macro_rules! windows_raw {
13 (unsafe $raw_args:expr) => {
14 #[cfg(windows)]
15 const _:() = {
16 enum ns {}
17 impl ns {
18 const raw_args: &'static [u8] = $raw_args.as_bytes();
19 const args: [u8; ns::raw_args.len()+1] = {
20 let mut bytes = [0; ns::raw_args.len() + 1];
21 let mut index = 0;
22 while index < ns::raw_args.len() {
23 bytes[index] = ns::raw_args[index];
24 index += 1;
25 }
26 bytes[index] = b' ';
27 bytes
28 };
29 }
30 $crate::impl_msvc_bytes!(
31 ns::args.len(),
32 ns::args
33 );
34 };
35 };
36}
37
38
39/// Turn the given bytes into a linker directive without any processing.
40///
41/// This will not check for errors such as invalid arguments.
42/// The bytes should end with a space (` `) otherwise to seperate it from any
43/// further arguments that may be added.
44#[doc(hidden)]
45#[macro_export]
46macro_rules! impl_msvc_bytes {
47 ($size:expr, $bytes:expr) => {
48 const _: () = {
49 // This cfg restraint can be loosend if we support another target_env.
50 #[cfg(all(windows, target_env = "msvc"))]
51 #[link_section = ".drectve"]
52 #[used]
53 static DIRECTIVE: [u8; $size] = $bytes;
54 };
55 };
56}
57
58/// Set how much virtual memory is avaliable for the stack.
59///
60/// You can also optionally allocate physical memory upfront. Be aware that
61/// Rust's `std::thread` can and will override these settings for all but the
62/// main thread.
63///
64/// # Examples
65///
66/// Reserve 8 MiB of virtual memory for the stack.
67///
68/// ```rust
69/// link_args::windows::stack_size!(0x800000);
70/// ```
71///
72/// Reserve 8 MiB for the stack and allocate 4 MiB as soon as the program starts.
73///
74/// ```rust
75/// link_args::windows::stack_size!(0x800000, 0x400000);
76/// ```
77#[macro_export]
78macro_rules! windows_msvc_stack_size {
79 ($reserve:expr) => {
80 const _: () = {
81 $crate::impl_msvc_bytes!(
82 $crate::windows::msvc::ArgSize::STACK_SIZE,
83 $crate::windows::msvc::LinkArgs::new().stack_size($reserve).into_array()
84 );
85 };
86 };
87 ($reserve:expr, $commit:expr) => {
88 const _: () = {
89 $crate::impl_msvc_bytes!(
90 $crate::windows::msvc::ArgSize::STACK_SIZE_WITH_COMMIT,
91 $crate::windows::msvc::LinkArgs::new().stack_size_with_commit($reserve, $commit).into_array()
92 );
93 };
94 };
95}
96
97/// Adds one or more default libraries.
98///
99/// Default libraries will be used to find symbols when they are not found in
100/// libraries specified on the command line.
101#[macro_export]
102macro_rules! windows_msvc_default_lib {
103 ($($lib:expr),+) => {
104 $crate::impl_msvc_bytes!(
105 $crate::impl_msvc_arg_size!(default_lib($($lib),+)),
106 $crate::impl_msvc_args!($crate::windows::msvc::LinkArgs::new(), default_lib($($lib),+)).into_array()
107 );
108 };
109}
110
111/// Set a group of arguments for the Windows linker.
112///
113/// The following safe arguments can be set:
114///
115/// * [`stack_size`](crate::windows::msvc::LinkArgs::stack_size)
116/// * [`default_lib`](crate::windows::msvc::LinkArgs::default_lib)
117///
118/// The following unsafe arguments can be set:
119///
120/// * [`no_default_lib`](crate::windows::msvc::LinkArgs::no_default_lib)
121/// * [`disable_all_default_libs`](crate::windows::msvc::LinkArgs::disable_all_default_libs)
122/// * [`raw`](crate::windows::msvc::LinkArgs::raw)
123///
124/// # Examples
125///
126/// # Safe arguments
127///
128/// ```rust
129/// link_args::windows! {
130/// stack_size(0x80000);
131/// default_lib("kernel32.lib", "Shell32.lib");
132/// }
133/// ```
134///
135/// # Unsafe arguments
136///
137/// ```no_run
138/// link_args::windows! {
139/// unsafe {
140/// // Prevent some libraries being used unless they specified on the
141/// // comamnd line.
142/// no_default_lib("kernel32.lib", "Shell32.lib");
143/// // This makes the above line redundant.
144/// disable_all_default_libs();
145/// // Set the entry point.
146/// raw("/ENTRY:mainCRTStartup");
147/// }
148/// }
149/// ```
150#[macro_export]
151macro_rules! windows {
152 (unsafe {
153 $($tt:tt(
154 $($expr:expr),*
155 $(,)?
156 ));+;
157 }) => {
158 #[cfg(target_env="msvc")]
159 const _: () = {
160 use $crate::{impl_msvc_arg_size, impl_msvc_args, impl_msvc_bytes, windows::msvc::LinkArgs};
161 enum ns {}
162 impl ns {
163 const SIZE: usize = 0$(+ impl_msvc_arg_size!($tt($($expr),*)))+;
164 #[allow(unused_unsafe)]
165 const BUFFER: LinkArgs::<{ns::SIZE}> = unsafe {
166 let mut buf = LinkArgs::new();
167 $(
168 buf = impl_msvc_args!(buf, $tt($($expr),*));
169 )+
170 buf
171 };
172 }
173 impl_msvc_bytes!(ns::SIZE, ns::BUFFER.into_array());
174 };
175 };
176 ($($tt:tt(
177 $($expr:expr),*
178 $(,)?
179 ));+;) => {
180 #[cfg(target_env="msvc")]
181 const _: () = {
182 use $crate::{impl_msvc_arg_size, impl_msvc_args, impl_msvc_bytes, windows::msvc::LinkArgs};
183 enum ns {}
184 impl ns {
185 const SIZE: usize = 0$(+ impl_msvc_arg_size!($tt($($expr),*)))+;
186 const BUFFER: LinkArgs::<{ns::SIZE}> = {
187 let mut buf = LinkArgs::new();
188 $(
189 buf = impl_msvc_args!(buf, $tt($($expr),*));
190 )+
191 buf
192 };
193 }
194 impl_msvc_bytes!(ns::SIZE, ns::BUFFER.into_array());
195 };
196 };
197}
198
199/// Build the linker arguments using a macro.
200#[doc(hidden)]
201#[macro_export]
202macro_rules! impl_msvc_args {
203 // These are (probably) safe.
204 ($args:expr, stack_size($reserve:expr)) => {
205 $args.stack_size($reserve)
206 };
207 ($args:expr, stack_size($reserve:expr, $commit:expr)) => {
208 $args.stack_size_with_commit($reserve, $commit)
209 };
210 ($args:expr, default_lib($($lib:expr),+)) => {
211 $args
212 $(
213 .default_lib($lib)
214 )+
215 };
216 // These are unsafe
217 ($args:expr, no_default_lib($($lib:expr),+)) => {
218 $args
219 $(
220 .no_default_lib($lib)
221 )+
222 };
223 ($args:expr, disable_all_default_libs()) => {
224 $args.disable_all_default_libs()
225 };
226 ($args:expr, raw($raw:expr)) => {
227 $args.raw($raw)
228 };
229}
230
231/// Calculate the size of linker arguments using a macro.
232#[doc(hidden)]
233#[macro_export]
234macro_rules! impl_msvc_arg_size {
235 // These are (probably) safe.
236 (stack_size($reserve:expr)) => {
237 $crate::windows::msvc::ArgSize::STACK_SIZE
238 };
239 (stack_size($reserve:expr, $commit:expr)) => {
240 $crate::windows::msvc::ArgSize::STACK_SIZE_WITH_COMMIT
241 };
242 (default_lib($($lib:expr),+)) => {
243 0$(
244 +$crate::windows::msvc::ArgSize::default_lib($lib)
245 )+
246 };
247 // These are unsafe.
248 (no_default_lib($($lib:expr),+)) => {
249 0$(
250 +$crate::windows::msvc::ArgSize::no_default_lib($lib)
251 )+
252 };
253 (disable_all_default_libs()) => {
254 $crate::windows::msvc::ArgSize::DISABLE_ALL_DEFAULT_LIBS
255 };
256 (raw($lib:expr)) => {
257 $lib.len() + 1
258 };
259}