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}