diff options
Diffstat (limited to 'klcc/klcc.in')
-rw-r--r-- | klcc/klcc.in | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/klcc/klcc.in b/klcc/klcc.in new file mode 100644 index 0000000..fab3239 --- /dev/null +++ b/klcc/klcc.in @@ -0,0 +1,277 @@ +# -*- 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 = <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); |