summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2010-11-03 20:57:04 +0100
committerGravatar waker <wakeroid@gmail.com>2010-11-03 20:57:04 +0100
commit9c8a436caa2a80830433bf1afa2ce75efe6d62de (patch)
tree6ff76e610e7da799567d0e4ac8dd0d14b1ad7cae /tools
parentba90064d6b33270032bc4664a809d51bff5b9d4a (diff)
merged apbuild into deadbeef tree
Diffstat (limited to 'tools')
-rw-r--r--tools/apbuild/Apbuild/GCC.pm539
-rw-r--r--tools/apbuild/Apbuild/Utils.pm195
-rw-r--r--tools/apbuild/BINARY-PORTABILITY-NOTES36
-rw-r--r--tools/apbuild/ChangeLog375
-rw-r--r--tools/apbuild/README1
-rwxr-xr-xtools/apbuild/apg++10
-rwxr-xr-xtools/apbuild/apgcc1023
-rw-r--r--tools/apbuild/apsymbols.h275
-rwxr-xr-xtools/apbuild/buildlist48
-rw-r--r--tools/apbuild/ctype.h268
-rwxr-xr-xtools/apbuild/make-icons58
-rwxr-xr-xtools/apbuild/relaytool584
-rw-r--r--tools/apbuild/relaytool.m428
-rwxr-xr-xtools/apbuild/scandeps137
-rw-r--r--tools/apbuild/test-app/randomapp1.c16
15 files changed, 3593 insertions, 0 deletions
diff --git a/tools/apbuild/Apbuild/GCC.pm b/tools/apbuild/Apbuild/GCC.pm
new file mode 100644
index 00000000..b4246148
--- /dev/null
+++ b/tools/apbuild/Apbuild/GCC.pm
@@ -0,0 +1,539 @@
+# Various gcc-related functions
+package Apbuild::GCC;
+
+use strict;
+use Apbuild::Utils;
+use IPC::Open3;
+
+
+######## Special constants; used for parsing GCC parameters ########
+
+# Parameters that require an extra parameter
+our $extraTypes = 'o|u|Xlinker|b|V|MF|MT|MQ|I|L|R|Wl,-rpath|isystem|D|x';
+# Linker parameters
+our $linkerTypes = 'L|Wl|o$|l|s|n|R';
+# Files with these extensions are objects
+our $staticLibTypes = 'a|al';
+our $objectTypes = "o|os|so(\\.\\d+)*|la|lo|$staticLibTypes";
+our $headerTypes = 'h|hpp';
+# Source file types
+our $cTypes = 'c|C';
+our $cxxTypes = 'cpp|cxx|cc|c\+\+';
+our $srcTypes = "$cTypes|$cxxTypes";
+
+
+######## Methods ########
+
+##
+# Apbuild::GCC->new(gcc_command)
+# gcc_command: The command for invoking GCC.
+#
+# Create a new Apbuild:GCC object.
+sub new {
+ my ($class, $gcc) = @_;
+ my %self;
+
+ $self{gcc} = $gcc;
+ $self{gcc_file} = checkCommand($gcc);
+ if (!defined $self{gcc_file}) {
+ error "$gcc: command not found\n";
+ exit 127;
+ }
+
+ # FIXME: should use gcc -print-search-paths.
+ $self{searchPaths} = ["/usr/lib", "/usr/local/lib"];
+ foreach (reverse(split(/:/, $ENV{LIBRARY_PATH}))) {
+ push @{$self{searchPaths}}, $_;
+ }
+
+ bless \%self, $class;
+ return \%self;
+}
+
+##
+# $gcc->capabilities()
+# Returns: a hash with capabilities for this compiler.
+#
+# Check GCC's capabilities. This function will return
+# a hash with the following keys:
+# libgcc : Is 1 if gcc supports the parameter -{shared,static}-libgcc.
+# as_needed: Is 1 if gcc's linker supports --as-needed.
+# abi2 : Is 1 if gcc supports -fabi-version=2.
+#
+# This function takes care of caching results.
+sub capabilities {
+ my ($self) = @_;
+ my (%capabilities, %cache);
+
+ my $gcc = $self->{gcc};
+ my $gcc_file = $self->{gcc_file};
+
+ # First, check the cache
+ my @stat = stat $gcc_file;
+ my $gcc_mtime = $stat[9];
+ my $home = homeDir();
+ if (-f "$home/.apbuild") {
+ parseDataFile("$home/.apbuild", \%cache);
+ if ($cache{version} != 2) {
+ # Cache file version incompatible; delete cache
+ %cache = ();
+
+ } else {
+ if ($cache{"mtime_$gcc_file"} != $gcc_mtime) {
+ # Cache out of date for this compiler; update cache
+ delete $cache{"libgcc_$gcc_file"};
+ delete $cache{"abi2_$gcc_file"};
+ delete $cache{"as_needed_$gcc_file"};
+ delete $cache{"hash_style_$gcc_file"};
+ delete $cache{"stack_protector_$gcc_file"};
+ delete $cache{"fortify_source_$gcc_file"};
+ }
+ }
+ }
+
+ my $lc_all = $ENV{LC_ALL};
+ $ENV{LC_ALL} = 'C';
+
+ if (exists $cache{"libgcc_$gcc_file"} && exists $cache{"abi2_$gcc_file"}) {
+ $capabilities{libgcc} = $cache{"libgcc_$gcc_file"};
+ $capabilities{abi2} = $cache{"abi2_$gcc_file"};
+
+ } else {
+ # Get output from 'gcc -v'
+ my ($r, $w, $e);
+
+ my $pid = open3($w, $r, $e, $gcc_file, '-v');
+ close $w if ($w);
+ close $e if ($e);
+ my @output = <$r>;
+ waitpid $pid, 0;
+
+ # Check whether gcc >= 3.0
+ my ($major, $minor) = $output[@output - 1] =~ /version ([0-9]+)\.([0-9]+)/;
+ if ($major >= 3) {
+ $capabilities{libgcc} = 1;
+ $cache{"libgcc_$gcc_file"} = 1;
+ } else {
+ $capabilities{libgcc} = 0;
+ $cache{"libgcc_$gcc_file"} = 0;
+ }
+
+ if ($major > 3 || ($major >= 3 && $minor >= 4)) {
+ $capabilities{abi2} = 1;
+ $cache{"abi2_$gcc_file"} = 1;
+ } else {
+ $capabilities{abi2} = 0;
+ $cache{"abi2_$gcc_file"} = 0;
+ }
+
+ $cache{"mtime_$gcc_file"} = $gcc_mtime;
+ }
+
+ if (exists $cache{"as_needed_$gcc_file"}) {
+ $capabilities{as_needed} = $cache{"as_needed_$gcc_file"};
+
+ } else {
+ my ($r, $w, $e);
+
+ my $pid = open3($w, $r, $e, $gcc_file, '-Wl,--help');
+ close $w if ($w);
+ close $e if ($e);
+ local($/);
+ my $output = <$r>;
+ waitpid $pid, 0;
+
+ if ($output =~ /--as-needed/) {
+ $capabilities{as_needed} = 1;
+ $cache{"as_needed_$gcc_file"} = 1;
+ } else {
+ $capabilities{as_needed} = 0;
+ $cache{"as_needed_$gcc_file"} = 0;
+ }
+ }
+
+ if (exists $cache{"hash_style_$gcc_file"}) {
+ $capabilities{hash_style} = $cache{"hash_style_$gcc_file"};
+ } else {
+ my ($r, $w, $e);
+
+ my $pid = open3($w, $r, $e, $gcc_file, '-Wl,--help');
+ close $w if ($w);
+ close $e if ($e);
+ local($/);
+ my $output = <$r>;
+ waitpid $pid, 0;
+
+ if ($output =~ /--hash-style/) {
+ $capabilities{hash_style} = 1;
+ $cache{"hash_style_$gcc_file"} = 1;
+ } else {
+ $capabilities{hash_style} = 0;
+ $cache{"hash_style_$gcc_file"} = 0;
+ }
+ }
+
+ if (exists $cache{"stack_protector_$gcc_file"}) {
+ $capabilities{stack_protector} = $cache{"stack_protector_$gcc_file"};
+ } else {
+ # Get output from 'gcc -v'
+ my ($r, $w, $e);
+
+ my $pid = open3($w, $r, $e, $gcc_file, '-v');
+ close $w if ($w);
+ close $e if ($e);
+ my @output = <$r>;
+ waitpid $pid, 0;
+
+ # Check whether gcc >= 3.0
+ my ($major, $minor) = $output[@output - 1] =~ /version ([0-9]+)\.([0-9]+)/;
+ if ($major >= 4 && $minor >= 1) {
+ $capabilities{stack_protector} = 1;
+ $cache{"stack_protector_$gcc_file"} = 1;
+ } else {
+ $capabilities{stack_protector} = 0;
+ $cache{"stack_protector_$gcc_file"} = 0;
+ }
+ }
+
+ if (exists $cache{"fortify_source_$gcc_file"}) {
+ $capabilities{fortify_source} = $cache{"fortify_source_$gcc_file"};
+ } else {
+ # Get output from 'gcc -v'
+ my ($r, $w, $e);
+
+ my $pid = open3($w, $r, $e, $gcc_file, '-v');
+ close $w if ($w);
+ close $e if ($e);
+ my @output = <$r>;
+ waitpid $pid, 0;
+
+ # Check whether gcc >= 4.1
+ my ($major, $minor) = $output[@output - 1] =~ /version ([0-9]+)\.([0-9]+)/;
+ if ($major >= 4 && $minor >= 1) {
+ $capabilities{fortify_source} = 1;
+ $cache{"fortify_source_$gcc_file"} = 1;
+ } else {
+ $capabilities{fortify_source} = 0;
+ $cache{"fortify_source_$gcc_file"} = 0;
+ }
+ }
+
+ if (defined $lc_all) {
+ $ENV{LC_ALL} = $lc_all;
+ } else {
+ delete $ENV{LC_ALL};
+ }
+
+ $cache{version} = 2;
+ writeDataFile("$home/.apbuild", \%cache);
+ return %capabilities;
+}
+
+
+##
+# $gcc->command()
+#
+# Returns the GCC command associated with this Apbuild::GCC object.
+sub command {
+ my ($self) = @_;
+ return $self->{gcc};
+}
+
+
+##
+# $gcc->foreach(args, callback)
+# args: a reference to an array which contains GCC parameters.
+# callback: the callback function which will be called in every iteration of the loop.
+#
+# Iterate through each GCC parameter. $callback will be called as follows:
+# $callback->(type, args...);
+# $type is the current parameter's type, either "param" or "file" (source file).
+# args is an array of parameters. If this parameter is a parameter which excepts
+# another parameter (such as -o, it expects a filename), then the expected
+# parameter will also be passed to the callback function.
+sub foreach {
+ my ($self, $args, $callback) = @_;
+ for (my $i = 0; $i < @{$args}; $i++) {
+ $_ = $args->[$i];
+ if (/^-/ || /\.($objectTypes|$headerTypes)$/ || /.*\.so\.?$/) {
+ # Parameter
+ if (/^-($extraTypes)$/) {
+ # This parameter expects another parameter
+ $callback->("param", $_, $args->[$i + 1]);
+ $i++;
+ } else {
+ $callback->("param", $_);
+ }
+
+ } else {
+ # File
+ $callback->("file", $_);
+ }
+ }
+}
+
+##
+# $gcc->splitParams(args, files, params)
+# args: a reference to an array which contains GCC parameters.
+# files: a reference to an array, or undef.
+# params: a reference to an array, or undef.
+#
+# Parse GCC's parameters. Seperate files and arguments.
+# A list of files will be stored in the array referenced to by $file,
+# a list of non-file parameters will be stored in the array referenced to by $params.
+sub splitParams {
+ my ($self, $args, $files, $params) = @_;
+
+ my $callback = sub {
+ my $type = shift;
+ if ($type eq "param") {
+ push @{$params}, @_ if ($params);
+ } elsif ($type eq "file") {
+ push @{$files}, $_[0] if ($files);
+ }
+ };
+ $self->foreach($args, $callback);
+}
+
+
+sub stripLinkerParams {
+ my ($self, $r_params, $linking) = @_;
+ my @params;
+ my $i = 0;
+
+ my $callback = sub {
+ my $type = shift;
+ if ($type eq 'param' && $_[0] =~ /^-($linkerTypes)/) {
+ push @{$linking}, @_;
+ } else {
+ push @params, @_;
+ }
+ };
+ $self->foreach($r_params, $callback);
+ @{$r_params} = @params;
+}
+
+
+sub addSearchPaths {
+ my ($self, $dir) = @_;
+ push @{$self->{searchPaths}}, $dir;
+}
+
+# Parse $args and extract library search paths from it.
+# Those paths, along with paths added by addSearchPaths(),
+# will be appended to $paths.
+sub getSearchPaths {
+ my ($self, $args, $paths) = @_;
+
+ my $callback = sub {
+ my $type = shift;
+ return if ($type ne "param");
+
+ if ($_[0] eq "-L") {
+ push @{$paths}, $_[1];
+
+ } elsif ($_[0] =~ /^-L(.+)/ || $_[0] =~ /^--library-path=(.+)/) {
+ push @{$paths}, $1;
+ }
+ };
+ $self->foreach($args, $callback);
+
+ push @{$paths}, @{$self->{searchPaths}};
+}
+
+
+##
+# $gcc->isLibrary(arg, libname)
+#
+# Check whether $arg is a (dynamic) library argument.
+# The base library name will be stored in $$libname.
+sub isLibrary {
+ my ($self, $arg, $libname) = @_;
+ if ($arg =~ /^-l(.+)/ || $arg =~ /^--library=(.+)/ || $arg =~ /^(?:.*\/)?lib([^\/]+)\.so/) {
+ $$libname = $1 if ($libname);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+##
+# $gcc->isObject(arg)
+#
+# Check whether $arg is an object. This includes static libraries.
+sub isObject {
+ my ($self, $arg) = @_;
+ return $arg !~ /^-/ && $arg =~ /\.($objectTypes)$/;
+}
+
+sub isStaticLib {
+ my ($self, $arg) = @_;
+ return $arg !~ /^-/ && $arg =~ /\.($staticLibTypes)$/;
+}
+
+##
+# $gcc->isSource(file)
+#
+# Checks whether $file is a source file.
+sub isSource {
+ my ($self, $file) = @_;
+ return $file =~ /\.($srcTypes)$/;
+}
+
+##
+# $gcc->isCxxSource(file)
+#
+# Checks whether $file is a C++ source file.
+sub isCxxSource {
+ my ($self, $file) = @_;
+ return $file =~ /\.($cxxTypes)$/;
+}
+
+
+# I wish I know how to explain what these functions do, but I can't. :(
+# If you know a better way to name these, please do tell me.
+sub sourceOrderIsImportant {
+ my ($self, $arg) = @_;
+ return $arg =~ /^-(x)$/;
+}
+
+sub linkOrderIsImportant {
+ my ($self, $arg) = @_;
+ return $arg =~ /^-(Wl,--whole-archive|Wl,--no-whole-archive)$/;
+}
+
+##
+# $gcc->getOutputFile(args)
+# args: a reference to an array which contains GCC parameters.
+# Returns: a filename.
+#
+# Parse the GCC arguments and detect the output filename.
+sub getOutputFile {
+ my ($gcc, $args) = @_;
+ my ($output, $compilingToObject, $source);
+
+ my $callback = sub {
+ my $type = shift;
+ if ($type eq 'param' && $_[0] eq '-o') {
+ $output = $_[1];
+
+ } elsif ($type eq 'param' && $_[0] eq '-c') {
+ $compilingToObject = 1;
+
+ } elsif ($type eq 'file' && $gcc->isSource($_[0])) {
+ $source = $_[0];
+ }
+ };
+ $gcc->foreach($args, $callback);
+
+ if (defined $output) {
+ return $output;
+ } elsif ($compilingToObject) {
+ $source =~ s/\.[^.]*?$/.o/;
+ return $source;
+ } else {
+ return "a.out";
+ }
+}
+
+##
+# $gcc->setOutputFile(args, new_output_file)
+# args: a reference to an array which contains GCC parameters.
+# new_output_file: the new output filename.
+#
+# Parse the GCC arguments and change the output filename.
+# The array referenced by $args will be modified.
+sub setOutputFile {
+ my ($gcc, $args, $new_output_file) = @_;
+ my (@newArgs, $changed);
+
+ my $callback = sub {
+ my $type = shift;
+
+ if ($type eq 'param' && $_[0] eq '-o') {
+ push @newArgs, "-o", $new_output_file;
+ $changed = 1;
+
+ } else {
+ push @newArgs, @_;
+ }
+ };
+ $gcc->foreach($args, $callback);
+
+ if (!$changed) {
+ push @newArgs, "-o", $new_output_file if (!$changed);
+ }
+ @{$args} = @newArgs;
+}
+
+
+##
+# $gcc->situation(args)
+# args: a reference to an array which contains GCC arguments.
+# Returns: 'compile', 'depcheck', 'compile and link', 'linking' or 'other'.
+#
+# Detect the situation in which the compiler is used.
+# Basically, there are 5 situations in which the compiler is used:
+# 1) Compilation (to an object file).
+# 2) Linking.
+# 3) Compilation and linking.
+# 4) Dependancy checking with -M* or -E.
+# 5) None of the above. Compiler is invoked with --help or something.
+# Note that source files may also contain non-C/C++ files.
+sub situation {
+ my ($self, $args) = @_;
+
+ my $files = 0;
+ for (@{$args}) {
+ $files++ if (!(/^-/));
+ }
+
+ for (@{$args}) {
+ if (/^-c$/) {
+ # Situation 1
+ return 'compile';
+ } elsif (/^-M(|M|G)$/ || /^-E$/) {
+ # Situation 4
+ return 'depcheck';
+ }
+ }
+
+ if ($files == 1)
+ {
+ my $i = 0;
+ for (@{$args})
+ {
+ if (!(/^-/) && (/\.($headerTypes)$/))
+ {
+ print($args->[$i], "\n");
+ return 'precompiled header';
+ }
+ $i++;
+ }
+ }
+
+ my $i = 0;
+ for (@{$args}) {
+ if (!(/^-/) && !(/\.($objectTypes)$/)) {
+ if ($i > 0 && $args->[$i - 1] =~ /^-($extraTypes)$/) {
+ $i++;
+ next;
+ } else {
+ # Situation 3
+ return 'compile and link';
+ }
+ }
+ $i++;
+ }
+
+ if ($files == 0) {
+ # Situation 5
+ return 'other';
+ } else {
+ # Situation 2
+ return 'linking';
+ }
+}
+
+
+1;
diff --git a/tools/apbuild/Apbuild/Utils.pm b/tools/apbuild/Apbuild/Utils.pm
new file mode 100644
index 00000000..a5089299
--- /dev/null
+++ b/tools/apbuild/Apbuild/Utils.pm
@@ -0,0 +1,195 @@
+package Apbuild::Utils;
+
+use strict;
+use warnings;
+use Exporter;
+use base qw(Exporter);
+use IO::Handle;
+use IPC::Open2;
+use POSIX;
+use Cwd qw(abs_path);
+
+
+our @EXPORT = qw(debug error checkCommand empty homeDir searchLib searchStaticLib soname run parseDataFile writeDataFile);
+our $debugOpened = 0;
+
+
+##
+# debug(message)
+#
+# If the environment variable $APBUILD_DEBUG is set to 1,
+# then print a debugging message to /dev/tty (not stdout or stderr).
+sub debug {
+ return if (empty($ENV{APBUILD_DEBUG}) || !$ENV{APBUILD_DEBUG});
+
+ if (!$debugOpened) {
+ if (open DEBUG, '>/dev/tty') {
+ $debugOpened = 1;
+ } else {
+ return;
+ }
+ }
+
+ my @args = split /\n/, "@_";
+ foreach (@args) {
+ $_ = '# ' . $_;
+ $_ .= "\n";
+ }
+
+ print DEBUG "\033[1;33m";
+ print DEBUG join '', @args;
+ print DEBUG "\033[0m";
+ DEBUG->flush;
+}
+
+
+##
+# error(message)
+#
+# Print an error message to stderr. It will be displayed in red.
+sub error {
+ print STDERR "\033[1;31m";
+ print STDERR $_[0];
+ print STDERR "\033[0m";
+ STDERR->flush;
+}
+
+
+##
+# checkCommand(file)
+# file: an command's filename.
+# Returns: the full path to $file, or undef if $file is not a valid command.
+#
+# Checks whether $file is an executable which is in $PATH or the working directory.
+#
+# Example:
+# checkCommand('gcc'); # Returns "/usr/bin/gcc"
+sub checkCommand {
+ my ($file, $file2) = split / /, $_[0];
+ $file = $file2 if ($file =~ /ccache/);
+
+ return abs_path($file) if (-x $file);
+ foreach my $dir (split /:+/, $ENV{PATH}) {
+ if (-x "$dir/$file") {
+ return "$dir/$file";
+ }
+ }
+ return undef;
+}
+
+##
+# empty(str)
+#
+# Checks whether $str is undefined or empty.
+sub empty {
+ return !defined($_[0]) || $_[0] eq '';
+}
+
+##
+# homeDir()
+#
+# Returns the user's home folder.
+sub homeDir {
+ if (!$ENV{HOME}) {
+ my $user = getpwuid(POSIX::getuid());
+ $ENV{HOME} = (getpwnam($user))[7];
+ }
+ return $ENV{HOME};
+}
+
+##
+# searchLib(basename, [extra_paths])
+# basename: the base name of the library.
+# extra_paths: a reference to an array, which contains extra folders in which to look for the library.
+# Returns: the absolute path to the library, or undef if not found.
+#
+# Get the absolute path of a (static or shared) library.
+#
+# Example:
+# searchLib("libfoo.so.1"); # Returns "/usr/lib/libfoo.so.1"
+sub searchLib {
+ my ($basename, $extra_paths) = @_;
+
+ if ($extra_paths) {
+ foreach my $path (reverse(@{$extra_paths})) {
+ return "$path/$basename" if (-f "$path/$basename");
+ }
+ }
+ foreach my $path ('/usr/local/lib', '/lib', '/usr/lib') {
+ return "$path/$basename" if (-f "$path/$basename");
+ }
+ return undef;
+}
+
+##
+# soname(lib)
+# lib: a filename to a shared library.
+# Returns: the soname.
+#
+# Get the soname of the specified shared library by reading
+# the SONAME section of the shared library file.
+sub soname {
+ my ($lib) = @_;
+ my ($r, $w);
+
+ if (open2($r, $w, 'objdump', '-p', $lib)) {
+ close $w;
+ my @lines = <$r>;
+ close $r;
+
+ my ($soname) = grep {/SONAME/} @lines;
+ $soname =~ s/.*?SONAME[ \t]+//;
+ $soname =~ s/\n//gs;
+ return $soname;
+
+ } else {
+ my ($soname) = $lib =~ /.*\/lib(.+)\.so/;
+ return $soname;
+ }
+}
+
+##
+# run(args...)
+# Returns: the command's exit code.
+#
+# Run a command with system().
+sub run {
+ # split the first item in @_ into "words". The `printf ...`
+ # takes care of respecting ' and " quotes so we don't split a
+ # quoted string that contains whitespace. If $cmd itself
+ # contains \n, this will still go wrong.
+ my $cmd = shift @_;
+ my @words = `printf '%s\n' $cmd`;
+ chomp @words;
+ my $status = system(@words, @_);
+ return 127 if ($status == -1);
+ return $status / 256 if ($status != 0);
+ return 0;
+}
+
+sub parseDataFile {
+ my ($file, $r_hash) = @_;
+
+ %{$r_hash} = ();
+ return if (!open FILE, "< $file");
+ foreach (<FILE>) {
+ next if (/^#/);
+ s/[\r\n]//g;
+ next if (length($_) == 0);
+
+ my ($key, $value) = split / /, $_, 2;
+ $r_hash->{$key} = $value;
+ }
+ close FILE;
+}
+
+sub writeDataFile {
+ my ($file, $r_hash) = @_;
+ return if (!open FILE, "> $file");
+ foreach my $key (sort(keys %{$r_hash})) {
+ print FILE "$key $r_hash->{$key}\n";
+ }
+ close FILE;
+}
+
+1;
diff --git a/tools/apbuild/BINARY-PORTABILITY-NOTES b/tools/apbuild/BINARY-PORTABILITY-NOTES
new file mode 100644
index 00000000..9a34566a
--- /dev/null
+++ b/tools/apbuild/BINARY-PORTABILITY-NOTES
@@ -0,0 +1,36 @@
+1) C++ ABI
+The C++ ABI generated by GCC version 2.95, 2.96, 3.0, and 3.1.1 are
+incompatible with each other. This means that, for examples, apps compiled
+with GCC 2.95 cannot link to libraries compiled with GCC 3.2.
+
+GCC 3.4 is the latest ABI at the moment (April 2005). But the most widely
+used ABI at the moment is the GCC 3.2 ABI.
+
+2) Symbol collisions, be aware of what libraries are implicitly linked in.
+Imagine the following situation:
+- foo contains the symbol foobar (a function).
+- libbar contains a symbol with the same name, but is a totally different
+ function.
+- foo is linked to libbar.
+When foo tries to call foobar(), it's undefined whether it will call the
+foobar() from it's own binary, or the one from libbar. Depending on what
+those functions do, foo may crash or do something it isn't supposed to do.
+
+Solution: rtld features, -Bgroup. However, at this moment these are not
+supported by glibc. Until they are, keep these in mind:
+- You should mark all functions that you do not want to export (or show up
+ in the symbol table) as static.
+- If you're a library, you should namespace all functions.
+- Internal functions that are used within a library, but across multiple
+ .c files, should be prefixed by a _ or __.
+
+3) Linking against shared versions of X11 extension libs
+Some X libraries, such as libXrender, are originally not shared libraries.
+Distributions just created shared library versions to save memory. So
+some distributions don't ship the shared versions at all. Apbuild
+automatically statically links some of those X libraries (you can turn
+this behavior off of course).
+
+4) Usage of sys_errlist
+
+5) Don't use TLS (the __thread keyword).
diff --git a/tools/apbuild/ChangeLog b/tools/apbuild/ChangeLog
new file mode 100644
index 00000000..fe1587ce
--- /dev/null
+++ b/tools/apbuild/ChangeLog
@@ -0,0 +1,375 @@
+2009-03-13 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * apgcc: Use warn instead of print to display warnings. Thanks to Scott
+ Pakin for the patch.
+
+-------------------- 2.0.8 was released --------------------
+
+2009-03-11 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * Apbuild/GCC.pm: Applied patch by Mike Lundy which fixes compiling of
+ libpng where apgcc detected a symbol list as precompiled header rather than
+ a depcheck. Fixes #118.
+ * apsymbols.h: New symbol list created on a GLIBC_2.9 machine by Mike
+ Lundy. Thanks! Fixes #117.
+
+2009-03-11 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * apgcc: Applied patch by Scott Pakin which shows a warning message when
+ a library in APBUILD_STATIC isn't found.
+ * Apbuild/GCC.pm: getSearchPaths: Correctly add the content of the list not
+ a reference. Also a patch by Scott Pakin, thanks!
+
+2009-03-10 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * apgcc: Applied patch by Scott Pakin which fixes statically compiling
+ of libuuid.
+
+-------------------- 2.0.7 was released --------------------
+
+2008-11-10 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * Apbuild/GCC.pm: Check if FORTIFY_SOURCE is available. I'm not sure if
+ this really was introduced in gcc 4.1, but it should fix the the linker
+ errors in Ubuntu 8.10 and other new distros using this feature.
+ * apgcc: Add -U_FORTIFY_SOURCE to deactivate FORTIFY_SOURCE=2.
+
+2008-09-11 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * buildlist: Bump minimum GLibc version to 2.3 (from 2.2)
+ * apsymbols.h: update list to work with the new 2.3 glibc min version
+ (Patch from Taj, me and Isak, should fix #20)
+ * apgcc: Check if APBUILD_STATIC_X is definied to prevent warnings.
+
+2008-08-03 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * relaytool: Check if /dev/tty exists. Fixes #63
+
+2008-08-03 Jan Niklas Hasse <jhasse@gmail.com>
+
+ * apgcc: Don't statically link X11 libs by default. Fixes #61
+
+-------------------- 2.0.6 was released --------------------
+
+Sun Dec 30 19:17:03 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * relaytool: Apply patch from res in ticket #52. Now, if a lib cannot be relaytooled
+ for some reason, a stub that ensures libwhatever_is_present is defined will be
+ generated.
+
+Sun Sep 30 00:29:13 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * relaytool: When multi-linking, use the first SONAME passed to --multilink
+ as the name to use for the _is_present variable and _symbol_is_present function.
+ Fixes #37.
+
+Sat Sep 22 02:39:11 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * relaytool: Add --out-dir feature by user 'res' in ticket #50.
+
+2007-09-22 Isak Savo <isak.savo@gmail.com>
+
+ * relaytool (arch_ptr_size): Use 'uname -m' instead of 'arch' to get
+ machine name. Patch from user 'res' in ticket #51 (ticket fixed by
+ this commit)
+
+Tue Aug 14 17:04:32 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Apply patch from Unfleshed One for precompiled header support. Fixes #32.
+ * Apbuild/GCC.pm: Apply patch from Unfleshed One from precompiled header and
+ SCons/Qt4 integration. Fixes #32.
+
+Tue Aug 14 16:51:30 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * relaytool: When running on unsupported arch, give correct
+ defines for lib_is_present and symbol_is_present.
+
+Mon Jul 9 23:22:21 UTC 2007 Curtis L. Knight <knighcl@gmail.com>
+ * apgcc: Update for 2.0.6 release.
+ * Makefile: Update for 2.0.6 release.
+
+-------------------- 2.0.5 was released --------------------
+
+Mon Jun 4 02:03:06 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Append statically linked file's deps before adjusting
+ link line so that you can statically link the deps of the
+ libs you're statically linking (if that made any sense).
+
+Sat May 26 15:28:14 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * make-icons: Put icons into a directory called icons relative to
+ where make-icons was run from. Ask user for type so that icons get
+ put in correct subdirectory.
+
+Fri May 25 03:02:28 UTC 2007 Curtis L. Knight <knighcl@gmail.com>
+ * apgcc: Update for 2.0.5 release.
+ * Makefile: Update for 2.0.5 release.
+
+Wed May 23 00:45:48 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * apgcc: When statically linking, find the lib's DT_NEEDED entries
+ and link against them so we don't get linking errors.
+
+Thu May 17 20:38:11 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * relaytool: Use /bin/bash instead of /bin/sh so we can work on
+ Ubuntu (where sh -> dash). Thanks ACSpike. Add multilink support
+ to relaytool (TODO: document it better).
+
+-------------------- 2.0.4 was released --------------------
+
+Sun Apr 8 11:22:23 UTC 2007 Curtis L. Knight <knighcl@gmail.com>
+ * apgcc: Update for 2.0.4 release.
+ * Makefile: Update for 2.0.4 release.
+
+Sat Mar 31 21:09:45 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * Apbuild/GCC.pm: Check if gcc supports -fstack-protector,
+ so it can be disabled.
+ * apgcc: If gcc supports -fstack-protector, disable it (it adds a
+ silent dependency on GLIBC 2.4).
+ * apsymbols.h: Rebuilt with GLIBC 2.4. Thanks to Chris Guirl for
+ rebuilding.
+
+Thu Mar 29 05:08:40 UTC 2007 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Respect the $APBUILD_NO_STATIC_X variable (as
+ documented on website). This doesn't mean it's a good idea
+ to use this features.
+
+-------------------- 2.0.3 was released --------------------
+
+Sun Dec 17 01:05:08 UTC 2006 Curtis L. Knight <knighcl@fastmail.fm>
+ * apgcc: Update for 2.0.3 release.
+ * Makefile: Update for 2.0.3 release.
+
+Sat Nov 25 23:20:07 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * Apbuild/GCC.pm: Detect if ld supports --hash-style so that we
+ can force both .gnu.hash and .hash to be generated on FC6.
+ * apgcc: If linker supports --hash-style, generate both .gnu.hash
+ and .hash sections so that binary works with linkers with support for
+ either type. By default, FC6 only generates .gnu.hash which makes its
+ binaries only work on systems with .gnu.hash. See:
+ http://fcp.surfsite.org/modules/newbb/viewtopic.php?topic_id=29929&forum=10&post_id=128939
+
+-------------------- 2.0.2 was released --------------------
+
+Thu Nov 2 22:53:33 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Allow people to replace -I flags passed to apgcc with ones from
+ $APBUILD_INCLUDE. For example /opt/kde/include=/home/taj/kde-includes/3.3
+ replaces -I/opt/kde/include with -I/home/taj/kde-includes/3.3. This is only
+ useful for apps where include path order is important (amarok 1.4.3, see
+ comments for details).
+
+-------------------- 2.0.1 was released --------------------
+
+Fri Oct 13 14:54:54 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Revert commit that "Just use[d] the multiple-file code for link and compile
+ in 1 command." This broke compiling main/libexec. Post 1.2 this code will get
+ better, I promise. :)
+
+Thu Oct 12 04:36:56 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: [translateLibNames()]: Always find libstdc++ if compiling C++, force
+ use of the compilers libstdc++, instead of what libtool provides (which
+ is probably wrong when using your non-system g++).
+
+Mon Oct 9 00:57:48 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: Remove special case with compiling and linking in 1 command with
+ 1 file. This code never called linkObjects() and so X libs were never
+ statically linked in. Just use the multiple-file code for link and compile in 1
+ command.
+ [forceStatic()]: Link Xfixes if Xcursor is linked because sometimes Xcursor
+ depends on Xfixes (on Slack 11, xorg 6.9.0, at least).
+
+Sun Sep 24 22:38:50 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: [rearrangeForAsNeeded()]: Put -lXRender at the end of the
+ link command. See
+ http://lists.sunsite.dk/cgi-bin/ezmlm-cgi?21:mss:5187:200609:lkfnloheeaingojmnemi
+ for details.
+
+2006-09-13 Isak Savo <isak.savo@gmail.com>
+
+ * Makefile (PREFIX): Replaced bash specific '[[' testing with 'test' to work better with Ubuntu Edgy's 'dash' shell
+
+Thu Sep 7 19:10:53 UTC 2006 Taj Morton <tajmorton@gmail.com>
+ * apgcc: When compiling and linking in 1 command make sure
+ bogus deps are stripped. Note: I did not update the
+ double-compilation part of the code to have the fix because
+ it's dead code.
+
+Tue May 30 01:04:05 2006 Mike Hearn <mike@plan99.net>
+
+ * relaytool: Add x64 support based on patch by Psyche.
+ Fix a couple of minor bugs and make the code flow better.
+
+Thu Apr 13 23:56:32 2006 Mike Hearn <mike@plan99.net>
+
+ * apgcc (translateLibNames): Only drop libstdc++.so from the
+ arguments list when double compiling. This fixes the case
+ when libtool passes -nostdlib and then gives us a libstdc++
+ directly. However it's kind of a hack and will need to be
+ changed to work properly with double compiling.
+
+2006-03-04 Hongli Lai <hongli@plan99.net>
+
+ * apgcc: Apply patch by Francesco Montorsi.
+ This adds a new option APBUILD_RESOLVE_LIBPATH, which is a
+ space-seperated list of regular expressions which specify the
+ libraries whose path must be resolved into absolute paths.
+ This works around certain linking problems with static libraries,
+ when the order of the linking arguments is changed.
+
+2006-02-04 Peter Lund <firefly@diku.dk>
+
+ * APBuild/GCC.pm: Fix double linking of .moc.o files
+
+2006-02-01 Peter Lund <firefly@diku.dk>
+
+ * apgcc: Add support gcc-2.9x.
+ Minor comment/--help fixes. See
+ http://comments.gmane.org/gmane.comp.autopackage.devel/4408
+ for more details
+ * APBuild/GCC.pm, APBuild/Utils.pm: Make apgcc work with ccache.
+
+2006-01-23 Peter Lund <firefly@diku.dk>
+
+ * Makefile: Use eager notation (`:=') instead of `=' for var assignment. Add $(PROGS)-variable to hold all binary names.
+
+
+2005-12-02 Hongli Lai <hongli@plan99.net>
+ * apgcc (rearrangeForAsNeeded):
+ Special case -lbfd and -liberty as they can cause link failures in
+ some cases.
+
+2005-11-30 Hongli Lai <hongli@plan99.net>
+ * apgcc:
+ Do not link to incorrect libstdc++ version: remove
+ /usr/lib/libstdc++.so.x from the arguments.
+
+2005-11-08 Hongli Lai <hongli@plan99.net>
+ * apgcc, Apbuild/GCC.pm, Apbuild/Utils.pm:
+ - Code cleanups.
+ - Fix C++ double compiling bugs: correctly set output filename
+ when -o is not given, surpress gcc output when double compiling.
+
+2005-11-07 Hongli Lai <hongli@plan99.net>
+ * apgcc (linkObjects): remove duplicate system() call which
+ does nothing good but breaks some libtool versions.
+
+2005-10-30 Jan Nieuwenhuizen <janneke@gnu.org>
+
+ * Apbuild/GCC.pm (new): New member variable: searchPaths. Bugfix:
+ add LIBRARY_PATH to initialization.
+ (addSearchPaths): New function.
+ (getSearchPaths): Use searchPaths.
+
+ * Apbuild/Utils.pm (searchLib): Bugfix: correct order of search
+ dirs.
+
+ * apgcc (removeLibraries): Maintain searchPath for full .so name.
+
+October 16 2005 <hongli@plan99.net>
+ * apgcc: Correctly double compile C++ binaries during linking.
+
+September 28 2005 Hongli Lai <hongli@plan99.net>
+ * Support $APBUILD_NO_RPATH: don't add rpath entries.
+ Feature request by Andreas.
+
+September 3 2005 Hongli Lai <hongli@plan99.net>
+ * relaytool: support W, V and G symbols (experimental C++ support)
+
+August 5 2005 Hongli Lai <hongli@plan99.net>
+ * apgcc and GCC.pm: fixed an argument reordering bug.
+ * Makefile: add make-icons to distrbution.
+
+2005-08-02 Mike Hearn <mike@plan99.net>
+ * relaytool: Remove -include flags, if any. This makes relaytool
+ precompiled-header safe.
+
+2005-07-31 Mike Hearn <mike@plan99.net>
+ * relaytool.m4, relaytool: Optimization: use -ffunction-sections
+ and --gc-sections to eliminate unused jump slots
+ * relaytool: Don't break when CFLAGS is set
+ * relaytool: Optimization: only generate jump slots for exported
+ symbols from the library.
+
+July 30 2005 Hongli Lai <hongli@plan99.net>
+ * Apbuild/GCC.pm: Commit Joseph's patch: fix $gcc->isLibrary()
+
+2005-07-20 Mike Hearn <mike@plan99.net>
+ * Makefile (dist): Ship relaytool.m4, make extra scripts +x
+ * relaytool.m4: Big improvements to the way you integrate with
+ C/C++ build systems.
+
+July 9 2005 Hongli Lai <hongli@plan99.net>
+ * apgcc, Apbuild/GCC.pm (rearrangeForAsNeeded):
+ Fix rearrangement of objects: don't recognize parameters
+ (-Wl,foo.so) as objects.
+
+Thu Jun 16 22:43:55 2005 Mike Hearn <mike@navi.cx>
+ * make-icons: Add a script to generate icon theme dropins from an SVG
+ file, a convenient utility for developers
+
+May 31 2005 Hongli Lai <hongli@navi.cx>
+ * apgcc: Automatically compile C++ source files with two different
+ ABIs. By default, C++ files are compiled with ABI 1. Another
+ file with ABI 2 is stored as output.o.GCCABI2
+
+May 16th 2005 Vincent Béron <vberon@mecano.gme.usherb.ca>
+ * relaytool: Keep only one copy of a given symbol per lib.
+ * relaytool: libdl won't ever be supported by relaytool, so skip it.
+ * relaytool: Add a --version option, reorganize a bit the rest of --help.
+ * relaytool: Allow generating a stub file for every library passed in args.
+ * relaytool: Skip generating a stub for libraries for which no functions
+ are called or no variables used.
+ * relaytool: Use proper quoting.
+ * relaytool: Support old nm versions
+
+May 15th 2005 Vincent Béron <vberon@mecano.gme.usherb.ca>
+ * relaytool: Allow relaytool to understand more than one --relay
+ parameter.
+ * relaytool: Enable (via --minimal-list) relaytool to only
+ generate the minimum list of symbols by looking which ones are
+ undefined in .o objects.
+ * relaytool: Use CFLAGS (if available) while compiling the stub file.
+ * relaytool: Use a shell function to do the same thing as
+ readlink -f as the latter isn't always understood by readlink.
+ * relaytool: Fix a typo in PPC C code.
+
+May 14th 2005 Vincent Béron <vberon@mecano.gme.usherb.ca>
+ * relaytool: Don't accidentally exclude all symbols with _init
+ or _fini in their names.
+
+April 16 2005 Hongli Lai <hongli@navi.cx>
+ * Add new tool 'scandeps' which makes it easier for you to find
+ your software's library dependancies.
+ * Improve documentation.
+
+April 15 2005 Hongli Lai <hongli@navi.cx>
+ * apgcc: add support for $APBUILD_INCLUDE, which allows you
+ to prepend any folder to the header search path.
+ * Improve documentation.
+
+Fri Apr 15 22:47:06 2005 Mike Hearn <mike@navi.cx>
+ * apsymbols.h: Update to glibc 2.3.5
+ * buildlist: Don't spew so many errors
+
+April 10 2005 Hongli Lai <hongli@navi.cx>
+ * What? We have a ChangeLog? I didn't know that!
+ In the last 2 weeks I worked on these:
+ - Support for GCC 3.4+'s --as-needed, for smarter automatic bogus
+ dependancy stripping.
+ - Improved our own dependancy stripper.
+ - Big code cleanups.
+
+Tue Apr 5 02:14:49 2005 Mike Hearn <mike@navi.cx>
+ * relaytool.m4: Add an autoconf check for relaytool
+
+Mon Feb 14 00:37:46 2005 Mike Hearn <mike@navi.cx>
+ * relaytool: Add --no-replace option, fix misc bugs revealed by
+ actually using relaytool in a real app
+
+Fri Feb 11 23:49:24 2005 Mike Hearn <mike@navi.cx>
+ * relaytool: don't request PROT_EXEC permissions, they aren't
+ needed
+
+2004-06-06 Mike Hearn <mike@navi.cx>
+ * relaytool: make relaytool jump thunks NX safe by using mmap
+ rather than malloc.
+
+ * relaytool: Fix ELF scoping of dummy symbols for variable
+ imports, so the definitions in the imported lib don't get
+ resolved to the dummies (not all libs are compiled -Bsymbolic)
+
+ * relaytool: support partial maps
+
diff --git a/tools/apbuild/README b/tools/apbuild/README
new file mode 100644
index 00000000..9bc79658
--- /dev/null
+++ b/tools/apbuild/README
@@ -0,0 +1 @@
+Please read http://autopackage.org/aptools.html for documentation.
diff --git a/tools/apbuild/apg++ b/tools/apbuild/apg++
new file mode 100755
index 00000000..30357b53
--- /dev/null
+++ b/tools/apbuild/apg++
@@ -0,0 +1,10 @@
+#!/usr/bin/env perl
+# Simple C++ wrapper for apgcc.
+
+use strict;
+use FindBin;
+
+my $apgcc = "$FindBin::Bin/apgcc";
+$ENV{APBUILD_CXX_MODE} = 1;
+my $a = do $apgcc;
+die $@ if ($@);
diff --git a/tools/apbuild/apgcc b/tools/apbuild/apgcc
new file mode 100755
index 00000000..2aba0071
--- /dev/null
+++ b/tools/apbuild/apgcc
@@ -0,0 +1,1023 @@
+#!/usr/bin/env perl
+# apbuild - a GCC wrapper for creating portable binaries
+# Copyright (c) 2003,2004,2005 Hongli Lai
+# Distributed under the GNU General Public License
+
+use warnings;
+use strict;
+use FindBin qw($RealBin);
+use File::Spec;
+use lib $RealBin;
+use lib "$RealBin/../share/apbuild";
+use IPC::Open2;
+use POSIX;
+use Cwd;
+
+use Apbuild::GCC;
+use Apbuild::Utils;
+
+# Don't forget to bump the version in Makefile too.
+our $APBUILD_VERSION = "2.0.9";
+
+
+######## Initialization ########
+
+# In C mode:
+# $gcc is the default compiler.
+# $gxx2 is not set.
+#
+# In C++ mode:
+# $gcc is g++ 3.2.
+# $gxx2 is g++ 3.4, and it might not be set.
+# Double compiling is only enabled if both are set.
+#
+# Note that $APBUILD_CXX_MODE is an internal environment variable
+# which should not be set by the user.
+our ($gcc, $gxx2);
+
+if ($ENV{APBUILD_CXX_MODE}) {
+ # C++ support; user can:
+ # - Not set APBUILD_CXX1/2 at all -> use g++ as default, and don't double compile C++ sources.
+ # - Set APBUILD_CXX1 and APBUILD_CXX2 -> enable double compiling.
+ # - Set only APBUILD_CXX1 -> don't double compile.
+ # - Set only APBUILD_CXX2 -> use 'g++' as default for APBUILD_CXX1, and enable double compiling.
+
+ if (empty($ENV{APBUILD_CXX1}) && empty($ENV{APBUILD_CXX2})) {
+ $gcc = new Apbuild::GCC('g++');
+
+ } elsif (!empty($ENV{APBUILD_CXX1}) && !empty($ENV{APBUILD_CXX2})) {
+ $gcc = new Apbuild::GCC($ENV{APBUILD_CXX1});
+ $gxx2 = new Apbuild::GCC($ENV{APBUILD_CXX2});
+
+ } elsif (!empty($ENV{APBUILD_CXX1})) {
+ $gcc = new Apbuild::GCC($ENV{APBUILD_CXX1});
+
+ } elsif (!empty($ENV{APBUILD_CXX2})) {
+ $gcc = new Apbuild::GCC('g++');
+ $gxx2 = new Apbuild::GCC($ENV{APBUILD_CXX2});
+ }
+
+} else {
+ my $gcc_command = 'gcc';
+ $gcc_command = $ENV{APBUILD_CC} if (!empty($ENV{APBUILD_CC}));
+ $gcc = new Apbuild::GCC($gcc_command);
+}
+
+
+our $appath;
+our $libgcc = $ENV{APBUILD_STATIC_LIBGCC} ? '-static-libgcc' : '-shared-libgcc';
+
+# Find out where apgcc is located and determine the apbuild header
+# path relative to the apgcc script location.
+$appath = $ENV{APBUILD_PATH} if (!empty($ENV{APBUILD_PATH}));
+if (!defined $appath) {
+ $appath = $FindBin::Bin;
+ $appath =~ s/\/*$//g;
+ $appath =~ s/^(.*)\/.*?$/$1/;
+ $appath .= '/include/apbuild';
+ if (! -f "$appath/apsymbols.h" && -f "$FindBin::Bin/apsymbols.h") {
+ $appath = $FindBin::Bin;
+ }
+}
+
+# Special constants
+our @linking = ('-Wl,--enable-new-dtags,--rpath,${ORIGIN}/../lib,--rpath,${ORIGIN}/../lib/autopackage');
+our @include = ("-I$appath", '-include', "$appath/apsymbols.h", "-DAPBUILD_VERSION=\"$APBUILD_VERSION\"");
+our $extraTypes = $Apbuild::GCC::extraTypes;
+our $srcTypes = $Apbuild::GCC::srcTypes;
+
+
+@linking = () if ($ENV{APBUILD_NO_RPATH});
+if (!empty($ENV{APBUILD_INCLUDE})) {
+ foreach my $dir (split /:+/, $ENV{APBUILD_INCLUDE}) {
+ if ($dir =~ /=/) {
+ # allow people to force changing a path with oldpath=newpath, e.g.,:
+ # $echo $APBUILD_INCLUDE
+ # /opt/kde/include=/home/taj/kde-headers/kde-3.3.2/kde/include
+ # would change -I/opt/kde/include to my KDE 3.3 headers.
+ # this works around problems where the order of the include
+ # directories is important. Added for amarok 1.4.3 which has a
+ # header named scriptmanager.h. KDE also has a header named
+ # scriptmanager. Order of -I flags forces amarok header to be
+ # included.
+ my @splitpaths = split(/=/, $dir);
+ if (-d $splitpaths[1]) {
+ foreach (@ARGV) {
+ s/-I$splitpaths[0]$/-I$splitpaths[1]/g;
+ }
+ }
+ }
+ else {
+ push @include, "-I$dir" if (-d $dir);
+ }
+ }
+}
+
+# Include the apbuild include folder, and all folders inside that folder.
+if (opendir D, $appath) {
+ foreach my $dir (readdir D) {
+ if ($dir !~ /^\./ && -d "$appath/$dir") {
+ push @include, "-I$appath/$dir";
+ }
+ }
+ closedir D;
+}
+
+if (!empty($ENV{APBUILD_PROJECTNAME})) {
+ push @linking, '-Wl,--rpath,${ORIGIN}/../lib/' . $ENV{APBUILD_PROJECTNAME};
+}
+
+
+our %capabilities = $gcc->capabilities;
+if ($capabilities{hash_style}) {
+ # By default FC6 only generates a .gnu.hash section, not
+ # .hash (which is the only thing that FC5 and most other
+ # distros understand).
+ # Force generation of both sections if the linker supports it
+ # so that the binary will run on other systems.
+ # See http://fcp.surfsite.org/modules/newbb/viewtopic.php?topic_id=29929&forum=10&post_id=128939
+ # for more details
+ push @linking, '-Wl,--hash-style=both';
+}
+
+if ($capabilities{stack_protector}) {
+ # gcc-4.1 introduced stack protection to help check for
+ # buffer overflows. This introduces a silent dependency on
+ # glibc 2.4 (__stack_chk_fail@@GLIBC_2.4)
+ # Not many people have glibc 2.4 yet, so disable it.
+ push @include, "-fno-stack-protector";
+}
+
+if ($capabilities{fortify_source}) {
+ # Some distros (e.g. Ubuntu 8.10) activate a bufferoverflow protection
+ # which is only available since glibc 2.3.4. Apbuild removes all symbols
+ # newer then 2.3, so this can't be used.
+ push @include, "-U_FORTIFY_SOURCE";
+}
+
+our %capabilities_gxx2;
+%capabilities_gxx2 = $gxx2->capabilities if ($gxx2);
+push @linking, $libgcc if ($capabilities{libgcc});
+
+
+############# Detect compilation situation #############
+
+our $situation = $gcc->situation(\@ARGV);
+if ($ENV{APBUILD_CXX_MODE}) {
+ debug "apg++ @ARGV\n";
+} else {
+ debug "apgcc @ARGV\n";
+}
+debug "Situation: $situation\n";
+
+
+# Handle each situation
+# Only situations that involve compiling or linking need to be treated specially
+if ($situation eq 'compile') {
+ # Extract the parameters and files
+ my (@files, @params);
+ $gcc->splitParams(\@ARGV, \@files, \@params);
+
+ # Compile each source file to an object file.
+ # Force GCC to compile C/C++ source files with older glibc symbols.
+ debug "\@files: is @files\n";
+ foreach my $file (@files) {
+ if ($gxx2 && $gxx2->isCxxSource($file)) {
+ # This is a C++ source file. Compile the file twice with different ABIs.
+ my $src = $file;
+ my $old_gcc;
+ my %old_cap;
+
+ compileSource($src, \@ARGV);
+
+ $old_gcc = $gcc;
+ %old_cap = %capabilities;
+ $gcc = $gxx2;
+ %capabilities = %capabilities_gxx2;
+
+ beginDoubleCompiling();
+ compileSource($src, \@ARGV, '.GCCABI2');
+ endDoubleCompiling();
+
+ $gcc = $old_gcc;
+ %capabilities = %old_cap;
+
+ } else {
+ compileSource($file, \@ARGV);
+ }
+ }
+ exit;
+
+} elsif ($situation eq 'linking') {
+ linkObjects(\@ARGV);
+
+ if ($gxx2) {
+ # Check whether there are .GCCABI2 objects. Link them if there are.
+ my @options;
+ my $doubleCompile;
+
+ my $callback = sub {
+ my $type = shift;
+
+ if ($type eq 'param' && ($gxx2->isLibrary($_[0]) || $gxx2->isObject($_[0])) && !$gxx2->isStaticLib($_[0]) && -f "$_[0].GCCABI2") {
+ push @options, "$_[0].GCCABI2";
+ $doubleCompile = 1;
+ } else {
+ push @options, @_;
+ }
+ };
+
+ $gcc = $gxx2;
+ %capabilities = %capabilities_gxx2;
+
+ $gcc->foreach(\@ARGV, $callback);
+
+ if ($doubleCompile) {
+ debug "Double compiling.\n";
+ beginDoubleCompiling();
+ linkObjects(\@options, ".GCCABI2");
+ endDoubleCompiling();
+ }
+ }
+ exit;
+} elsif ($situation eq 'precompiled header') {
+ # Extract the parameters and files
+ my (@files, @params);
+ $gcc->splitParams(\@ARGV, \@files, \@params);
+
+ # Compile each source file to an object file.
+ # Force GCC to compile C/C++ source files with older glibc symbols.
+ debug "\@files: is @files\n";
+ foreach my $file (@files)
+ {
+ compileSource($file, \@ARGV);
+ }
+} elsif ($situation eq 'compile and link') {
+ # Extract the parameters and files
+ my (@params, @files, @linking2);
+ my @command;
+ my $status;
+
+ # Seperate files and linker options.
+ # @params are all options except linker options, and is used for compilation of each individual source file.
+ # @files are the source files.
+ $gcc->splitParams(\@ARGV, \@files, \@params);
+ $gcc->stripLinkerParams(\@params, \@linking2);
+
+ # Compile & link only one source file
+ if (@files == 1) {
+ my @options = modifyLinkerOptions(@params);
+ push @options, @linking2;
+
+ if ($gxx2 && $gxx2->isCxxSource($files[0])) {
+ # This is a C++ file. Compile twice with different ABIs.
+ compileSource($files[0], \@ARGV);
+ manipulateDeps(@options);
+
+ $gcc = $gxx2;
+ %capabilities = %capabilities_gxx2;
+
+ beginDoubleCompiling();
+ compileSource($files[0], \@ARGV, '.GCCABI2');
+ manipulateDeps(@options);
+ endDoubleCompiling();
+
+ } else {
+ compileSource($files[0], [@linking, @options], undef);
+ manipulateDeps($files[0], @options);
+ }
+
+ exit;
+ }
+
+ # Compile individual files into objects
+ my $cxx;
+ debug "Multiple source files: @files\n";
+ foreach my $file (@files) {
+ my $out = $file;
+ $out =~ s/^(.*)\..*?$/$1.o/;
+
+ if ($gxx2 && $gxx2->isCxxSource($file)) {
+ # This is a C++ file. Compile twice with different ABIs.
+ my $old_gcc;
+ my %old_cap;
+
+ $cxx = 1;
+ compileSource($file, [@ARGV, '-c']);
+
+ $old_gcc = $gcc;
+ %old_cap = %capabilities;
+ $gcc = $gxx2;
+ %capabilities = %capabilities_gxx2;
+
+ beginDoubleCompiling();
+ compileSource($file, [@ARGV, '-c'], '.GCCABI2');
+ endDoubleCompiling();
+
+ $gcc = $old_gcc;
+ %capabilities = %old_cap;
+
+ } else {
+ compileSource($file, [@params, '-c'], undef);
+ }
+
+ $file = $out;
+ }
+
+ # Finally, link all objects together.
+ my @options = (@params, @linking2);
+ linkObjects([@files, @options]);
+
+ if ($cxx) {
+ $gcc = $gxx2;
+ %capabilities = %capabilities_gxx2;
+
+ # Also link the objects with ABI 2 together
+ foreach (@files) {
+ $_ .= ".GCCABI2";
+ }
+ beginDoubleCompiling();
+ linkObjects([@files, @options], '.GCCABI2');
+ endDoubleCompiling();
+ }
+ exit;
+
+} else {
+ my $ret = run($gcc->command, @ARGV);
+ if (defined $ARGV[0] && $ARGV[0] eq '--help') {
+ print "\napbuild environment variables:\n";
+ print " APBUILD_PATH=path Specifies the include path for apsymbols.h\n" .
+ " (like: /usr/local/include/apbuild)\n" .
+ " APBUILD_DEBUG=1 Enable debugging messages\n" .
+ " APBUILD_BOGUS_DEPS=deps Specify a list of whitespace-seperated bogus\n" .
+ " library dependancies (like: X11 ICE png). These\n" .
+ " libraries will not be linked.\n" .
+ " APBUILD_STATIC=deps Specify a list of whitespace-seperated libraries\n" .
+ " to statically link to (like: popt z). You can also\n" .
+ " explicitly specify a filename to the static library.\n" .
+ " Example: popt=/usr/lib/libpopt.a\n" .
+ " APBUILD_STATIC_X=1 Force static linking of some X extension libraries\n" .
+ " Don't use this unless you know what you're doing.\n" .
+ " APBUILD_DISABLE_BOGUS_DETECTOR=1 Disable the automatic bogus dependancy\n" .
+ " detector. This is useful when linking to libraries\n" .
+ " don't have correct DT_NEEDED entries, like GTK 1.2.\n" .
+ " APBUILD_NOT_BOGUS=deps If you want to use the automatic bogus dependancy\n" .
+ " dectector anyway, then you can specify a list of\n" .
+ " dependancies here that are not bogus.\n" .
+ " APBUILD_STATIC_LIBGCC=1 Link all binaries with -static-libgcc. See the gcc\n" .
+ " info page for more info about this option.\n" .
+ " APBUILD_PROJECTNAME If non-empty, apbuild will add\n" .
+ " \$ORIGIN/../lib/\$APBUILD_PROJECTNAME to the library\n" .
+ " search path.\n" .
+ " APBUILD_INCLUDE Prepend the specified directory to the compiler's\n" .
+ " header search path. The compiler will search this\n" .
+ " directory first, before searching any other\n" .
+ " directory. This is useful in combination with the\n" .
+ " older GTK headers package (see the autopackage\n" .
+ " website). You can specify multiple directories,\n" .
+ " seperated by a ':', just like the \$PATH environment\n" .
+ " variable.\n" .
+ " APBUILD_NO_RPATH Do not add rpath entries during linking.\n" .
+ " APBUILD_CC Use the specified C compiler. Default value: gcc\n" .
+ " APBUILD_CXX1,APBUILD_CXX2 Use the specified C++ compiler. Default value: g++\n" .
+ " Set both variables to enable double compiling. The\n" .
+ " first should be set to the g++ 3.2 compiler and the\n" .
+ " second should be set to the g++ 3.4 (or newer)\n" .
+ " compiler.\n" .
+ " APBUILD_RESOLVE_LIBPATH A whitespace-separated list of regular expressions which\n" .
+ " specify the libraries whose path must be resolved into\n" .
+ " an absolute path.\n";
+ }
+ exit $ret;
+}
+
+
+######## Functions ########
+
+
+sub modifyLinkerOptions {
+ my @argv = @_;
+
+ # Remove manually specified bogus library dependancies
+ my @bogusDeps;
+ @bogusDeps = split / +/, $ENV{APBUILD_BOGUS_DEPS} if (!empty($ENV{APBUILD_BOGUS_DEPS}));
+
+ # We call removeLibraries() twice because it may detect
+ # some dependancies after we've resolved the library names
+ @argv = removeLibraries(\@bogusDeps, @argv);
+ @argv = translateLibNames(@argv);
+ @argv = removeLibraries(\@bogusDeps, @argv);
+
+ @argv = removeStaticGlibc(@argv);
+ if ($capabilities{as_needed}) {
+ @argv = rearrangeForAsNeeded(@argv);
+ @argv = forceStatic(@argv);
+ }
+
+ return @argv;
+}
+
+
+sub removeLibraries {
+ my $blacklist = shift;
+ return @_ if (@{$blacklist} == 0);
+
+ my @args;
+ my $callback = sub {
+ my $type = shift;
+ if ($type ne "param") {
+ push @args, @_;
+ return;
+ }
+
+ my $lib;
+ $_ = $_[0];
+ if (/^-l(.+)/) {
+ $lib = $1
+ } elsif (/(.*)\/lib(.+)\.so/) {
+ $gcc->addSearchPaths($1);
+ $lib = $2;
+ } else {
+ push @args, @_;
+ return;
+ }
+
+ # We now have a library parameter; remove this parameter
+ # if the library's in the blacklist
+ foreach my $dep (@{$blacklist}) {
+ return if ($lib eq $dep);
+ }
+ push @args, @_;
+ };
+
+ $gcc->foreach(\@_, $callback);
+ return @args;
+}
+
+
+# This function translates library linker options to something saner.
+# - On my system, -lpng links to libpng.so. However, libpng.so is a symlink to libpng12.so.
+# This function translates -lpng to -lpng12 so that the automatic bogus dependancy stripper
+# can detect this as a bogus dependancy.
+# - Translate /usr/lib/libpng.so to /usr/lib/libpng12.so because the soname is different.
+# - Translates -pthread to -lpthread.
+# - When in C++ mode, removes libstdc++.so from the argument list. This causes trouble when
+# double compiling, unless the -nostdlib option is specified and we're not double compiling.
+# libtool can put us in this configuration.
+
+# TODO: correctly handle static libraries.
+# apg++ ... -L/usr/lib -Wl,-Bstatic -lphysfs -Wl,-Bdynamic
+# -> /usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.5/../../../../i686-pc-linux-gnu/bin/ld: cannot find -lphysfs-1.0
+sub translateLibNames {
+ my (@args, @searchPaths);
+
+ # Get a list of search paths
+ $gcc->getSearchPaths(\@_, \@searchPaths);
+
+ my $staticMode = 0;
+ my $callback = sub {
+ my $type = shift;
+ my $dontAdd;
+
+ if ($type ne 'param') {
+ push @args, @_;
+ return;
+ }
+
+ $_ = $_[0];
+ if (/^-Wl,(.+)/) {
+ # Detect whether the next library will be linked statically or dynamically
+ foreach my $arg (split /,/, $1) {
+ if ($arg eq '-Bdynamic') {
+ $staticMode = 0;
+ } elsif ($arg eq '-Bstatic') {
+ $staticMode = 1;
+ }
+ }
+
+ } elsif ($staticMode) {
+ # Don't try to resolve library name if it's linked statically
+
+ } elsif (/^-l(.+)/ || /--library=(.+)/) {
+ my $libname = $1;
+
+ # Resolve libname if explicitely asked to, through APBUILD_RESOLVE_LIBPATH.
+ my @libtosolve = split / +/, $ENV{APBUILD_RESOLVE_LIBPATH} if (!empty($ENV{APBUILD_RESOLVE_LIBPATH}));
+ foreach (@libtosolve) {
+ my $regexp = $_;
+ if ($libname =~ /($regexp)/) {
+ my $file = searchLib("lib$libname.a", \@searchPaths);
+ if ($file && -f $file) {
+ debug "resolved", $_[0], "as", $file;
+ # Replace -lXXX with the absolute path for libXXX.a
+ $_[0] = $file;
+ last;
+ }
+ }
+ }
+
+ # Library is a symlink; check whether the sonames match
+ my $lib = searchLib("lib$libname.so", \@searchPaths);
+ if ($lib && -l $lib) {
+ my ($soname1) = $lib =~ /.*\/lib(.+)\.so/;
+ my $lib2 = soname($lib);
+ my ($soname2) = $lib2 =~ /lib(.+)\.so/;
+
+ if ($soname1 ne $soname2 && defined searchLib("lib$soname2.so", \@searchPaths)) {
+ $_[0] = "-l$soname2";
+ }
+ }
+
+ } elsif ($_ eq '-pthread') {
+ $_[0] = "-lpthread";
+
+ } elsif ($ENV{APBUILD_CXX_MODE} && /\/?libstdc\+\+\.so(.[56])?/) {
+ # drop this in double compile mode as it can cause issues
+ # in single-compile mode leave it alone, otherwise, libtool can break
+ # ^^^ That used to be true
+ # Now drop it and add the compilers stdc++
+ # Works around libtool problems where the wrong libstdc++.so is
+ # picked up from .la files of dependencies
+ my @command = ($gcc->command, "--print-file-name=libstdc++.so");
+ chomp($_[0] = `@command`);
+
+ } elsif (/(.*)\/?(lib.+\.so.*)/) {
+ $gcc->addSearchPaths ($1);
+ push @searchPaths, $1;
+ my $lib = searchLib($2, \@searchPaths);
+ if (defined $lib) {
+ my $soname = soname($lib);
+ $lib = searchLib($soname, \@searchPaths);
+ $_[0] = $lib if (defined $lib);
+ }
+ }
+ push @args, @_ if (!$dontAdd);
+ };
+ $gcc->foreach(\@_, $callback);
+
+ return @args;
+}
+
+
+# Replace -static with something else. We can't statically link to glibc!
+# So we statically link to everything but glibc.
+sub removeStaticGlibc {
+ my $hasStatic = 0;
+ foreach (@_) {
+ if ($_ eq '-static') {
+ $hasStatic = 1;
+ last;
+ }
+ }
+ return @_ if (!$hasStatic);
+
+ my @argv;
+ foreach (@_) {
+ if ((/^-l(.+)/ || /^--library=(.+)/) && defined $1 && $1 ne 'c') {
+ push @argv, '-Wl,-Bstatic';
+ push @argv, $_;
+ push @argv, '-Wl,-Bdynamic';
+ } elsif ($_ ne "-static") {
+ push @argv, $_;
+ }
+ }
+ return @argv;
+}
+
+
+# 'gcc -Wl,--as-needed foo.o -lpng' breaks the binary.
+# 'gcc foo.o -Wl,--as-needed -lpng' doesn't.
+# Move object files to before the first library flag.
+#
+# Furthermore, -lbfd and -liberty must be the last arguments, or
+# an app won't link properly in some cases. XRender needs to be
+# after XCursor for some reason, so push it to the end too.
+sub rearrangeForAsNeeded {
+ my @args;
+ my @nonParams;
+ my @last;
+
+ my $callback = sub {
+ my $type = shift;
+
+ if ($type ne "param") {
+ push @nonParams, @_;
+
+ } elsif ($_[0] eq "-lbfd" || $_[0] eq "-liberty" || $_[0] eq "-lXrender") {
+ push @last, @_;
+
+ } elsif ($gcc->isLibrary($_[0])) {
+ push @args, @_;
+
+ } elsif ($gcc->isObject($_[0]) || $gcc->linkOrderIsImportant($_[0])) {
+ push @nonParams, @_;
+
+ } else {
+ push @args, @_;
+ }
+ };
+
+ $gcc->foreach(\@_, $callback);
+ unshift @args, "-Wl,--as-needed";
+ unshift @args, @nonParams;
+ push @args, @last;
+ return @args;
+}
+
+
+################ Automatic bogus dependancy stripper ################
+
+
+# Automatically detecting bogus dependancies & force static linking to certain X libraries
+sub manipulateDeps {
+ return if ($capabilities{as_needed});
+ my @searchPaths;
+ my $output = 'a.out';
+ my $i = 0;
+ my @deps;
+ my @argv;
+
+ if ($ENV{APBUILD_DISABLE_BOGUS_DETECTOR}) {
+ @argv = @_;
+ goto FINAL;
+ }
+
+ # Get a list of search paths and the output filename
+ for ($i = 0; $i < @_; $i++) {
+ if ($_[$i] eq "-L") {
+ push (@searchPaths, $_[$i + 1]) if (defined $_[$i + 1]);
+ $i++;
+ } elsif ($_[$i] =~ /^-L(.+)/ || $_[$i] =~ /^--library-path=(.+)/) {
+ push (@searchPaths, $1);
+ } elsif ($_[$i] eq "-o") {
+ $output = $_[$i + 1] if (defined $_[$i + 1]);
+ $i++;
+ }
+ }
+
+ # Find out what libraries the executable needs
+ my ($r, $w);
+ my $pid = open2 ($r, $w, 'objdump', '-p', $output);
+ close ($w);
+ foreach (<$r>) {
+ next unless (/^ NEEDED/);
+ s/^ NEEDED[ \t]+//;
+ s/\n//;
+ my $lib = searchLib ($_, \@searchPaths);
+ push (@deps, $lib) if (defined $lib);
+ }
+ close ($r);
+ waitpid ($pid, 0);
+
+ # Some -l options have no effect. For example, when linking apollon,
+ # -lXinerama is passed, yet the resulting executable doesn't have a
+ # DT_NEEDED entry for libXinerama.so. Remove those options so that
+ # they won't interfere with forceStatic().
+ foreach (@_) {
+ if ((/^-l(.+)/ || /^--library=(.+)/)
+ && !searchLib("lib$1.a", \@searchPaths)
+ && !(/^-lpng$/) # Special case the libpng mess, bah
+ ) {
+ # "Xinerama"
+ my $arg = $1;
+ # Only add to @argv if $arg is in @deps
+ foreach my $dep (@deps) {
+ # "/usr/X11R6/lib/libXinerama.so.1" -> "Xinerama"
+ my ($soname) = $dep =~ /.*\/lib(.+)\.so/;
+ if ($arg eq $soname) {
+ push (@argv, "-l$arg");
+ last;
+ }
+ }
+ } else {
+ push (@argv, $_);
+ }
+ }
+
+ # Find out which symbols the executable needs, and which symbols are provided
+ # by the libraries it's linked to.
+ my %appsyms = extractSymbols ('UBV', $output);
+ my @bogusDeps;
+
+ foreach my $lib (@deps) {
+ # Never remove libc, libgcc_s and libstdc++
+ next if ($lib =~ /^\/lib\/lib(c|gcc_s|stdc\+\+)\.so/);
+
+ my %libsyms = extractSymbols ('TBVRDSWG', $lib);
+ my $bogus = 1;
+
+ foreach my $sym (keys %libsyms) {
+ if (defined $appsyms{$sym}) {
+ debug ("Real dependancy $lib: $sym (lib: $libsyms{$sym} - app: $appsyms{$sym})\n");
+ $bogus = 0;
+ last;
+ }
+ }
+
+ if ($bogus) {
+ my ($soname) = $lib =~ /.*\/lib(.+)\.so/;
+ push (@bogusDeps, $soname);
+ }
+ }
+
+ FINAL: {
+ # Don't strip dependancies that are explicitly marked as not bogus
+ my %notBogus;
+ if (!empty($ENV{APBUILD_NOT_BOGUS})) {
+ foreach (split / +/, $ENV{APBUILD_NOT_BOGUS}) {
+ $notBogus{$_} = 1;
+ }
+ }
+
+ my @tmp;
+ foreach (@bogusDeps) {
+ push @tmp, $_ if (!$notBogus{$_});
+ }
+ @bogusDeps = @tmp;
+
+ my @options = removeLibraries(\@bogusDeps, @argv);
+ @options = forceStatic(@options);
+
+ if ("@options" ne "@argv") {
+ my @command = ($gcc->command, @include, @linking, @options);
+ debug("Bogus dependancies: @bogusDeps\n") if (@bogusDeps);
+ debug("Relinking: @command\n");
+ my $status = run(@command);
+ exit($status) if ($status != 0);
+ }
+ }
+}
+
+sub extractSymbols {
+ my $types = shift;
+ my %symbols = ();
+ my ($r, $w);
+ my $pid = open2 ($r, $w, 'nm', '-D', @_);
+
+ close ($w);
+ foreach (<$r>) {
+ if (/^.{9}[$types]/) {
+ s/\n//;
+ s/^.{9}//;
+ my ($type, $name) = split (/ /, $_, 2);
+ $symbols{$name} = $type;
+ }
+ }
+ close ($r);
+ waitpid ($pid, 0);
+ return %symbols;
+}
+
+
+# Force static linking against libraries in $APBUILD_STATIC and certain X libraries.
+sub forceStatic {
+ my (%xlibs, %staticList, $X11linked, $linkedToStaticX);
+ my (@args, @searchPaths);
+
+ # Create a list of libraries that we want to statically link
+ $gcc->getSearchPaths(\@_, \@searchPaths);
+ if (defined $ENV{'APBUILD_NO_STATIC_X'}) {
+ warn "WARNING: APBUILD_NO_STATIC_X is no longer used because it became the default behaviour.\n";
+ }
+ if (defined $ENV{'APBUILD_STATIC_X'} && $ENV{'APBUILD_STATIC_X'} eq "1") {
+ foreach (qw(Xrender Xcursor Xfixes Xi Xinerama Xrandr Xv Xxf86dga Xxf86misc Xxf86vm)) {
+ my $file = searchLib("lib$_.a", \@searchPaths);
+ $staticList{$_} = $file if (defined $file);
+ $xlibs{$_} = 1;
+ }
+ }
+
+ my @static_deps;
+ if (!empty($ENV{APBUILD_STATIC})) {
+ foreach (split / +/, $ENV{APBUILD_STATIC}) {
+ my ($lib, $file) = split /=/, $_, 2;
+ $file = searchLib("lib$lib.a", \@searchPaths) if (!defined $file);
+ $staticList{$lib} = $file if (defined $file);
+
+ if (defined $file) {
+ # find the DT_NEEDED entries that this library-to-be-made-static
+ # has so that final linking works (the deps need to be added after the static lib so the bogus stripper doesn't remove them)
+ my ($r, $w);
+ my $abslib = searchLib("lib$lib.so", \@searchPaths);
+ if (!defined $abslib) {
+ warn "WARNING: Failed to find lib$lib.so in " . join(":", @searchPaths) . ".\n";
+ next;
+ }
+ my $pid = open2 ($r, $w, 'objdump', '-p', $abslib);
+ close ($w);
+ foreach (<$r>) {
+ next unless (/^ NEEDED\s+lib(.+?)\.so/);
+ s/^ NEEDED\s+lib(.+?)\.so(.*)/$1/;
+ s/\n//;
+ push(@static_deps, "-l$_");
+ }
+ close ($r);
+ waitpid ($pid, 0);
+ }
+ }
+ }
+
+ push (@_, @static_deps);
+
+ # Modify linker options for static linking
+ my $callback = sub {
+ my $type = shift;
+ my $libname;
+ if ($type eq "param" && $gcc->isLibrary($_[0], \$libname)) {
+ $X11linked = 1 if (!$X11linked && $libname eq 'X11');
+ if ($staticList{$libname}) {
+ # This parameter is a library and is in the list of libraries
+ # to statically link; replace parameter by a filename to the
+ # static library
+ push @args, $staticList{$libname};
+ $linkedToStaticX = 1 if ($xlibs{$libname});
+
+ if ($libname eq "Xcursor") {
+ # With some versions of X11 (on Slack 11,
+ # xorg 6.9.0, anyway), Xcursor links against Xfixes.
+ # If we switch Xcursor to being linked statically,
+ # force linking of Xfixes too so we don't get
+ # undefined symbol errors from Xcursor.
+ push @args, $staticList{"Xfixes"};
+ }
+
+ } else {
+ push @args, @_;
+ }
+
+ } else {
+ push @args, @_;
+ }
+ };
+ $gcc->foreach(\@_, $callback);
+
+ # The app must be linked to libX11 if it has statically linked any the static X libraries
+ push @args, "-lX11" if ($linkedToStaticX && !$X11linked);
+ return @args;
+}
+
+##
+# compileSource(source, argss, extension, extra...)
+# source: the source filename.
+# args: the full GCC arguments (may include other source files) used for compilation.
+# extension: if not undef, $extension will be appended to the output object file's filename.
+# extra: extra parameters to pass to the compiler.
+sub compileSource {
+ my ($source, $args, $ext) = @_;
+ my (@command, @tmp, @params, @sourceParams, @otherParams);
+
+ $gcc->splitParams($args, undef, \@tmp);
+ push @tmp, $source;
+
+ if (defined $ext) {
+ # Change the output file's extension.
+ $gcc->setOutputFile(\@tmp, $gcc->getOutputFile(\@tmp) . $ext);
+ }
+ $gcc->splitParams(\@tmp, undef, \@params);
+
+ my $callback = sub {
+ my $type = shift;
+ if ($type eq 'param' && $gcc->sourceOrderIsImportant($_[0])) {
+ push @sourceParams, @_;
+ } else {
+ push @otherParams, @_;
+ }
+ };
+ $gcc->foreach(\@params, $callback);
+
+ if ($source =~ /\.($srcTypes)$/) {
+ @command = ($gcc->command, @include, @sourceParams, $source, @otherParams);
+ } else {
+ @command = ($gcc->command, @sourceParams, $source, @otherParams);
+ }
+
+ debug "@command\n";
+ my $status = run(@command);
+ exit($status) if ($status != 0);
+}
+
+# Checks whether there should be an ABI2 version of a certain static library.
+sub checkStaticLibrary {
+ my ($lib, $ext) = @_;
+ my ($pid, $r, $w, @objects, $doubleCompile);
+ my (undef, $libdir, $libname) = File::Spec->splitpath($lib);
+ my $newlib = "$lib$ext";
+
+ # Return the ABI2 version if already exists.
+ return $newlib if (-f $newlib);
+
+ # Check the content of the archive. Check whether
+ # there are ABI2 versions of the object files inside.
+ $pid = open2($r, $w, 'ar', 't', $lib);
+ close($w);
+ while ((my $file = <$r>)) {
+ $file =~ s/\n//g;
+ if (-f "$libdir/$file$ext") {
+ push @objects, "$file$ext";
+ $doubleCompile = 1;
+ } else {
+ push @objects, $file;
+ }
+ }
+ close($r);
+ waitpid ($pid, 0);
+
+ if ($doubleCompile) {
+ my $oldDir = getcwd();
+ $newlib = "$libname$ext";
+ debug "Creating static library $newlib\n";
+
+ chdir($libdir);
+ my @command = ("ar", "cru", $newlib, @objects);
+ debug(@command);
+ my $ret = run(@command);
+ exit($ret) if ($ret != 0);
+
+ @command = ("ranlib", $newlib);
+ debug(@command);
+ $ret = run(@command);
+ exit($ret) if ($ret != 0);
+
+ chdir($oldDir);
+ return $newlib;
+ } else {
+ return undef;
+ }
+}
+
+sub linkObjects {
+ my ($args, $ext) = @_;
+ my @options = modifyLinkerOptions(@{$args});
+
+ if (defined $ext) {
+ $gcc->setOutputFile(\@options, $gcc->getOutputFile(\@options) . $ext);
+
+ # Check whether this object links to any static libraries.
+ # If it does, check whether there should be an ABI2 version of that
+ # static library, and attempt to create it.
+ my @options2;
+
+ my $callback = sub {
+ my $type = shift;
+ if ($type eq 'param' && $gcc->isStaticLib($_[0])) {
+ my $newlib = checkStaticLibrary($_[0], $ext);
+ if (defined $newlib) {
+ push @options2, $newlib;
+ } else {
+ push @options2, @_;
+ }
+ } else {
+ push @options2, @_;
+ }
+ };
+ $gcc->foreach(\@options, $callback);
+ @options = @options2;
+ }
+
+ my @command = ($gcc->command, @linking, @options);
+ debug "@command\n";
+
+ my $status = run(@command);
+ exit ($status) if ($status != 0);
+
+ my (@files, @options2);
+ $gcc->splitParams(\@options, \@files, \@options2);
+ manipulateDeps(@files, @options2);
+}
+
+##
+# beginDoubleCompiling()
+#
+# Prepare the environment for double compiling.
+sub beginDoubleCompiling {
+ # Since g++ will be executed another time, we don't want it to
+ # print output to stdout/stderr, because it can potentially
+ # screw up some build systems such as libtool.
+ # stderr will go to the console (/dev/tty), stdout will be
+ # lost (/dev/null).
+
+ our $stdout_fd = fileno(STDOUT);
+ our $stderr_fd = fileno(STDERR);
+ our $stdout_saved = POSIX::dup($stdout_fd);
+ our $stderr_saved = POSIX::dup($stderr_fd);
+
+ my $fd1 = POSIX::open("/dev/null", O_CREAT | O_WRONLY, 0644);
+ my $fd2 = POSIX::open("/dev/tty", O_CREAT | O_WRONLY, 0644);
+ POSIX::dup2($fd1, $stdout_fd);
+ POSIX::dup2($fd2, $stderr_fd);
+ POSIX::close($fd1);
+ POSIX::close($fd2);
+}
+
+##
+# endDoubleCompiling()
+#
+# Unprepare the environment for double compiling.
+sub endDoubleCompiling {
+ our ($stdout_fd, $stderr_fd, $stdout_saved, $stderr_saved);
+
+ POSIX::dup2($stdout_saved, $stdout_fd);
+ POSIX::dup2($stderr_saved, $stderr_fd);
+ POSIX::close($stdout_saved);
+ POSIX::close($stderr_saved);
+}
diff --git a/tools/apbuild/apsymbols.h b/tools/apbuild/apsymbols.h
new file mode 100644
index 00000000..32c7b18c
--- /dev/null
+++ b/tools/apbuild/apsymbols.h
@@ -0,0 +1,275 @@
+/* apbuild embedded metadata */
+#define APBUILD_NOTE_METADATA(s) __asm__(".section .metadata, \"MS\", @note, 1\n\t.string \"" s "\"\n\t.previous\n\t")
+
+#ifdef APBUILD_VERSION
+APBUILD_NOTE_METADATA("apbuild.version=" APBUILD_VERSION);
+#endif
+
+/* apbuild generated symbol exclusion list */
+__asm__(".symver _sys_errlist,_sys_errlist@GLIBC_2.0");
+__asm__(".symver _sys_nerr,_sys_nerr@GLIBC_2.0");
+__asm__(".symver _sys_siglist,_sys_siglist@GLIBC_2.0");
+__asm__(".symver clnt_pcreateerror,clnt_pcreateerror@GLIBC_2.0");
+__asm__(".symver clnt_spcreateerror,clnt_spcreateerror@GLIBC_2.0");
+__asm__(".symver feupdateenv,feupdateenv@GLIBC_2.1");
+__asm__(".symver lio_listio,lio_listio@GLIBC_2.1");
+__asm__(".symver lio_listio64,lio_listio64@GLIBC_2.1");
+__asm__(".symver nftw,nftw@GLIBC_2.1");
+__asm__(".symver nftw64,nftw64@GLIBC_2.1");
+__asm__(".symver posix_fadvise64,posix_fadvise64@GLIBC_2.2");
+__asm__(".symver posix_fallocate64,posix_fallocate64@GLIBC_2.2");
+__asm__(".symver pthread_cond_broadcast,pthread_cond_broadcast@GLIBC_2.0");
+__asm__(".symver pthread_cond_destroy,pthread_cond_destroy@GLIBC_2.0");
+__asm__(".symver pthread_cond_init,pthread_cond_init@GLIBC_2.0");
+__asm__(".symver pthread_cond_signal,pthread_cond_signal@GLIBC_2.0");
+__asm__(".symver pthread_cond_timedwait,pthread_cond_timedwait@GLIBC_2.0");
+__asm__(".symver pthread_cond_wait,pthread_cond_wait@GLIBC_2.0");
+__asm__(".symver regexec,regexec@GLIBC_2.0");
+__asm__(".symver rpc_createerr,rpc_createerr@GLIBC_2.0");
+__asm__(".symver sys_errlist,sys_errlist@GLIBC_2.0");
+__asm__(".symver sys_nerr,sys_nerr@GLIBC_2.0");
+__asm__(".symver sys_sigabbrev,sys_sigabbrev@GLIBC_2.0");
+__asm__(".symver sys_siglist,sys_siglist@GLIBC_2.0");
+__asm__(".symver vm86,vm86@GLIBC_2.0");
+__asm__(".symver __rpc_thread_createerr,__rpc_thread_createerr@GLIBC_2.2.3");
+__asm__(".symver __guard,__guard@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __gethostname_chk,__gethostname_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver epoll_create,epoll_create@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __getdomainname_chk,__getdomainname_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vswprintf_chk,__vswprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __stpcpy_chk,__stpcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver timerfd_gettime,timerfd_gettime@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inotify_init1,inotify_init1@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcstombs_chk,__wcstombs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __printf_chk,__printf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fgetws_chk,__fgetws_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __register_atfork,__register_atfork@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver gnu_dev_major,gnu_dev_major@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vfwprintf_chk,__vfwprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcpcpy_chk,__wcpcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver open_wmemstream,open_wmemstream@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_append,inet6_opt_append@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver timerfd_create,timerfd_create@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __swprintf_chk,__swprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver getipv4sourcefilter,getipv4sourcefilter@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vwprintf_chk,__vwprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver readlinkat,readlinkat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wctomb_chk,__wctomb_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __readlink_chk,__readlink_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver setipv4sourcefilter,setipv4sourcefilter@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_sscanf,__isoc99_sscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __getlogin_r_chk,__getlogin_r_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver sync_file_range,sync_file_range@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __open64_2,__open64_2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_init,inet6_rth_init@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_next,inet6_opt_next@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fxstatat64,__fxstatat64@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver unlinkat,unlinkat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fwprintf_chk,__fwprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __mempcpy_chk,__mempcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver epoll_wait,epoll_wait@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mkfifoat,mkfifoat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_scanf,__isoc99_scanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __read_chk,__read_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fgetws_unlocked_chk,__fgetws_unlocked_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vsprintf_chk,__vsprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcsncpy_chk,__wcsncpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __stack_chk_fail,__stack_chk_fail@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inotify_rm_watch,inotify_rm_watch@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver xdr_quad_t,xdr_quad_t@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __sched_cpualloc,__sched_cpualloc@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __obstack_vprintf_chk,__obstack_vprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_swscanf,__isoc99_swscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vfwscanf,__isoc99_vfwscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __sched_cpufree,__sched_cpufree@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_finish,inet6_opt_finish@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __confstr_chk,__confstr_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcsncat_chk,__wcsncat_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver setsourcefilter,setsourcefilter@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver xdr_u_quad_t,xdr_u_quad_t@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fread_unlocked_chk,__fread_unlocked_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver eaccess,eaccess@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_alloc,inet6_option_alloc@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __openat64_2,__openat64_2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver sched_setaffinity,sched_setaffinity@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_append,inet6_option_append@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver futimens,futimens@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver renameat,renameat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wmemset_chk,__wmemset_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_get_val,inet6_opt_get_val@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver unshare,unshare@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vsscanf,__isoc99_vsscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver signalfd,signalfd@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_next,inet6_option_next@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_add,inet6_rth_add@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver semtimedop,semtimedop@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver utimensat,utimensat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_segments,inet6_rth_segments@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pread_chk,__pread_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __syslog_chk,__syslog_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver eventfd,eventfd@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fgets_unlocked_chk,__fgets_unlocked_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __getcwd_chk,__getcwd_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver fchmodat,fchmodat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver dup3,dup3@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vprintf_chk,__vprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fprintf_chk,__fprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wmemcpy_chk,__wmemcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_wscanf,__isoc99_wscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcscpy_chk,__wcscpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_fscanf,__isoc99_fscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __mbstowcs_chk,__mbstowcs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __dprintf_chk,__dprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wmempcpy_chk,__wmempcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver symlinkat,symlinkat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __memmove_chk,__memmove_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __getwd_chk,__getwd_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vsnprintf_chk,__vsnprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mkostemp64,mkostemp64@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver eventfd_read,eventfd_read@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver remap_file_pages,remap_file_pages@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vswscanf,__isoc99_vswscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver fdopendir,fdopendir@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __openat_2,__openat_2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fgets_chk,__fgets_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __strncpy_chk,__strncpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __sched_cpucount,__sched_cpucount@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __mbsrtowcs_chk,__mbsrtowcs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcscat_chk,__wcscat_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_space,inet6_option_space@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver sched_getaffinity,sched_getaffinity@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __open_2,__open_2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver fchownat,fchownat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver timerfd_settime,timerfd_settime@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver sched_getcpu,sched_getcpu@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __getgroups_chk,__getgroups_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_init,inet6_opt_init@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __snprintf_chk,__snprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mkdirat,mkdirat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __memset_chk,__memset_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __strncat_chk,__strncat_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_space,inet6_rth_space@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __recv_chk,__recv_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_reverse,inet6_rth_reverse@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __stack_smash_handler,__stack_smash_handler@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __realpath_chk,__realpath_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver qsort_r,qsort_r@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __obstack_printf_chk,__obstack_printf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_rth_getaddr,inet6_rth_getaddr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver splice,splice@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver eventfd_write,eventfd_write@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver vmsplice,vmsplice@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver getsourcefilter,getsourcefilter@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vwscanf,__isoc99_vwscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver epoll_ctl,epoll_ctl@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver gnu_dev_minor,gnu_dev_minor@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __memcpy_chk,__memcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vfscanf,__isoc99_vfscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __stpncpy_chk,__stpncpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_find,inet6_opt_find@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __mbsnrtowcs_chk,__mbsnrtowcs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver strerror_l,strerror_l@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __fread_chk,__fread_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcsnrtombs_chk,__wcsnrtombs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wprintf_chk,__wprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver epoll_create1,epoll_create1@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vfprintf_chk,__vfprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vsyslog_chk,__vsyslog_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inotify_add_watch,inotify_add_watch@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcrtomb_chk,__wcrtomb_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver epoll_pwait,epoll_pwait@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __strcpy_chk,__strcpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vdprintf_chk,__vdprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __vasprintf_chk,__vasprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __xpg_strerror_r,__xpg_strerror_r@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcpncpy_chk,__wcpncpy_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_init,inet6_option_init@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wmemmove_chk,__wmemmove_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __sprintf_chk,__sprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver futimesat,futimesat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pread64_chk,__pread64_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver strptime_l,strptime_l@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver lchmod,lchmod@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __chk_fail,__chk_fail@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_vscanf,__isoc99_vscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __wcsrtombs_chk,__wcsrtombs_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pipe2,pipe2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __strcat_chk,__strcat_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver faccessat,faccessat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __asprintf_chk,__asprintf_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ppoll,ppoll@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __recvfrom_chk,__recvfrom_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_opt_set_val,inet6_opt_set_val@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __ptsname_r_chk,__ptsname_r_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __isoc99_fwscanf,__isoc99_fwscanf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __gets_chk,__gets_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver gnu_dev_makedev,gnu_dev_makedev@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __xmknodat,__xmknodat@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver inet6_option_find,inet6_option_find@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __ttyname_r_chk,__ttyname_r_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __readlinkat_chk,__readlinkat_chk@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver dlmopen,dlmopen@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver dladdr1,dladdr1@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver dlinfo,dlinfo@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_getprotocol,pthread_mutexattr_getprotocol@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutex_setprioceiling,pthread_mutex_setprioceiling@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_setprioceiling,pthread_mutexattr_setprioceiling@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pthread_unregister_cancel_restore,__pthread_unregister_cancel_restore@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_attr_setaffinity_np,pthread_attr_setaffinity_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pthread_cleanup_routine,__pthread_cleanup_routine@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_condattr_getclock,pthread_condattr_getclock@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pthread_register_cancel_defer,__pthread_register_cancel_defer@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __pthread_unwind_next,__pthread_unwind_next@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_timedjoin_np,pthread_timedjoin_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_setaffinity_np,pthread_setaffinity_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutex_getprioceiling,pthread_mutex_getprioceiling@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_getprioceiling,pthread_mutexattr_getprioceiling@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_attr_getaffinity_np,pthread_attr_getaffinity_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_barrierattr_getpshared,pthread_barrierattr_getpshared@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_condattr_setclock,pthread_condattr_setclock@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_tryjoin_np,pthread_tryjoin_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_setschedprio,pthread_setschedprio@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_getaffinity_np,pthread_getaffinity_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_setrobust_np,pthread_mutexattr_setrobust_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_getrobust_np,pthread_mutexattr_getrobust_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutexattr_setprotocol,pthread_mutexattr_setprotocol@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver pthread_mutex_consistent_np,pthread_mutex_consistent_np@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_put16,ns_put16@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_pton,ns_name_pton@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_skip,ns_name_skip@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_pack,ns_name_pack@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_ntol,ns_name_ntol@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_sprintrr,ns_sprintrr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_format_ttl,ns_format_ttl@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_ntop,ns_name_ntop@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_compress,ns_name_compress@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_unpack,ns_name_unpack@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_put32,ns_put32@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_sprintrrf,ns_sprintrrf@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_datetosecs,ns_datetosecs@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_get16,ns_get16@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_msg_getflag,ns_msg_getflag@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_samedomain,ns_samedomain@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __p_rcode,__p_rcode@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_parse_ttl,ns_parse_ttl@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_get32,ns_get32@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_skiprr,ns_skiprr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_parserr,ns_parserr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_rollback,ns_name_rollback@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_samename,ns_samename@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_name_uncompress,ns_name_uncompress@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_subdomain,ns_subdomain@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_makecanon,ns_makecanon@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver ns_initparse,ns_initparse@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_open,mq_open@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver __mq_open_2,__mq_open_2@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_timedsend,mq_timedsend@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_notify,mq_notify@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_receive,mq_receive@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_close,mq_close@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_getattr,mq_getattr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_send,mq_send@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_unlink,mq_unlink@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_setattr,mq_setattr@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver mq_timedreceive,mq_timedreceive@GLIBC_DONT_USE_THIS_SYMBOL");
+__asm__(".symver td_thr_tlsbase,td_thr_tlsbase@GLIBC_DONT_USE_THIS_SYMBOL");
diff --git a/tools/apbuild/buildlist b/tools/apbuild/buildlist
new file mode 100755
index 00000000..24e789fd
--- /dev/null
+++ b/tools/apbuild/buildlist
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# get a list of all symbols - YOU MUST RUN THIS SCRIPT WITH THE LATEST VERSIONS OF GLIBC
+# currently blacklists all newer than 2.3.0
+
+if [ -e syms ]; then rm syms; fi
+if [ -e allsym ]; then rm allsym; fi
+for f in /lib/*; do
+ if [ ! -f $f ]; then continue; fi
+ readelf -s --wide $f >>syms
+ objdump -T $f | grep "GLIBC_" | sed 's/\(.*\)GLIBC_//; s/)//' | grep -v PRIVATE | column -t >>allsym
+done
+
+
+# get a list of all symbol versions only available in 2.3+
+grep @@GLIBC_ syms | awk ' { print $8 } ' | sed 's/@@/ /; /GLIBC_P/d; s/GLIBC_//' | awk ' { if ($2 > 2.3) print $1 " " $2 } ' | column -t >glibc2.4.syms
+
+# select the symbols that already existed, but were obsoleted by 2.2+ versions
+cat glibc2.4.syms | awk '{print $1}' | while read; do grep $REPLY allsym; done | sed '/2\.4/d' >syms-to-header
+
+# select the latest symbols of that set
+# build a header from them
+cat syms-to-header | awk '{print $2 " " $1 }' | sort | uniq >output
+cat glibc2.4.syms | sort | uniq >> output
+
+cat output | sort | uniq | awk '{print $2 " " $1}' | sort -k2,1 | awk '{ if ($1 <= 2.3) print $1 " " $2 }' | column -t | sort -k2 | uniq -f1 >output2
+
+# output the symbols that are brand new to 2.3+, ie not the ones that had earlier versions
+cat glibc2.4.syms | awk '{ print $1 }' | while read; do if ! grep "$REPLY" output2 >/dev/null; then echo "DONT_USE_THIS_SYMBOL $REPLY" >>output2; fi; done;
+
+cat output2 | column -t | awk '{ print "__asm__(\".symver " $2 "," $2 "@GLIBC_" $1 "\");" }' > output
+
+# now remove dl_iterate_phdr as it's weak anyway (we should probably do this for all weak syms)
+cat output | sed 's/__asm__("\.symver dl_iterate_phdr.*//' >output2
+
+cat <<EOF >apsymbols.h
+/* apbuild embedded metadata */
+#define APBUILD_NOTE_METADATA(s) \
+ __asm__(".section .metadata, \"MS\", @note, 1\n\t.string \"" s "\"\n\t.previous\n\t")
+
+#ifdef APBUILD_VERSION
+APBUILD_NOTE_METADATA("apbuild.version=" APBUILD_VERSION);
+#endif
+
+/* apbuild generated symbol exclusion list */
+EOF
+cat output2 >> apsymbols.h
+rm output2
diff --git a/tools/apbuild/ctype.h b/tools/apbuild/ctype.h
new file mode 100644
index 00000000..2db84cc1
--- /dev/null
+++ b/tools/apbuild/ctype.h
@@ -0,0 +1,268 @@
+/* Copyright (C) 1991,92,93,95,96,97,98,99,2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * ISO C99 Standard 7.4: Character handling <ctype.h>
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H 1
+
+#include <features.h>
+#include <bits/types.h>
+
+__BEGIN_DECLS
+
+#ifndef _ISbit
+/* These are all the characteristics of characters.
+ If there get to be more than 16 distinct characteristics,
+ many things must be changed that use `unsigned short int's.
+
+ The characteristics are stored always in network byte order (big
+ endian). We define the bit value interpretations here dependent on the
+ machine's byte order. */
+
+# include <endian.h>
+# if __BYTE_ORDER == __BIG_ENDIAN
+# define _ISbit(bit) (1 << (bit))
+# else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+# define _ISbit(bit) ((bit) < 8 ? ((1 << (bit)) << 8) : ((1 << (bit)) >> 8))
+# endif
+
+enum
+{
+ _ISupper = _ISbit (0), /* UPPERCASE. */
+ _ISlower = _ISbit (1), /* lowercase. */
+ _ISalpha = _ISbit (2), /* Alphabetic. */
+ _ISdigit = _ISbit (3), /* Numeric. */
+ _ISxdigit = _ISbit (4), /* Hexadecimal numeric. */
+ _ISspace = _ISbit (5), /* Whitespace. */
+ _ISprint = _ISbit (6), /* Printing. */
+ _ISgraph = _ISbit (7), /* Graphical. */
+ _ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
+ _IScntrl = _ISbit (9), /* Control character. */
+ _ISpunct = _ISbit (10), /* Punctuation. */
+ _ISalnum = _ISbit (11) /* Alphanumeric. */
+};
+#endif /* ! _ISbit */
+
+/* These are defined in ctype-info.c.
+ The declarations here must match those in localeinfo.h.
+
+ These point into arrays of 384, so they can be indexed by any `unsigned
+ char' value [0,255]; by EOF (-1); or by any `signed char' value
+ [-128,-1). ISO C requires that the ctype functions work for `unsigned
+ char' values and for EOF; we also support negative `signed char' values
+ for broken old programs. The case conversion arrays are of `int's
+ rather than `unsigned char's because tolower (EOF) must be EOF, which
+ doesn't fit into an `unsigned char'. But today more important is that
+ the arrays are also used for multi-byte character sets. */
+extern __const unsigned short int *__ctype_b; /* Characteristics. */
+extern __const __int32_t *__ctype_tolower; /* Case conversions. */
+extern __const __int32_t *__ctype_toupper; /* Case conversions. */
+
+__asm__(".symver __ctype_b,__ctype_b@GLIBC_2.0");
+__asm__(".symver __ctype_tolower,__ctype_tolower@GLIBC_2.0");
+__asm__(".symver __ctype_toupper,__ctype_toupper@GLIBC_2.0");
+
+#define __isctype(c, type) \
+ (__ctype_b[(int) (c)] & (unsigned short int) type)
+
+#define __isascii(c) (((c) & ~0x7f) == 0) /* If C is a 7 bit value. */
+#define __toascii(c) ((c) & 0x7f) /* Mask off high bits. */
+
+#define __exctype(name) extern int name (int) __THROW
+
+/* The following names are all functions:
+ int isCHARACTERISTIC(int c);
+ which return nonzero iff C has CHARACTERISTIC.
+ For the meaning of the characteristic names, see the `enum' above. */
+__exctype (isalnum);
+__exctype (isalpha);
+__exctype (iscntrl);
+__exctype (isdigit);
+__exctype (islower);
+__exctype (isgraph);
+__exctype (isprint);
+__exctype (ispunct);
+__exctype (isspace);
+__exctype (isupper);
+__exctype (isxdigit);
+
+#ifdef __USE_ISOC99
+__exctype (isblank);
+#endif
+
+
+/* Return the lowercase version of C. */
+extern int tolower (int __c) __THROW;
+
+/* Return the uppercase version of C. */
+extern int toupper (int __c) __THROW;
+
+
+#if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+
+/* Return nonzero iff C is in the ASCII set
+ (i.e., is no more than 7 bits wide). */
+extern int isascii (int __c) __THROW;
+
+/* Return the part of C that is in the ASCII set
+ (i.e., the low-order 7 bits of C). */
+extern int toascii (int __c) __THROW;
+
+/* These are the same as `toupper' and `tolower' except that they do not
+ check the argument for being in the range of a `char'. */
+__exctype (_toupper);
+__exctype (_tolower);
+#endif /* Use SVID or use misc. */
+
+/* This code is needed for the optimized mapping functions. */
+#define __tobody(c, f, a, args) \
+ (__extension__ \
+ ({ int __res; \
+ if (sizeof (c) > 1) \
+ { \
+ if (__builtin_constant_p (c)) \
+ { \
+ int __c = (c); \
+ __res = __c < -128 || __c > 255 ? __c : a[__c]; \
+ } \
+ else \
+ __res = f args; \
+ } \
+ else \
+ __res = a[(int) (c)]; \
+ __res; }))
+
+#ifndef __NO_CTYPE
+# define isalnum(c) __isctype((c), _ISalnum)
+# define isalpha(c) __isctype((c), _ISalpha)
+# define iscntrl(c) __isctype((c), _IScntrl)
+# define isdigit(c) __isctype((c), _ISdigit)
+# define islower(c) __isctype((c), _ISlower)
+# define isgraph(c) __isctype((c), _ISgraph)
+# define isprint(c) __isctype((c), _ISprint)
+# define ispunct(c) __isctype((c), _ISpunct)
+# define isspace(c) __isctype((c), _ISspace)
+# define isupper(c) __isctype((c), _ISupper)
+# define isxdigit(c) __isctype((c), _ISxdigit)
+
+# ifdef __USE_ISOC99
+# define isblank(c) __isctype((c), _ISblank)
+# endif
+
+# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
+# define tolower(c) __tobody (c, tolower, __ctype_tolower, (c))
+# define toupper(c) __tobody (c, toupper, __ctype_toupper, (c))
+# endif /* Optimizing gcc */
+
+# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+# define isascii(c) __isascii (c)
+# define toascii(c) __toascii (c)
+
+# define _tolower(c) ((int) __ctype_tolower[(int) (c)])
+# define _toupper(c) ((int) __ctype_toupper[(int) (c)])
+# endif
+
+#endif /* Not __NO_CTYPE. */
+
+
+#ifdef __USE_GNU
+/* The concept of one static locale per category is not very well
+ thought out. Many applications will need to process its data using
+ information from several different locales. Another application is
+ the implementation of the internationalization handling in the
+ upcoming ISO C++ standard library. To support this another set of
+ the functions using locale data exist which have an additional
+ argument.
+
+ Attention: all these functions are *not* standardized in any form.
+ This is a proof-of-concept implementation. */
+
+/* Structure for reentrant locale using functions. This is an
+ (almost) opaque type for the user level programs. */
+# include <xlocale.h>
+
+/* These definitions are similar to the ones above but all functions
+ take as an argument a handle for the locale which shall be used. */
+# define __isctype_l(c, type, locale) \
+ ((locale)->__ctype_b[(int) (c)] & (unsigned short int) type)
+
+# define __exctype_l(name) extern int name (int, __locale_t) __THROW
+
+/* The following names are all functions:
+ int isCHARACTERISTIC(int c, locale_t *locale);
+ which return nonzero iff C has CHARACTERISTIC.
+ For the meaning of the characteristic names, see the `enum' above. */
+__exctype_l (__isalnum_l);
+__exctype_l (__isalpha_l);
+__exctype_l (__iscntrl_l);
+__exctype_l (__isdigit_l);
+__exctype_l (__islower_l);
+__exctype_l (__isgraph_l);
+__exctype_l (__isprint_l);
+__exctype_l (__ispunct_l);
+__exctype_l (__isspace_l);
+__exctype_l (__isupper_l);
+__exctype_l (__isxdigit_l);
+
+__exctype_l (__isblank_l);
+
+
+/* Return the lowercase version of C in locale L. */
+extern int __tolower_l (int __c, __locale_t __l) __THROW;
+
+/* Return the uppercase version of C. */
+extern int __toupper_l (int __c, __locale_t __l) __THROW;
+
+# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
+# define __tolower_l(c, locale) \
+ __tobody (c, __tolower_l, (locale)->__ctype_tolower, (c, locale))
+# define __toupper_l(c, locale) \
+ __tobody (c, __toupper_l, (locale)->__ctype_toupper, (c, locale))
+# endif /* Optimizing gcc */
+
+
+# ifndef __NO_CTYPE
+# define __isalnum_l(c,l) __isctype_l((c), _ISalnum, (l))
+# define __isalpha_l(c,l) __isctype_l((c), _ISalpha, (l))
+# define __iscntrl_l(c,l) __isctype_l((c), _IScntrl, (l))
+# define __isdigit_l(c,l) __isctype_l((c), _ISdigit, (l))
+# define __islower_l(c,l) __isctype_l((c), _ISlower, (l))
+# define __isgraph_l(c,l) __isctype_l((c), _ISgraph, (l))
+# define __isprint_l(c,l) __isctype_l((c), _ISprint, (l))
+# define __ispunct_l(c,l) __isctype_l((c), _ISpunct, (l))
+# define __isspace_l(c,l) __isctype_l((c), _ISspace, (l))
+# define __isupper_l(c,l) __isctype_l((c), _ISupper, (l))
+# define __isxdigit_l(c,l) __isctype_l((c), _ISxdigit, (l))
+
+# define __isblank_l(c,l) __isctype_l((c), _ISblank, (l))
+
+# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+# define __isascii_l(c,l) __isascii(c)
+# define __toascii_l(c,l) __toascii(c)
+# endif
+
+# endif /* Not __NO_CTYPE. */
+
+#endif /* Use GNU. */
+
+__END_DECLS
+
+#endif /* ctype.h */
diff --git a/tools/apbuild/make-icons b/tools/apbuild/make-icons
new file mode 100755
index 00000000..32c0c600
--- /dev/null
+++ b/tools/apbuild/make-icons
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+#
+# This script generates a directory and an automake fragment from an SVG
+# file. It's useful when you have an SVG and want to pre-render icons of
+# various sizes from it, then install them into the users icon theme.
+#
+# For autopackage users, put the following line in your specfile:
+#
+# installIcon share/icons/hicolor
+#
+# It uses rsvg to render the icons
+
+if [[ "$1" == "" ]] || [[ "$2" == "" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
+ echo "Usage: make-icons myprogram.svg type"
+ echo
+ echo "Generates a subdirectory called icons with an icon theme tree"
+ echo "in it. Also outputs some automake code you can copy/paste".
+ echo ""
+ echo "type is the type of icon and should be one of the following:"
+ echo "apps, mimetypes, actions, devices, filesystems"
+ echo "See FDO spec for details--you most likely want apps or mimetypes"
+ exit 0
+fi
+
+if ! which rsvg >/dev/null; then
+ # a part of librsvg
+ echo "make-icons: this script needs the rsvg program installed"
+ exit 1
+fi
+
+if [ ! -e $1 ]; then
+ echo "make-icons: the given file does not exist"
+ exit 1
+fi
+
+if [[ "$2" != "apps" && "$2" != "mimetypes" && "$2" != "actions" && "$2" != "devices" && "$2" != "filesystems" ]]; then
+ echo "make-icons: $2 is not a valid icon type. type should be one of these:"
+ echo "apps, mimetypes, actions, devices, filesystems"
+ echo "See FDO spec for details--you most likely want apps or mimetypes"
+ exit 1
+fi
+mkdir -p icons/scalable/$2
+cp $1 icons/scalable/$2
+
+newname="`basename $1`"
+echo "iconSVGdir = \$(datadir)/icons/hicolor/scalable/$2"
+echo "iconSVG_DATA = icons/scalable/$2/$newname"
+
+newname="${newname/.svg/}.png"
+
+
+for size in 128 64 48 24 16; do
+ mkdir -p icons/${size}x${size}/$2
+ rsvg --width=$size --height=$size $1 icons/${size}x${size}/$2/$newname
+ echo "icon${size}dir = \$(datadir)/icons/hicolor/${size}x${size}/$2"
+ echo "icon${size}_DATA = icons/${size}x${size}/$2/$newname"
+done
diff --git a/tools/apbuild/relaytool b/tools/apbuild/relaytool
new file mode 100755
index 00000000..40b6de03
--- /dev/null
+++ b/tools/apbuild/relaytool
@@ -0,0 +1,584 @@
+#!/bin/bash
+
+# relaytool 1.2
+# Copyright 2004-2005 Mike Hearn <mike@plan99.net>
+# Copyright 2005 Vincent Béron <vberon@mecano.gme.usherb.ca>
+# Copyright 2006 Psyche <psyche@ruidoabsurdo.com>
+# Copyright 2007 Taj Morton <tajmorton@gmail.com>
+#
+#############################################################################
+#
+# 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
+# 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.
+#
+#############################################################################
+#
+# TODO:
+# - Figure out how to grab the GOT addr on PowerPC
+# - Port to more archs
+# - Figure out a way to check if we're on an ELF platform or not,
+# maybe check for _GLOBAL_OFFSET_TABLE_ ?
+
+using_partial_map=false
+using_minimal_list=false
+using_multilink=false
+outdir="."
+
+if [[ "$1" == "--version" ]]; then
+ echo "Relaytool 1.11"
+ echo "Copyright 2004 Mike Hearn"
+ echo "Copyright 2005 Vincent Béron"
+ echo
+ echo "See $0 for license details."
+ exit 1
+fi
+
+if [[ "$@" == "" ]] || [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
+ echo "Relaytool will generate a file that can be used instead of linking"
+ echo "directly against a library, which will dlopen the DSO at init time"
+ echo
+ echo "Usage: relaytool [OPTION]... [LINKER COMMAND]..."
+ echo
+ echo "Options:"
+ echo " --relay LIB If a matching -lLIB is found, generate a file"
+ echo " that can be used instead of linking directly to"
+ echo " LIB. The name of the file is echoed on stdout."
+ echo " Multiple --relay can be used together, a file will"
+ echo " be generated for each matching ones."
+ echo " --replace-all-libs Generate a file for every -lLIB parameter."
+ echo " --minimal-list OBJ_LIST Will look in OBJ_LIST for undefined symbols, and"
+ echo " generate a file creating only the needed symbols"
+ echo " for each LIB."
+ echo " --partial-map MAP_FILE Generate a file creating only the symbols contained"
+ echo " in MAP_FILE. Will apply to all further -lLIB"
+ echo " parameters, so in general is not suitable to"
+ echo " multiple libs in the same invocation of relaytool."
+ echo " --no-replace Echo -lLIB on stdout even if a --relay LIB is"
+ echo " found, so it'll be linked in normally."
+ echo " --multilink [SONAMES...] If a library has different SONAMES on different"
+ echo " Linux distributions you can specify the various"
+ echo " SONAMES that it's known by here. Relaytool will"
+ echo " attempt to load them (in the order provided) until"
+ echo " one if found. This cannot be used with multiple"
+ echo " --relay options. The first SONAME in the list will"
+ echo " be used as the name in the _is_present variable and"
+ echo " _symbol_is_present function."
+ echo " --out-dir DIRECTORY Write stub file to DIRECTORY instead of CWD."
+ echo "Linker commands:"
+ echo " -LPATH Add PATH to the list of paths to search for LIBs."
+ echo " -lLIB If a matching --relay LIB is found (or if"
+ echo " --replace-all-libs is specified), generate a file"
+ echo " that can be used instead of linking directly to"
+ echo " LIB. If there's no --relay LIB, echo -lLIB to"
+ echo " stdout."
+ echo " All other linker commands are passed as is to stdout."
+ echo "Other commands:"
+ echo " --help|-h Print this help."
+ echo " --version Print version information."
+ exit 1
+fi
+
+function error() {
+ echo $@ >/dev/stderr
+ exit 1
+}
+
+function readfinallink() {
+ link_name="$1"
+ while [ -L "$link_name" ]; do
+ new_name=$( readlink "$link_name" )
+ if [ "${new_name:0:1}" == "/" ]; then
+ link_name="$new_name"
+ else
+ link_name="`dirname "$link_name"`/$new_name"
+ fi
+ done
+ if [ -f "$link_name" ]; then
+ echo -n "$link_name"
+ exit 0
+ else
+ exit 1
+ fi
+}
+
+function relay() {
+ lib="$1"
+ if $using_multilink; then
+ libname=$( echo $( basename ${multilinklist[0]} ) | sed 's/\.so.*//' | tr '-' '_' | tr '.' '_' )
+ else
+ libname=$( echo $( basename "$lib" ) | sed 's/\.so.*//' | tr '-' '_' | tr '.' '_' )
+ fi
+ soname=$( objdump -x "$lib" |grep SONAME | awk '{print $2}' )
+ outfile="$outdir/`basename "$soname"`.stub.c"
+
+ echo -n "$outfile"
+
+ if $using_partial_map; then
+ functions=$( grep "^F " "$partial_map" | cut -d' ' -f2 )
+ variables=$( grep "^V " "$partial_map" | cut -d' ' -f2 )
+ else
+ functions=$( nm --extern-only -D "$lib" | awk '{ if (($2 == "T") || ($2 == "W")) print $3; }' | LC_ALL=C grep -v '\(\<_init\>\|\<_fini\>\)' | LC_ALL=C sort -u )
+ variables=$( nm --extern-only -D "$lib" | awk '{ if (($2 == "D") || ($2 == "G") || ($2 == "B") || ($2 == "V")) print $3; }' | LC_ALL=C sort -u )
+ fi
+ if $using_minimal_list; then
+ functions="$functions
+$( nm `echo "$object_list"` | awk '{ if ($1 == "U") print $2; }' | LC_ALL=C sort -u )"
+ functions=$( echo "$functions" | LC_ALL=C sort | LC_ALL=C uniq -d )
+ variables="$variables
+$( nm `echo "$object_list"` | awk '{ if ($1 == "U") print $2; }' | LC_ALL=C sort -u )"
+ variables=$( echo "$variables" | LC_ALL=C sort | LC_ALL=C uniq -d )
+ fi
+
+ if [ "$functions" == "" ] && [ "$variables" == "" ]; then
+ # Nothing will be used, so do nothing for that lib
+ exit 1
+ fi
+
+ cat <<EOF >"$outfile"
+/* automatically generated: `date` by `id -un`@`uname -n`, do not edit
+ *
+ * Built by relaytool, a program for building delay-load jumptables
+ * relaytool is (C) 2004 Mike Hearn <mike@navi.cx>
+ * See http://autopackage.org/ for details.
+ */
+#include <dlfcn.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/mman.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+static void **ptrs;
+static char *functions[] = {
+EOF
+
+ for s in $functions; do
+ echo " \"$s\"," >>"$outfile"
+ done
+ echo " 0" >>"$outfile"
+
+ cat <<EOF >>"$outfile"
+};
+
+static char *variables[] = {
+EOF
+
+ for s in $variables; do
+ echo " \"$s\"," >>"$outfile"
+ done
+ echo " 0" >>"$outfile"
+
+ cat <<EOF >>"$outfile"
+};
+
+/* 1 if present, 0 if not */
+int ${libname}_is_present = 0;
+
+static void *handle = 0;
+
+/* 1 if present, 0 if not, 0 with warning to stderr if lib not present or symbol not found */
+int ${libname}_symbol_is_present(char *s)
+{
+ int i;
+
+ if( !${libname}_is_present ) {
+ fprintf(stderr, "%s: relaytool: `basename "$lib"` not present so cannot check for symbol %s.\n", getenv("_"), s);
+ fprintf(stderr, "%s: relaytool: This probably indicates a bug in the application, please report.\n", getenv("_"));
+ return 0;
+ }
+
+ i = 0;
+ while (functions[i++]) if (!strcmp( functions[i - 1], s )) return ptrs[i - 1] > 0 ? 1 : 0;
+ i = 0;
+ while (variables[i++]) if (!strcmp( variables[i - 1], s )) return dlsym( handle, s ) > 0 ? 1 : 0;
+
+ fprintf( stderr, "%s: relaytool: %s is an unknown symbol in `basename "$lib"`.\n", getenv("_"), s );
+ fprintf( stderr, "%s: relaytool: If you are the developer of this program, please correct the symbol name or rerun relaytool.\n", getenv("_") );
+ return 0;
+}
+
+__attribute__((noreturn)) void _relaytool_stubcall_${libname}(int offset)
+{
+ fprintf( stderr, "%s: relaytool: stub call to `basename "${lib}"`:%s, aborting.\n", getenv("_"),
+ functions[offset / sizeof(void*)] );
+ exit( 1 );
+}
+
+#if defined( __i386__ )
+ #define FIXUP_GOT_RELOC(sym, addr) \\
+ asm("\tmovl %0, %%eax\n" \\
+ "\tmovl %%eax, " sym "@GOT(%%ebx)\n" : : "r" (addr));
+#elif defined( __powerpc__ )
+
+ /* The PowerPC ELF ABI is a twisted nightmare. Until I figure it out,
+ for now we don't support GOT fixup on this architecture */
+
+ #error Variables are not currently supported on PowerPC
+
+#elif defined( __x86_64__ )
+ #define FIXUP_GOT_RELOC(sym, addr) \\
+ asm("\tmovq %0, %%rax\n" \\
+ "\tmovq %%rax, " sym "@GOT(%%rbx)\n" : : "r" (addr));
+#else
+ #error Please define FIXUP_GOT_RELOC for your architecture
+#endif
+
+void __attribute__((constructor)) _relaytool_init_${libname}()
+{
+ int i = 0;
+
+ ptrs = malloc( sizeof(functions) );
+ memset( ptrs, 0, sizeof(functions) );
+EOF
+ if $using_multilink; then
+ echo -n "char *multilink_libs[${#multilinklist[@]}] = {" | cat >> "$outfile"
+ for l in ${multilinklist[@]}; do
+ echo -n "\"$l\"" | cat >> "$outfile";
+ if [[ "$l" != "${multilinklist[${#multilinklist[@]}-1]}" ]]; then
+ echo -n ", " | cat >> "$outfile";
+ else
+ echo "};" | cat >> "$outfile"
+ fi
+ done
+ echo 'int multilink_count=0;' | cat >> "$outfile"
+
+ echo 'while (!handle) {
+ handle = dlopen(multilink_libs[multilink_count++], RTLD_LAZY );' | cat >> "$outfile"
+ echo "if (multilink_count==${#multilinklist[@]}) break;}"| cat >> "$outfile"
+ else
+ echo "handle = dlopen( \"$soname\", RTLD_LAZY );" | cat >> "$outfile"
+ fi
+cat <<EOF >>"$outfile"
+ if (!handle) return;
+
+ ${libname}_is_present = 1;
+
+ /* build function jumptable */
+ while (functions[i++]) ptrs[i - 1] = dlsym( handle, functions[i - 1] );
+
+EOF
+
+ if [ "$variables" != "" ]; then echo " /* now fixup the global offset table for variable imports */" >>"$outfile"; fi
+ for s in $variables; do
+ echo " FIXUP_GOT_RELOC( \"$s\", dlsym(handle, \"$s\") );" >>"$outfile"
+ done
+
+ cat <<EOF >>"$outfile"
+}
+
+#if defined( __i386__ )
+
+#define JUMP_SLOT(name, index) \\
+ asm(".section .text." name ", \"ax\", @progbits\n" \\
+ ".globl " name "\n" \\
+ ".hidden " name "\n" \\
+ " .type " name ", @function\n" \\
+ name ":\n" \\
+ " movl ptrs, %eax\n" \\
+ " movl " #index "(%eax), %eax\n" \\
+ " test %eax, %eax\n" \\
+ " jnz JS" #index "\n" \\
+ " push \$" #index "\n" \\
+ " call _relaytool_stubcall_${libname}\n" \\
+ "JS" #index ": jmp *%eax\n");
+
+
+#elif defined( __x86_64__ )
+
+#define JUMP_SLOT(name, index) \\
+ asm(".section .text." name ", \"ax\", @progbits\n" \\
+ ".globl " name "\n" \\
+ ".hidden " name "\n" \\
+ " .type " name ", @function\n" \\
+ name ":\n" \\
+ " movq ptrs, %r11\n" \\
+ " movq " #index "(%r11), %r11\n" \\
+ " test %r11, %r11\n" \\
+ " jnz JS" #index "\n" \\
+ " push $" #index "\n" \\
+ " call _relaytool_stubcall_${libname}\n" \\
+ "JS" #index ": jmp *%r11\n");
+#elif defined( __powerpc__ )
+
+#define JUMP_SLOT(name, index) \ \
+ asm(".section .text." name ", \"ax\", @progbits\n" \\
+ ".globl " name "\n" \\
+ ".hidden " name "\n" \\
+ " .type " name ", @function\n" \\
+ name ":\n" \\
+ " lis r11, ptrs@ha\n" \\
+ " lwz r11, " #index "(r11)\n" \\
+ " cmpi cr0,r11,0\n" \\
+ " beq- 1f\n" \\
+ " mtctr r11\n" \\
+ " bctr\n" \\
+ "1: li r3, " #index "\n" \\
+ " b _relaytool_stubcall_${libname}\n" \\
+ );
+
+#else
+ #error Please define JUMP_SLOT for your architecture
+#endif
+
+/* define placeholders for the variable imports: their type doesn't matter,
+ however we must restrict ELF symbol scope to prevent the definition in the imported
+ shared library being bound to this dummy symbol (not all libs are compiled -Bsymbolic)
+ */
+EOF
+
+ for s in $variables; do
+ echo "int $s __attribute__(( visibility(\"hidden\") )) = -1;" >>"$outfile"
+ done
+
+ cat <<EOF >>"$outfile"
+
+/* define each jump slot in its own section. this increases generated code
+ size, but it means unused slots can be deleted by the linker when
+ --gc-sections is used.
+ */
+EOF
+
+# now generate the stubs
+ c=0
+ for s in $functions; do
+ echo "JUMP_SLOT(\"$s\", $[c * $arch_ptr_size]);" >>"$outfile"
+ (( c++ ))
+ done
+
+ echo >>"$outfile"
+
+ cat <<EOF >>"$outfile"
+
+#ifdef __cplusplus
+ }
+#endif
+EOF
+
+}
+
+function fakerelay() {
+ lib="$1"
+ libname=$( echo $( basename "$lib" ) | sed 's/\.so.*//' | tr '-' '_' | tr '.' '_' )
+ soname=$( objdump -x "$lib" |grep SONAME | awk '{print $2}' )
+ outfile="$outdir/`basename "$soname"`.stub.c"
+
+ echo -n "$outfile"
+
+ cat <<EOF >"$outfile"
+/* automatically generated: `date` by `id -un`@`uname -n`, do not edit
+ *
+ * Built by relaytool, a program for building delay-load jumptables
+ * relaytool is (C) 2004 Mike Hearn <mike@navi.cx>
+ * See http://autopackage.org/ for details.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* 1 if present, 0 if not */
+int ${libname}_is_present = 1;
+
+/* 1 if present, 0 if not, 0 with warning to stderr if lib not present or symbol not found */
+int ${libname}_symbol_is_present(char * s)
+{
+ return 1;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+EOF
+
+}
+
+no_replace=false
+replace_all=false
+arch_ok=false
+arch_ptr_size=0
+case `uname -m` in
+ i386 | i486 | i586 | i686 )
+ arch_ok=true
+ arch_ptr_size=4
+ ;;
+ x86_64)
+ arch_ok=true
+ arch_ptr_size=8
+ ;;
+esac
+
+searchpath=( "/usr/lib" "/usr/local/lib" "/lib" `pwd` )
+multilinklist=( )
+relaylist=( )
+
+# process arguments
+i=1
+while (( i <= $# )); do
+ a="${!i}"
+
+ if [ "${a:0:2}" == "-L" ]; then
+ searchpath[${#searchpath}]="${a:2}"
+ echo -n "$a " # copy to stdout
+
+ elif [ "$a" == "--replace-all-libs" ]; then
+ replace_all=true
+
+ elif [ "$a" == "--partial-map" ]; then
+ using_partial_map=true
+ (( i++ ))
+ partial_map="${!i}"
+
+ elif [ "$a" == "--minimal-list" ]; then
+ using_minimal_list=true
+ (( i++ ))
+ object_list="${!i}"
+
+ elif [ "$a" == "--no-replace" ]; then
+ no_replace=true
+
+ elif [ "$a" == "--multilink" ]; then
+ using_multilink=true
+ (( i++ ))
+ while [[ $i -lt $# && ${!i:0:2} != "--" ]]; do
+ multilinklist[${#multilinklist[@]}]="${!i}"
+ (( i++ ))
+ done
+ continue # $i has already been incremented, just continue with the loop
+
+ elif [ "$a" == "--relay" ]; then
+ (( i++ ))
+ relaylist[${#relaylist[@]}]="${!i}"
+
+ elif [ "$a" == "--out-dir" ]; then
+ (( i++ ))
+ outdir="${!i}"
+
+ elif [ "$a" == "-ldl" ]; then
+ # libdl won't ever be supported by relaytool, so just pass it to stdout
+ echo -n "$a "
+
+ elif [ "${a:0:2}" == "-l" ]; then
+ lib="${a:2}"
+
+ # is this lib meant to be relayed?
+ if $replace_all; then
+ found=true
+ else
+ found=false
+ for b in ${relaylist[@]}; do
+ if [ "$b" == "$lib" ]; then
+ found=true
+ fi
+ done
+ fi
+
+ if $found && $arch_ok; then
+
+ # yes, so let's find its absolute filename by checking in each search path directory
+ spfound=false
+ for d in ${searchpath[@]}; do
+ if [ -e "$d/lib$lib.so" ]; then
+
+ absname=$( readfinallink "$d/lib$lib.so" )
+ if [ $? != 0 ] || [ ! -f "$absname" ]; then
+ error broken symlink "$absname"
+ fi
+
+ stubfile=$( relay "$absname" )
+
+ # now we have to compile the stub
+ if [ $? == 0 ]; then
+ stubobj=$( echo "$stubfile" | sed 's/\.c$/\.o/' )
+ # remove -include flags from CFLAGS, if any
+ CFLAGS=$( echo $CFLAGS | sed 's/-include .*\.h//g' )
+ if [ -e /dev/tty ]; then
+ ${CC:-gcc} ${CFLAGS} -fPIC -c -o "$stubobj" "$stubfile" 2>/dev/tty
+ else
+ ${CC:-gcc} ${CFLAGS} -fPIC -c -o "$stubobj" "$stubfile"
+ fi
+ echo -n "$stubobj "
+ fi
+
+ if $no_replace; then
+ echo -n "-l$lib "
+ fi
+
+ spfound=true
+ break;
+ fi
+ done
+
+ if ! $spfound; then
+ error could not find "$lib" in search path
+ fi
+ elif $found && ! $arch_ok; then
+ # yes, so let's find its absolute filename by checking in each search path directory
+ spfound=false
+ for d in ${searchpath[@]}; do
+ if [ -e "$d/lib$lib.so" ]; then
+
+ absname=$( readfinallink "$d/lib$lib.so" )
+ if [ $? != 0 ] || [ ! -f "$absname" ]; then
+ error broken symlink "$absname"
+ fi
+
+ # Create a stub C source that just contains dummy
+ # libwhatever_... support functions
+ stubfile=$( fakerelay "$absname" )
+
+ # now we have to compile the stub
+ if [ $? == 0 ]; then
+ stubobj=$( echo "$stubfile" | sed 's/\.c$/\.o/' )
+ # remove -include flags from CFLAGS, if any
+ CFLAGS=$( echo $CFLAGS | sed 's/-include .*\.h//g' )
+ if [ -e /dev/tty ]; then
+ ${CC:-gcc} ${CFLAGS} -fPIC -c -o "$stubobj" "$stubfile" 2>/dev/tty
+ else
+ ${CC:-gcc} ${CFLAGS} -fPIC -c -o "$stubobj" "$stubfile"
+ fi
+ echo -n "$stubobj "
+ fi
+
+ if $no_replace; then
+ echo -n "-l$lib "
+ fi
+
+ spfound=true
+ break;
+ fi
+ done
+
+ if ! $spfound; then
+ error could not find "$lib" in search path
+ fi
+ else
+ echo -n "$a "
+ fi
+
+ else
+ # just copy whatever we don't recognise
+ echo -n "$a "
+ fi
+
+ (( i++ ))
+done
+echo
diff --git a/tools/apbuild/relaytool.m4 b/tools/apbuild/relaytool.m4
new file mode 100644
index 00000000..f8f20f98
--- /dev/null
+++ b/tools/apbuild/relaytool.m4
@@ -0,0 +1,28 @@
+dnl Usage: RELAYTOOL(LIBRARY_NAME, LIBS, CFLAGS, ACTION-IF-WEAK-LINK-IS-POSSIBLE)
+
+dnl Example:
+dnl RELAYTOOL("gtkspell", GTKSPELL_LIBS, GTKSPELL_CFLAGS, gtkspell_weak=yes)
+dnl Will modify GTKSPELL_LIBS to include a call to relaytool if available
+dnl or if not, will modify GTKSPELL_CFLAGS to include -D switches to define
+dnl libgtkspell_is_present=1 and libgtkspell_symbol_is_present=1
+
+AC_DEFUN([RELAYTOOL], [
+ if test -z "$RELAYTOOL_PROG"; then
+ AC_PATH_PROG(RELAYTOOL_PROG, relaytool, no)
+ fi
+
+ AC_MSG_CHECKING(whether we can weak link $1)
+
+ _RELAYTOOL_PROCESSED_NAME=`echo "$1" | sed 's/-/_/g;s/\./_/g;'`
+ _RELAYTOOL_UPPER_NAME=`echo $_RELAYTOOL_PROCESSED_NAME | tr '[[:lower:]]' '[[:upper:]]'`
+
+ if test "$RELAYTOOL_PROG" = "no"; then
+ AC_MSG_RESULT(no)
+ $3="-DRELAYTOOL_${_RELAYTOOL_UPPER_NAME}='static const int lib${_RELAYTOOL_PROCESSED_NAME}_is_present = 1; static int __attribute__((unused)) lib${_RELAYTOOL_PROCESSED_NAME}_symbol_is_present(char *m) { return 1; }' $$3"
+ else
+ AC_MSG_RESULT(yes)
+ $2="-Wl,--gc-sections \`relaytool --relay $1 $$2\`"
+ $3="-DRELAYTOOL_${_RELAYTOOL_UPPER_NAME}='extern int lib${_RELAYTOOL_PROCESSED_NAME}_is_present; extern int lib${_RELAYTOOL_PROCESSED_NAME}_symbol_is_present(char *s);' $$3"
+ $4
+ fi
+])
diff --git a/tools/apbuild/scandeps b/tools/apbuild/scandeps
new file mode 100755
index 00000000..7d057129
--- /dev/null
+++ b/tools/apbuild/scandeps
@@ -0,0 +1,137 @@
+#!/usr/bin/env perl
+use strict;
+use IPC::Open2;
+
+if ($ARGV[0] eq '--version') {
+ print "scandeps version 1.0\n";
+ print "Copright (c) 2005 Hongli Lai\n";
+ print "Licensed under the GNU General Public License v2.\n";
+ exit;
+} elsif ($ARGV[0] eq '--help') {
+ print "Usage: scandeps [FILES...]\n";
+ print "This script scans ELF binaries' library dependancies and prints a nice report\n" .
+ "of the dependancies.\n";
+ exit;
+}
+
+
+# First, generate a list of binaries. Either scan user-specified files,
+# or scan all files in the current directory (including subfolders).
+my @files;
+
+if (@ARGV > 0) {
+ # Scan user-specified files
+ @files = @ARGV;
+} else {
+ # Scan directory recursively
+ @files = scandir(".");
+}
+
+# Now get the dependancies for all binaries
+# %fileDeps: hash which contains a list of dependancies. The filename is the key.
+# %depFiles: hash which contains a list of files. The dependancy is the key.
+my (%fileDeps, %depFiles);
+getdeps(\%fileDeps, \%depFiles, \@files);
+
+print "Common dependancies:\n";
+foreach my $dep (keys %depFiles) {
+ if (@{$depFiles{$dep}} == @files) {
+ print " $dep\n";
+ }
+}
+print "\n";
+
+print "All dependancies:\n";
+my @keys = keys %depFiles;
+@keys = sort { @{$depFiles{$b}} - @{$depFiles{$a}} } @keys;
+foreach my $dep (@keys) {
+ my $num = scalar(@{$depFiles{$dep}});
+ my $word = ($num > 1) ? "files" : "file";
+ printf " %-40s (used by %3d $word)\n", $dep, $num;
+}
+
+print "\n";
+print "Dependancies and associated binaries:\n";
+foreach my $dep (@keys) {
+ print " $dep:\n";
+ if (@{$depFiles{$dep}} == @files) {
+ print " All files depend on this library.\n";
+ } else {
+ foreach my $file (@{$depFiles{$dep}}) {
+ print " $file\n";
+ }
+ }
+ print "\n";
+}
+
+
+##################################
+
+sub fatal {
+ print STDERR $_[0];
+ exit 1;
+}
+
+sub isELF {
+ my ($f, $data);
+
+ if (!open($f, $_[0])) {
+ print STDERR "Warning: cannot open file '$_[0]' for reading.\n";
+ return 0;
+ }
+
+ binmode $f;
+ sysread $f, $data, 4;
+ close $f;
+ return $data eq "\177ELF";
+}
+
+sub scandir {
+ my $d;
+
+ if (!opendir($d, $_[0])) {
+ print STDERR "Warning: cannot open directory '$_[0]' for reading.\n";
+ return;
+ }
+
+ my @files;
+ foreach my $file (readdir($d)) {
+ next if ($file eq "." || $file eq "..");
+
+ $file = "$_[0]/$file";
+ if (-d $file) {
+ # Recurse into subdirectory
+ push @files, scandir("$file");
+
+ } elsif (-f $file && -x $file && isELF($file)) {
+ push @files, $file;
+ }
+ }
+ closedir($d);
+ return @files;
+}
+
+sub getdeps {
+ my ($fileDeps, $depFiles, $files) = @_;
+ my ($r, $w);
+ if (!open2($r, $w, 'objdump', '-p', @{$files})) {
+ fatal("Cannot communicate with objdump.\n");
+ }
+ close $w;
+
+ my $currentFile;
+ foreach my $line (<$r>) {
+ if ($line =~ /^(.+):[ \t]+file format /) {
+ $currentFile = $1;
+ $currentFile =~ s/^.\///;
+
+ } elsif ($line =~ /NEEDED[ \t]+(.+)$/) {
+ $fileDeps->{$currentFile} = [] if (!exists $fileDeps->{$currentFile});
+ push @{$fileDeps->{$currentFile}}, $1;
+
+ $depFiles->{$1} = [] if (!exists $depFiles->{$1});
+ push @{$depFiles->{$1}}, $currentFile;
+ }
+ }
+ close $r;
+}
diff --git a/tools/apbuild/test-app/randomapp1.c b/tools/apbuild/test-app/randomapp1.c
new file mode 100644
index 00000000..70252276
--- /dev/null
+++ b/tools/apbuild/test-app/randomapp1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fnmatch.h>
+
+int main() {
+ char *respath = malloc(PATH_MAX);
+ unsigned char c = (unsigned char)"c";
+
+ printf("foo\n");
+ printf("%d\n", isalpha(c));
+ realpath("/some/path", respath);
+ fnmatch ("foo", "bar", 0);
+ return 0;
+}