Include log level in log messages
[delight/core.git] / dmd2 / link.c
blobabe69972844026e66b3acfe91233300056de25ec
3 // Copyright (c) 1999-2007 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <assert.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <stdlib.h>
19 #if _WIN32
20 #include <process.h>
21 #endif
23 #if linux
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #endif
29 #include "root.h"
31 #include "mars.h"
33 #include "mem.h"
35 int executecmd(char *cmd, char *args, int useenv);
36 int executearg0(char *cmd, char *args);
38 /*****************************
39 * Run the linker. Return status of execution.
42 int runLINK()
44 #if _WIN32
45 char *p;
46 int i;
47 int status;
48 OutBuffer cmdbuf;
50 global.params.libfiles->push((void *) "user32");
51 global.params.libfiles->push((void *) "kernel32");
53 for (i = 0; i < global.params.objfiles->dim; i++)
55 if (i)
56 cmdbuf.writeByte('+');
57 p = (char *)global.params.objfiles->data[i];
58 char *ext = FileName::ext(p);
59 if (ext)
60 cmdbuf.write(p, ext - p - 1);
61 else
62 cmdbuf.writestring(p);
64 cmdbuf.writeByte(',');
65 if (global.params.exefile)
66 cmdbuf.writestring(global.params.exefile);
67 else
68 { // Generate exe file name from first obj name
69 char *n = (char *)global.params.objfiles->data[0];
70 n = FileName::name(n);
71 FileName *fn = FileName::forceExt(n, "exe");
72 global.params.exefile = fn->toChars();
75 // Make sure path to exe file exists
76 { char *p = FileName::path(global.params.exefile);
77 FileName::ensurePathExists(p);
78 mem.free(p);
81 cmdbuf.writeByte(',');
82 if (global.params.run)
83 cmdbuf.writestring("nul");
84 // if (mapfile)
85 // cmdbuf.writestring(output);
86 cmdbuf.writeByte(',');
88 for (i = 0; i < global.params.libfiles->dim; i++)
90 if (i)
91 cmdbuf.writeByte('+');
92 cmdbuf.writestring((char *) global.params.libfiles->data[i]);
95 if (global.params.deffile)
97 cmdbuf.writeByte(',');
98 cmdbuf.writestring(global.params.deffile);
101 /* Eliminate unnecessary trailing commas */
102 while (1)
103 { i = cmdbuf.offset;
104 if (!i || cmdbuf.data[i - 1] != ',')
105 break;
106 cmdbuf.offset--;
109 if (global.params.resfile)
111 cmdbuf.writestring("/RC:");
112 cmdbuf.writestring(global.params.resfile);
115 #if 0
116 if (mapfile)
117 cmdbuf.writestring("/m");
118 if (debuginfo)
119 cmdbuf.writestring("/li");
120 if (codeview)
122 cmdbuf.writestring("/co");
123 if (codeview3)
124 cmdbuf.writestring(":3");
126 #else
127 if (global.params.symdebug)
128 cmdbuf.writestring("/co");
129 #endif
131 cmdbuf.writestring("/noi");
132 for (i = 0; i < global.params.linkswitches->dim; i++)
134 cmdbuf.writestring((char *) global.params.linkswitches->data[i]);
136 cmdbuf.writeByte(';');
138 p = cmdbuf.toChars();
140 FileName *lnkfilename = NULL;
141 size_t plen = strlen(p);
142 if (plen > 7000)
144 lnkfilename = FileName::forceExt(global.params.exefile, "lnk");
145 File flnk(lnkfilename);
146 flnk.setbuffer(p, plen);
147 flnk.ref = 1;
148 if (flnk.write())
149 error("error writing file %s", lnkfilename);
150 if (lnkfilename->len() < plen)
151 sprintf(p, "@%s", lnkfilename->toChars());
154 char *linkcmd = getenv("LINKCMD");
155 if (!linkcmd)
156 linkcmd = "link";
157 status = executecmd(linkcmd, p, 1);
158 if (lnkfilename)
160 remove(lnkfilename->toChars());
161 delete lnkfilename;
163 return status;
164 #elif linux
165 pid_t childpid;
166 int i;
167 int status;
169 // Build argv[]
170 Array argv;
172 char *cc = getenv("CC");
173 if (!cc)
174 cc = "gcc";
175 argv.push((void *)cc);
176 argv.insert(1, global.params.objfiles);
178 // None of that a.out stuff. Use explicit exe file name, or
179 // generate one from name of first source file.
180 argv.push((void *)"-o");
181 if (global.params.exefile)
183 argv.push(global.params.exefile);
185 else
186 { // Generate exe file name from first obj name
187 char *n = (char *)global.params.objfiles->data[0];
188 char *e;
189 char *ex;
191 n = FileName::name(n);
192 e = FileName::ext(n);
193 if (e)
195 e--; // back up over '.'
196 ex = (char *)mem.malloc(e - n + 1);
197 memcpy(ex, n, e - n);
198 ex[e - n] = 0;
200 else
201 ex = (char *)"a.out"; // no extension, so give up
202 argv.push(ex);
203 global.params.exefile = ex;
206 // Make sure path to exe file exists
207 { char *p = FileName::path(global.params.exefile);
208 FileName::ensurePathExists(p);
209 mem.free(p);
212 argv.insert(argv.dim, global.params.libfiles);
214 if (global.params.symdebug)
215 argv.push((void *)"-g");
217 argv.push((void *)"-m32");
219 if (0 && global.params.exefile)
221 /* This switch enables what is known as 'smart linking'
222 * in the Windows world, where unreferenced sections
223 * are removed from the executable. It eliminates unreferenced
224 * functions, essentially making a 'library' out of a module.
225 * Although it is documented to work with ld version 2.13,
226 * in practice it does not, but just seems to be ignored.
227 * Thomas Kuehne has verified that it works with ld 2.16.1.
228 * BUG: disabled because it causes exception handling to fail
230 argv.push((void *)"-Xlinker");
231 argv.push((void *)"--gc-sections");
234 for (i = 0; i < global.params.linkswitches->dim; i++)
235 { char *p = (char *)global.params.linkswitches->data[i];
236 if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l'))
237 // Don't need -Xlinker if switch starts with -l
238 argv.push((void *)"-Xlinker");
239 argv.push((void *) p);
242 /* Standard libraries must go after user specified libraries
243 * passed with -l.
245 char *libname = (global.params.symdebug)
246 ? global.params.debuglibname
247 : global.params.defaultlibname;
248 char *buf = (char *)malloc(2 + strlen(libname) + 1);
249 strcpy(buf, "-l");
250 strcpy(buf + 2, libname);
251 argv.push((void *)buf); // turns into /usr/lib/libphobos2.a
253 argv.push((void *)"-lpthread");
254 argv.push((void *)"-lm");
256 if (!global.params.quiet || global.params.verbose)
258 // Print it
259 for (i = 0; i < argv.dim; i++)
260 printf("%s ", (char *)argv.data[i]);
261 printf("\n");
262 fflush(stdout);
265 argv.push(NULL);
266 childpid = fork();
267 if (childpid == 0)
269 execvp((char *)argv.data[0], (char **)argv.data);
270 perror((char *)argv.data[0]); // failed to execute
271 return -1;
274 waitpid(childpid, &status, 0);
276 status=WEXITSTATUS(status);
277 if (status)
278 printf("--- errorlevel %d\n", status);
279 return status;
280 #else
281 printf ("Linking is not yet supported for this version of DMD.\n");
282 return -1;
283 #endif
286 /**********************************
287 * Delete generated EXE file.
290 void deleteExeFile()
292 if (global.params.exefile)
294 //printf("deleteExeFile() %s\n", global.params.exefile);
295 remove(global.params.exefile);
299 /******************************
300 * Execute a rule. Return the status.
301 * cmd program to run
302 * args arguments to cmd, as a string
303 * useenv if cmd knows about _CMDLINE environment variable
306 #if _WIN32
307 int executecmd(char *cmd, char *args, int useenv)
309 int status;
310 char *buff;
311 size_t len;
313 if (!global.params.quiet || global.params.verbose)
315 printf("%s %s\n", cmd, args);
316 fflush(stdout);
319 if ((len = strlen(args)) > 255)
320 { char *q;
321 static char envname[] = "@_CMDLINE";
323 envname[0] = '@';
324 switch (useenv)
325 { case 0: goto L1;
326 case 2: envname[0] = '%'; break;
328 q = (char *) alloca(sizeof(envname) + len + 1);
329 sprintf(q,"%s=%s", envname + 1, args);
330 status = putenv(q);
331 if (status == 0)
332 args = envname;
333 else
336 error("command line length of %d is too long",len);
340 status = executearg0(cmd,args);
341 #if _WIN32
342 if (status == -1)
343 status = spawnlp(0,cmd,cmd,args,NULL);
344 #endif
345 // if (global.params.verbose)
346 // printf("\n");
347 if (status)
349 if (status == -1)
350 printf("Can't run '%s', check PATH\n", cmd);
351 else
352 printf("--- errorlevel %d\n", status);
354 return status;
356 #endif
358 /**************************************
359 * Attempt to find command to execute by first looking in the directory
360 * where DMD was run from.
361 * Returns:
362 * -1 did not find command there
363 * !=-1 exit status from command
366 #if _WIN32
367 int executearg0(char *cmd, char *args)
369 char *file;
370 char *argv0 = global.params.argv0;
372 //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args);
374 // If cmd is fully qualified, we don't do this
375 if (FileName::absolute(cmd))
376 return -1;
378 file = FileName::replaceName(argv0, cmd);
380 //printf("spawning '%s'\n",file);
381 #if _WIN32
382 return spawnl(0,file,file,args,NULL);
383 #elif linux
384 char *full;
385 int cmdl = strlen(cmd);
387 full = (char*) mem.malloc(cmdl + strlen(args) + 2);
388 if (full == NULL)
389 return 1;
390 strcpy(full, cmd);
391 full [cmdl] = ' ';
392 strcpy(full + cmdl + 1, args);
394 int result = system(full);
396 mem.free(full);
397 return result;
398 #else
399 assert(0);
400 #endif
402 #endif
404 /***************************************
405 * Run the compiled program.
406 * Return exit status.
409 int runProgram()
411 //printf("runProgram()\n");
412 if (global.params.verbose)
414 printf("%s", global.params.exefile);
415 for (size_t i = 0; i < global.params.runargs_length; i++)
416 printf(" %s", (char *)global.params.runargs[i]);
417 printf("\n");
420 // Build argv[]
421 Array argv;
423 argv.push((void *)global.params.exefile);
424 for (size_t i = 0; i < global.params.runargs_length; i++)
425 { char *a = global.params.runargs[i];
427 #if _WIN32
428 // BUG: what about " appearing in the string?
429 if (strchr(a, ' '))
430 { char *b = (char *)mem.malloc(3 + strlen(a));
431 sprintf(b, "\"%s\"", a);
432 a = b;
434 #endif
435 argv.push((void *)a);
437 argv.push(NULL);
439 #if _WIN32
440 char *ex = FileName::name(global.params.exefile);
441 if (ex == global.params.exefile)
442 ex = FileName::combine(".", ex);
443 else
444 ex = global.params.exefile;
445 return spawnv(0,ex,(char **)argv.data);
446 #elif linux
447 pid_t childpid;
448 int status;
450 childpid = fork();
451 if (childpid == 0)
453 char *fn = (char *)argv.data[0];
454 if (!FileName::absolute(fn))
455 { // Make it "./fn"
456 fn = FileName::combine(".", fn);
458 execv(fn, (char **)argv.data);
459 perror(fn); // failed to execute
460 return -1;
463 waitpid(childpid, &status, 0);
465 status = WEXITSTATUS(status);
466 return status;
467 #else
468 assert(0);
469 #endif