diff options
Diffstat (limited to '')
-rw-r--r-- | klcc/.gitignore | 2 | ||||
-rw-r--r-- | klcc/Kbuild | 47 | ||||
-rw-r--r-- | klcc/klcc.1 | 118 | ||||
-rw-r--r-- | klcc/klcc.in | 277 | ||||
-rw-r--r-- | klcc/makeklcc.pl | 63 |
5 files changed, 507 insertions, 0 deletions
diff --git a/klcc/.gitignore b/klcc/.gitignore new file mode 100644 index 0000000..b331920 --- /dev/null +++ b/klcc/.gitignore @@ -0,0 +1,2 @@ +klcc +klibc.config diff --git a/klcc/Kbuild b/klcc/Kbuild new file mode 100644 index 0000000..82ca0e8 --- /dev/null +++ b/klcc/Kbuild @@ -0,0 +1,47 @@ +# +# Build klcc +# + +always := $(KLIBCCROSS)klcc + +$(obj)/$(KLIBCCROSS)klibc.config: $(src)/Kbuild \ + $(srctree)/Makefile \ + $(srctree)/scripts/Kbuild.klibc + @$(kecho) ' GEN $@' + $(Q)rm -f $@ + $(Q)echo 'ARCH=$(KLIBCARCH)' >> $@ + $(Q)echo 'ARCHDIR=$(KLIBCARCHDIR)' >> $@ + $(Q)echo 'CROSS=$(KLIBCROSS)' >> $@ + $(Q)echo 'KCROSS=$(KCROSS)' >> $@ + $(Q)echo 'CC=$(KLIBCCC)' >> $@ + $(Q)echo 'LD=$(KLIBCLD)' >> $@ + $(Q)echo 'REQFLAGS=$(filter-out -I%,$(KLIBCDEFS) $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS) $(KLIBCCPPFLAGS))' >> $@ + $(Q)echo 'OPTFLAGS=$(KLIBCOPTFLAGS)' >> $@ + $(Q)echo 'LDFLAGS=$(KLIBCLDFLAGS)' >> $@ + $(Q)echo 'STRIP=$(STRIP)' >> $@ + $(Q)echo 'STRIPFLAGS=$(KLIBCSTRIPFLAGS)' >> $@ + $(Q)echo 'EMAIN=$(KLIBCEMAIN)' >> $@ + $(Q)echo 'CRTSHARED=$(notdir $(KLIBCCRTSHARED))' >> $@ + $(Q)echo 'BITSIZE=$(KLIBCBITSIZE)' >> $@ + $(Q)echo 'VERSION=$(shell cat $(srctree)/usr/klibc/version)' >> $@ + $(Q)echo 'prefix=$(INSTALLDIR)' >> $@ + $(Q)echo 'bindir=$(INSTALLDIR)/$(KCROSS)bin' >> $@ + $(Q)echo 'libdir=$(INSTALLDIR)/$(KCROSS)lib' >> $@ + $(Q)echo 'includedir=$(INSTALLDIR)/$(KCROSS)include' >> $@ + + +# Generate klcc +targets := $(KLIBCCROSS)klcc + +quiet_cmd_klcc = GEN $@ + cmd_klcc = $(PERL) $< $(srctree)/$(src)/klcc.in \ + $(obj)/$(KLIBCCROSS)klibc.config \ + $(shell command -v $(PERL) 2>/dev/null) \ + > $@ || ( rm -f $@ ; exit 1 ) && \ + chmod a+x $@ +$(obj)/$(KLIBCCROSS)klcc: $(src)/makeklcc.pl $(src)/klcc.in \ + $(obj)/$(KLIBCCROSS)klibc.config + $(call if_changed,klcc) + +# Cleaning targets +clean-files := $(KLIBCCROSS)klibc.config $(KLIBCCROSS)klcc diff --git a/klcc/klcc.1 b/klcc/klcc.1 new file mode 100644 index 0000000..0186931 --- /dev/null +++ b/klcc/klcc.1 @@ -0,0 +1,118 @@ +.\" $Id: klcc.1,v 1.3 2005/04/19 23:27:46 hpa Exp $ +.\" ----------------------------------------------------------------------- +.\" +.\" Copyright 2005 H. Peter Anvin - All Rights Reserved +.\" +.\" Permission is hereby granted, free of charge, to any person +.\" obtaining a copy of this software and associated documentation +.\" files (the "Software"), to deal in the Software without +.\" restriction, including without limitation the rights to use, +.\" copy, modify, merge, publish, distribute, sublicense, and/or +.\" sell copies of the Software, and to permit persons to whom +.\" the Software is furnished to do so, subject to the following +.\" conditions: +.\" +.\" The above copyright notice and this permission notice shall +.\" be included in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +.\" OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +.\" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +.\" HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +.\" WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +.\" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +.\" OTHER DEALINGS IN THE SOFTWARE. +.\" +.\" ----------------------------------------------------------------------- + +.TH klcc "1" "1 March 2005" "klibc" "H. Peter Anvin" +.SH NAME +klcc \- compile a program against klibc +.SH SYNOPSIS +.B klcc +[\fIgcc options\fP] +[\fB\-o\fP \fIoutfile\fP] +\fIinfile...\fP +.SH DESCRIPTION +.PP +.B klcc +is a wrapper around +.BR gcc (1) +and +.BR ld (1) +which compiles and links a program against the +.B klibc +tiny C library. It supports most +.B gcc +options. +.PP +Unlike +.BR gcc , +.B klcc +compiles with optimization on by default. Furthermore, the +optimization level used depends on whether or not +.B \-g +is specified, since +.B klcc +frequently uses options in the normal case which makes debugging +impossible. Therefore, compile without +.BR \-g , +.BR \-O , +.B \-f +or +.B \-m +option to use the default optimization level; this will generally +result in the smallest binaries. You may want to use +.B \-s +when linking, however. Use +.B \-O0 +to compile without any optimization whatsoever; this may not work depending +on the version of +.B gcc +used. +.TP +.B \-nostdinc +allows to turn off klibc include files. +.PP +Use the +.B \-shared +or +.B \-static +option to compile for and link against shared or static klibc. Note +that shared klibc only supports running against the exact same klibc +binary as the binary was linked with. +.PP +In addition to standard +.B gcc +options, +.B klcc +supports options of the form \fB\-print-klibc-\fP\fIoption\fP, +which prints the corresponding klibc configuration option. +.SH AUTHOR +Written by H. Peter Anvin <hpa@zytor.com>. +.SH COPYRIGHT +Copyright \(co 2005 H. Peter Anvin \- All Rights Reserved +.PP +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom +the Software is furnished to do so, subject to the following +conditions: +.PP +The above copyright notice and this permission notice shall +be included in all copies or substantial portions of the Software. +.PP +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +.SH "SEE ALSO" +.BR gcc (1) 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); diff --git a/klcc/makeklcc.pl b/klcc/makeklcc.pl new file mode 100644 index 0000000..41c5cf4 --- /dev/null +++ b/klcc/makeklcc.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl +# +# Combine klibc.config, klcc.in to produce a klcc script +# +# Usage: makeklcc klcc.in klibc.config perlpath +# + +use File::Spec; + +($klccin, $klibcconf, $perlpath) = @ARGV; + +sub pathsearch($) { + my($file) = @_; + my(@path); + my($p,$pp); + + if ( $file =~ /\// ) { + return File::Spec->rel2abs($file); + } + + foreach $p ( split(/\:/, $ENV{'PATH'}) ) { + $pp = File::Spec->rel2abs(File::Spec->catpath(undef, $p, $file)); + return $pp if ( -x $pp ); + } + + return undef; +} + +print "#!${perlpath}\n"; + +open(KLIBCCONF, "< $klibcconf\0") + or die "$0: cannot open $klibcconf: $!\n"; +while ( defined($l = <KLIBCCONF>) ) { + chomp $l; + if ( $l =~ /^([^=]+)\=\s*(.*)$/ ) { + $n = $1; $s = $2; + my @s = split(/\s+/, $s); + + if ( $n eq 'CC' || $n eq 'LD' || $n eq 'STRIP' ) { + $s1 = pathsearch($s[0]); + die "$0: Cannot find $n: $s\n" unless ( defined($s1) ); + $s[0] = $s1; + } + + print "\$$n = \"\Q$s\E\";\n"; + print "\$conf{\'\L$n\E\'} = \\\$$n;\n"; + + print "\@$n = ("; $sep = ''; + for (@s) { + print $sep, "\"\Q$_\E\""; + $sep = ', '; + } + print ");\n"; + } +} +close(KLIBCCONF); + +open(KLCCIN, "< $klccin\0") +or die "$0: cannot open $klccin: $!\n"; +while ( defined($l = <KLCCIN>) ) { + print $l; +} +close(KLCCIN); |