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: