summaryrefslogtreecommitdiffstats
path: root/klcc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--klcc/.gitignore2
-rw-r--r--klcc/Kbuild47
-rw-r--r--klcc/klcc.1118
-rw-r--r--klcc/klcc.in277
-rw-r--r--klcc/makeklcc.pl63
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);