Mercurial > mxe-octave
comparison src/build-msvctools/cc-msvc.cc @ 3061:f8299bb6c872
Initial support for native MSVC compilation.
* add MSVC support files: compiler wrappers and support libraries
* adapt libiconv to work with MSVC
* adapt gettext to work with MSVC
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Mon, 17 Jun 2013 22:43:11 -0400 |
parents | |
children | b39e8dc859f7 |
comparison
equal
deleted
inserted
replaced
3060:cbdf4575016d | 3061:f8299bb6c872 |
---|---|
1 /* | |
2 * cc-msvc | |
3 * This code is a C translation of the cccl script from Geoffrey Wossum | |
4 * (http://cccl.sourceforge.net), with minor modifications and support for | |
5 * additional compilation flags. This tool is primarily intended to compile | |
6 * Octave source code with MSVC compiler. | |
7 * | |
8 * Copyright (C) 2006 Michael Goffioul | |
9 * | |
10 * cccl | |
11 * Wrapper around MS's cl.exe and link.exe to make them act more like | |
12 * Unix cc and ld | |
13 * | |
14 * Copyright (C) 2000-2003 Geoffrey Wossum (gwossum@acm.org) | |
15 * | |
16 * ========================================================================= | |
17 * | |
18 * This program is free software; you can redistribute it and/or modify | |
19 * it under the terms of the GNU General Public License as published by | |
20 * the Free Software Foundation; either version 2 of the License, or | |
21 * (at your option) any later version. | |
22 * | |
23 * This program is distributed in the hope that it will be useful, but | |
24 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 * General Public License for more details. | |
27 * | |
28 * You should have received a copy of the GNU General Public License | |
29 * along with this program; If not, see <http://www.gnu.org/licenses/>. | |
30 * | |
31 * ========================================================================= | |
32 * | |
33 * Compile this file with "cl -EHs -O2 cc-msvc.cc" and install it into | |
34 * your PATH environment variable. | |
35 * | |
36 */ | |
37 | |
38 #include <iostream> | |
39 #include <string> | |
40 #include <vector> | |
41 #include <list> | |
42 #include <algorithm> | |
43 #include <io.h> | |
44 #include <stdio.h> | |
45 #define WIN32_LEAN_AND_MEAN | |
46 #include <windows.h> | |
47 | |
48 #ifdef _MSC_VER | |
49 #define popen _popen | |
50 #define pclose _pclose | |
51 #endif | |
52 | |
53 using namespace std; | |
54 | |
55 static string usage_msg = | |
56 "Usage: cc-msvc [OPTIONS]\n" | |
57 "\n" | |
58 "cc-msvc is a wrapper around Microsoft's cl.exe and link.exe. It translates\n" | |
59 "parameters that Unix cc's and ld's understand to parameters that cl and link\n" | |
60 "understand."; | |
61 static string version_msg = | |
62 "cc-msvc 0.1\n" | |
63 "\n" | |
64 "Copyright 2006 Michael Goffioul\n" | |
65 "This is free software; see the source for copying conditions. There is NO\n" | |
66 "waranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; | |
67 | |
68 inline bool starts_with(const string& s, const string& prefix) | |
69 { | |
70 return (s.length() >= prefix.length() && s.find(prefix) == 0); | |
71 } | |
72 | |
73 inline bool ends_with(const string& s, const string& suffix) | |
74 { | |
75 return (s.length() >= suffix.length() && s.rfind(suffix) == s.length()-suffix.length()); | |
76 } | |
77 | |
78 static list<string> split(const string& s, char delim) | |
79 { | |
80 list<string> result; | |
81 size_t current = 0, pos, len = s.length (); | |
82 | |
83 while (current < len) | |
84 { | |
85 pos = s.find (delim, current); | |
86 if (pos == string::npos) | |
87 { | |
88 result.push_back (s.substr (current)); | |
89 break; | |
90 } | |
91 else | |
92 { | |
93 result.push_back (s.substr (current, pos - current)); | |
94 current = pos + 1; | |
95 } | |
96 } | |
97 | |
98 return result; | |
99 } | |
100 | |
101 static string get_line(FILE *fp) | |
102 { | |
103 static vector<char> buf(100); | |
104 int idx = 0; | |
105 char c; | |
106 | |
107 while (1) | |
108 { | |
109 c = (char)fgetc(fp); | |
110 if (c == '\n' || c == EOF) | |
111 break; | |
112 if (buf.size() <= idx) | |
113 buf.resize(buf.size() + 100); | |
114 buf[idx++] = c; | |
115 } | |
116 if (idx == 0) | |
117 return string(""); | |
118 else | |
119 return string(&buf[0], idx); | |
120 } | |
121 | |
122 static string process_depend(const string& s) | |
123 { | |
124 string result; | |
125 string tmp(s); | |
126 | |
127 if (tmp.find(' ') != std::string::npos) | |
128 { | |
129 std::string sp; | |
130 int len; | |
131 | |
132 sp.resize(tmp.length()+1); | |
133 len = GetShortPathName(tmp.c_str(), &sp[0], tmp.length()+1); | |
134 sp.resize(len); | |
135 tmp = sp; | |
136 } | |
137 | |
138 for (int i=0; i<tmp.length(); i++) | |
139 { | |
140 if (tmp[i] == ' ') | |
141 result += "\\ "; | |
142 else if (tmp[i] == '\\' && i < tmp.length()-1 && tmp[i+1] == '\\') | |
143 { | |
144 result.push_back('/'); | |
145 i++; | |
146 } | |
147 else | |
148 result.push_back(tmp[i]); | |
149 } | |
150 return result; | |
151 } | |
152 | |
153 static string de_cygwin_path(const string& s) | |
154 { | |
155 string result = s; | |
156 | |
157 if (starts_with(s, "/cygdrive/")) | |
158 { | |
159 string cmd = "cygpath -m \"" + s + "\""; | |
160 FILE* pout = _popen(cmd.c_str(), "r"); | |
161 | |
162 if (pout != NULL) | |
163 { | |
164 result = get_line(pout); | |
165 _pclose(pout); | |
166 } | |
167 } | |
168 | |
169 return result; | |
170 } | |
171 | |
172 static string quote_path(const string& s) | |
173 { | |
174 string result = de_cygwin_path(s); | |
175 | |
176 if (result.find(' ') != string::npos) | |
177 return "\"" + result + "\""; | |
178 return result; | |
179 } | |
180 | |
181 static string quote_define(const string& name, const string& value) | |
182 { | |
183 if (value[0] == '"') | |
184 { | |
185 string result; | |
186 | |
187 for (int i=0; i<value.length(); i++) | |
188 switch (value[i]) | |
189 { | |
190 case '"': | |
191 result += "\\\""; | |
192 break; | |
193 case '&': | |
194 case '<': | |
195 case '>': | |
196 case '(': | |
197 case ')': | |
198 case '|': | |
199 case '^': | |
200 case '@': | |
201 result.push_back('^'); | |
202 default: | |
203 result.push_back(value[i]); | |
204 break; | |
205 } | |
206 return ("\"" + name + "=" + result + "\""); | |
207 } | |
208 else | |
209 { | |
210 if (value.find_first_of("&<>()@^| ") != string::npos) | |
211 return ("\"" + name + "=" + value + "\""); | |
212 else | |
213 return (name + "=" + value); | |
214 } | |
215 } | |
216 | |
217 static string quote_quotes(const string& s) | |
218 { | |
219 string result; | |
220 | |
221 if (s.find('"') != string::npos) | |
222 { | |
223 for (int i=0; i<s.length(); i++) | |
224 if (s[i] == '"') | |
225 result += "\\\""; | |
226 else | |
227 result.push_back(s[i]); | |
228 } | |
229 else | |
230 result = s; | |
231 | |
232 if (result.find_first_of("&<>()@^| ") != string::npos) | |
233 result = "\"" + result + "\""; | |
234 | |
235 #if 0 | |
236 if (result.find_first_of("<>") != string::npos) | |
237 { | |
238 /* Could not find a better way to avoid the problem | |
239 * with those characters. */ | |
240 replace(result.begin(), result.end(), '<', '['); | |
241 replace(result.begin(), result.end(), '>', ']'); | |
242 } | |
243 #endif | |
244 | |
245 return result; | |
246 } | |
247 | |
248 static int do_system(const string& cmd) | |
249 { | |
250 STARTUPINFO info; | |
251 PROCESS_INFORMATION proc; | |
252 DWORD result; | |
253 | |
254 ZeroMemory (&info, sizeof (info)); | |
255 info.cb = sizeof (info); | |
256 ZeroMemory (&proc, sizeof (proc)); | |
257 | |
258 if (CreateProcess (NULL, (char*)cmd.c_str (), NULL, NULL, TRUE, 0, NULL, NULL, | |
259 &info, &proc)) | |
260 { | |
261 WaitForSingleObject (proc.hProcess, INFINITE); | |
262 GetExitCodeProcess (proc.hProcess, &result); | |
263 CloseHandle (proc.hProcess); | |
264 CloseHandle (proc.hThread); | |
265 } | |
266 else | |
267 result = (DWORD)-1; | |
268 | |
269 return result; | |
270 } | |
271 | |
272 static bool read_stdin(const char *filename) | |
273 { | |
274 char buf[1024]; | |
275 int n; | |
276 FILE *fout = fopen(filename, "wb"); | |
277 | |
278 if (fout == NULL) | |
279 { | |
280 cerr << filename << ": cannot open file for writing" << endl; | |
281 return false; | |
282 } | |
283 while ((n = fread(buf, 1, 1024, stdin)) > 0) | |
284 fwrite(buf, 1, n, fout); | |
285 fclose(fout); | |
286 return true; | |
287 } | |
288 | |
289 static void replace_option(string& s, const string& opt, const string& val = string()) | |
290 { | |
291 if (starts_with(s, opt)) | |
292 s.erase(0, opt.length()).insert(0, val); | |
293 if (ends_with(s, opt)) | |
294 s.erase(s.length()-opt.length()).append(val); | |
295 | |
296 string look_str = (" " + opt + " "); | |
297 int n = opt.length(); | |
298 int pos; | |
299 | |
300 while ((pos = s.find(look_str)) != string::npos) | |
301 s.replace(pos+1, n, val); | |
302 } | |
303 | |
304 static void update_environment (void) | |
305 { | |
306 char name_buffer[1024]; | |
307 DWORD len = GetModuleFileName (NULL, name_buffer, sizeof (name_buffer)); | |
308 | |
309 if (len == 0 && len >= sizeof (name_buffer)) | |
310 return; | |
311 | |
312 string root (name_buffer); | |
313 size_t pos = root.find_last_of ("\\/"); | |
314 | |
315 if (pos != string::npos) | |
316 root.resize (pos); | |
317 | |
318 if (root == "bin" | |
319 || ends_with (root, "\\bin") | |
320 || ends_with (root, "/bin")) | |
321 { | |
322 if (root.size () == 3) | |
323 root.clear (); | |
324 else | |
325 root.resize (root.size () - 4); | |
326 | |
327 string include_var = getenv ("INCLUDE"); | |
328 string lib_var = getenv ("LIB"); | |
329 | |
330 if (include_var.empty ()) | |
331 include_var = "INCLUDE=" + root + "\\include"; | |
332 else | |
333 include_var = "INCLUDE=" + root + "\\include;" + include_var; | |
334 | |
335 if (lib_var.empty ()) | |
336 lib_var = "LIB=" + root + "\\lib"; | |
337 else | |
338 lib_var = "LIB=" + root + "\\lib;" + lib_var; | |
339 | |
340 putenv (include_var.c_str ()); | |
341 putenv (lib_var.c_str ()); | |
342 } | |
343 } | |
344 | |
345 int main(int argc, char **argv) | |
346 { | |
347 string clopt, linkopt, cllinkopt, sourcefile, objectfile, optarg, prog, exefile; | |
348 list<string> Xlinkopt; | |
349 bool gotparam, dodepend, exeoutput, doshared, debug = false, read_from_stdin, gotXlinker; | |
350 bool mt_embed = true; | |
351 bool no_exceptions = false, default_libs = true, incremental_link = false; | |
352 bool cppmode = false; | |
353 | |
354 prog = "cl"; | |
355 clopt = "-nologo -MD -DWIN32 -D_WIN32 -D__WIN32__"; | |
356 linkopt = "-nologo"; | |
357 cllinkopt = ""; | |
358 sourcefile = ""; | |
359 objectfile = ""; | |
360 gotparam = false; | |
361 dodepend = false; | |
362 exeoutput = true; | |
363 exefile = ""; | |
364 doshared = false; | |
365 read_from_stdin = false; | |
366 gotXlinker = false; | |
367 | |
368 cppmode = (ends_with (argv[0], "c++-msvc.exe") | |
369 || ends_with (argv[0], "c++-msvc") | |
370 || ends_with (argv[0], "clg++.exe") | |
371 || ends_with (argv[0], "clg++")); | |
372 if (cppmode) | |
373 clopt += " -EHsc"; | |
374 | |
375 update_environment (); | |
376 | |
377 if (argc == 1) | |
378 { | |
379 cout << usage_msg << endl; | |
380 return 1; | |
381 } | |
382 | |
383 for (int i=1; i<argc; i++) | |
384 { | |
385 string arg = argv[i]; | |
386 size_t pos; | |
387 | |
388 optarg = ""; | |
389 gotparam = true; | |
390 | |
391 if (gotXlinker) | |
392 { | |
393 Xlinkopt.push_back(arg); | |
394 gotXlinker = false; | |
395 continue; | |
396 } | |
397 | |
398 if (!starts_with(arg, "-D") && (pos=arg.find('=')) != string::npos) | |
399 { | |
400 optarg = arg.substr(pos+1); | |
401 } | |
402 | |
403 if (starts_with(arg, "-D")) | |
404 { | |
405 if ((pos=arg.find('=')) != string::npos) | |
406 { | |
407 optarg = arg.substr(pos+1); | |
408 arg.resize(pos); | |
409 arg = quote_define(arg, optarg); | |
410 } | |
411 clopt += " " + arg; | |
412 continue; | |
413 } | |
414 | |
415 if (arg == "--version" || arg == "-V") | |
416 { | |
417 cout << version_msg << endl; | |
418 return 0; | |
419 } | |
420 else if (arg == "-M") | |
421 { | |
422 dodepend = true; | |
423 if (!exeoutput) | |
424 clopt += " -E"; | |
425 else | |
426 { | |
427 exeoutput = false; | |
428 clopt += " -E -c"; | |
429 } | |
430 } | |
431 else if (arg == "-P") | |
432 { | |
433 clopt += " -EP"; | |
434 } | |
435 else if (arg == "-ansi") | |
436 { | |
437 clopt += " -Za"; | |
438 } | |
439 else if (arg == "-c") | |
440 { | |
441 if (!dodepend) | |
442 { | |
443 clopt += " -c"; | |
444 exeoutput = false; | |
445 } | |
446 } | |
447 else if (arg == "-g" || (starts_with(arg, "-g") && arg.length() == 3 && arg[2] >= '0' && arg[2] <= '9')) | |
448 { | |
449 clopt += " -Zi"; | |
450 linkopt += " -debug"; | |
451 } | |
452 else if (arg == "-d") | |
453 { | |
454 debug = true; | |
455 } | |
456 else if (arg == "-shared") | |
457 { | |
458 clopt += " -LD"; | |
459 linkopt += " -DLL"; | |
460 doshared = true; | |
461 } | |
462 else if (arg == "-mwindows") | |
463 { | |
464 linkopt += " -subsystem:windows"; | |
465 } | |
466 else if (arg == "-O2" || arg == "-MD") | |
467 { | |
468 // do not pass those to the linker | |
469 clopt += (" " + arg); | |
470 } | |
471 else if (starts_with(arg, "-I")) | |
472 { | |
473 string path = arg.substr(2); | |
474 clopt += " -I" + quote_path(path); | |
475 } | |
476 else if (arg == "-isystem") | |
477 { | |
478 // Convert -isystem arguments into regular -I flags | |
479 if (i < argc-1) | |
480 { | |
481 arg = argv[++i]; | |
482 // sysroot include prefix is not supported!! | |
483 if (arg.length () > 0 && arg[0] == '=') | |
484 { | |
485 cerr << "ERROR: isystem argument starting with '=' is not supported" << endl; | |
486 return 1; | |
487 } | |
488 clopt += " -I" + quote_path(arg); | |
489 } | |
490 else | |
491 { | |
492 cerr << "ERROR: isystem argument missing" << endl; | |
493 return 1; | |
494 } | |
495 } | |
496 else if (arg == "-isysroot" | |
497 || arg == "--sysroot") | |
498 { | |
499 // Ignore directory specifications (for the time being) | |
500 if (i < argc-1) | |
501 ++i; | |
502 else | |
503 { | |
504 cerr << "ERROR: missing argument for " << arg << endl; | |
505 return 1; | |
506 } | |
507 } | |
508 else if (starts_with(arg, "-L")) | |
509 { | |
510 string path = arg.substr(2); | |
511 linkopt += " -LIBPATH:" + quote_path(path); | |
512 cllinkopt += " -LIBPATH:" + quote_path(path); | |
513 } | |
514 else if (arg == "-link") | |
515 { | |
516 while (++i < argc) | |
517 { | |
518 arg = argv[i]; | |
519 cllinkopt += " " + arg; | |
520 linkopt += " " + arg; | |
521 } | |
522 } | |
523 else if (starts_with(arg, "-l")) | |
524 { | |
525 string libname = arg.substr(2) + ".lib"; | |
526 if (sourcefile.empty()) | |
527 clopt += " " + libname; | |
528 else | |
529 cllinkopt += " " + libname; | |
530 linkopt += " " + libname; | |
531 } | |
532 else if (starts_with(arg, "-Wl,")) | |
533 { | |
534 list<string> flags = split (arg.substr (4), ','); | |
535 Xlinkopt.splice (Xlinkopt.end (), flags); | |
536 } | |
537 else if (arg == "-Xlinker") | |
538 { | |
539 gotXlinker = true; | |
540 } | |
541 else if (arg == "-Werror") | |
542 { | |
543 clopt += " -WX"; | |
544 } | |
545 else if (arg == "-Wall") | |
546 { | |
547 //clopt += " -Wall"; | |
548 } | |
549 else if (arg == "-fno-rtti") | |
550 { | |
551 clopt += " -GR-"; | |
552 } | |
553 else if (arg == "-fno-exceptions") | |
554 { | |
555 no_exceptions = true; | |
556 } | |
557 else if (arg == "-m386" || arg == "-m486" || arg == "-mpentium" || | |
558 arg == "-mpentiumpro" || arg == "-pedantic" || starts_with(arg, "-W") || | |
559 arg == "-fPIC" || arg == "-nostdlib") | |
560 { | |
561 // ignore | |
562 } | |
563 else if (arg == "-noembed") | |
564 { | |
565 mt_embed = false; | |
566 } | |
567 else if (arg == "-nodefaultlibs") | |
568 { | |
569 default_libs = false; | |
570 } | |
571 else if (arg == "-incremental-link") | |
572 { | |
573 incremental_link = true; | |
574 } | |
575 else if (arg == "-o") | |
576 { | |
577 if (i < argc-1) | |
578 { | |
579 arg = argv[++i]; | |
580 if (ends_with(arg, ".o") || ends_with(arg, ".obj")) | |
581 { | |
582 clopt += " -Fo" + quote_path(arg); | |
583 objectfile = arg; | |
584 } | |
585 else if (ends_with(arg, ".exe") || ends_with(arg, ".dll") || ends_with(arg, ".oct") | |
586 || ends_with(arg, ".mex")) | |
587 { | |
588 clopt += " -Fe" + quote_path(arg); | |
589 linkopt += " -out:" + quote_path(arg); | |
590 exefile = arg; | |
591 } | |
592 else | |
593 { | |
594 cerr << "WARNING: unrecognized output file type " << arg << ", assuming executable" << endl; | |
595 arg += ".exe"; | |
596 clopt += " -Fe" + quote_path(arg); | |
597 linkopt += " -out:" + quote_path(arg); | |
598 exefile = arg; | |
599 } | |
600 } | |
601 else | |
602 { | |
603 cerr << "ERROR: output file name missing" << endl; | |
604 return 1; | |
605 } | |
606 } | |
607 else if (ends_with(arg, ".cc") || ends_with(arg, ".cxx") || ends_with(arg, ".C")) | |
608 { | |
609 clopt += " -Tp" + quote_path(arg); | |
610 sourcefile = arg; | |
611 } | |
612 else if (ends_with(arg, ".o") || ends_with(arg, ".obj") || ends_with(arg, ".a") || | |
613 ends_with(arg, ".lib") || ends_with(arg, ".so")) | |
614 { | |
615 if (ends_with(arg, ".a")) | |
616 { | |
617 if (_access(arg.c_str(), 00) != 0) | |
618 { | |
619 string libarg; | |
620 int pos1 = arg.rfind('/'); | |
621 | |
622 if (pos1 != string::npos) | |
623 libarg = arg.substr(pos1+1); | |
624 else | |
625 libarg = arg; | |
626 if (starts_with(libarg, "lib")) | |
627 libarg = libarg.substr(3); | |
628 libarg = arg.substr(0, pos1+1) + libarg.substr(0, libarg.length()-1) + "lib"; | |
629 if (_access(libarg.c_str(), 00) == 0) | |
630 { | |
631 cerr << "WARNING: Converting " << arg << " into " << libarg << endl; | |
632 arg = libarg; | |
633 } | |
634 } | |
635 } | |
636 | |
637 if (sourcefile.empty()) | |
638 { | |
639 linkopt += " " + quote_path(arg); | |
640 prog = "link"; | |
641 } | |
642 else | |
643 { | |
644 cllinkopt += " " + quote_path(arg); | |
645 } | |
646 } | |
647 else if (ends_with(arg, ".c") || ends_with(arg, ".cpp")) | |
648 { | |
649 clopt += " " + quote_path(arg); | |
650 sourcefile = arg; | |
651 } | |
652 else if (ends_with(arg, ".dll")) | |
653 { | |
654 // trying to link against a DLL: convert to .lib file, keeping the same basename | |
655 string libarg = (" " + arg.substr(0, arg.length()-4) + ".lib"); | |
656 clopt += libarg; | |
657 linkopt += libarg; | |
658 } | |
659 else if (ends_with (arg, ".def")) | |
660 { | |
661 cllinkopt += " -DEF:" + arg; | |
662 linkopt += " -DEF:" + arg; | |
663 } | |
664 else if (arg == "-") | |
665 { | |
666 // read source file from stdin | |
667 read_from_stdin = true; | |
668 } | |
669 else | |
670 { | |
671 clopt += " " + quote_quotes(arg); | |
672 linkopt += " " + quote_quotes(arg); | |
673 if (!optarg.empty()) | |
674 { | |
675 clopt += "=" + quote_quotes(optarg); | |
676 linkopt += "=" + quote_quotes(optarg); | |
677 } | |
678 } | |
679 } | |
680 | |
681 for (list<string>::const_iterator it = Xlinkopt.begin(); it != Xlinkopt.end(); ++it) | |
682 { | |
683 string arg = *it; | |
684 | |
685 if (arg == "--out-implib" | |
686 || starts_with (arg, "--out-implib=")) | |
687 { | |
688 string implib; | |
689 | |
690 if (arg == "--out-implib") | |
691 { | |
692 ++it; | |
693 if (it != Xlinkopt.end ()) | |
694 implib = *it; | |
695 else | |
696 { | |
697 cerr << "WARNING: missing import library name, ignored" << endl; | |
698 continue; | |
699 } | |
700 } | |
701 else | |
702 implib = arg.substr (13); | |
703 | |
704 cllinkopt += " -IMPLIB:" + implib; | |
705 linkopt += " -IMPLIB:" + implib; | |
706 } | |
707 else if (arg == "--enable-auto-import" | |
708 || arg == "--enable-auto-image-base") | |
709 { | |
710 // Ignore these. | |
711 } | |
712 else if (arg == "--output-def") | |
713 { | |
714 ++it; | |
715 if (it == Xlinkopt.end ()) | |
716 break; | |
717 } | |
718 else | |
719 { | |
720 cllinkopt += " " + arg; | |
721 linkopt += " " + arg; | |
722 } | |
723 } | |
724 | |
725 if (! incremental_link) | |
726 { | |
727 std::string arg ("-incremental:no"); | |
728 | |
729 cllinkopt += " " + arg; | |
730 linkopt += " " + arg; | |
731 } | |
732 | |
733 if (no_exceptions) | |
734 { | |
735 replace_option(clopt, "-EHsc"); | |
736 replace_option(clopt, "-EHcs"); | |
737 replace_option(clopt, "-EHs"); | |
738 replace_option(clopt, "-EHc"); | |
739 replace_option(clopt, "-EHa"); | |
740 replace_option(clopt, "-GX-"); | |
741 replace_option(clopt, "-GX"); | |
742 } | |
743 | |
744 if (dodepend && prog != "cl") | |
745 { | |
746 cerr << "ERROR: dependency generation only possible for source file" << endl; | |
747 return 1; | |
748 } | |
749 | |
750 if (read_from_stdin) | |
751 { | |
752 sourcefile = "cc-msvc-tmp.c"; | |
753 if (!read_stdin(sourcefile.c_str())) | |
754 { | |
755 unlink(sourcefile.c_str()); | |
756 return 1; | |
757 } | |
758 clopt += (" " + sourcefile); | |
759 } | |
760 | |
761 if (!exeoutput && !sourcefile.empty() && objectfile.empty()) | |
762 { | |
763 // use .o suffix by default | |
764 int pos = sourcefile.rfind('.'); | |
765 if (pos == string::npos) | |
766 objectfile = sourcefile + ".o"; | |
767 else | |
768 objectfile = sourcefile.substr(0, pos) + ".o"; | |
769 pos = objectfile.rfind('/'); | |
770 if (pos != string::npos) | |
771 objectfile = objectfile.substr(pos+1); | |
772 clopt += " -Fo" + objectfile; | |
773 } | |
774 | |
775 if (exeoutput && exefile.empty()) | |
776 { | |
777 if (doshared) | |
778 exefile = "a.dll"; | |
779 else | |
780 exefile = "a.exe"; | |
781 clopt += " -Fe" + exefile; | |
782 linkopt += " -out:" + exefile; | |
783 } | |
784 | |
785 if (exeoutput && default_libs) | |
786 { | |
787 cllinkopt += " dirent.lib msvcmath.lib shell32.lib advapi32.lib user32.lib kernel32.lib"; | |
788 linkopt += " dirent.lib msvcmath.lib shell32.lib advapi32.lib user32.lib kernel32.lib"; | |
789 } | |
790 | |
791 string opts; | |
792 if (prog == "cl") | |
793 { | |
794 opts = clopt; | |
795 if (!cllinkopt.empty()) | |
796 opts += " -link " + cllinkopt; | |
797 } | |
798 else | |
799 opts = linkopt; | |
800 | |
801 if (dodepend) | |
802 { | |
803 FILE *fd; | |
804 string cmd = prog + " " + opts, line; | |
805 list<string> depend_list; | |
806 | |
807 if (objectfile.empty()) | |
808 { | |
809 cerr << "ERROR: object file name missing and cannot be determined" << endl; | |
810 return 1; | |
811 } | |
812 cout << objectfile << ":"; | |
813 | |
814 fd = popen(cmd.c_str(), "r"); | |
815 if (fd == NULL) | |
816 { | |
817 cerr << "ERROR: cannot execute " << cmd << endl; | |
818 return 1; | |
819 } | |
820 while (!feof(fd)) | |
821 { | |
822 line = get_line(fd); | |
823 if (starts_with(line, "#line")) | |
824 { | |
825 int pos1 = line.find('"'), pos2 = line.find('"', pos1+1); | |
826 depend_list.push_back(process_depend(line.substr(pos1+1, pos2-pos1-1))); | |
827 } | |
828 } | |
829 pclose(fd); | |
830 | |
831 depend_list.sort(); | |
832 depend_list.unique(); | |
833 for (list<string>::const_iterator it=depend_list.begin(); it!=depend_list.end(); ++it) | |
834 cout << " \\" << endl << " " << *it; | |
835 cout << endl; | |
836 return 0; | |
837 } | |
838 else | |
839 { | |
840 string cmd = prog + " " + opts; | |
841 int cmdresult; | |
842 | |
843 if (debug) | |
844 cout << cmd << endl; | |
845 if ((cmdresult=do_system(cmd)) == 0 && exeoutput) | |
846 { | |
847 // auto-embed the manifest, if any | |
848 if (exefile.empty()) | |
849 { | |
850 if (!sourcefile.empty()) | |
851 { | |
852 if (doshared) | |
853 exefile = sourcefile + ".dll"; | |
854 else | |
855 exefile = sourcefile + ".exe"; | |
856 } | |
857 else | |
858 { | |
859 cerr << "ERROR: cannot determine the output executable file" << endl; | |
860 return 1; | |
861 } | |
862 } | |
863 | |
864 if (_access((exefile + ".manifest").c_str(), 00) == 0) | |
865 { | |
866 // Do not auto-embed for conftest.exe (temporary executable generated | |
867 // by configure scripts): this avoids wrong test results when an AV | |
868 // software is scanning the executable while mt.exe tries to update it | |
869 // (results in "mt.exe:general error c101008d:..." | |
870 // | |
871 // This should be harmless for common situations (can only be a problem | |
872 // if the target application uses conftest.exe as executable name; but | |
873 // I don't know any). | |
874 | |
875 if (mt_embed && exefile != "conftest.exe") | |
876 { | |
877 cmd = "mt -nologo -outputresource:" + exefile | |
878 + (doshared ? ";2" : ";1") + " -manifest " + exefile + ".manifest"; | |
879 | |
880 if (debug) | |
881 cout << cmd << endl; | |
882 | |
883 cmdresult = do_system(cmd); | |
884 | |
885 if (cmdresult == 0) | |
886 _unlink((exefile + ".manifest").c_str()); | |
887 } | |
888 } | |
889 } | |
890 | |
891 if (read_from_stdin) | |
892 unlink(sourcefile.c_str()); | |
893 | |
894 return cmdresult; | |
895 } | |
896 } |