forked from ocaml/flexdll
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmdline.ml
294 lines (239 loc) · 9.42 KB
/
cmdline.ml
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
(************************************************************************)
(* FlexDLL *)
(* Alain Frisch *)
(* *)
(* Copyright 2007 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(************************************************************************)
let underscore = ref true
(* Are "normal" symbols prefixed with an underscore? *)
let machine : [ `x86 | `x64 ] ref = ref `x86
let noexport = ref false
let custom_crt = ref false
let reexport_from_implibs = ref true
let use_default_libs = ref true
let subsystem = ref "console"
let explain = ref false
let builtin_linker = ref false
let toolchain : [ `MSVC | `MSVC64 | `MINGW | `MINGW64 | `GNAT | `CYGWIN | `CYGWIN64 | `LIGHTLD ] ref = ref `MSVC
let save_temps = ref false
let show_exports = ref false
let show_imports = ref false
let dry_mode = ref false
let verbose = ref 0
let dirs = ref []
let no_merge_manifest = ref false
let merge_manifest = ref false
let real_manifest = ref true
let add_flexdll_obj = ref true
let files = ref []
let exts = ref []
let output_file = ref ""
let exe_mode : [`DLL | `EXE | `MAINDLL] ref = ref `DLL
let extra_args = ref []
let mode : [`NORMAL | `DUMP | `PATCH] ref = ref `NORMAL
let defexports = ref []
let noentry = ref false
let use_cygpath = ref true
let cygpath_arg : [`Yes | `No | `None] ref = ref `None
let implib = ref false
let deffile = ref None
let stack_reserve = ref None
let no_rel_relocs = ref false
let base_addr = ref "0x10000"
let usage_msg =
Printf.sprintf
"FlexDLL version %s\n\nUsage:\n flexlink -o <result.dll/exe> file1.obj file2.obj ... -- <extra linker arguments>\n"
Version.version
let footer =
"\
Notes:
* The -I, -l and -L options do not need to be separated from their argument.
* An option like /linkXXX is an abbrevation for '-link XXX'.
* FlexDLL's object files are searched by default in the same directory as
flexlink, or in the directory given by the environment variable FLEXDIR
if it is defined.
* Extra argument can be passed in the environment variable FLEXLINKFLAGS.
Homepage: http://alain.frisch.fr/flexdll.html"
let specs = [
"-o", Arg.Set_string output_file,
" Choose the name of the output file";
"-exe", Arg.Unit (fun () -> exe_mode := `EXE),
" Link the main program as an exe file";
"-maindll", Arg.Unit (fun () -> exe_mode := `MAINDLL),
" Link the main program as a dll file";
"-noflexdllobj", Arg.Clear add_flexdll_obj,
" Do not add the Flexdll runtime object (for exe)";
"-noentry", Arg.Set noentry,
" Do not use the Flexdll entry point (for dll)";
"-noexport", Arg.Set noexport,
" Do not export any symbol";
"-norelrelocs", Arg.Set no_rel_relocs,
" Ensure that no relative relocation is generated";
"-base", Arg.String (fun s -> base_addr := s),
" Specify base address (Win64 only)";
"-I", Arg.String (fun dir -> dirs := dir :: !dirs),
"<dir> Add a directory where to search for files";
"-L", Arg.String (fun dir -> dirs := dir :: !dirs),
"<dir> Add a directory where to search for files";
"-l", Arg.String (fun s -> files := ("-l" ^ s) :: !files),
"<lib> Library file";
"-chain", Arg.Symbol (["msvc";"msvc64";"cygwin";"cygwin64";"mingw";"mingw64";"gnat";"ld"],
(fun s ->
machine := `x86; underscore := true;
toolchain := match s with
| "msvc" -> `MSVC
| "msvc64" -> machine := `x64; underscore := false; `MSVC64
| "cygwin" -> `CYGWIN
| "cygwin64" -> machine := `x64; underscore := false; `CYGWIN64
| "mingw" -> `MINGW
| "gnat" -> `GNAT
| "mingw64" -> machine := `x64; underscore := false; `MINGW64
| "ld" -> `LIGHTLD
| _ -> assert false)),
" Choose which linker to use";
"-x64", Arg.Unit (fun () -> machine := `x64; underscore := false; toolchain := `MSVC64),
" (Deprecated)";
"-defaultlib", Arg.String (fun s -> exts := s :: !exts),
"<obj> External object (no export, no import)";
"-save-temps", Arg.Set save_temps,
" Do not delete intermediate files";
"-implib", Arg.Set implib,
" Do not delete the generated import library";
"-outdef", Arg.String (fun s -> deffile := Some s),
" Produce a def file with exported symbols";
"-v", Arg.Unit (fun () -> incr verbose),
" Increment verbosity (can be repeated)";
"-show-exports", Arg.Set show_exports,
" Show exported symbols";
"-show-imports", Arg.Set show_imports,
" Show imported symbols";
"-dry", Arg.Set dry_mode,
" Show the linker command line, do not actually run it";
"-dump", Arg.Unit (fun () -> mode := `DUMP),
" Only dump the content of object files";
"-patch", Arg.Unit (fun () -> mode := `PATCH),
" Only patch the target image (to be used with -stack)";
"-nocygpath", Arg.Unit (fun () -> cygpath_arg := `No),
" Do not use cygpath (default for msvc, mingw)";
"-cygpath", Arg.Unit (fun () -> cygpath_arg := `Yes),
" Use cygpath (default for cygwin)";
"-no-merge-manifest", Arg.Set no_merge_manifest,
" Do not merge the manifest (takes precedence over -merge-manifest)";
"-merge-manifest", Arg.Set merge_manifest,
" Merge manifest to the dll or exe (if generated)";
"-real-manifest", Arg.Set real_manifest,
" Use the generated manifest (default behavior)";
"-default-manifest", Arg.Clear real_manifest,
" Use the default manifest (default.manifest/default_amd64.manifest)";
"-export", Arg.String (fun s -> defexports := s :: !defexports),
"<sym> Explicitly export a symbol";
"-noreexport", Arg.Clear reexport_from_implibs,
" Do not reexport symbols imported from import libraries";
"-where", Arg.Unit
(fun () ->
print_endline (Filename.dirname Sys.executable_name);
exit 0
),
" Show the FlexDLL directory";
"-nounderscore", Arg.Clear underscore,
" Normal symbols are not prefixed with an underscore";
"-nodefaultlibs", Arg.Clear use_default_libs,
" Do not assume any default library";
"-builtin", Arg.Set builtin_linker,
" Use built-in linker to produce a dll";
"-explain", Arg.Set explain,
" Explain why library objects are linked";
"-subsystem", Arg.Set_string subsystem,
"<id> Set the subsystem (default: console)";
"-custom-crt", Arg.Set custom_crt,
" Use a custom CRT";
"-stack", Arg.String (fun s -> try stack_reserve := Some (Int32.of_string s) with _ -> raise (Arg.Bad "integer argument expected for -stack")),
"<int> Set the stack reserve in the resulting image";
"-link", Arg.String (fun s -> extra_args := s :: !extra_args),
"<option> Next argument is passed verbatim to the linker";
"-D", Arg.String (fun _ -> ()),
"<symbol> (Ignored)";
"-U", Arg.String (fun _ -> ()),
"<symbol> (Ignored)";
"--", Arg.Rest (fun s -> extra_args := s :: !extra_args),
" Following arguments are passed verbatim to the linker";
]
let flexlinkflags =
let s =
try Sys.getenv "FLEXLINKFLAGS"
with Not_found -> ""
in
let n = String.length s in
let rec skip_ws i = if i < n && s.[i] = ' ' then skip_ws (i + 1) else i in
let rec scan_quote i = if i = n then i else if s.[i] = '"' then i + 1 else scan_quote (i+1) in
let rec scan_arg i =
if i = n || s.[i] = ' ' then i
else if s.[i] = '"' then scan_arg (scan_quote (i + 1))
else scan_arg (i + 1) in
let rec args i =
let i = skip_ws i in
if i = n then []
else let j = scan_arg i in String.sub s i (j - i) :: args j
in
args 0
let parse_cmdline () =
(* Split -lXXX, -LXXX and -IXXX options *)
let tosplit = function
| "-l" | "-L" | "-I" | "-D" | "-U" -> true
| _ -> false
in
let rec tr = function
| (("-defaultlib"|"-link") as d) :: x :: rest -> d :: x :: tr rest
| "/link" :: x :: rest -> "-link" :: x :: tr rest
| s :: rest when String.length s > 2 && tosplit (String.sub s 0 2) ->
String.sub s 0 2 :: String.sub s 2 (String.length s - 2) :: tr rest
| s :: rest when String.length s >= 5 && String.sub s 0 5 = "/link" ->
"-link" :: String.sub s 5 (String.length s - 5) :: tr rest
| x :: rest when x <> "" && x.[0] = '-' ->
begin
try
let i = String.index x ':' in
String.sub x 0 i :: String.sub x (i + 1) (String.length x - i - 1)
:: tr rest
with Not_found ->
x :: tr rest
end
| x :: rest -> x :: tr rest
| [] -> []
in
let args =
match Array.to_list Sys.argv with
| pgm :: args -> pgm :: tr (flexlinkflags @ args)
| _ -> assert false
in
let add_file s =
if s.[0] = '@' then
let ic = open_in (String.sub s 1 (String.length s - 1)) in
begin
try
while true do
let fn = input_line ic in
if fn <> "" then
(* todo: better unquoting *)
let fn =
if fn.[0] = '\"' && fn.[String.length fn - 1] = '\"'
then String.sub fn 1 (String.length fn - 2)
else fn
in
files := fn :: !files
done
with End_of_file -> ()
end;
close_in ic
else
files := s :: !files
in
Arg.parse_argv (Array.of_list args) (Arg.align specs)
add_file usage_msg;
if !output_file = "" && !mode <> `DUMP then begin
Printf.eprintf
"Please specify an output file (-help to get some usage information)\n";
exit 1
end
let usym s = if !underscore then "_" ^ s else s