# -*- perl -*- use IPC::Open3; # Standard includes @includes = ("-I${prefix}/${KCROSS}include/arch/${ARCHDIR}", "-I${prefix}/${KCROSS}include/bits${BITSIZE}", "-I${prefix}/${KCROSS}include"); # Default optimization options (for compiles without -g) @optopt = @OPTFLAGS; @goptopt = ('-O'); # Standard library directories @stdlibpath = ("-L${prefix}/${KCROSS}lib"); # Options and libraries to pass to ld; shared versus static @staticopt = ("${prefix}/${KCROSS}lib/crt0.o"); @staticlib = ("${prefix}/${KCROSS}lib/libc.a"); @sharedopt = (@EMAIN, map { "${prefix}/${KCROSS}lib/$_" } @CRTSHARED); @sharedlib = ('-R', "${prefix}/${KCROSS}lib/libc.so"); # Returns the language (-x option string) for a specific extension. sub filename2lang($) { my ($file) = @_; return 'c' if ( $file =~ /\.c$/ ); return 'c-header' if ( $file =~ /\.h$/ ); return 'cpp-output' if ( $file =~ /\.i$/ ); return 'c++-cpp-output' if ( $file =~ /\.ii$/ ); return 'objective-c' if ( $file =~ /\.m$/ ); return 'objc-cpp-output' if ( $file =~ /\.mi$/ ); return 'c++' if ( $file =~/\.(cc|cp|cxx|cpp|CPP|c\+\+|C)$/ ); return 'c++-header' if ( $file =~ /\.(hh|H)$/ ); return 'f77' if ( $file =~ /\.(f|for|FOR)$/ ); return 'f77-cpp-input' if ( $file =~ /\.(F|fpp|FPP)$/ ); return 'ratfor' if ( $file =~ /\.r$/ ); # Is this correct? return 'ada' if ( $file =~ /\.(ads|adb)$/ ); return 'assembler' if ( $file =~ /\.s$/ ); return 'assembler-with-cpp' if ( $file =~/\.S$/ ); # Linker file; there is no option to gcc to assume something # is a linker file, so we make up our own... return 'obj'; } # Produces a series of -x options and files sub files_with_lang($$) { my($files, $flang) = @_; my(@as) = (); my($xopt) = 'none'; my($need); foreach $f ( @{$files} ) { $need = ${$flang}{$f}; # Skip object files if ( $need ne 'obj' ) { unless ( $xopt eq $need || $need eq 'stdin') { push(@as, '-x', $need); $xopt = $need; } push(@as, $f); } } return @as; } # Convert a return value from system() to an exit() code sub syserr($) { my($e) = @_; return ($e & 0x7f) | 0x80 if ( $e & 0xff ); return $e >> 8; } # Run a program; printing out the command line if $verbose is set sub mysystem(@) { print STDERR join(' ', @_), "\n" if ( $verbose ); my $cmd = shift; open(INPUT, "<&STDIN"); # dup STDIN filehandle to INPUT my $childpid = open3("<&INPUT", ">&STDOUT", ">&STDERR", $cmd, @_); waitpid ($childpid, 0); return $?; } # # Initialization # open(NULL, '+<', '/dev/null') or die "$0: cannot open /dev/null\n"; # # Begin parsing options. # @ccopt = (); @ldopt = (); @libs = (); @files = (); # List of files %flang = (); # Languages for files # This is 'c' for compile only, 'E' for preprocess only, # 'S' for compile to assembly. $operation = ''; # Compile and link # Current -x option. If undefined, it means autodetect. undef $lang; $save_temps = 0; # The -save-temps option $verbose = 0; # The -v option $shared = 0; # Are we compiling shared? $debugging = 0; # -g or -p option present? $strip = 0; # -s option present? undef $output; # -o option present? while ( defined($a = shift(@ARGV)) ) { if ( $a !~ /^\-/ ) { # Not an option. Must be a filename then. push(@files, $a); $flang{$a} = $lang || filename2lang($a); } elsif ( $a eq '-' ) { # gcc gets its input from stdin push(@files, $a); # prevent setting -x $flang{$a} = 'stdin' } elsif ( $a =~ /^-print-klibc-(.*)$/ ) { # This test must precede -print if ( defined($conf{$1}) ) { print ${$conf{$1}}, "\n"; exit 0; } else { die "$0: unknown option: $a\n"; } } elsif ( $a =~ /^(-print|-dump|--help|--version|-v)/ ) { # These share prefixes with some other options, so put this test early! # Pseudo-operations; just pass to gcc and don't do anything else push(@ccopt, $a); $operation = 'c' if ( $operation eq '' ); } elsif ( $a =~ /^-Wl,(.*)$/ ) { # -Wl used to pass options to the linker push(@ldopt, split(/,/, $1)); } elsif ( $a =~ /^-([fmwWQdO]|std=|ansi|pedantic|M[GPD]|MMD)/ ) { # Options to gcc push(@ccopt, $a); } elsif ( $a =~ /^-([DUI]|M[FQT])(.*)$/ ) { # Options to gcc, which can take either a conjoined argument # (-DFOO) or a disjoint argument (-D FOO) push(@ccopt, $a); push(@ccopt, shift(@ARGV)) if ( $2 eq '' ); } elsif ( $a eq '-include' ) { # Options to gcc which always take a disjoint argument push(@ccopt, $a, shift(@ARGV)); } elsif ( $a eq '-M' || $a eq '-MM' ) { # gcc options, that force preprocessing mode push(@ccopt, $a); $operation = 'E'; } elsif ( $a =~ /^--param/ ) { # support --param name=value and --param=name=value my @values=split('=', $a); if ( @values == 1 ) { push(@ccopt, $a); push(@ccopt, shift(@ARGV)); } elsif ( @values == 3 ) { push(@ccopt, $values[0]); push(@ccopt, join('=', $values[1],$values[2])); } } elsif ( $a =~ /^-[gp]/ || $a eq '-p' ) { # Debugging options to gcc push(@ccopt, $a); $debugging = 1; } elsif ( $a eq '-v' ) { push(@ccopt, $a); $verbose = 1; } elsif ( $a eq '-save-temps' ) { push(@ccopt, $a); $save_temps = 1; } elsif ( $a =~ '^-([cSE])$' ) { push(@ccopt, $a); $operation = $1; } elsif ( $a eq '-shared' ) { $shared = 1; } elsif ( $a eq '-static' ) { $shared = 0; } elsif ( $a eq '-s' ) { $strip = 1; } elsif ( $a eq '-o' ) { $output = shift(@ARGV); } elsif ( $a =~ /^\-x(.*)$/ ) { # -x can be conjoined or disjoined $lang = $1; if ( $lang eq '' ) { $lang = shift(@ARGV); } } elsif ( $a eq '-nostdinc' ) { push(@ccopt, $a); @includes = (); } elsif ( $a =~ /^-([lL])(.*)$/ ) { # Libraries push(@libs, $a); push(@libs, shift(@ARGV)) if ( $2 eq '' ); } else { die "$0: unknown option: $a\n"; } } if ( $debugging ) { @ccopt = (@REQFLAGS, @includes, @goptopt, @ccopt); } else { @ccopt = (@REQFLAGS, @includes, @optopt, @ccopt); } if ( $operation ne '' ) { # Just run gcc with the appropriate options @outopt = ('-o', $output) if ( defined($output) ); $rv = mysystem(@CC, @ccopt, @outopt, files_with_lang(\@files, \%flang)); } else { if ( scalar(@files) == 0 ) { die "$0: No input files!\n"; } @outopt = ('-o', $output || 'a.out'); @objs = (); @rmobjs = (); foreach $f ( @files ) { if ( $flang{$f} eq 'obj' ) { push(@objs, $f); } else { $fo = $f; $fo =~ s/\.[^\/.]+$/\.o/; die if ( $f eq $fo ); # safety check push(@objs, $fo); push(@rmobjs, $fo) unless ( $save_temps ); $rv = mysystem(@CC, @ccopt, '-c', '-o', $fo, '-x', $flang{$f}, $f); if ( $rv ) { unlink(@rmobjs); exit syserr($rv); } } } # Get the libgcc pathname for the *current* gcc open(LIBGCC, '-|', @CC, @ccopt, '-print-libgcc-file-name') or die "$0: cannot get libgcc filename\n"; $libgcc = ; chomp $libgcc; close(LIBGCC); if ( $shared ) { $rv = mysystem(@LD, @LDFLAGS, @sharedopt, @ldopt, @outopt, @objs, @libs, @stdlibpath, '--start-group', @sharedlib, $libgcc, '--end-group'); } else { $rv = mysystem(@LD, @LDFLAGS, @staticopt, @ldopt, @outopt, @objs, @libs, @stdlibpath, '--start-group', @staticlib, $libgcc, '--end-group'); } unlink(@rmobjs); if ( $strip && !$rv ) { $rv = mysystem(@STRIP, @STRIPFLAGS, $output); } } exit syserr($rv);