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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
mod 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<const CAPACITY: usize> {
buffer: Buffer::<CAPACITY>
}
impl<const CAPACITY: usize> LinkArgs<CAPACITY> {
/// 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
}
}