Mercurial > projects > ldc
annotate dmd/link.c @ 133:44a95ac7368a trunk
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
In particular, assertions has been fixed to include file/line info, and much more!
author | lindquist |
---|---|
date | Mon, 14 Jan 2008 05:11:54 +0100 |
parents | 1700239cab2e |
children | 5acec6b2eef8 |
rev | line source |
---|---|
1 | 1 |
2 | |
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. | |
10 | |
11 | |
12 #include <stdio.h> | |
13 #include <ctype.h> | |
14 #include <assert.h> | |
15 #include <stdarg.h> | |
16 #include <string.h> | |
17 #include <stdlib.h> | |
18 | |
19 #if _WIN32 | |
20 #include <process.h> | |
21 #endif | |
22 | |
23 #if linux | |
24 #include <sys/types.h> | |
25 #include <sys/wait.h> | |
26 #include <unistd.h> | |
27 #endif | |
28 | |
29 #include "root.h" | |
30 | |
31 #include "mars.h" | |
32 | |
33 #include "mem.h" | |
34 | |
35 int executecmd(char *cmd, char *args, int useenv); | |
36 int executearg0(char *cmd, char *args); | |
37 | |
38 /***************************** | |
39 * Run the linker. Return status of execution. | |
40 */ | |
41 | |
42 int runLINK() | |
43 { | |
44 #if _WIN32 | |
45 assert(0 && "linking not done for win32"); | |
46 | |
47 char *p; | |
48 int i; | |
49 int status; | |
50 OutBuffer cmdbuf; | |
51 | |
52 global.params.libfiles->push((void *) "user32"); | |
53 global.params.libfiles->push((void *) "kernel32"); | |
54 | |
55 for (i = 0; i < global.params.objfiles->dim; i++) | |
56 { | |
57 if (i) | |
58 cmdbuf.writeByte('+'); | |
59 p = (char *)global.params.objfiles->data[i]; | |
60 char *ext = FileName::ext(p); | |
61 if (ext) | |
62 cmdbuf.write(p, ext - p - 1); | |
63 else | |
64 cmdbuf.writestring(p); | |
65 } | |
66 cmdbuf.writeByte(','); | |
67 if (global.params.exefile) | |
68 cmdbuf.writestring(global.params.exefile); | |
69 else | |
70 { // Generate exe file name from first obj name | |
71 char *n = (char *)global.params.objfiles->data[0]; | |
72 char *ex; | |
73 | |
74 n = FileName::name(n); | |
75 FileName *fn = FileName::forceExt(n, "exe"); | |
76 global.params.exefile = fn->toChars(); | |
77 } | |
78 | |
79 // Make sure path to exe file exists | |
80 { char *p = FileName::path(global.params.exefile); | |
81 FileName::ensurePathExists(p); | |
82 mem.free(p); | |
83 } | |
84 | |
85 cmdbuf.writeByte(','); | |
86 if (global.params.run) | |
87 cmdbuf.writestring("nul"); | |
88 // if (mapfile) | |
89 // cmdbuf.writestring(output); | |
90 cmdbuf.writeByte(','); | |
91 | |
92 for (i = 0; i < global.params.libfiles->dim; i++) | |
93 { | |
94 if (i) | |
95 cmdbuf.writeByte('+'); | |
96 cmdbuf.writestring((char *) global.params.libfiles->data[i]); | |
97 } | |
98 | |
99 if (global.params.deffile) | |
100 { | |
101 cmdbuf.writeByte(','); | |
102 cmdbuf.writestring(global.params.deffile); | |
103 } | |
104 | |
105 /* Eliminate unnecessary trailing commas */ | |
106 while (1) | |
107 { i = cmdbuf.offset; | |
108 if (!i || cmdbuf.data[i - 1] != ',') | |
109 break; | |
110 cmdbuf.offset--; | |
111 } | |
112 | |
113 if (global.params.resfile) | |
114 { | |
115 cmdbuf.writestring("/RC:"); | |
116 cmdbuf.writestring(global.params.resfile); | |
117 } | |
118 | |
119 #if 0 | |
120 if (mapfile) | |
121 cmdbuf.writestring("/m"); | |
122 if (debuginfo) | |
123 cmdbuf.writestring("/li"); | |
124 if (codeview) | |
125 { | |
126 cmdbuf.writestring("/co"); | |
127 if (codeview3) | |
128 cmdbuf.writestring(":3"); | |
129 } | |
130 #else | |
131 if (global.params.symdebug) | |
132 cmdbuf.writestring("/co"); | |
133 #endif | |
134 | |
135 cmdbuf.writestring("/noi"); | |
136 for (i = 0; i < global.params.linkswitches->dim; i++) | |
137 { | |
138 cmdbuf.writestring((char *) global.params.linkswitches->data[i]); | |
139 } | |
140 cmdbuf.writeByte(';'); | |
141 | |
142 p = cmdbuf.toChars(); | |
143 | |
144 FileName *lnkfilename = NULL; | |
145 size_t plen = strlen(p); | |
146 if (plen > 7000) | |
147 { | |
148 lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); | |
149 File flnk(lnkfilename); | |
150 flnk.setbuffer(p, plen); | |
151 flnk.ref = 1; | |
152 if (flnk.write()) | |
153 error("error writing file %s", lnkfilename); | |
154 if (lnkfilename->len() < plen) | |
155 sprintf(p, "@%s", lnkfilename->toChars()); | |
156 } | |
157 | |
158 char *linkcmd = getenv("LINKCMD"); | |
159 if (!linkcmd) | |
160 linkcmd = "link"; | |
161 status = executecmd(linkcmd, p, 1); | |
162 if (lnkfilename) | |
163 { | |
164 remove(lnkfilename->toChars()); | |
165 delete lnkfilename; | |
166 } | |
167 return status; | |
168 #elif linux | |
169 pid_t childpid; | |
170 int i; | |
171 int status; | |
172 | |
173 // Build argv[] | |
174 Array argv; | |
175 | |
176 //char *cc = getenv("CC"); | |
177 //if (!cc) | |
178 //cc = "gcc"; | |
179 char *cc = "llvm-ld"; | |
180 argv.push((void *)cc); | |
181 | |
182 // None of that a.out stuff. Use explicit exe file name, or | |
183 // generate one from name of first source file. | |
184 OutBuffer* exestr = new OutBuffer; | |
185 if (global.params.exefile) | |
186 { | |
187 exestr->printf("-o=%s", global.params.exefile); | |
188 argv.push(exestr->toChars()); | |
189 } | |
190 else | |
191 { // Generate exe file name from first obj name | |
192 char *n = (char *)global.params.objfiles->data[0]; | |
193 char *e; | |
194 char *ex; | |
195 | |
196 n = FileName::name(n); | |
197 e = FileName::ext(n); | |
198 if (e) | |
199 { | |
200 e--; // back up over '.' | |
201 ex = (char *)mem.malloc(e - n + 1); | |
202 memcpy(ex, n, e - n); | |
203 ex[e - n] = 0; | |
204 } | |
205 else | |
206 ex = (char *)"a.out"; // no extension, so give up | |
207 exestr->printf("-o=%s", ex); | |
208 ex = exestr->toChars(); | |
209 argv.push(ex); | |
210 global.params.exefile = ex; | |
211 } | |
212 | |
213 // Make sure path to exe file exists | |
214 { char *p = FileName::path(global.params.exefile); | |
215 FileName::ensurePathExists(p); | |
216 mem.free(p); | |
217 } | |
218 | |
219 argv.insert(argv.dim, global.params.libfiles); | |
220 | |
126 | 221 if (!global.params.symdebug) |
222 argv.push((void *)"-strip-debug"); | |
1 | 223 |
224 //argv.push((void *)"-m32"); | |
225 | |
226 | |
227 if (!global.params.optimize) | |
228 argv.push((void *)"-disable-opt"); | |
229 else { | |
230 const char* s = 0; | |
231 switch(global.params.optimizeLevel) { | |
232 case 0: | |
233 s = "-O0"; break; | |
234 case 1: | |
235 s = "-O1"; break; | |
236 case 2: | |
237 s = "-O2"; break; | |
238 case 3: | |
239 s = "-O3"; break; | |
240 case 4: | |
241 s = "-O4"; break; | |
242 case 5: | |
243 s = "-O5"; break; | |
244 default: | |
245 assert(0); | |
246 } | |
247 argv.push((void*)s); | |
248 } | |
249 | |
129
8096ba7082db
[svn r133] Fixed some problems with inlining not happening :P
lindquist
parents:
126
diff
changeset
|
250 if (!(global.params.useInline || global.params.llvmInline)) { |
126 | 251 argv.push((void *)"-disable-inlining"); |
252 } | |
253 | |
1 | 254 #if 0 |
255 if (0 && global.params.exefile) | |
256 { | |
257 /* This switch enables what is known as 'smart linking' | |
258 * in the Windows world, where unreferenced sections | |
259 * are removed from the executable. It eliminates unreferenced | |
260 * functions, essentially making a 'library' out of a module. | |
261 * Although it is documented to work with ld version 2.13, | |
262 * in practice it does not, but just seems to be ignored. | |
263 * Thomas Kuehne has verified that it works with ld 2.16.1. | |
264 * BUG: disabled because it causes exception handling to fail | |
265 */ | |
266 argv.push((void *)"-Xlinker"); | |
267 argv.push((void *)"--gc-sections"); | |
268 } | |
269 #endif | |
270 | |
271 for (i = 0; i < global.params.linkswitches->dim; i++) | |
272 { char *p = (char *)global.params.linkswitches->data[i]; | |
273 //if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l')) | |
274 //{ // Don't need -Xlinker if switch starts with -l | |
275 // argv.push((void *)"-Xlinker"); | |
276 //} | |
277 argv.push((void *) p); | |
278 } | |
279 | |
280 argv.push((void*)"-native"); | |
281 | |
282 /* Standard libraries must go after user specified libraries | |
283 * passed with -l. | |
284 */ | |
285 | |
133
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
286 argv.push((void*)"-ltango-base-c-llvmdc"); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
287 argv.push((void*)"-lpthread"); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
288 argv.push((void*)"-ldl"); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
289 argv.push((void*)"-lm"); |
131 | 290 |
1 | 291 argv.append(global.params.objfiles); |
133
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
292 |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
293 std::string runtime_path(global.params.runtimePath); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
294 if (*runtime_path.rbegin() != '/') |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
295 runtime_path.append("/"); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
296 runtime_path.append("libtango-base-llvmdc.a"); |
44a95ac7368a
[svn r137] Many fixes towards tango.io.Console working, but not quite there yet...
lindquist
parents:
132
diff
changeset
|
297 argv.push((void*)runtime_path.c_str()); |
92 | 298 |
1 | 299 if (!global.params.quiet) |
300 { | |
301 // Print it | |
302 for (i = 0; i < argv.dim; i++) | |
303 printf("%s ", (char *)argv.data[i]); | |
304 printf("\n"); | |
305 fflush(stdout); | |
306 } | |
307 | |
308 argv.push(NULL); | |
309 childpid = fork(); | |
310 if (childpid == 0) | |
311 { | |
312 execvp((char *)argv.data[0], (char **)argv.data); | |
313 perror((char *)argv.data[0]); // failed to execute | |
314 return -1; | |
315 } | |
316 | |
317 waitpid(childpid, &status, 0); | |
318 | |
319 status=WEXITSTATUS(status); | |
320 if (status) | |
321 printf("--- errorlevel %d\n", status); | |
322 return status; | |
323 #else | |
324 printf ("Linking is not yet supported for this version of LLVMDMD.\n"); | |
325 return -1; | |
326 #endif | |
327 } | |
328 | |
329 /********************************** | |
330 * Delete generated EXE file. | |
331 */ | |
332 | |
333 void deleteExeFile() | |
334 { | |
335 if (global.params.exefile) | |
336 { | |
337 //printf("deleteExeFile() %s\n", global.params.exefile); | |
338 remove(global.params.exefile); | |
339 } | |
340 } | |
341 | |
342 /****************************** | |
343 * Execute a rule. Return the status. | |
344 * cmd program to run | |
345 * args arguments to cmd, as a string | |
346 * useenv if cmd knows about _CMDLINE environment variable | |
347 */ | |
348 | |
349 #if _WIN32 | |
350 int executecmd(char *cmd, char *args, int useenv) | |
351 { | |
352 int status; | |
353 char *buff; | |
354 size_t len; | |
355 | |
356 if (!global.params.quiet || global.params.verbose) | |
357 { | |
358 printf("%s %s\n", cmd, args); | |
359 fflush(stdout); | |
360 } | |
361 | |
362 if ((len = strlen(args)) > 255) | |
363 { char *q; | |
364 static char envname[] = "@_CMDLINE"; | |
365 | |
366 envname[0] = '@'; | |
367 switch (useenv) | |
368 { case 0: goto L1; | |
369 case 2: envname[0] = '%'; break; | |
370 } | |
371 q = (char *) alloca(sizeof(envname) + len + 1); | |
372 sprintf(q,"%s=%s", envname + 1, args); | |
373 status = putenv(q); | |
374 if (status == 0) | |
375 args = envname; | |
376 else | |
377 { | |
378 L1: | |
379 error("command line length of %d is too long",len); | |
380 } | |
381 } | |
382 | |
383 status = executearg0(cmd,args); | |
384 #if _WIN32 | |
385 if (status == -1) | |
386 status = spawnlp(0,cmd,cmd,args,NULL); | |
387 #endif | |
388 // if (global.params.verbose) | |
389 // printf("\n"); | |
390 if (status) | |
391 { | |
392 if (status == -1) | |
393 printf("Can't run '%s', check PATH\n", cmd); | |
394 else | |
395 printf("--- errorlevel %d\n", status); | |
396 } | |
397 return status; | |
398 } | |
399 #endif | |
400 | |
401 /************************************** | |
402 * Attempt to find command to execute by first looking in the directory | |
403 * where DMD was run from. | |
404 * Returns: | |
405 * -1 did not find command there | |
406 * !=-1 exit status from command | |
407 */ | |
408 | |
409 #if _WIN32 | |
410 int executearg0(char *cmd, char *args) | |
411 { | |
412 char *file; | |
413 char *argv0 = global.params.argv0; | |
414 | |
415 //printf("argv0='%s', cmd='%s', args='%s'\n",argv0,cmd,args); | |
416 | |
417 // If cmd is fully qualified, we don't do this | |
418 if (FileName::absolute(cmd)) | |
419 return -1; | |
420 | |
421 file = FileName::replaceName(argv0, cmd); | |
422 | |
423 //printf("spawning '%s'\n",file); | |
424 #if _WIN32 | |
425 return spawnl(0,file,file,args,NULL); | |
426 #elif linux | |
427 char *full; | |
428 int cmdl = strlen(cmd); | |
429 | |
430 full = (char*) mem.malloc(cmdl + strlen(args) + 2); | |
431 if (full == NULL) | |
432 return 1; | |
433 strcpy(full, cmd); | |
434 full [cmdl] = ' '; | |
435 strcpy(full + cmdl + 1, args); | |
436 | |
437 int result = system(full); | |
438 | |
439 mem.free(full); | |
440 return result; | |
441 #else | |
442 assert(0); | |
443 #endif | |
444 } | |
445 #endif | |
446 | |
447 /*************************************** | |
448 * Run the compiled program. | |
449 * Return exit status. | |
450 */ | |
451 | |
452 int runProgram() | |
453 { | |
454 //printf("runProgram()\n"); | |
455 if (global.params.verbose) | |
456 { | |
457 printf("%s", global.params.exefile); | |
458 for (size_t i = 0; i < global.params.runargs_length; i++) | |
459 printf(" %s", (char *)global.params.runargs[i]); | |
460 printf("\n"); | |
461 } | |
462 | |
463 // Build argv[] | |
464 Array argv; | |
465 | |
466 argv.push((void *)global.params.exefile); | |
467 for (size_t i = 0; i < global.params.runargs_length; i++) | |
468 { char *a = global.params.runargs[i]; | |
469 | |
470 #if _WIN32 | |
471 // BUG: what about " appearing in the string? | |
472 if (strchr(a, ' ')) | |
473 { char *b = (char *)mem.malloc(3 + strlen(a)); | |
474 sprintf(b, "\"%s\"", a); | |
475 a = b; | |
476 } | |
477 #endif | |
478 argv.push((void *)a); | |
479 } | |
480 argv.push(NULL); | |
481 | |
482 #if _WIN32 | |
483 char *ex = FileName::name(global.params.exefile); | |
484 if (ex == global.params.exefile) | |
485 ex = FileName::combine(".", ex); | |
486 else | |
487 ex = global.params.exefile; | |
488 return spawnv(0,ex,(char **)argv.data); | |
489 #elif linux | |
490 pid_t childpid; | |
491 int status; | |
492 | |
493 childpid = fork(); | |
494 if (childpid == 0) | |
495 { | |
496 char *fn = (char *)argv.data[0]; | |
497 if (!FileName::absolute(fn)) | |
498 { // Make it "./fn" | |
499 fn = FileName::combine(".", fn); | |
500 } | |
501 execv(fn, (char **)argv.data); | |
502 perror(fn); // failed to execute | |
503 return -1; | |
504 } | |
505 | |
506 waitpid(childpid, &status, 0); | |
507 | |
508 status = WEXITSTATUS(status); | |
509 return status; | |
510 #else | |
511 assert(0); | |
512 #endif | |
513 } |