PageRenderTime 82ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/d/dmd-script

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