| # -*- perl -*- |
| |
| use IPC::Open3; |
| |
| # Standard includes |
| @includes = ("-I${prefix}/${KCROSS}include/arch/${ARCH}", |
| "-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, "${prefix}/${KCROSS}lib/interp.o"); |
| @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)/ ) { |
| # 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 = <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); |