1:
2: // Copyright (c) 1999-2011 by Digital Mars
3: // All Rights Reserved
4: // written by Walter Bright
5: // http://www.digitalmars.com
6: // License for redistribution is by either the Artistic License
7: // in artistic.txt, or the GNU General Public License in gnu.txt.
8: // See the included readme.txt for details.
9:
10:
11: #include <stdio.h>
12: #include <ctype.h>
13: #include <assert.h>
14: #include <stdarg.h>
15: #include <string.h>
16: #include <stdlib.h>
17:
18: #if _WIN32
19: #include <process.h>
20: #endif
21:
22: #if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
23: #include <sys/types.h>
24: #include <sys/wait.h>
25: #include <unistd.h>
26: #endif
27:
28: #include "root.h"
29:
30: #include "mars.h"
31:
32: #include "rmem.h"
33:
34: #include "arraytypes.h"
35:
36: int executecmd(char *cmd, char *args, int useenv);
37: int executearg0(char *cmd, char *args);
38:
39: /****************************************
40: * Write filename to cmdbuf, quoting if necessary.
41: */
42:
43: void writeFilename(OutBuffer *buf, char *filename, size_t len)
44: {
45: /* Loop and see if we need to quote
46: */
47: for (size_t i = 0; i < len; i++)
48: { char c = filename[i];
49:
50: if (isalnum(c) || c == '_')
warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isalnum'
51: continue;
52:
53: /* Need to quote
54: */
55: buf->writeByte('"');
56: buf->write(filename, len);
57: buf->writeByte('"');
58: return;
59: }
60:
61: /* No quoting necessary
62: */
63: buf->write(filename, len);
64: }
65:
66: void writeFilename(OutBuffer *buf, char *filename)
67: {
68: writeFilename(buf, filename, strlen(filename));
69: }
70:
71: /*****************************
72: * Run the linker. Return status of execution.
73: */
74:
75: int runLINK()
76: {
77: #if _WIN32
78: char *p;
79: int i;
80: int status;
81: OutBuffer cmdbuf;
82:
83: global.params.libfiles->push("user32");
84: global.params.libfiles->push("kernel32");
85:
86: for (i = 0; i < global.params.objfiles->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
87: {
88: if (i)
89: cmdbuf.writeByte('+');
90: p = global.params.objfiles->tdata()[i];
91: char *basename = FileName::removeExt(FileName::name(p));
92: char *ext = FileName::ext(p);
93: if (ext && !strchr(basename, '.'))
94: // Write name sans extension (but not if a double extension)
95: writeFilename(&cmdbuf, p, ext - p - 1);
96: else
97: writeFilename(&cmdbuf, p);
98: mem.free(basename);
99: }
100: cmdbuf.writeByte(',');
101: if (global.params.exefile)
102: writeFilename(&cmdbuf, global.params.exefile);
103: else
104: { /* Generate exe file name from first obj name.
105: * No need to add it to cmdbuf because the linker will default to it.
106: */
107: char *n = global.params.objfiles->tdata()[0];
108: n = FileName::name(n);
109: FileName *fn = FileName::forceExt(n, "exe");
110: global.params.exefile = fn->toChars();
111: }
112:
113: // Make sure path to exe file exists
114: { char *p = FileName::path(global.params.exefile);
warning C6246: Local declaration of 'p' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '78' of 'c:\projects\extern\d\dmd\src\link.c': Lines: 78
115: FileName::ensurePathExists(p);
116: mem.free(p);
117: }
118:
119: cmdbuf.writeByte(',');
120: if (global.params.mapfile)
121: writeFilename(&cmdbuf, global.params.mapfile);
122: else if (global.params.map)
123: {
124: FileName *fn = FileName::forceExt(global.params.exefile, "map");
125:
126: char *path = FileName::path(global.params.exefile);
127: char *p;
warning C6246: Local declaration of 'p' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '78' of 'c:\projects\extern\d\dmd\src\link.c': Lines: 78
128: if (path[0] == '\0')
129: p = FileName::combine(global.params.objdir, fn->toChars());
130: else
131: p = fn->toChars();
132:
133: writeFilename(&cmdbuf, p);
134: }
135: else
136: cmdbuf.writestring("nul");
137: cmdbuf.writeByte(',');
138:
139: for (i = 0; i < global.params.libfiles->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
140: {
141: if (i)
142: cmdbuf.writeByte('+');
143: writeFilename(&cmdbuf, global.params.libfiles->tdata()[i]);
144: }
145:
146: if (global.params.deffile)
147: {
148: cmdbuf.writeByte(',');
149: writeFilename(&cmdbuf, global.params.deffile);
150: }
151:
152: /* Eliminate unnecessary trailing commas */
153: while (1)
154: { i = cmdbuf.offset;
155: if (!i || cmdbuf.data[i - 1] != ',')
156: break;
157: cmdbuf.offset--;
158: }
159:
160: if (global.params.resfile)
161: {
162: cmdbuf.writestring("/RC:");
163: writeFilename(&cmdbuf, global.params.resfile);
164: }
165:
166: if (global.params.map || global.params.mapfile)
167: cmdbuf.writestring("/m");
168:
169: #if 0
170: if (debuginfo)
171: cmdbuf.writestring("/li");
172: if (codeview)
173: {
174: cmdbuf.writestring("/co");
175: if (codeview3)
176: cmdbuf.writestring(":3");
177: }
178: #else
179: if (global.params.symdebug)
180: cmdbuf.writestring("/co");
181: #endif
182:
183: cmdbuf.writestring("/noi");
184: for (i = 0; i < global.params.linkswitches->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
185: {
186: cmdbuf.writestring(global.params.linkswitches->tdata()[i]);
187: }
188: cmdbuf.writeByte(';');
189:
190: p = cmdbuf.toChars();
191:
192: FileName *lnkfilename = NULL;
193: size_t plen = strlen(p);
194: if (plen > 7000)
195: {
196: lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
197: File flnk(lnkfilename);
198: flnk.setbuffer(p, plen);
199: flnk.ref = 1;
200: if (flnk.write())
201: error("error writing file %s", lnkfilename);
202: if (lnkfilename->len() < plen)
203: sprintf(p, "@%s", lnkfilename->toChars());
warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h(371) : see declaration of 'sprintf'
204: }
205:
206: char *linkcmd = getenv("LINKCMD");
warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(433) : see declaration of 'getenv'
207: if (!linkcmd)
208: linkcmd = "link";
209: status = executecmd(linkcmd, p, 1);
210: if (lnkfilename)
211: {
212: remove(lnkfilename->toChars());
213: delete lnkfilename;
214: }
215: return status;
216: #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
217: pid_t childpid;
218: int i;
219: int status;
220:
221: // Build argv[]
222: Strings argv;
223:
224: const char *cc = getenv("CC");
225: if (!cc)
226: cc = "gcc";
227: argv.push((char *)cc);
228: argv.insert(1, global.params.objfiles);
229:
230: #if __APPLE__
231: // If we are on Mac OS X and linking a dynamic library,
232: // add the "-dynamiclib" flag
233: if (global.params.dll)
234: argv.push((char *) "-dynamiclib");
235: #endif
236:
237: // None of that a.out stuff. Use explicit exe file name, or
238: // generate one from name of first source file.
239: argv.push((char *)"-o");
240: if (global.params.exefile)
241: {
242: if (global.params.dll)
243: global.params.exefile = FileName::forceExt(global.params.exefile, global.dll_ext)->toChars();
244: argv.push(global.params.exefile);
245: }
246: else
247: { // Generate exe file name from first obj name
248: char *n = global.params.objfiles->tdata()[0];
249: char *e;
250: char *ex;
251:
252: n = FileName::name(n);
253: e = FileName::ext(n);
254: if (e)
255: {
256: e--; // back up over '.'
257: ex = (char *)mem.malloc(e - n + 1);
258: memcpy(ex, n, e - n);
259: ex[e - n] = 0;
260: // If generating dll then force dll extension
261: if (global.params.dll)
262: ex = FileName::forceExt(ex, global.dll_ext)->toChars();
263: }
264: else
265: ex = (char *)"a.out"; // no extension, so give up
266: argv.push(ex);
267: global.params.exefile = ex;
268: }
269:
270: // Make sure path to exe file exists
271: { char *p = FileName::path(global.params.exefile);
272: FileName::ensurePathExists(p);
273: mem.free(p);
274: }
275:
276: if (global.params.symdebug)
277: argv.push((char *)"-g");
278:
279: if (global.params.is64bit)
280: argv.push((char *)"-m64");
281: else
282: argv.push((char *)"-m32");
283:
284: if (global.params.map || global.params.mapfile)
285: {
286: argv.push((char *)"-Xlinker");
287: #if __APPLE__
288: argv.push((char *)"-map");
289: #else
290: argv.push((char *)"-Map");
291: #endif
292: if (!global.params.mapfile)
293: {
294: FileName *fn = FileName::forceExt(global.params.exefile, "map");
295:
296: char *path = FileName::path(global.params.exefile);
297: char *p;
298: if (path[0] == '\0')
299: p = FileName::combine(global.params.objdir, fn->toChars());
300: else
301: p = fn->toChars();
302:
303: global.params.mapfile = p;
304: }
305: argv.push((char *)"-Xlinker");
306: argv.push(global.params.mapfile);
307: }
308:
309: if (0 && global.params.exefile)
310: {
311: /* This switch enables what is known as 'smart linking'
312: * in the Windows world, where unreferenced sections
313: * are removed from the executable. It eliminates unreferenced
314: * functions, essentially making a 'library' out of a module.
315: * Although it is documented to work with ld version 2.13,
316: * in practice it does not, but just seems to be ignored.
317: * Thomas Kuehne has verified that it works with ld 2.16.1.
318: * BUG: disabled because it causes exception handling to fail
319: * because EH sections are "unreferenced" and elided
320: */
321: argv.push((char *)"-Xlinker");
322: argv.push((char *)"--gc-sections");
323: }
324:
325: for (i = 0; i < global.params.linkswitches->dim; i++)
326: { char *p = global.params.linkswitches->tdata()[i];
327: if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l'))
328: // Don't need -Xlinker if switch starts with -l
329: argv.push((char *)"-Xlinker");
330: argv.push(p);
331: }
332:
333: /* Add each library, prefixing it with "-l".
334: * The order of libraries passed is:
335: * 1. any libraries passed with -L command line switch
336: * 2. libraries specified on the command line
337: * 3. libraries specified by pragma(lib), which were appended
338: * to global.params.libfiles.
339: * 4. standard libraries.
340: */
341: for (i = 0; i < global.params.libfiles->dim; i++)
342: { char *p = global.params.libfiles->tdata()[i];
343: size_t plen = strlen(p);
344: if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a')
345: argv.push(p);
346: else
347: {
348: char *s = (char *)mem.malloc(plen + 3);
349: s[0] = '-';
350: s[1] = 'l';
351: memcpy(s + 2, p, plen + 1);
352: argv.push(s);
353: }
354: }
355:
356: /* Standard libraries must go after user specified libraries
357: * passed with -l.
358: */
359: const char *libname = (global.params.symdebug)
360: ? global.params.debuglibname
361: : global.params.defaultlibname;
362: char *buf = (char *)malloc(2 + strlen(libname) + 1);
363: strcpy(buf, "-l");
364: strcpy(buf + 2, libname);
365: argv.push(buf); // turns into /usr/lib/libphobos2.a
366:
367: // argv.push((void *)"-ldruntime");
368: argv.push((char *)"-lpthread");
369: argv.push((char *)"-lm");
370:
371: if (!global.params.quiet || global.params.verbose)
372: {
373: // Print it
374: for (i = 0; i < argv.dim; i++)
375: printf("%s ", argv.tdata()[i]);
376: printf("\n");
377: fflush(stdout);
378: }
379:
380: argv.push(NULL);
381: childpid = fork();
382: if (childpid == 0)
383: {
384: execvp(argv.tdata()[0], argv.tdata());
385: perror(argv.tdata()[0]); // failed to execute
386: return -1;
387: }
388:
389: waitpid(childpid, &status, 0);
390:
391: if (WIFEXITED(status))
392: {
393: status = WEXITSTATUS(status);
394: if (status)
395: printf("--- errorlevel %d\n", status);
396: }
397: else if (WIFSIGNALED(status))
398: {
399: printf("--- killed by signal %d\n", WTERMSIG(status));
400: status = 1;
401: }
402: return status;
403: #else
404: printf ("Linking is not yet supported for this version of DMD.\n");
405: return -1;
406: #endif
407: }
408:
409: /**********************************
410: * Delete generated EXE file.
411: */
412:
413: void deleteExeFile()
414: {
415: if (global.params.exefile)
416: {
417: //printf("deleteExeFile() %s\n", global.params.exefile);
418: remove(global.params.exefile);
419: }
420: }
421:
422: /******************************
423: * Execute a rule. Return the status.
424: * cmd program to run
425: * args arguments to cmd, as a string
426: * useenv if cmd knows about _CMDLINE environment variable
427: */
428:
429: #if _WIN32
430: int executecmd(char *cmd, char *args, int useenv)
431: {
432: int status;
433: char *buff;
warning C4101: 'buff' : unreferenced local variable
434: size_t len;
435:
436: if (!global.params.quiet || global.params.verbose)
437: {
438: printf("%s %s\n", cmd, args);
439: fflush(stdout);
440: }
441:
442: if ((len = strlen(args)) > 255)
443: { char *q;
444: static char envname[] = "@_CMDLINE";
445:
446: envname[0] = '@';
447: switch (useenv)
448: { case 0: goto L1;
449: case 2: envname[0] = '%'; break;
450: }
451: q = (char *) alloca(sizeof(envname) + len + 1);
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
452: sprintf(q,"%s=%s", envname + 1, args);
warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h(371) : see declaration of 'sprintf'
453: status = putenv(q);
warning C4996: 'putenv': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _putenv. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(869) : see declaration of 'putenv'
454: if (status == 0)
455: args = envname;
456: else
457: {
458: L1:
459: error("command line length of %d is too long",len);
460: }
461: }
462:
463: status = executearg0(cmd,args);
464: #if _WIN32
465: if (status == -1)
466: status = spawnlp(0,cmd,cmd,args,NULL);
warning C4996: 'spawnlp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _spawnlp. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\process.h(197) : see declaration of 'spawnlp'
467: #endif
468: // if (global.params.verbose)
469: // printf("\n");
470: if (status)
471: {
472: if (status == -1)
473: printf("Can't run '%s', check PATH\n", cmd);
474: else
475: printf("--- errorlevel %d\n", status);
476: }
477: return status;
478: }
479: #endif
480:
481: /**************************************
482: * Attempt to find command to execute by first looking in the directory
483: * where DMD was run from.
484: * Returns:
485: * -1 did not find command there
486: * !=-1 exit status from command
487: */
488:
489: #if _WIN32
490: int executearg0(char *cmd, char *args)
491: {
492: const char *file;
493: char *argv0 = global.params.argv0;
494:
495: //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args);
496:
497: // If cmd is fully qualified, we don't do this
498: if (FileName::absolute(cmd))
499: return -1;
500:
501: file = FileName::replaceName(argv0, cmd);
502:
503: //printf("spawning '%s'\n",file);
504: #if _WIN32
505: return spawnl(0,file,file,args,NULL);
warning C4996: 'spawnl': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _spawnl. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\process.h(195) : see declaration of 'spawnl'
506: #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
507: char *full;
508: int cmdl = strlen(cmd);
509:
510: full = (char*) mem.malloc(cmdl + strlen(args) + 2);
511: if (full == NULL)
512: return 1;
513: strcpy(full, cmd);
514: full [cmdl] = ' ';
515: strcpy(full + cmdl + 1, args);
516:
517: int result = system(full);
518:
519: mem.free(full);
520: return result;
521: #else
522: assert(0);
523: #endif
524: }
525: #endif
526:
527: /***************************************
528: * Run the compiled program.
529: * Return exit status.
530: */
531:
532: int runProgram()
533: {
534: //printf("runProgram()\n");
535: if (global.params.verbose)
536: {
537: printf("%s", global.params.exefile);
538: for (size_t i = 0; i < global.params.runargs_length; i++)
539: printf(" %s", (char *)global.params.runargs[i]);
540: printf("\n");
541: }
542:
543: // Build argv[]
544: Strings argv;
545:
546: argv.push(global.params.exefile);
547: for (size_t i = 0; i < global.params.runargs_length; i++)
548: { char *a = global.params.runargs[i];
549:
550: #if _WIN32
551: // BUG: what about " appearing in the string?
552: if (strchr(a, ' '))
553: { char *b = (char *)mem.malloc(3 + strlen(a));
554: sprintf(b, "\"%s\"", a);
warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h(371) : see declaration of 'sprintf'
555: a = b;
556: }
557: #endif
558: argv.push(a);
559: }
560: argv.push(NULL);
561:
562: #if _WIN32
563: char *ex = FileName::name(global.params.exefile);
564: if (ex == global.params.exefile)
565: ex = FileName::combine(".", ex);
566: else
567: ex = global.params.exefile;
568: return spawnv(0,ex,argv.tdata());
warning C4996: 'spawnv': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _spawnv. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\process.h(199) : see declaration of 'spawnv'
569: #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
570: pid_t childpid;
571: int status;
572:
573: childpid = fork();
574: if (childpid == 0)
575: {
576: char *fn = argv.tdata()[0];
577: if (!FileName::absolute(fn))
578: { // Make it "./fn"
579: fn = FileName::combine(".", fn);
580: }
581: execv(fn, argv.tdata());
582: perror(fn); // failed to execute
583: return -1;
584: }
585:
586: waitpid(childpid, &status, 0);
587:
588: if (WIFEXITED(status))
589: {
590: status = WEXITSTATUS(status);
591: //printf("--- errorlevel %d\n", status);
592: }
593: else if (WIFSIGNALED(status))
594: {
595: printf("--- killed by signal %d\n", WTERMSIG(status));
596: status = 1;
597: }
598: return status;
599: #else
600: assert(0);
601: #endif
602: }
603: