comparison dmd2/link.c.nolink @ 758:f04dde6e882c

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