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