PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/d/dmd-script

https://bitbucket.org/alexrp/gdc
Perl | 704 lines | 581 code | 64 blank | 59 comment | 124 complexity | cad0e7b4c236cdd366482c11c202b468 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. #! /usr/bin/perl -w
  2. # GDC -- D front-end for GCC
  3. # Copyright (C) 2004 David Friedman
  4. #
  5. # Modified by
  6. # Michael Parrott, (C) 2010
  7. # Iain Buclaw, (C) 2010
  8. #
  9. # This program is free software; you can redistribute it and/or modify
  10. # it under the terms of the GNU General Public License as published by
  11. # the Free Software Foundation; either version 2 of the License, or
  12. # (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. # This is a wrapper script for gdc that emulates the dmd command.
  23. # -f and -m options are passed to gdc. Extra options are:
  24. #
  25. # -vdmd Print commands executed by this wrapper script
  26. # -q,<arg1>[,<arg2>,<arg3>,...] Pass the comma-separated arguments to gdc
  27. use strict;
  28. use warnings;
  29. use Cwd qw(abs_path);
  30. use FindBin qw($Bin);
  31. use File::Basename;
  32. use File::Spec;
  33. use File::Path;
  34. use File::Temp qw(tempdir);
  35. my $output_directory;
  36. my $output_parents;
  37. my $output_file;
  38. my $header_directory;
  39. my $header_file;
  40. my $documentation_directory;
  41. my $documentation_file;
  42. my $debug = 0;
  43. my $link = 1;
  44. my $header = 0;
  45. my $documentation = 0;
  46. my $json = 0;
  47. my $json_file;
  48. my $map = 0;
  49. my $map_file;
  50. my $run = 0;
  51. my $verbose = 0;
  52. my $show_commands = 0;
  53. my $seen_all_sources_flag = 0;
  54. my $first_input_file;
  55. my $combine; # Compile multiple sources into a single object file
  56. my $lib = 0;
  57. my $tmpdir;
  58. my %tmpdir_objs;
  59. my @sources;
  60. my @objects;
  61. my @dobjects;
  62. my @out;
  63. my @link_out;
  64. my @run_args;
  65. # Use the gdc executable in the same directory as this script and account
  66. # for the target prefix.
  67. basename($0) =~ m/^(.*-)?g?dmd(-.*)?$/;
  68. my $target_prefix = $1?$1:"";
  69. my $gdc_dir = abs_path(dirname($0));
  70. my $gdc = File::Spec->catfile( $gdc_dir, $target_prefix . "gdc" . ($2?$2:""));
  71. sub osHasEXE() {
  72. return $^O =~ m/MS(DOS|Win32)|os2/i; # taken from File::Basename
  73. }
  74. sub targetHasEXE() {
  75. my $target = `$gdc -dumpmachine`;
  76. return $target =~ m/mingw/ || $target =~ m/cygwin/;
  77. }
  78. sub pathSep() {
  79. return ";" if $^O =~ m/MS(DOS|Win32)/i;
  80. return "," if $^O =~ m/MacOS/i;
  81. return ":";
  82. }
  83. sub expandHome($) {
  84. my ($path) = (@_);
  85. if ( $^O !~ m/MS(DOS|Win32)|MacOS/i ) {
  86. $path =~ s/^~/$ENV{HOME}/;
  87. }
  88. return $path;
  89. }
  90. sub printUsage() {
  91. print <<EOF
  92. Documentation: http://www.digitalmars.com/d/1.0/index.html
  93. http://dgcc.sourceforge.net/
  94. http://bitbucket.org/goshawk/gdc/wiki/Home
  95. Usage:
  96. gdmd files.d ... { -switch }
  97. files.d D source files
  98. -arch ... pass an -arch ... option to gdc
  99. -c do not link
  100. -cov do code coverage analysis
  101. -D generate documentation
  102. -Dddocdir write documentation file to docdir directory
  103. -Dffilename write documentation file to filename
  104. -d allow deprecated features
  105. -debug compile in debug code
  106. -debug=level compile in debug code <= level
  107. -debug=ident compile in debug code identified by ident
  108. -debuglib=lib debug library to use instead of phobos
  109. -defaultlib=lib default library to use instead of phobos
  110. -deps=filename write module dependencies to filename
  111. -f... pass an -f... option to gdc
  112. -fall-sources for every source file, semantically process each file preceding it
  113. -framework ... pass a -framework ... option to gdc
  114. -g add symbolic debug info
  115. -gc add symbolic debug info, pretend to be C
  116. -H generate 'header' file
  117. -Hdhdrdir write 'header' file to hdrdir directory
  118. -Hffilename write 'header' file to filename
  119. --help print help
  120. -Ipath where to look for imports
  121. -ignore ignore unsupported pragmas
  122. -property enforce property syntax
  123. -inline do function inlining
  124. -Jpath where to look for string imports
  125. -Llinkerflag pass linkerflag to link
  126. -lib generate library rather than object files
  127. -m... pass an -m... option to gdc
  128. -man open web browser on manual page
  129. -map generate linker .map file
  130. -noboundscheck turns off array bounds checking for all functions
  131. -nofloat do not emit reference to floating point
  132. -O optimize
  133. -o- do not write object file
  134. -odobjdir write object files to directory objdir
  135. -offilename name output file to filename
  136. -op do not strip paths from source file
  137. -pipe use pipes rather than intermediate files
  138. -profile profile runtime performance of generated code
  139. -quiet suppress unnecessary messages
  140. -q,arg1,... pass arg1, arg2, etc. to to gdc
  141. -release compile release version
  142. -run srcfile args... run resulting program, passing args
  143. -unittest compile in unit tests
  144. -v verbose
  145. -v1 D language version 1
  146. -vdmd print commands run by this script
  147. -version=level compile in version code >= level
  148. -version=ident compile in version code identified by ident
  149. -vtls list all variables going into thread local storage
  150. -w enable warnings
  151. -wi enable informational warnings
  152. -X generate JSON file
  153. -Xffilename write JSON file to filename
  154. EOF
  155. ;
  156. }
  157. sub errorExit(@) {
  158. print STDERR "gdmd: ", @_, "\n" if @_;
  159. exit 1;
  160. }
  161. use subs qw(errorExit);
  162. sub readINI {
  163. # look for dmd.conf in the following sequence of directories:
  164. # - current working directory
  165. # - directory specified by the HOME environment variable
  166. # - directory gdmd resides in
  167. # - /etc directory
  168. my @confpaths = ("./", "$ENV{HOME}/", "$Bin/", "/etc/");
  169. my $dmdconfpath = "";
  170. my $dmdconf = "";
  171. foreach my $confpath (@confpaths) {
  172. if (-e $confpath."dmd.conf") {
  173. $dmdconfpath = $confpath;
  174. $dmdconf = $confpath."dmd.conf";
  175. last;
  176. }
  177. }
  178. if (-e $dmdconf) {
  179. open(DMDCONF, "<$dmdconf");
  180. my $envsection = 0;
  181. while(<DMDCONF>) {
  182. # Ignore all lines up to [Environment] section
  183. if ($_ =~ /^\s*\[\s*Environment\s*\]\s*$/) {
  184. $envsection = 1;
  185. next;
  186. }
  187. next if (!$envsection);
  188. # Ignore comments
  189. next if ($_ =~ /^\s*;/);
  190. # Ignore empty lines
  191. next if ($_ =~ /^\s*$/);
  192. # Check correct syntax
  193. $_ =~ /^\s*(\S+?)\s*=\s*(.*)\s*$/;
  194. if ($&) {
  195. my $VAR = $1;
  196. my $VAL = $2;
  197. # The special name %@P% is replaced with the path to dmd.conf
  198. $VAL =~ s/%\@P%/$dmdconfpath/g;
  199. # Names enclosed by %% are searched for in the existing environment and inserted
  200. while ($VAL =~ /%(\S+?)%/) {
  201. my $envp = $1;
  202. if ($ENV{$envp}) {
  203. $VAL =~ s/%$envp%/$ENV{$envp}/g;
  204. } else {
  205. $VAL =~ s/%$envp%//g;
  206. }
  207. }
  208. $ENV{$VAR} = "$VAL";
  209. } else {
  210. errorExit "syntax error at line $. in file $dmdconf";
  211. }
  212. }
  213. close DMDCONF;
  214. }
  215. }
  216. my $gcc_version = `$gdc -dumpversion`;
  217. chomp $gcc_version;
  218. $gcc_version =~ m/^(\d+)\.(\d+)/;
  219. my ($gcc_maj, $gcc_min) = ( $1, $2 );
  220. #my $target_machine = `$gdc -dumpmachine`;
  221. #chomp $target_machine;
  222. sub addSourceFile($) {
  223. my ($arg) = @_;
  224. $first_input_file = $arg if ! $first_input_file;
  225. push @sources, $arg;
  226. }
  227. sub argCheck($$) {
  228. my ($name,$arg) = @_;
  229. errorExit "argument expected for switch '$name'" unless defined $arg;
  230. }
  231. sub determineARexe() {
  232. my $name = $target_prefix . 'ar';
  233. $name .= '.exe' if (osHasEXE());
  234. # Prefer the 'ar' in the same directory as gdc even if there is no
  235. # target prefix.
  236. my $path = File::Spec->catfile( $gdc_dir, $name );
  237. return $path if -x $path;
  238. if ( length $target_prefix ) {
  239. foreach my $dir (split pathSep, $ENV{PATH}) {
  240. $path = File::Spec->catfile( $dir, $name );
  241. return $name if -x $path; # Could return $path, but this looks better
  242. }
  243. errorExit "Could not find archiver command '$name'.";
  244. } else {
  245. return "ar";
  246. }
  247. }
  248. sub determineARcommand() {
  249. my @exe = determineARexe();
  250. return (@exe, 'cru');
  251. }
  252. sub browse($) {
  253. my ($url) = @_;
  254. my @cmd;
  255. if ($^O =~ m/MSWin32/i) {
  256. @cmd = qw(cmd /c start);
  257. } elsif ($^O =~ m/darwin/i &&
  258. -x '/usr/bin/open') { # MacOS X vs. just Darwin
  259. @cmd = 'open';
  260. } elsif ($ENV{KDE_FULL_SESSION} eq 'true') {
  261. @cmd = qw(kfmclient exec);
  262. } elsif ($ENV{GNOME_DESKTOP_SESSION_ID} ne '') {
  263. @cmd = 'gnome-open';
  264. } else {
  265. errorExit "Sorry, I do not know how to start your browser.\nManual URL: $url"
  266. }
  267. push @cmd, $url;
  268. system @cmd;
  269. print "Opening documentation page.";
  270. exit 0;
  271. }
  272. # Load dmd.conf before before parsing arguments.
  273. readINI();
  274. if ($ENV{DFLAGS}) {
  275. push @ARGV, split /\s+/, $ENV{DFLAGS};
  276. }
  277. my $arg_i = 0;
  278. while ( $arg_i < scalar(@ARGV) ) {
  279. my $arg = $ARGV[$arg_i++];
  280. if ($arg eq '-arch' ) {
  281. push @out, '-arch', $ARGV[$arg_i++];
  282. } elsif ($arg =~ m/^-c$/ ) {
  283. $link = 0;
  284. } elsif ( $arg eq '-cov' ) {
  285. push @out, '-fprofile-arcs', '-ftest-coverage';
  286. } elsif ( $arg =~ m/^-D$/ ) {
  287. $documentation = 1;
  288. } elsif ( $arg =~ m/^-Dd(.*)$/ ) {
  289. $documentation = 1;
  290. $documentation_directory = $1;
  291. } elsif ( $arg =~ m/^-Df(.*)$/ ) {
  292. $documentation = 1;
  293. $documentation_file = $1;
  294. } elsif ( $arg =~ m/^-d$/ ) {
  295. push @out, '-fdeprecated';
  296. } elsif ( $arg =~ m/^-debug(?:=(.*))?$/ ) {
  297. push @out, (defined($1) ? "-fdebug=$1" : '-fdebug');
  298. } elsif ( $arg =~ m/^-debuglib=(.*)$/ ) {
  299. push @link_out, '-debuglib', $1;
  300. } elsif ( $arg =~ m/^-debug.*$/ ) {
  301. # Passing this to gdc only gives warnings; exit with an error here
  302. errorExit "unrecognized switch '$arg'";
  303. } elsif ( $arg =~ m/^-defaultlib=(.*)$/ ) {
  304. push @link_out, '-defaultlib', $1;
  305. } elsif ( $arg =~ m/^-deps=(.*)$/ ) {
  306. push @out, (defined($1) ? "-fdeps=$1" : '-fdeps');
  307. } elsif ( $arg =~ m/^-g$/ ) {
  308. $debug = 1;
  309. push @out, '-g';
  310. } elsif ( $arg =~ m/^-gc$/ ) {
  311. $debug = 1;
  312. push @out, '-fdebug-c';
  313. } elsif ( $arg =~ m/^-gt$/ ) {
  314. errorExit "use -profile instead of -gt";
  315. push @out, '-pg';
  316. } elsif ( $arg =~ m/^-H$/ ) {
  317. $header = 1;
  318. } elsif ( $arg =~ m/^-Hd(.*)$/ ) {
  319. $header = 1;
  320. $header_directory = $1;
  321. } elsif ( $arg =~ m/^-Hf(.*)$/ ) {
  322. $header = 1;
  323. $header_file = $1;
  324. } elsif ( $arg eq '--help' ) {
  325. printUsage;
  326. exit 0;
  327. } elsif ($arg eq '-framework' ) {
  328. push @link_out, '-framework', $ARGV[$arg_i++];
  329. } elsif ( $arg eq '-ignore' ) {
  330. push @out, '-fignore-unknown-pragmas';
  331. } elsif ( $arg eq '-property' ) {
  332. push @out, '-fproperty';
  333. } elsif ( $arg =~ m/^-inline$/ ) {
  334. push @out, '-finline-functions';
  335. } elsif ( $arg =~ m/^-I(.*)$/ ) {
  336. foreach my $i (split pathSep, $1) {
  337. push @out, '-I', expandHome $i;
  338. }
  339. } elsif ( $arg =~ m/^-J(.*)$/ ) {
  340. foreach my $i (split pathSep, $1) {
  341. push @out, '-J', expandHome $i;
  342. }
  343. } elsif ( $arg =~ m/^-L(.*)$/ ) {
  344. push @link_out, '-Wl,' . $1;
  345. } elsif ( $arg eq '-lib' ) {
  346. $lib = 1;
  347. $link = 0;
  348. $tmpdir = tempdir(CLEANUP => 1);
  349. } elsif ( $arg =~ m/^-O$/ ) {
  350. push @out, '-O3';
  351. if( ! grep(/^-inline$/,@ARGV) ) {
  352. push @out, '-fno-inline-functions';
  353. }
  354. if ( $gcc_maj < 4) {
  355. push @out, '-frename-registers';
  356. }
  357. if ( $gcc_maj > 3 || ( $gcc_maj == 3 && $gcc_min >= 4 ) ) {
  358. push @out, '-fweb';
  359. }
  360. } elsif ( $arg =~ m/^-o-$/ ) {
  361. push @out, '-fsyntax-only';
  362. $link = 0;
  363. } elsif ( $arg =~ m/^-od(.*)$/ ) {
  364. $output_directory = $1;
  365. } elsif ( $arg =~ m/^-of(.*)$/ ) {
  366. $output_file = $1;
  367. } elsif ( $arg =~ m/^-op$/ ) {
  368. $output_parents = 1;
  369. } elsif ( $arg =~ m/^-nofloat$/ ) {
  370. # do nothing
  371. } elsif ( $arg =~ m/^-pipe$/ ) {
  372. push @out, '-pipe';
  373. } elsif ( $arg =~ m/^-profile$/ ) {
  374. # there is more to profiling than this ... -finstrument-functions?
  375. push @out, '-pg';
  376. } elsif ( $arg =~ m/^-release$/ ) {
  377. push @out, '-frelease';
  378. } elsif ( $arg eq '-run' ) {
  379. $run = 1;
  380. $arg = $ARGV[$arg_i++];
  381. argCheck '-run', $arg;
  382. addSourceFile $arg;
  383. push @run_args, @ARGV[$arg_i..$#ARGV];
  384. last;
  385. } elsif ( $arg =~ m/^-noboundscheck$/ ) {
  386. push @out, '-fno-bounds-check';
  387. } elsif ( $arg =~ m/^-unittest$/ ) {
  388. push @out, '-funittest';
  389. } elsif ( $arg =~ m/^-v$/ ) {
  390. $verbose = 1;
  391. push @out, '-fd-verbose';
  392. } elsif ( $arg =~ m/^-vtls$/ ) {
  393. push @out, '-fd-vtls';
  394. } elsif ( $arg =~ m/^-v1$/ ) {
  395. push @out, '-fd-version=1';
  396. } elsif ( $arg =~ m/^-version=(.*)$/ ) {
  397. push @out, "-fversion=$1";
  398. } elsif ( $arg =~ m/^-version.*$/ ) {
  399. errorExit "unrecognized switch '$arg'";
  400. } elsif ( $arg =~ m/^-vdmd$/ ) {
  401. $show_commands = 1;
  402. } elsif ( $arg =~ m/^-w$/ ) {
  403. push @out, "-Werror";
  404. } elsif ( $arg =~ m/^-wi$/ ) {
  405. push @out, "-Wall";
  406. } elsif ( $arg =~ m/^-quiet$/ ) {
  407. # ignored
  408. } elsif ( $arg =~ m/^-q,(.*)$/ ) {
  409. push @out, split(qr/,/, $1);
  410. } elsif ( $arg =~ m/^-X$/ ) {
  411. $json = 1;
  412. } elsif ( $arg =~ m/^-Xf(.*)$/ ) {
  413. $json = 1;
  414. $json_file = $1;
  415. } elsif ( $arg eq '-fall-sources' ) {
  416. $seen_all_sources_flag = 1;
  417. } elsif ( $arg =~ m/^-f.+/ ) {
  418. # Pass -fxxx options
  419. push @out, $arg;
  420. } elsif ($arg eq '-man') {
  421. browse("http://bitbucket.org/goshawk/gdc/wiki/UserDocumentation");
  422. exit 0;
  423. } elsif ( $arg =~ m/^-map$/ ) {
  424. $map = 1;
  425. if ($ARGV[$arg_i] =~ m/.map$/ ) {
  426. $map_file = $ARGV[$arg_i++];
  427. }
  428. } elsif ( $arg =~ m/^-m.+/ ) {
  429. # Pass -mxxx options
  430. push @out, $arg;
  431. } elsif ( $arg =~ m/^-.+$/ ) {
  432. errorExit "unrecognized switch '$arg'";
  433. } elsif ( $arg =~ m/^.+\.d$/i ||
  434. $arg =~ m/^.+\.dd$/i ||
  435. $arg =~ m/^.+\.di$/i ||
  436. $arg =~ m/^.+\.htm$/i ||
  437. $arg =~ m/^.+\.html$/i ||
  438. $arg =~ m/^.+\.xhtml$/i) {
  439. addSourceFile $arg;
  440. } elsif ( $arg =~ m/^.+\.ddoc/i ) {
  441. push @out, "-fdoc-inc=$arg";
  442. } elsif ( $arg !~ m/\./ ) {
  443. addSourceFile $arg . ".d";
  444. } elsif ( $arg =~ m/^(.+)(\.exe)$/i ) {
  445. $first_input_file = $arg if ! $first_input_file;
  446. $output_file = $1;
  447. if ( targetHasEXE() ) {
  448. $output_file .= $2;
  449. }
  450. } else {
  451. push @objects, $arg
  452. }
  453. }
  454. # Slightly different from dmd... allows -of to specify
  455. # the name of the executable.
  456. $combine =
  457. (! $link && ! $lib && scalar(@sources) > 1 && $output_file ) ||
  458. ($link && scalar(@sources) > 1); # > 0 ? does DMD now do the same for 1 vs many sources?
  459. if ( $run && ! $link ) {
  460. errorExit "flags conflict with -run";
  461. }
  462. if ( ($link || $lib) && ! $output_file && $first_input_file ) {
  463. $output_file = fileparse( $first_input_file, qr/\..*$/ );
  464. if ( $link && targetHasEXE() ) {
  465. $output_file .= '.exe';
  466. } elsif ( $lib ) {
  467. $output_file .= '.a';
  468. }
  469. }
  470. if (! scalar(@sources) && ! ($link && scalar(@objects))) {
  471. my @cmd = ($gdc, '--version', @out);
  472. my $result = system(@cmd);
  473. errorExit if $result & 0xff; # Give up if can't exec or gdc exited with a signal
  474. printUsage;
  475. exit 1;
  476. }
  477. my $ok = 1;
  478. foreach my $srcf_i (@sources) {
  479. # Step 1: Determine the object file path
  480. my $outf;
  481. my $hdrd;
  482. my $docd;
  483. my $srcf = $srcf_i; # To avoid modifying elements of @sources
  484. my @outbits;
  485. my @hdrbits;
  486. my @docbits;
  487. if ( $lib ) {
  488. # Generate a unique name in the temporary directory. The -op argument
  489. # is ignored in this case and there could very well be duplicate base
  490. # names.
  491. my $base = basename( $srcf, '.d' );
  492. my $i = 1;
  493. $outf = $base . '.o';
  494. while ( defined $tmpdir_objs{$outf} ) {
  495. $outf = $base . '-' . $i++ . '.o';
  496. }
  497. $tmpdir_objs{$outf} = 1;
  498. $outf = File::Spec->catfile( $tmpdir, $outf );
  499. } elsif ( ! ($link || $lib) && $output_file ) {
  500. $outf = $output_file;
  501. } else {
  502. if ( $output_directory ) {
  503. push @outbits, $output_directory;
  504. }
  505. if ( $output_parents ) {
  506. push @outbits, dirname( $srcf );
  507. }
  508. if ( scalar( @outbits )) {
  509. my $dir = File::Spec->catfile( @outbits );
  510. eval { mkpath($dir) };
  511. if ($@) {
  512. errorExit "could not create $dir: $@";
  513. }
  514. }
  515. # Note: There is currently no ($combine && $lib) case to check
  516. if ( $combine && $link) {
  517. push @outbits, basename( $output_file, '.exe' ) . '.o';
  518. } else {
  519. push @outbits, basename( $srcf, '.d' ) . '.o';
  520. }
  521. $outf = File::Spec->catfile( @outbits );
  522. if ( $combine && $link && $outf eq $output_file) {
  523. $outf .= '.o';
  524. }
  525. }
  526. if ($header) {
  527. if ( $header_directory ) {
  528. push @hdrbits, $header_directory;
  529. }
  530. if ( $output_parents ) {
  531. push @hdrbits, dirname( $srcf );
  532. }
  533. if ( scalar( @hdrbits )) {
  534. $hdrd = File::Spec->catfile( @hdrbits );
  535. eval { mkpath($hdrd) };
  536. if ($@) {
  537. errorExit "could not create $hdrd: $@";
  538. }
  539. }
  540. }
  541. if ($documentation) {
  542. if ( $documentation_directory ) {
  543. push @docbits, $documentation_directory;
  544. }
  545. if ( $output_parents ) {
  546. push @docbits, dirname( $srcf );
  547. }
  548. if ( scalar( @docbits )) {
  549. $docd = File::Spec->catfile( @docbits );
  550. eval { mkpath($docd) };
  551. if ($@) {
  552. errorExit "could not create $docd: $@";
  553. }
  554. }
  555. }
  556. if ($json) {
  557. if (! $json_file) {
  558. $json_file = substr($first_input_file, 0, length($first_input_file)-2) . ".json";
  559. }
  560. push @out, '-fXf=' . $json_file;
  561. }
  562. if ($map) {
  563. if (! $map_file) {
  564. $map_file = substr($first_input_file, 0, length($first_input_file)-2) . ".map";
  565. }
  566. # Check for Mac (Untested)
  567. if ($^O =~ m/darwin/i) {
  568. push @link_out, '-Wl,-map=' . $map_file;
  569. } else {
  570. push @link_out, '-Wl,-Map=' . $map_file;
  571. }
  572. }
  573. push @dobjects, $outf;
  574. my @source_args;
  575. if ( $combine ) {
  576. if ($gcc_maj >= 4 && $gcc_min <= 5) {
  577. push @source_args, "-combine";
  578. }
  579. push @source_args, @sources;
  580. } elsif ( $seen_all_sources_flag ) {
  581. @source_args = (@sources, "-fonly=$srcf");
  582. } else {
  583. @source_args = $srcf;
  584. }
  585. my @interface;
  586. if ( $header ) {
  587. push @interface, '-fintfc';
  588. push @interface, "-fintfc-dir=$hdrd" if $hdrd;
  589. push @interface, "-fintfc-file=$header_file" if $header_file;
  590. }
  591. my @documentation;
  592. if ( $documentation ) {
  593. push @documentation, '-fdoc';
  594. push @documentation, "-fdoc-dir=$docd" if $docd;
  595. push @documentation, "-fdoc-file=$documentation_file" if $documentation_file;
  596. }
  597. # Step 2: Run the compiler driver
  598. my @cmd = ($gdc, @out, '-c', @source_args, '-o', $outf, @interface, @documentation);
  599. if ( $show_commands ) {
  600. print join(' ', @cmd), "\n";
  601. }
  602. my $result = system(@cmd);
  603. errorExit if $result & 0xff; # Give up if can't exec or gdc exited with a signal
  604. $ok = $ok && $result == 0;
  605. last if $combine;
  606. }
  607. if ($ok && $link) {
  608. my @cmd = ($gdc, @out, @dobjects, @objects, @link_out);
  609. if ( $output_file ) {
  610. push @cmd, '-o', $output_file;
  611. }
  612. if ( $show_commands ) {
  613. print join(' ', @cmd), "\n";
  614. }
  615. $ok = $ok && system(@cmd) == 0;
  616. } elsif ($ok && $lib) {
  617. my @ar_cmd = determineARcommand();
  618. my @cmd = (@ar_cmd, $output_file, @dobjects, @objects);
  619. if ( $show_commands ) {
  620. print join(' ', @cmd), "\n";
  621. }
  622. $ok = $ok && system(@cmd) == 0;
  623. }
  624. if ($ok && $run) {
  625. my @cmd = (abs_path($output_file), @run_args);
  626. if ($verbose) {
  627. print join(' ', @cmd), "\n";
  628. }
  629. my $result = system @cmd;
  630. unlink ($output_file, @dobjects);
  631. if ($result == -1) {
  632. print STDERR "$output_file: $!\n";
  633. exit 127;
  634. } elsif ($result & 127) {
  635. exit 128 + ($result & 127);
  636. } else {
  637. exit $result >> 8;
  638. }
  639. }
  640. exit ($ok ? 0 : 1);