summaryrefslogtreecommitdiff
path: root/buildtools
diff options
context:
space:
mode:
authorbubulle <bubulle@alioth.debian.org>2011-11-12 13:00:54 +0000
committerbubulle <bubulle@alioth.debian.org>2011-11-12 13:00:54 +0000
commit6fba685eec3a1165ec0b82d72d3ae71e946a1404 (patch)
treef3c0543c8f9df4a22ed62e3bd99d9d7bc1054c14 /buildtools
parent77a7925c0509068d5cd2affd94a3996d0a86035a (diff)
downloadsamba-6fba685eec3a1165ec0b82d72d3ae71e946a1404.tar.gz
Merge upstream 3.6.1 source
git-svn-id: svn://svn.debian.org/svn/pkg-samba/trunk/samba@3972 fc4039ab-9d04-0410-8cac-899223bdd6b0
Diffstat (limited to 'buildtools')
-rw-r--r--buildtools/bin/README16
l---------buildtools/bin/waf1
-rwxr-xr-xbuildtools/bin/waf-svnbin0 -> 109281 bytes
-rwxr-xr-xbuildtools/compare_config_h3.sh19
-rwxr-xr-xbuildtools/compare_config_h4.sh12
-rwxr-xr-xbuildtools/compare_generated.sh50
-rwxr-xr-xbuildtools/compare_install.sh8
-rw-r--r--buildtools/mktowscript/mklist.txt86
-rwxr-xr-xbuildtools/mktowscript/mktowscript.pl451
-rwxr-xr-xbuildtools/mktowscript/rebuild_all.sh37
-rw-r--r--buildtools/scripts/Makefile.waf72
-rwxr-xr-xbuildtools/scripts/abi_gen.sh21
-rwxr-xr-xbuildtools/scripts/autogen-waf.sh27
-rwxr-xr-xbuildtools/scripts/configure.waf14
-rwxr-xr-xbuildtools/testwaf.sh70
-rw-r--r--buildtools/wafsamba/README8
-rw-r--r--buildtools/wafsamba/gccdeps.py128
-rw-r--r--buildtools/wafsamba/generic_cc.py71
-rw-r--r--buildtools/wafsamba/hpuxcc.py56
-rw-r--r--buildtools/wafsamba/irixcc.py77
-rw-r--r--buildtools/wafsamba/nothreads.py219
-rw-r--r--buildtools/wafsamba/pkgconfig.py68
-rw-r--r--buildtools/wafsamba/samba3.py110
-rw-r--r--buildtools/wafsamba/samba_abi.py234
-rw-r--r--buildtools/wafsamba/samba_autoconf.py715
-rw-r--r--buildtools/wafsamba/samba_autoproto.py23
-rw-r--r--buildtools/wafsamba/samba_bundled.py191
-rw-r--r--buildtools/wafsamba/samba_conftests.py414
-rw-r--r--buildtools/wafsamba/samba_cross.py134
-rw-r--r--buildtools/wafsamba/samba_deps.py1184
-rw-r--r--buildtools/wafsamba/samba_dist.py204
-rw-r--r--buildtools/wafsamba/samba_headers.py180
-rw-r--r--buildtools/wafsamba/samba_install.py227
-rw-r--r--buildtools/wafsamba/samba_optimisation.py165
-rw-r--r--buildtools/wafsamba/samba_patterns.py29
-rw-r--r--buildtools/wafsamba/samba_pidl.py167
-rw-r--r--buildtools/wafsamba/samba_python.py69
-rw-r--r--buildtools/wafsamba/samba_utils.py620
-rw-r--r--buildtools/wafsamba/samba_version.py269
-rw-r--r--buildtools/wafsamba/samba_wildcard.py128
-rw-r--r--buildtools/wafsamba/stale_files.py98
-rw-r--r--buildtools/wafsamba/symbols.py496
-rw-r--r--buildtools/wafsamba/tru64cc.py77
-rw-r--r--buildtools/wafsamba/wafsamba.py825
-rwxr-xr-xbuildtools/wafsamba/wscript405
45 files changed, 8475 insertions, 0 deletions
diff --git a/buildtools/bin/README b/buildtools/bin/README
new file mode 100644
index 0000000000..9ef8a1f651
--- /dev/null
+++ b/buildtools/bin/README
@@ -0,0 +1,16 @@
+This copy of waf-svn is taken from the git mirror of waf
+at:
+
+ git://git.samba.org/tridge/waf-svn.git
+
+using the waf-samba branch
+
+It was built using the command:
+
+ ./waf-light --zip-type=gz --make-waf
+
+See http://code.google.com/p/waf/ for more information on waf
+
+You can get a svn copy of the upstream source with:
+
+ svn checkout http://waf.googlecode.com/svn/trunk/ waf-read-only
diff --git a/buildtools/bin/waf b/buildtools/bin/waf
new file mode 120000
index 0000000000..1e5b242062
--- /dev/null
+++ b/buildtools/bin/waf
@@ -0,0 +1 @@
+waf-svn \ No newline at end of file
diff --git a/buildtools/bin/waf-svn b/buildtools/bin/waf-svn
new file mode 100755
index 0000000000..b2e4885840
--- /dev/null
+++ b/buildtools/bin/waf-svn
Binary files differ
diff --git a/buildtools/compare_config_h3.sh b/buildtools/compare_config_h3.sh
new file mode 100755
index 0000000000..294af30930
--- /dev/null
+++ b/buildtools/compare_config_h3.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# compare the generated config.h from a waf build with existing samba
+# build
+
+OLD_CONFIG=$HOME/samba_old/source3/include/config.h
+if test "x$1" != "x" ; then
+ OLD_CONFIG=$1
+fi
+
+if test "x$DIFF" = "x" ; then
+ DIFF="comm -23"
+fi
+
+grep "^.define" bin/default/source3/include/config.h | sort > waf-config.h
+grep "^.define" $OLD_CONFIG | sort > old-config.h
+
+$DIFF old-config.h waf-config.h
+
diff --git a/buildtools/compare_config_h4.sh b/buildtools/compare_config_h4.sh
new file mode 100755
index 0000000000..b78b36fdd0
--- /dev/null
+++ b/buildtools/compare_config_h4.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# compare the generated config.h from a waf build with existing samba
+# build
+
+grep "^.define" bin/default/source4/include/config.h | sort > waf-config.h
+grep "^.define" $HOME/samba_old/source4/include/config.h | sort > old-config.h
+
+comm -23 old-config.h waf-config.h
+
+#echo
+#diff -u old-config.h waf-config.h
diff --git a/buildtools/compare_generated.sh b/buildtools/compare_generated.sh
new file mode 100755
index 0000000000..ebef8a979b
--- /dev/null
+++ b/buildtools/compare_generated.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+# compare the generated files from a waf
+
+old_build=$HOME/samba_old
+
+gen_files=$(cd bin/default && find . -type f -name '*.[ch]')
+
+2>&1
+
+strip_file()
+{
+ in_file=$1
+ out_file=$2
+ cat $in_file |
+ grep -v 'The following definitions come from' |
+ grep -v 'Automatically generated at' |
+ grep -v 'Generated from' |
+ sed 's|/home/tnagy/samba/source4||g' |
+ sed 's|/home/tnagy/samba/|../|g' |
+ sed 's|bin/default/source4/||g' |
+ sed 's|bin/default/|../|g' |
+ sed 's/define _____/define ___/g' |
+ sed 's/define __*/define _/g' |
+ sed 's/define _DEFAULT_/define _/g' |
+ sed 's/define _SOURCE4_/define ___/g' |
+ sed 's/define ___/define _/g' |
+ sed 's/ifndef ___/ifndef _/g' |
+ sed 's|endif /* ____|endif /* __|g' |
+ sed s/__DEFAULT_SOURCE4/__/ |
+ sed s/__DEFAULT_SOURCE4/__/ |
+ sed s/__DEFAULT/____/ > $out_file
+}
+
+compare_file()
+{
+ f=$f
+ bname=$(basename $f)
+ t1=/tmp/$bname.old.$$
+ t2=/tmp/$bname.new.$$
+ strip_file $old_build/$f $t1
+ strip_file bin/default/$f $t2
+ diff -u -b $t1 $t2 2>&1
+ rm -f $t1 $t2
+}
+
+for f in $gen_files; do
+ compare_file $f
+done
+
diff --git a/buildtools/compare_install.sh b/buildtools/compare_install.sh
new file mode 100755
index 0000000000..b964117550
--- /dev/null
+++ b/buildtools/compare_install.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+prefix1="$1"
+prefix2="$2"
+
+(cd $prefix1 && find . ) | sort > p1.txt
+(cd $prefix2 && find . ) | sort > p2.txt
+diff -u p[12].txt
diff --git a/buildtools/mktowscript/mklist.txt b/buildtools/mktowscript/mklist.txt
new file mode 100644
index 0000000000..ee77bb99df
--- /dev/null
+++ b/buildtools/mktowscript/mklist.txt
@@ -0,0 +1,86 @@
+source4/main.mk
+source4/lib/basic.mk
+pidl/config.mk
+nsswitch/config.mk
+nsswitch/libwbclient/config.mk
+source4/heimdal_build/internal.mk
+source4/lib/ldb-samba/config.mk
+source4/librpc/config.mk
+source4/utils/config.mk
+source4/utils/net/config.mk
+source4/scripting/python/config.mk
+source4/auth/config.mk
+source4/auth/gensec/config.mk
+source4/auth/kerberos/config.mk
+source4/auth/ntlm/config.mk
+source4/auth/credentials/config.mk
+source4/auth/ntlmssp/config.mk
+source4/libnet/config.mk
+source4/nbt_server/config.mk
+source4/wrepl_server/config.mk
+source4/ntvfs/config.mk
+source4/ntvfs/unixuid/config.mk
+source4/ntvfs/sysdep/config.mk
+source4/ntvfs/common/config.mk
+source4/ntvfs/posix/config.mk
+source4/selftest/config.mk
+source4/cldap_server/config.mk
+source4/smb_server/config.mk
+source4/smb_server/smb2/config.mk
+source4/smb_server/smb/config.mk
+source4/smbd/config.mk source4/smbd/process_model.mk
+source4/kdc/config.mk
+source4/dsdb/config.mk
+source4/dsdb/samdb/ldb_modules/config.mk
+source4/web_server/config.mk
+source4/param/config.mk
+source4/winbind/config.mk
+source4/cluster/config.mk
+source4/client/config.mk
+source4/ntptr/config.mk
+source4/rpc_server/config.mk
+source4/libcli/config.mk
+source4/libcli/smb2/config.mk
+source4/libcli/wbclient/config.mk
+source4/libcli/security/config.mk
+source4/libcli/ldap/config.mk
+source4/ntp_signd/config.mk
+source4/torture/config.mk
+source4/torture/smb2/config.mk
+source4/torture/local/config.mk
+source4/torture/drs/config.mk
+source4/torture/winbind/config.mk
+source4/torture/libsmbclient/config.mk
+source4/torture/libnetapi/config.mk
+source4/lib/messaging/config.mk
+source4/lib/events/config.mk
+source4/lib/stream/config.mk
+source4/lib/cmdline/config.mk
+source4/lib/com/config.mk
+source4/lib/registry/config.mk
+source4/lib/wmi/config.mk
+source4/lib/socket/config.mk
+source4/lib/samba3/config.mk
+source4/ldap_server/config.mk
+libgpo/config.mk
+libcli/cldap/config.mk
+libcli/samsync/config.mk
+libcli/nbt/config.mk
+libcli/auth/config.mk
+libcli/drsuapi/config.mk
+libcli/security/config.mk
+libcli/smb/config.mk
+libcli/named_pipe_auth/config.mk
+libcli/ldap/config.mk
+lib/uid_wrapper/config.mk
+lib/crypto/config.mk
+lib/socket_wrapper/config.mk
+lib/util/config.mk
+lib/util/charset/config.mk
+lib/nss_wrapper/config.mk
+lib/tsocket/config.mk
+lib/popt/config.mk
+lib/async_req/config.mk
+lib/tdr/config.mk
+lib/torture/config.mk
+lib/smbconf/config.mk
diff --git a/buildtools/mktowscript/mktowscript.pl b/buildtools/mktowscript/mktowscript.pl
new file mode 100755
index 0000000000..a05506bcbd
--- /dev/null
+++ b/buildtools/mktowscript/mktowscript.pl
@@ -0,0 +1,451 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Data::Dumper;
+use File::Basename;
+use List::MoreUtils qw(uniq);
+
+my $globals;
+my $dname;
+
+sub read_file($)
+{
+ my $filename = shift;
+ open(CONFIG_MK, "$filename");
+ my @lines = <CONFIG_MK>;
+ close(CONFIG_MK);
+ return @lines;
+}
+
+sub trim($)
+{
+ my $string = shift;
+ $string =~ s/^\s+//;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
+sub strlist($)
+{
+ my $s = shift;
+ $s =~ s/\$\(SHLIBEXT\)/so/g;
+ $s =~ s/\$\(heimdalsrcdir\)/..\/heimdal/g;
+ $s =~ s/\$\(heimdalbuildsrcdir\)/..\/heimdal_build/g;
+ $s =~ s/\$\(nsswitchsrcdir\)/..\/nsswitch/g;
+ $s =~ s/\$\(param_OBJ_FILES\)/..\/pyparam.c/g;
+ $s =~ s/\$\(libclisrcdir\)\///g;
+ $s =~ s/\$\(socketwrappersrcdir\)\///g;
+ $s =~ s/\$\(libcompressionsrcdir\)\///g;
+ $s =~ s/\$\(\w*srcdir\)\///g;
+ $s =~ s/\$\(libgpodir\)\///g;
+ $s =~ s/\:\.o=\.ho//g;
+ $s =~ s/\:\.o=\.d//g;
+
+ # this one doesn't exist?
+ $s =~ s/\bLDAP_ENCODE\b//g;
+
+ # these need to use the library names
+ $s =~ s/\bLIBLDB\b/ldb/g;
+ $s =~ s/\bLDB\b/ldb/g;
+ $s =~ s/\bLIBTALLOC\b/talloc/g;
+ $s =~ s/\bTALLOC\b/talloc/g;
+ $s =~ s/\bLIBTEVENT\b/tevent/g;
+ $s =~ s/\bTEVENT\b/tevent/g;
+ $s =~ s/\bTSOCKET\b/LIBTSOCKET/g;
+ $s =~ s/\bGENSEC\b/gensec/g;
+ $s =~ s/\bLIBTDB\b/tdb/g;
+ $s =~ s/\bRESOLV\b/resolv/g;
+
+ return trim(join(' ', split(/\s+/, $s)));
+}
+
+sub expand_vars($$)
+{
+ my $vars = shift;
+ my $s = shift;
+ foreach my $v (keys %{$vars}) {
+ if ($s =~ /\$\($v\)/) {
+ $s =~ s/\$\($v\)/$vars->{$v}/g;
+ delete($vars->{$v});
+ }
+ }
+ foreach my $v (keys %{$globals}) {
+ if ($s =~ /\$\($v\)/) {
+ $s =~ s/\$\($v\)/$globals->{$v}/g;
+ }
+ }
+ return $s;
+}
+
+sub find_file($)
+{
+ my $f = shift;
+ my $orig = $f;
+
+ if ($f =~ /\$/) {
+ printf(STDERR "bad variable expansion for file $orig in $dname\n");
+ exit(1);
+ }
+
+ my $b = basename($f);
+ return $b if (-e $b);
+
+ return $f if (-e $f);
+
+ while ($f =~ /\//) {
+ $f =~ s/^[^\/]+\///g;
+ return $f if (-e $f);
+ }
+ my $f2;
+ $f2 = `find . -name "$f" -type f`;
+ return $f2 unless ($f2 eq "");
+ $f2 = `find .. -name "$f" -type f`;
+ return $f2 unless ($f2 eq "");
+ $f2 = `find ../.. -name "$f" -type f`;
+ return $f2 unless ($f2 eq "");
+ $f2 = `find ../../.. -name "$f" -type f`;
+ return $f2 unless ($f2 eq "");
+ printf(STDERR "Failed to find $orig in $dname\n");
+ exit(1);
+ return '';
+}
+
+sub find_files($)
+{
+ my $list = shift;
+ my $ret = '';
+ foreach my $f (split(/\s+/, $list)) {
+ if ($f =~ /\.[0-9]$/) {
+ # a man page
+ my $m = find_file($f . ".xml");
+ die("Unable to find man page $f\n") if ($m eq "");
+ $m =~ s/\.xml$//;
+ return $m;
+ }
+ $f = find_file($f);
+ $f =~ s/^[.]\///;
+ $ret .= ' ' . $f;
+ }
+ $ret = strlist($ret);
+ my @list = split(/\s+/, $ret);
+ @list = uniq(@list);
+ $ret = trim(join(' ', @list));
+ return $ret;
+}
+
+sub read_config_mk($)
+{
+ my $filename = shift;
+ my @lines = read_file($filename);
+ my $prev = "";
+ my $linenum = 1;
+ my $section = "GLOBAL";
+ my $infragment;
+ my $result;
+ my $line = "";
+ my $secnumber = 1;
+
+ $result->{"GLOBAL"}->{SECNUMBER} = $secnumber++;
+
+ foreach (@lines) {
+ $linenum++;
+
+ # lines beginning with '#' are ignored
+ next if (/^\#.*$/);
+
+ if (/^(.*)\\$/) {
+ $prev .= $1;
+ next;
+ } else {
+ $line = "$prev$_";
+ $prev = "";
+ }
+
+ if ($line =~ /^mkinclude.*asn1_deps.pl\s+([^\s]+)\s+([^\s]+)\s+\\\$\\\(\w+\\\)\/([^\s|]+)\s*([^|]*)\|$/) {
+ my $src = $1;
+ $section = $2;
+ my $dir = $3;
+ my $options = $4;
+ $section = "HEIMDAL_" . uc($section);
+ $result->{$section}->{TYPE} = 'ASN1';
+ $result->{$section}->{SECNUMBER} = $secnumber++;
+ if ($options ne '') {
+ $result->{$section}->{OPTIONS} = $options;
+ }
+ $result->{$section}->{DIRECTORY} = $dir;
+ $result->{$section}->{$section . '_OBJ_FILES'} = $src;
+ next;
+ }
+
+ if ($line =~ /^mkinclude.*et_deps.pl\s+([^\s]+)\s+\\\$\\\(\w+\\\)\/([^\s|]+)\|$/) {
+ my $src = $1;
+ my $dir = $2;
+ $section = basename($src);
+ $section =~ s/\./_/g;
+ $section = "HEIMDAL_" . uc($section);
+ $result->{$section}->{TYPE} = 'ERRTABLE';
+ $result->{$section}->{SECNUMBER} = $secnumber++;
+ $result->{$section}->{DIRECTORY} = "$dir";
+ $result->{$section}->{$section . '_OBJ_FILES'} = $src;
+ next;
+ }
+
+ if ($line =~ /^\[(\w+)::([\w-]+)\]/)
+ {
+ my $type = $1;
+ $section = $2;
+ $infragment = 0;
+
+ $result->{$section}->{TYPE} = $type;
+ $result->{$section}->{SECNUMBER} = $secnumber++;
+ next;
+ }
+
+ # include
+ if ($line =~ /^mkinclude (.*)$/) {
+ my $subfile = $1;
+ $result->{$subfile}->{TYPE} = 'SUBCONFIG';
+ $result->{$subfile}->{SECNUMBER} = $secnumber++;
+ next;
+ }
+
+ # empty line
+ if ($line =~ /^[ \t]*$/) {
+ next;
+ }
+
+ # global stuff is considered part of the makefile
+ if ($section eq "GLOBAL") {
+ $infragment = 1;
+ next;
+ }
+
+ # Assignment
+ if ($line =~ /^([a-zA-Z0-9_-]+)[\t ]*=(.*)$/) {
+ $result->{$section}->{$1} = expand_vars($result->{$section}, strlist($2));
+ $globals->{$1} = $result->{$section}->{$1};
+ next;
+ }
+
+ # +=
+ if ($line =~ /^([a-zA-Z0-9_-]+)[\t ]*\+=(.*)$/) {
+ if (!$result->{$section}->{$1}) {
+ $result->{$section}->{$1}="";
+ }
+ $result->{$section}->{$1} .= " " . expand_vars($result->{$section}, strlist($2));
+ $globals->{$1} = $result->{$section}->{$1};
+ next;
+ }
+
+ if ($line =~ /\$\(eval.\$\(call.proto_header_template.*,(.*),.*/) {
+ $result->{$section}->{AUTOPROTO} = $1;
+ }
+ if ($line =~ /^\$\(eval/) {
+ # skip eval lines for now
+ next;
+ }
+
+ printf(STDERR "$linenum: Bad line: $line");
+ }
+
+ return $result;
+}
+
+
+sub process_results($)
+{
+ my $result = shift;
+
+ foreach my $s (sort {$result->{$a}->{SECNUMBER} <=> $result->{$b}->{SECNUMBER}} keys %{$result}) {
+ next if ($s eq "GLOBAL");
+ my $sec = $result->{$s};
+ if ($sec->{TYPE} eq "SUBCONFIG") {
+ my $d = dirname($s);
+ next if ($d eq ".");
+ printf "bld.BUILD_SUBDIR('%s')\n", dirname($s);
+ } else {
+ printf "\nbld.SAMBA_%s('%s'", $sec->{TYPE}, $s;
+ my $trailer="";
+ my $got_src = 0;
+ my $got_private_deps = 0;
+
+ foreach my $k (keys %{$sec}) {
+ #print "key=$k\n";
+
+ next if ($k eq "SECNUMBER");
+ next if ($k eq "TYPE");
+ if ($k eq "INIT_FUNCTION") {
+ $trailer .= sprintf(",\n\tinit_function='%s'", trim($sec->{$k}));
+ next;
+ }
+ if ($k eq "INIT_FUNCTION_SENTINEL") {
+ $trailer .= sprintf(",\n\tinit_function_sentinal='%s'", trim($sec->{$k}));
+ next;
+ }
+ if ($k eq "_PY_FILES" ||
+ $k eq "EPYDOC_OPTIONS" ||
+ $k eq "COV_TARGET" ||
+ $k eq "GCOV" ||
+ $k eq "PC_FILES" ||
+ $k eq "CONFIG4FILE" ||
+ $k eq "LMHOSTSFILE4") {
+ $trailer .= sprintf(",\n\t# %s='%s'", $k, trim($sec->{$k}));
+ next;
+ }
+ if ($k eq "SUBSYSTEM") {
+ $trailer .= sprintf(",\n\tsubsystem='%s'", trim($sec->{$k}));
+ next;
+ }
+ if ($k eq "PRIVATE_DEPENDENCIES") {
+ $trailer .= sprintf(",\n\tdeps='%s'", strlist($sec->{$k}));
+ $got_private_deps = 1;
+ next;
+ }
+ if ($k eq "PUBLIC_DEPENDENCIES") {
+ $trailer .= sprintf(",\n\tpublic_deps='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "ALIASES") {
+ $trailer .= sprintf(",\n\taliases='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "CFLAGS") {
+ $trailer .= sprintf(",\n\tcflags='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "OPTIONS") {
+ $trailer .= sprintf(",\n\toptions='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "DIRECTORY") {
+ $trailer .= sprintf(",\n\tdirectory='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "LDFLAGS") {
+ $trailer .= sprintf(",\n\tldflags='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "INSTALLDIR") {
+ $trailer .= sprintf(",\n\tinstalldir='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "ASN1C") {
+ $trailer .= sprintf(",\n\tcompiler='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "ET_COMPILER") {
+ $trailer .= sprintf(",\n\tcompiler='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "ENABLE") {
+ my $v = strlist($sec->{$k});
+ if ($v eq "NO") {
+ $trailer .= sprintf(",\n\tenabled=False");
+ next;
+ }
+ next if ($v eq "YES");
+ die("Unknown ENABLE value $v in $s\n");
+ }
+ if ($k eq "USE_HOSTCC") {
+ my $v = strlist($sec->{$k});
+ if ($v eq "YES") {
+ $trailer .= sprintf(",\n\tuse_hostcc=True");
+ next;
+ }
+ next if ($v eq "NO");
+ die("Unknown HOST_CC value $v in $s\n");
+ }
+ if ($k eq "$s" . "_VERSION") {
+ $trailer .= sprintf(",\n\tvnum='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "$s" . "_SOVERSION") {
+ next;
+ }
+ if ($k eq "LIBRARY_REALNAME") {
+ $trailer .= sprintf(",\n\trealname='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "OUTPUT_TYPE") {
+ $trailer .= sprintf(",\n\toutput_type='%s'", strlist($sec->{$k}));
+ next;
+ }
+ if ($k eq "AUTOPROTO") {
+ my $list = trim(find_files(strlist($sec->{$k})));
+ $trailer .= sprintf(",\n\tautoproto='%s'", $list);
+ next;
+ }
+ if ($k eq "PUBLIC_HEADERS") {
+ my $list = trim(strlist($sec->{$k}));
+ if ($list =~ /\$\(addprefix .*,(.*)\)(.*)$/) {
+ $list = trim("$1 $2");
+ $list = find_files($list);
+ } else {
+ $list = trim(find_files(strlist($sec->{$k})));
+ }
+ $trailer .= sprintf(",\n\tpublic_headers='%s'", $list);
+ next;
+ }
+ if ($k eq "MANPAGES") {
+ my $list = trim(find_files(strlist($sec->{$k})));
+ $trailer .= sprintf(",\n\tmanpages='%s'", $list);
+ next;
+ }
+ if ($k eq "$s" . "_OBJ_FILES") {
+ my $list = trim(strlist($sec->{$k}));
+ $list =~ s/\.o/.c/g;
+ $list =~ s/\.ho/.c/g;
+ if ($list =~ /\$\(addprefix .*,(.*)\)(.*)$/) {
+ $list = trim("$1 $2");
+ $list = find_files($list);
+ $list = "'$list'";
+ } elsif ($list =~ /\$\(addprefix \$\((\w+)\)(.*),(.*)\)(.*)$/) {
+ my $src = trim($3);
+ my $dir = "$1$2";
+ $dir =~ s/\/$//;
+ my $res = "bld.SUBDIR('$dir', '$src')";
+ if ($4) {
+ $res = "$res + '$4'";
+ }
+ $list = $res;
+ } else {
+ $list = find_files($list);
+ $list="'$list'";
+ }
+ $list =~ s/\$\(\w+srcdir\)\///g;
+ printf(",\n\tsource=%s", $list);
+ $got_src = 1;
+ next;
+ }
+ if ($k eq "HEIMDAL_GSSAPI_KRB5_OBJ_FILES" ||
+ $k eq "HEIMDAL_GSSAPI_SPNEGO_OBJ_FILES" ||
+ $k eq "HEIMDAL_HEIM_ASN1_DER_OBJ_FILES" ||
+ $k eq "HEIMDAL_HX509_OBJH_FILES" ||
+ $k eq "HEIMDAL_HX509_OBJG_FILES" ||
+ $k eq "HEIMDAL_ROKEN_OBJ_FILES"
+ ) {
+ next;
+ }
+ die("Unknown keyword $k in $s\n");
+ }
+ die("No source list in $s\n") unless $got_src or $got_private_deps;
+ if (! $got_src) {
+ printf(",source=''\n\t");
+ }
+ printf("%s\n\t)\n\n", $trailer);
+ }
+ }
+}
+
+for (my $i=0; $i <= $#ARGV; $i++) {
+ my $filename=$ARGV[$i];
+ $dname=dirname($filename);
+ my $result = read_config_mk($filename);
+ if ($i != 0) {
+ print "\n\n\n";
+ }
+ print "# AUTOGENERATED by mktowscript.pl from $filename\n# Please remove this notice if hand editing\n\n";
+ die("Unable to chdir to $dname\n") unless chdir($dname);
+ process_results($result);
+}
+
diff --git a/buildtools/mktowscript/rebuild_all.sh b/buildtools/mktowscript/rebuild_all.sh
new file mode 100755
index 0000000000..e3ed7cfd24
--- /dev/null
+++ b/buildtools/mktowscript/rebuild_all.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+cat mklist.txt |
+while read line; do
+ ws=""
+ list=""
+ for f in $line; do
+ echo "Processing $f"
+ f="../../$f"
+ test -f $f || {
+ echo "$f doesn't exist"
+ exit 1
+ }
+ ws="$(dirname $f)/wscript_build"
+ if [ -f $ws ]; then
+ if test -s $ws && ! grep "AUTOGENERATED.by.mktowscript" $ws > /dev/null; then
+ echo "Skipping manually edited file $ws"
+ continue
+ fi
+ fi
+ list="$list $f"
+ done
+ if [ "$list" = "" ]; then
+ continue
+ fi
+ ./mktowscript.pl $list > wscript_build.$$ || {
+ echo "Failed on $f"
+ rm -f wscript_build.$$
+ exit 1
+ }
+ if cmp wscript_build.$$ $ws > /dev/null 2>&1; then
+ rm -f wscript_build.$$
+ else
+ mv wscript_build.$$ $ws || exit 1
+ fi
+ #exit 1
+done
diff --git a/buildtools/scripts/Makefile.waf b/buildtools/scripts/Makefile.waf
new file mode 100644
index 0000000000..716ab93270
--- /dev/null
+++ b/buildtools/scripts/Makefile.waf
@@ -0,0 +1,72 @@
+# simple makefile wrapper to run waf
+
+WAF_BINARY=BUILDTOOLS/bin/waf
+WAF=WAF_MAKE=1 $(WAF_BINARY)
+
+all:
+ $(WAF) build
+
+install:
+ $(WAF) install
+
+uninstall:
+ $(WAF) uninstall
+
+test:
+ $(WAF) test $(TEST_OPTIONS)
+
+help:
+ @echo NOTE: to run extended waf options use $(WAF_BINARY) or modify your PATH
+ $(WAF) --help
+
+testenv:
+ $(WAF) test --testenv $(TEST_OPTIONS)
+
+quicktest:
+ $(WAF) test --quick $(TEST_OPTIONS)
+
+dist:
+ $(WAF) dist
+
+distcheck:
+ $(WAF) distcheck
+
+clean:
+ $(WAF) clean
+
+distclean:
+ $(WAF) distclean
+
+reconfigure: configure
+ $(WAF) reconfigure
+
+show_waf_options:
+ $(WAF) --help
+
+# some compatibility make targets
+everything: all
+
+testsuite: all
+
+check: test
+
+torture: all
+
+# this should do an install as well, once install is finished
+installcheck: test
+
+etags:
+ $(WAF) etags
+
+ctags:
+ $(WAF) ctags
+
+bin/%:: FORCE
+ $(WAF) --targets=`basename $@`
+FORCE:
+
+configure: autogen-waf.sh BUILDTOOLS/scripts/configure.waf
+ ./autogen-waf.sh
+
+Makefile: autogen-waf.sh configure BUILDTOOLS/scripts/Makefile.waf
+ ./autogen-waf.sh
diff --git a/buildtools/scripts/abi_gen.sh b/buildtools/scripts/abi_gen.sh
new file mode 100755
index 0000000000..ed6f445519
--- /dev/null
+++ b/buildtools/scripts/abi_gen.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+# generate a set of ABI signatures from a shared library
+
+SHAREDLIB="$1"
+
+GDBSCRIPT="gdb_syms.$$"
+
+(
+cat <<EOF
+set height 0
+set width 0
+EOF
+nm "$SHAREDLIB" | cut -d' ' -f2- | egrep '^[BDGTRVWS]' | grep -v @ | cut -c3- | sort | while read s; do
+ echo "echo $s: "
+ echo p $s
+done
+) > $GDBSCRIPT
+
+# forcing the terminal avoids a problem on Fedora12
+TERM=none gdb -batch -x $GDBSCRIPT "$SHAREDLIB" < /dev/null
+rm -f $GDBSCRIPT
diff --git a/buildtools/scripts/autogen-waf.sh b/buildtools/scripts/autogen-waf.sh
new file mode 100755
index 0000000000..7a6e94c5ec
--- /dev/null
+++ b/buildtools/scripts/autogen-waf.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+p=`dirname $0`
+
+echo "Setting up for waf build"
+
+echo "Looking for the buildtools directory"
+
+d="buildtools"
+while test \! -d "$p/$d"; do d="../$d"; done
+
+echo "Found buildtools in $p/$d"
+
+echo "Setting up configure"
+rm -f $p/configure $p/include/config*.h*
+sed "s|BUILDTOOLS|$d|g;s|BUILDPATH|$p|g" < "$p/$d/scripts/configure.waf" > $p/configure
+chmod +x $p/configure
+
+echo "Setting up Makefile"
+rm -f $p/makefile $p/Makefile
+sed "s|BUILDTOOLS|$d|g" < "$p/$d/scripts/Makefile.waf" > $p/Makefile
+
+echo "done. Now run $p/configure or $p/configure.developer then make."
+if [ $p != "." ]; then
+ echo "Notice: The build invoke path is not 'source4'! Use make with the parameter"
+ echo "-C <'source4' path>. Example: make -C source4 all"
+fi
diff --git a/buildtools/scripts/configure.waf b/buildtools/scripts/configure.waf
new file mode 100755
index 0000000000..a7d8d1dbd6
--- /dev/null
+++ b/buildtools/scripts/configure.waf
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+PREVPATH=`dirname $0`
+
+WAF=BUILDTOOLS/bin/waf
+
+# using JOBS=1 gives maximum compatibility with
+# systems like AIX which have broken threading in python
+JOBS=1
+export JOBS
+
+cd BUILDPATH || exit 1
+$WAF configure "$@" || exit 1
+cd $PREVPATH
diff --git a/buildtools/testwaf.sh b/buildtools/testwaf.sh
new file mode 100755
index 0000000000..8b65af2c10
--- /dev/null
+++ b/buildtools/testwaf.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+set -e
+set -x
+
+d=$(dirname $0)
+
+cd $d/..
+PREFIX=$HOME/testprefix
+
+if [ $# -gt 0 ]; then
+ tests="$*"
+else
+ tests="lib/replace lib/talloc lib/tevent lib/tdb source4/lib/ldb"
+fi
+
+echo "testing in dirs $tests"
+
+for d in $tests; do
+ echo "`date`: testing $d"
+ pushd $d
+ rm -rf bin
+ type waf
+ waf dist
+ ./configure -C --enable-developer --prefix=$PREFIX
+ time make
+ make install
+ make distcheck
+ case $d in
+ "source4/lib/ldb")
+ ldd bin/ldbadd
+ ;;
+ "lib/replace")
+ ldd bin/replace_testsuite
+ ;;
+ "lib/talloc")
+ ldd bin/talloc_testsuite
+ ;;
+ "lib/tdb")
+ ldd bin/tdbtool
+ ;;
+ esac
+ popd
+done
+
+echo "testing python portability"
+pushd lib/talloc
+versions="python2.4 python2.5 python2.6 python3.0 python3.1"
+for p in $versions; do
+ ret=$(which $p || echo "failed")
+ if [ $ret = "failed" ]; then
+ echo "$p not found, skipping"
+ continue
+ fi
+ echo "Testing $p"
+ $p ../../buildtools/bin/waf configure -C --enable-developer --prefix=$PREFIX
+ $p ../../buildtools/bin/waf build install
+done
+popd
+
+echo "testing cross compiling"
+pushd lib/talloc
+ret=$(which arm-linux-gnueabi-gcc || echo "failed")
+if [ $ret != "failed" ]; then
+ CC=arm-linux-gnueabi-gcc ./configure -C --prefix=$PREFIX --cross-compile --cross-execute='runarm'
+ make && make install
+else
+ echo "Cross-compiler not installed, skipping test"
+fi
+popd
diff --git a/buildtools/wafsamba/README b/buildtools/wafsamba/README
new file mode 100644
index 0000000000..1968b55453
--- /dev/null
+++ b/buildtools/wafsamba/README
@@ -0,0 +1,8 @@
+This is a set of waf 'tools' to help make building the Samba
+components easier, by having common functions in one place. This gives
+us a more consistent build, and ensures that our project rules are
+obeyed
+
+
+TODO:
+ see http://wiki.samba.org/index.php/Waf
diff --git a/buildtools/wafsamba/gccdeps.py b/buildtools/wafsamba/gccdeps.py
new file mode 100644
index 0000000000..6600c9ca3b
--- /dev/null
+++ b/buildtools/wafsamba/gccdeps.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2008-2010 (ita)
+
+"""
+Execute the tasks with gcc -MD, read the dependencies from the .d file
+and prepare the dependency calculation for the next run
+"""
+
+import os, re, threading
+import Task, Logs, Utils, preproc
+from TaskGen import before, after, feature
+
+lock = threading.Lock()
+
+preprocessor_flag = '-MD'
+
+@feature('cc')
+@before('apply_core')
+def add_mmd_cc(self):
+ if self.env.get_flat('CCFLAGS').find(preprocessor_flag) < 0:
+ self.env.append_value('CCFLAGS', preprocessor_flag)
+
+@feature('cxx')
+@before('apply_core')
+def add_mmd_cxx(self):
+ if self.env.get_flat('CXXFLAGS').find(preprocessor_flag) < 0:
+ self.env.append_value('CXXFLAGS', preprocessor_flag)
+
+def scan(self):
+ "the scanner does not do anything initially"
+ nodes = self.generator.bld.node_deps.get(self.unique_id(), [])
+ names = []
+ return (nodes, names)
+
+re_o = re.compile("\.o$")
+re_src = re.compile("^(\.\.)[\\/](.*)$")
+
+def post_run(self):
+ # The following code is executed by threads, it is not safe, so a lock is needed...
+
+ if getattr(self, 'cached', None):
+ return Task.Task.post_run(self)
+
+ name = self.outputs[0].abspath(self.env)
+ name = re_o.sub('.d', name)
+ txt = Utils.readf(name)
+ #os.unlink(name)
+
+ txt = txt.replace('\\\n', '')
+
+ lst = txt.strip().split(':')
+ val = ":".join(lst[1:])
+ val = val.split()
+
+ nodes = []
+ bld = self.generator.bld
+
+ f = re.compile("^("+self.env.variant()+"|\.\.)[\\/](.*)$")
+ for x in val:
+ if os.path.isabs(x):
+
+ if not preproc.go_absolute:
+ continue
+
+ lock.acquire()
+ try:
+ node = bld.root.find_resource(x)
+ finally:
+ lock.release()
+ else:
+ g = re.search(re_src, x)
+ if g:
+ x = g.group(2)
+ lock.acquire()
+ try:
+ node = bld.bldnode.parent.find_resource(x)
+ finally:
+ lock.release()
+ else:
+ g = re.search(f, x)
+ if g:
+ x = g.group(2)
+ lock.acquire()
+ try:
+ node = bld.srcnode.find_resource(x)
+ finally:
+ lock.release()
+
+ if id(node) == id(self.inputs[0]):
+ # ignore the source file, it is already in the dependencies
+ # this way, successful config tests may be retrieved from the cache
+ continue
+
+ if not node:
+ raise ValueError('could not find %r for %r' % (x, self))
+ else:
+ nodes.append(node)
+
+ Logs.debug('deps: real scanner for %s returned %s' % (str(self), str(nodes)))
+
+ bld.node_deps[self.unique_id()] = nodes
+ bld.raw_deps[self.unique_id()] = []
+
+ try:
+ del self.cache_sig
+ except:
+ pass
+
+ Task.Task.post_run(self)
+
+import Constants, Utils
+def sig_implicit_deps(self):
+ try:
+ return Task.Task.sig_implicit_deps(self)
+ except Utils.WafError:
+ return Constants.SIG_NIL
+
+for name in 'cc cxx'.split():
+ try:
+ cls = Task.TaskBase.classes[name]
+ except KeyError:
+ pass
+ else:
+ cls.post_run = post_run
+ cls.scan = scan
+ cls.sig_implicit_deps = sig_implicit_deps
+
diff --git a/buildtools/wafsamba/generic_cc.py b/buildtools/wafsamba/generic_cc.py
new file mode 100644
index 0000000000..ea277dc655
--- /dev/null
+++ b/buildtools/wafsamba/generic_cc.py
@@ -0,0 +1,71 @@
+
+# compiler definition for a generic C compiler
+# based on suncc.py from waf
+
+import os, optparse
+import Utils, Options, Configure
+import ccroot, ar
+from Configure import conftest
+
+from compiler_cc import c_compiler
+
+c_compiler['default'] = ['gcc', 'generic_cc']
+c_compiler['hpux'] = ['gcc', 'generic_cc']
+
+@conftest
+def find_generic_cc(conf):
+ v = conf.env
+ cc = None
+ if v['CC']: cc = v['CC']
+ elif 'CC' in conf.environ: cc = conf.environ['CC']
+ if not cc: cc = conf.find_program('cc', var='CC')
+ if not cc: conf.fatal('generic_cc was not found')
+ cc = conf.cmd_to_list(cc)
+ v['CC'] = cc
+ v['CC_NAME'] = 'generic'
+
+@conftest
+def generic_cc_common_flags(conf):
+ v = conf.env
+
+ v['CC_SRC_F'] = ''
+ v['CC_TGT_F'] = ['-c', '-o', '']
+ v['CPPPATH_ST'] = '-I%s' # template for adding include paths
+
+ # linker
+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+ v['CCLNK_SRC_F'] = ''
+ v['CCLNK_TGT_F'] = ['-o', '']
+
+ v['LIB_ST'] = '-l%s' # template for adding libs
+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
+ v['STATICLIB_ST'] = '-l%s'
+ v['STATICLIBPATH_ST'] = '-L%s'
+ v['CCDEFINES_ST'] = '-D%s'
+
+# v['SONAME_ST'] = '-Wl,-h -Wl,%s'
+# v['SHLIB_MARKER'] = '-Bdynamic'
+# v['STATICLIB_MARKER'] = '-Bstatic'
+
+ # program
+ v['program_PATTERN'] = '%s'
+
+ # shared library
+# v['shlib_CCFLAGS'] = ['-Kpic', '-DPIC']
+# v['shlib_LINKFLAGS'] = ['-G']
+ v['shlib_PATTERN'] = 'lib%s.so'
+
+ # static lib
+# v['staticlib_LINKFLAGS'] = ['-Bstatic']
+# v['staticlib_PATTERN'] = 'lib%s.a'
+
+detect = '''
+find_generic_cc
+find_cpp
+find_ar
+generic_cc_common_flags
+cc_load_tools
+cc_add_flags
+link_add_flags
+'''
+
diff --git a/buildtools/wafsamba/hpuxcc.py b/buildtools/wafsamba/hpuxcc.py
new file mode 100644
index 0000000000..c263556cd8
--- /dev/null
+++ b/buildtools/wafsamba/hpuxcc.py
@@ -0,0 +1,56 @@
+# compiler definition for HPUX
+# based on suncc.py from waf
+
+import os, optparse, sys
+import Utils, Options, Configure
+import ccroot, ar
+from Configure import conftest
+import gcc
+
+
+@conftest
+def gcc_modifier_hpux(conf):
+ v=conf.env
+ v['CCFLAGS_DEBUG']=['-g']
+ v['CCFLAGS_RELEASE']=['-O2']
+ v['CC_SRC_F']=''
+ v['CC_TGT_F']=['-c','-o','']
+ v['CPPPATH_ST']='-I%s'
+ if not v['LINK_CC']:v['LINK_CC']=v['CC']
+ v['CCLNK_SRC_F']=''
+ v['CCLNK_TGT_F']=['-o','']
+ v['LIB_ST']='-l%s'
+ v['LIBPATH_ST']='-L%s'
+ v['STATICLIB_ST']='-l%s'
+ v['STATICLIBPATH_ST']='-L%s'
+ v['RPATH_ST']='-Wl,-rpath,%s'
+ v['CCDEFINES_ST']='-D%s'
+ v['SONAME_ST']='-Wl,-h,%s'
+ v['SHLIB_MARKER']=[]
+# v['STATICLIB_MARKER']='-Wl,-Bstatic'
+ v['FULLSTATIC_MARKER']='-static'
+ v['program_PATTERN']='%s'
+ v['shlib_CCFLAGS']=['-fPIC','-DPIC']
+ v['shlib_LINKFLAGS']=['-shared']
+ v['shlib_PATTERN']='lib%s.sl'
+# v['staticlib_LINKFLAGS']=['-Wl,-Bstatic']
+ v['staticlib_PATTERN']='lib%s.a'
+
+gcc.gcc_modifier_hpux = gcc_modifier_hpux
+
+from TaskGen import feature, after
+@feature('cprogram', 'cshlib')
+@after('apply_link', 'apply_lib_vars', 'apply_obj_vars')
+def hpux_addfullpath(self):
+ if sys.platform == 'hp-ux11':
+ link = getattr(self, 'link_task', None)
+ if link:
+ lst = link.env.LINKFLAGS
+ buf = []
+ for x in lst:
+ if x.startswith('-L'):
+ p2 = x[2:]
+ if not os.path.isabs(p2):
+ x = x[:2] + self.bld.srcnode.abspath(link.env) + "/../" + x[2:].lstrip('.')
+ buf.append(x)
+ link.env.LINKFLAGS = buf
diff --git a/buildtools/wafsamba/irixcc.py b/buildtools/wafsamba/irixcc.py
new file mode 100644
index 0000000000..1461bf8c83
--- /dev/null
+++ b/buildtools/wafsamba/irixcc.py
@@ -0,0 +1,77 @@
+
+# compiler definition for irix/MIPSpro cc compiler
+# based on suncc.py from waf
+
+import os, optparse
+import Utils, Options, Configure
+import ccroot, ar
+from Configure import conftest
+
+from compiler_cc import c_compiler
+
+c_compiler['irix'] = ['gcc', 'irixcc']
+
+@conftest
+def find_irixcc(conf):
+ v = conf.env
+ cc = None
+ if v['CC']: cc = v['CC']
+ elif 'CC' in conf.environ: cc = conf.environ['CC']
+ if not cc: cc = conf.find_program('cc', var='CC')
+ if not cc: conf.fatal('irixcc was not found')
+ cc = conf.cmd_to_list(cc)
+
+ try:
+ if Utils.cmd_output(cc + ['-version']) != '':
+ conf.fatal('irixcc %r was not found' % cc)
+ except ValueError:
+ conf.fatal('irixcc -v could not be executed')
+
+ v['CC'] = cc
+ v['CC_NAME'] = 'irix'
+
+@conftest
+def irixcc_common_flags(conf):
+ v = conf.env
+
+ v['CC_SRC_F'] = ''
+ v['CC_TGT_F'] = ['-c', '-o', '']
+ v['CPPPATH_ST'] = '-I%s' # template for adding include paths
+
+ # linker
+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+ v['CCLNK_SRC_F'] = ''
+ v['CCLNK_TGT_F'] = ['-o', '']
+
+ v['LIB_ST'] = '-l%s' # template for adding libs
+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
+ v['STATICLIB_ST'] = '-l%s'
+ v['STATICLIBPATH_ST'] = '-L%s'
+ v['CCDEFINES_ST'] = '-D%s'
+
+# v['SONAME_ST'] = '-Wl,-h -Wl,%s'
+# v['SHLIB_MARKER'] = '-Bdynamic'
+# v['STATICLIB_MARKER'] = '-Bstatic'
+
+ # program
+ v['program_PATTERN'] = '%s'
+
+ # shared library
+# v['shlib_CCFLAGS'] = ['-Kpic', '-DPIC']
+# v['shlib_LINKFLAGS'] = ['-G']
+ v['shlib_PATTERN'] = 'lib%s.so'
+
+ # static lib
+# v['staticlib_LINKFLAGS'] = ['-Bstatic']
+# v['staticlib_PATTERN'] = 'lib%s.a'
+
+detect = '''
+find_irixcc
+find_cpp
+find_ar
+irixcc_common_flags
+cc_load_tools
+cc_add_flags
+link_add_flags
+'''
+
diff --git a/buildtools/wafsamba/nothreads.py b/buildtools/wafsamba/nothreads.py
new file mode 100644
index 0000000000..9054a57af5
--- /dev/null
+++ b/buildtools/wafsamba/nothreads.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005-2008 (ita)
+
+# this replaces the core of Runner.py in waf with a varient that works
+# on systems with completely broken threading (such as Python 2.5.x on
+# AIX). For simplicity we enable this when JOBS=1, which is triggered
+# by the compatibility makefile used for the waf build. That also ensures
+# this code is tested, as it means it is used in the build farm, and by
+# anyone using 'make' to build Samba with waf
+
+"Execute the tasks"
+
+import sys, random, time, threading, traceback, os
+try: from Queue import Queue
+except ImportError: from queue import Queue
+import Build, Utils, Logs, Options
+from Logs import debug, error
+from Constants import *
+
+GAP = 15
+
+run_old = threading.Thread.run
+def run(*args, **kwargs):
+ try:
+ run_old(*args, **kwargs)
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except:
+ sys.excepthook(*sys.exc_info())
+threading.Thread.run = run
+
+
+class TaskConsumer(object):
+ consumers = 1
+
+def process(tsk):
+ m = tsk.master
+ if m.stop:
+ m.out.put(tsk)
+ return
+
+ try:
+ tsk.generator.bld.printout(tsk.display())
+ if tsk.__class__.stat: ret = tsk.__class__.stat(tsk)
+ # actual call to task's run() function
+ else: ret = tsk.call_run()
+ except Exception, e:
+ tsk.err_msg = Utils.ex_stack()
+ tsk.hasrun = EXCEPTION
+
+ # TODO cleanup
+ m.error_handler(tsk)
+ m.out.put(tsk)
+ return
+
+ if ret:
+ tsk.err_code = ret
+ tsk.hasrun = CRASHED
+ else:
+ try:
+ tsk.post_run()
+ except Utils.WafError:
+ pass
+ except Exception:
+ tsk.err_msg = Utils.ex_stack()
+ tsk.hasrun = EXCEPTION
+ else:
+ tsk.hasrun = SUCCESS
+ if tsk.hasrun != SUCCESS:
+ m.error_handler(tsk)
+
+ m.out.put(tsk)
+
+class Parallel(object):
+ """
+ keep the consumer threads busy, and avoid consuming cpu cycles
+ when no more tasks can be added (end of the build, etc)
+ """
+ def __init__(self, bld, j=2):
+
+ # number of consumers
+ self.numjobs = j
+
+ self.manager = bld.task_manager
+ self.manager.current_group = 0
+
+ self.total = self.manager.total()
+
+ # tasks waiting to be processed - IMPORTANT
+ self.outstanding = []
+ self.maxjobs = MAXJOBS
+
+ # tasks that are awaiting for another task to complete
+ self.frozen = []
+
+ # tasks returned by the consumers
+ self.out = Queue(0)
+
+ self.count = 0 # tasks not in the producer area
+
+ self.processed = 1 # progress indicator
+
+ self.stop = False # error condition to stop the build
+ self.error = False # error flag
+
+ def get_next(self):
+ "override this method to schedule the tasks in a particular order"
+ if not self.outstanding:
+ return None
+ return self.outstanding.pop(0)
+
+ def postpone(self, tsk):
+ "override this method to schedule the tasks in a particular order"
+ # TODO consider using a deque instead
+ if random.randint(0, 1):
+ self.frozen.insert(0, tsk)
+ else:
+ self.frozen.append(tsk)
+
+ def refill_task_list(self):
+ "called to set the next group of tasks"
+
+ while self.count > self.numjobs + GAP or self.count >= self.maxjobs:
+ self.get_out()
+
+ while not self.outstanding:
+ if self.count:
+ self.get_out()
+
+ if self.frozen:
+ self.outstanding += self.frozen
+ self.frozen = []
+ elif not self.count:
+ (jobs, tmp) = self.manager.get_next_set()
+ if jobs != None: self.maxjobs = jobs
+ if tmp: self.outstanding += tmp
+ break
+
+ def get_out(self):
+ "the tasks that are put to execute are all collected using get_out"
+ ret = self.out.get()
+ self.manager.add_finished(ret)
+ if not self.stop and getattr(ret, 'more_tasks', None):
+ self.outstanding += ret.more_tasks
+ self.total += len(ret.more_tasks)
+ self.count -= 1
+
+ def error_handler(self, tsk):
+ "by default, errors make the build stop (not thread safe so be careful)"
+ if not Options.options.keep:
+ self.stop = True
+ self.error = True
+
+ def start(self):
+ "execute the tasks"
+
+ while not self.stop:
+
+ self.refill_task_list()
+
+ # consider the next task
+ tsk = self.get_next()
+ if not tsk:
+ if self.count:
+ # tasks may add new ones after they are run
+ continue
+ else:
+ # no tasks to run, no tasks running, time to exit
+ break
+
+ if tsk.hasrun:
+ # if the task is marked as "run", just skip it
+ self.processed += 1
+ self.manager.add_finished(tsk)
+ continue
+
+ try:
+ st = tsk.runnable_status()
+ except Exception, e:
+ self.processed += 1
+ if self.stop and not Options.options.keep:
+ tsk.hasrun = SKIPPED
+ self.manager.add_finished(tsk)
+ continue
+ self.error_handler(tsk)
+ self.manager.add_finished(tsk)
+ tsk.hasrun = EXCEPTION
+ tsk.err_msg = Utils.ex_stack()
+ continue
+
+ if st == ASK_LATER:
+ self.postpone(tsk)
+ elif st == SKIP_ME:
+ self.processed += 1
+ tsk.hasrun = SKIPPED
+ self.manager.add_finished(tsk)
+ else:
+ # run me: put the task in ready queue
+ tsk.position = (self.processed, self.total)
+ self.count += 1
+ self.processed += 1
+ tsk.master = self
+
+ process(tsk)
+
+ # self.count represents the tasks that have been made available to the consumer threads
+ # collect all the tasks after an error else the message may be incomplete
+ while self.error and self.count:
+ self.get_out()
+
+ #print loop
+ assert (self.count == 0 or self.stop)
+
+
+# enable nothreads
+import Runner
+Runner.process = process
+Runner.Parallel = Parallel
diff --git a/buildtools/wafsamba/pkgconfig.py b/buildtools/wafsamba/pkgconfig.py
new file mode 100644
index 0000000000..09bfcb9c6b
--- /dev/null
+++ b/buildtools/wafsamba/pkgconfig.py
@@ -0,0 +1,68 @@
+# handle substitution of variables in pc files
+
+import Build, sys, Logs
+from samba_utils import *
+
+def subst_at_vars(task):
+ '''substiture @VAR@ style variables in a file'''
+ src = task.inputs[0].srcpath(task.env)
+ tgt = task.outputs[0].bldpath(task.env)
+
+ f = open(src, 'r')
+ s = f.read()
+ f.close()
+ # split on the vars
+ a = re.split('(@\w+@)', s)
+ out = []
+ done_var = {}
+ back_sub = [ ('PREFIX', '${prefix}'), ('EXEC_PREFIX', '${exec_prefix}')]
+ for v in a:
+ if re.match('@\w+@', v):
+ vname = v[1:-1]
+ if not vname in task.env and vname.upper() in task.env:
+ vname = vname.upper()
+ if not vname in task.env:
+ Logs.error("Unknown substitution %s in %s" % (v, task.name))
+ sys.exit(1)
+ v = SUBST_VARS_RECURSIVE(task.env[vname], task.env)
+ # now we back substitute the allowed pc vars
+ for (b, m) in back_sub:
+ s = task.env[b]
+ if s == v[0:len(s)]:
+ if not b in done_var:
+ # we don't want to substitute the first usage
+ done_var[b] = True
+ else:
+ v = m + v[len(s):]
+ break
+ out.append(v)
+ contents = ''.join(out)
+ f = open(tgt, 'w')
+ s = f.write(contents)
+ f.close()
+ return 0
+
+
+def PKG_CONFIG_FILES(bld, pc_files, vnum=None):
+ '''install some pkg_config pc files'''
+ dest = '${PKGCONFIGDIR}'
+ dest = bld.EXPAND_VARIABLES(dest)
+ for f in TO_LIST(pc_files):
+ base=os.path.basename(f)
+ t = bld.SAMBA_GENERATOR('PKGCONFIG_%s' % base,
+ rule=subst_at_vars,
+ source=f+'.in',
+ target=f)
+ t.vars = []
+ if t.env.RPATH_ON_INSTALL:
+ t.env.LIB_RPATH = t.env.RPATH_ST % t.env.LIBDIR
+ else:
+ t.env.LIB_RPATH = ''
+ if vnum:
+ t.env.PACKAGE_VERSION = vnum
+ for v in [ 'PREFIX', 'EXEC_PREFIX', 'LIB_RPATH' ]:
+ t.vars.append(t.env[v])
+ bld.INSTALL_FILES(dest, f, flat=True, destname=base)
+Build.BuildContext.PKG_CONFIG_FILES = PKG_CONFIG_FILES
+
+
diff --git a/buildtools/wafsamba/samba3.py b/buildtools/wafsamba/samba3.py
new file mode 100644
index 0000000000..cb459ad115
--- /dev/null
+++ b/buildtools/wafsamba/samba3.py
@@ -0,0 +1,110 @@
+# a waf tool to add autoconf-like macros to the configure section
+# and for SAMBA_ macros for building libraries, binaries etc
+
+import Options, Build, os
+from optparse import SUPPRESS_HELP
+from samba_utils import os_path_relpath, TO_LIST
+
+def SAMBA3_ADD_OPTION(opt, option, help=(), dest=None, default=True,
+ with_name="with", without_name="without"):
+ if help == ():
+ help = ("Build with %s support" % option)
+ if dest is None:
+ dest = "with_%s" % option.replace('-', '_')
+
+ with_val = "--%s-%s" % (with_name, option)
+ without_val = "--%s-%s" % (without_name, option)
+
+ #FIXME: This is broken and will always default to "default" no matter if
+ # --with or --without is chosen.
+ opt.add_option(with_val, help=help, action="store_true", dest=dest,
+ default=default)
+ opt.add_option(without_val, help=SUPPRESS_HELP, action="store_false",
+ dest=dest)
+Options.Handler.SAMBA3_ADD_OPTION = SAMBA3_ADD_OPTION
+
+def SAMBA3_IS_STATIC_MODULE(bld, module):
+ '''Check whether module is in static list'''
+ if module in bld.env['static_modules']:
+ return True
+ return False
+Build.BuildContext.SAMBA3_IS_STATIC_MODULE = SAMBA3_IS_STATIC_MODULE
+
+def SAMBA3_IS_SHARED_MODULE(bld, module):
+ '''Check whether module is in shared list'''
+ if module in bld.env['shared_modules']:
+ return True
+ return False
+Build.BuildContext.SAMBA3_IS_SHARED_MODULE = SAMBA3_IS_SHARED_MODULE
+
+def SAMBA3_IS_ENABLED_MODULE(bld, module):
+ '''Check whether module is in either shared or static list '''
+ return SAMBA3_IS_STATIC_MODULE(bld, module) or SAMBA3_IS_SHARED_MODULE(bld, module)
+Build.BuildContext.SAMBA3_IS_ENABLED_MODULE = SAMBA3_IS_ENABLED_MODULE
+
+
+
+def s3_fix_kwargs(bld, kwargs):
+ '''fix the build arguments for s3 build rules to include the
+ necessary includes, subdir and cflags options '''
+ s3dir = os.path.join(bld.env.srcdir, 'source3')
+ s3reldir = os_path_relpath(s3dir, bld.curdir)
+
+ # the extra_includes list is relative to the source3 directory
+ extra_includes = [ '.', 'include', 'lib' ]
+ if bld.env.use_intree_heimdal:
+ extra_includes += [ '../source4/heimdal/lib/com_err',
+ '../source4/heimdal/lib/gssapi',
+ '../source4/heimdal_build' ]
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TDB'):
+ extra_includes += [ '../lib/tdb/include' ]
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TEVENT'):
+ extra_includes += [ '../lib/tevent' ]
+
+ if not bld.CONFIG_SET('USING_SYSTEM_TALLOC'):
+ extra_includes += [ '../lib/talloc' ]
+
+ if not bld.CONFIG_SET('USING_SYSTEM_POPT'):
+ extra_includes += [ '../lib/popt' ]
+
+ # s3 builds assume that they will have a bunch of extra include paths
+ includes = []
+ for d in extra_includes:
+ includes += [ os.path.join(s3reldir, d) ]
+
+ # the rule may already have some includes listed
+ if 'includes' in kwargs:
+ includes += TO_LIST(kwargs['includes'])
+ kwargs['includes'] = includes
+
+ # some S3 code assumes that CONFIGFILE is set
+ cflags = ['-DCONFIGFILE="%s"' % bld.env['CONFIGFILE']]
+ if 'cflags' in kwargs:
+ cflags += TO_LIST(kwargs['cflags'])
+ kwargs['cflags'] = cflags
+
+# these wrappers allow for mixing of S3 and S4 build rules in the one build
+
+def SAMBA3_LIBRARY(bld, name, *args, **kwargs):
+ s3_fix_kwargs(bld, kwargs)
+ kwargs['allow_undefined_symbols'] = True
+ return bld.SAMBA_LIBRARY(name, *args, **kwargs)
+Build.BuildContext.SAMBA3_LIBRARY = SAMBA3_LIBRARY
+
+def SAMBA3_MODULE(bld, name, *args, **kwargs):
+ s3_fix_kwargs(bld, kwargs)
+ kwargs['allow_undefined_symbols'] = True
+ return bld.SAMBA_MODULE(name, *args, **kwargs)
+Build.BuildContext.SAMBA3_MODULE = SAMBA3_MODULE
+
+def SAMBA3_SUBSYSTEM(bld, name, *args, **kwargs):
+ s3_fix_kwargs(bld, kwargs)
+ return bld.SAMBA_SUBSYSTEM(name, *args, **kwargs)
+Build.BuildContext.SAMBA3_SUBSYSTEM = SAMBA3_SUBSYSTEM
+
+def SAMBA3_BINARY(bld, name, *args, **kwargs):
+ s3_fix_kwargs(bld, kwargs)
+ return bld.SAMBA_BINARY(name, *args, **kwargs)
+Build.BuildContext.SAMBA3_BINARY = SAMBA3_BINARY
diff --git a/buildtools/wafsamba/samba_abi.py b/buildtools/wafsamba/samba_abi.py
new file mode 100644
index 0000000000..990e1e5fdf
--- /dev/null
+++ b/buildtools/wafsamba/samba_abi.py
@@ -0,0 +1,234 @@
+# functions for handling ABI checking of libraries
+
+import Options, Utils, os, Logs, samba_utils, sys, Task, fnmatch, re, Build
+from TaskGen import feature, before, after
+
+# these type maps cope with platform specific names for common types
+# please add new type mappings into the list below
+abi_type_maps = {
+ '_Bool' : 'bool',
+ 'struct __va_list_tag *' : 'va_list'
+ }
+
+version_key = lambda x: map(int, x.split("."))
+
+def normalise_signature(sig):
+ '''normalise a signature from gdb'''
+ sig = sig.strip()
+ sig = re.sub('^\$[0-9]+\s=\s\{*', '', sig)
+ sig = re.sub('\}(\s0x[0-9a-f]+\s<\w+>)?$', '', sig)
+ sig = re.sub('0x[0-9a-f]+', '0xXXXX', sig)
+
+ for t in abi_type_maps:
+ # we need to cope with non-word characters in mapped types
+ m = t
+ m = m.replace('*', '\*')
+ if m[-1].isalnum() or m[-1] == '_':
+ m += '\\b'
+ if m[0].isalnum() or m[0] == '_':
+ m = '\\b' + m
+ sig = re.sub(m, abi_type_maps[t], sig)
+ return sig
+
+def normalise_varargs(sig):
+ '''cope with older versions of gdb'''
+ sig = re.sub(',\s\.\.\.', '', sig)
+ return sig
+
+def parse_sigs(sigs, abi_match):
+ '''parse ABI signatures file'''
+ abi_match = samba_utils.TO_LIST(abi_match)
+ ret = {}
+ a = sigs.split('\n')
+ for s in a:
+ if s.find(':') == -1:
+ continue
+ sa = s.split(':')
+ if abi_match:
+ matched = False
+ for p in abi_match:
+ if p[0] == '!' and fnmatch.fnmatch(sa[0], p[1:]):
+ break
+ elif fnmatch.fnmatch(sa[0], p):
+ matched = True
+ break
+ if not matched:
+ continue
+ ret[sa[0]] = normalise_signature(sa[1])
+ return ret
+
+def save_sigs(sig_file, parsed_sigs):
+ '''save ABI signatures to a file'''
+ sigs = ''
+ for s in sorted(parsed_sigs.keys()):
+ sigs += '%s: %s\n' % (s, parsed_sigs[s])
+ return samba_utils.save_file(sig_file, sigs, create_dir=True)
+
+
+def abi_check_task(self):
+ '''check if the ABI has changed'''
+ abi_gen = self.ABI_GEN
+
+ libpath = self.inputs[0].abspath(self.env)
+ libname = os.path.basename(libpath)
+
+ sigs = Utils.cmd_output([abi_gen, libpath])
+ parsed_sigs = parse_sigs(sigs, self.ABI_MATCH)
+
+ sig_file = self.ABI_FILE
+
+ old_sigs = samba_utils.load_file(sig_file)
+ if old_sigs is None or Options.options.ABI_UPDATE:
+ if not save_sigs(sig_file, parsed_sigs):
+ raise Utils.WafError('Failed to save ABI file "%s"' % sig_file)
+ Logs.warn('Generated ABI signatures %s' % sig_file)
+ return
+
+ parsed_old_sigs = parse_sigs(old_sigs, self.ABI_MATCH)
+
+ # check all old sigs
+ got_error = False
+ for s in parsed_old_sigs:
+ if not s in parsed_sigs:
+ Logs.error('%s: symbol %s has been removed - please update major version\n\tsignature: %s' % (
+ libname, s, parsed_old_sigs[s]))
+ got_error = True
+ elif normalise_varargs(parsed_old_sigs[s]) != normalise_varargs(parsed_sigs[s]):
+ Logs.error('%s: symbol %s has changed - please update major version\n\told_signature: %s\n\tnew_signature: %s' % (
+ libname, s, parsed_old_sigs[s], parsed_sigs[s]))
+ got_error = True
+
+ for s in parsed_sigs:
+ if not s in parsed_old_sigs:
+ Logs.error('%s: symbol %s has been added - please mark it _PRIVATE_ or update minor version\n\tsignature: %s' % (
+ libname, s, parsed_sigs[s]))
+ got_error = True
+
+ if got_error:
+ raise Utils.WafError('ABI for %s has changed - please fix library version then build with --abi-update\nSee http://wiki.samba.org/index.php/Waf#ABI_Checking for more information' % libname)
+
+
+t = Task.task_type_from_func('abi_check', abi_check_task, color='BLUE', ext_in='.bin')
+t.quiet = True
+# allow "waf --abi-check" to force re-checking the ABI
+if '--abi-check' in sys.argv:
+ Task.always_run(t)
+
+@after('apply_link')
+@feature('abi_check')
+def abi_check(self):
+ '''check that ABI matches saved signatures'''
+ env = self.bld.env
+ if not env.ABI_CHECK or self.abi_directory is None:
+ return
+
+ # if the platform doesn't support -fvisibility=hidden then the ABI
+ # checks become fairly meaningless
+ if not env.HAVE_VISIBILITY_ATTR:
+ return
+
+ topsrc = self.bld.srcnode.abspath()
+ abi_gen = os.path.join(topsrc, 'buildtools/scripts/abi_gen.sh')
+
+ abi_file = "%s/%s-%s.sigs" % (self.abi_directory, self.name, self.vnum)
+
+ tsk = self.create_task('abi_check', self.link_task.outputs[0])
+ tsk.ABI_FILE = abi_file
+ tsk.ABI_MATCH = self.abi_match
+ tsk.ABI_GEN = abi_gen
+
+
+def abi_process_file(fname, version, symmap):
+ '''process one ABI file, adding new symbols to the symmap'''
+ f = open(fname, mode='r')
+ for line in f:
+ symname = line.split(":")[0]
+ if not symname in symmap:
+ symmap[symname] = version
+ f.close()
+
+def abi_write_vscript(vscript, libname, current_version, versions, symmap, abi_match):
+ '''write a vscript file for a library in --version-script format
+
+ :param vscript: Path to the vscript file
+ :param libname: Name of the library, uppercased
+ :param current_version: Current version
+ :param versions: Versions to consider
+ :param symmap: Dictionary mapping symbols -> version
+ :param abi_match: List of symbols considered to be public in the current version
+ '''
+
+ invmap = {}
+ for s in symmap:
+ invmap.setdefault(symmap[s], []).append(s)
+
+ f = open(vscript, mode='w')
+ last_key = ""
+ versions = sorted(versions, key=version_key)
+ for k in versions:
+ symver = "%s_%s" % (libname, k)
+ if symver == current_version:
+ break
+ f.write("%s {\n" % symver)
+ if k in invmap:
+ f.write("\tglobal: \n")
+ for s in invmap.get(k, []):
+ f.write("\t\t%s;\n" % s);
+ f.write("}%s;\n\n" % last_key)
+ last_key = " %s" % symver
+ f.write("%s {\n" % current_version)
+ f.write("\tglobal:\n")
+ for x in abi_match:
+ f.write("\t\t%s;\n" % x)
+ if abi_match != ["*"]:
+ f.write("\tlocal: *;\n")
+ f.write("};\n")
+ f.close()
+
+
+def abi_build_vscript(task):
+ '''generate a vscript file for our public libraries'''
+
+ tgt = task.outputs[0].bldpath(task.env)
+
+ symmap = {}
+ versions = []
+ for f in task.inputs:
+ fname = f.abspath(task.env)
+ basename = os.path.basename(fname)
+ version = basename[len(task.env.LIBNAME)+1:-len(".sigs")]
+ versions.append(version)
+ abi_process_file(fname, version, symmap)
+ abi_write_vscript(tgt, task.env.LIBNAME, task.env.VERSION, versions, symmap,
+ task.env.ABI_MATCH)
+
+
+def ABI_VSCRIPT(bld, libname, abi_directory, version, vscript, abi_match=None):
+ '''generate a vscript file for our public libraries'''
+ if abi_directory:
+ source = bld.path.ant_glob('%s/%s-[0-9]*.sigs' % (abi_directory, libname))
+ def abi_file_key(path):
+ return version_key(path[:-len(".sigs")].rsplit("-")[-1])
+ source = sorted(source.split(), key=abi_file_key)
+ else:
+ source = ''
+
+ libname = os.path.basename(libname)
+ version = os.path.basename(version)
+ libname = libname.replace("-", "_").replace("+","_").upper()
+ version = version.replace("-", "_").replace("+","_").upper()
+
+ t = bld.SAMBA_GENERATOR(vscript,
+ rule=abi_build_vscript,
+ source=source,
+ group='vscripts',
+ target=vscript)
+ if abi_match is None:
+ abi_match = ["*"]
+ else:
+ abi_match = samba_utils.TO_LIST(abi_match)
+ t.env.ABI_MATCH = abi_match
+ t.env.VERSION = version
+ t.env.LIBNAME = libname
+ t.vars = ['LIBNAME', 'VERSION', 'ABI_MATCH']
+Build.BuildContext.ABI_VSCRIPT = ABI_VSCRIPT
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
new file mode 100644
index 0000000000..174ca14210
--- /dev/null
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -0,0 +1,715 @@
+# a waf tool to add autoconf-like macros to the configure section
+
+import Build, os, sys, Options, preproc, Logs
+import string
+from Configure import conf
+from samba_utils import *
+import samba_cross
+
+missing_headers = set()
+
+####################################################
+# some autoconf like helpers, to make the transition
+# to waf a bit easier for those used to autoconf
+# m4 files
+
+@runonce
+@conf
+def DEFINE(conf, d, v, add_to_cflags=False, quote=False):
+ '''define a config option'''
+ conf.define(d, v, quote=quote)
+ if add_to_cflags:
+ conf.env.append_value('CCDEFINES', d + '=' + str(v))
+
+def hlist_to_string(conf, headers=None):
+ '''convert a headers list to a set of #include lines'''
+ hdrs=''
+ hlist = conf.env.hlist
+ if headers:
+ hlist = hlist[:]
+ hlist.extend(TO_LIST(headers))
+ for h in hlist:
+ hdrs += '#include <%s>\n' % h
+ return hdrs
+
+
+@conf
+def COMPOUND_START(conf, msg):
+ '''start a compound test'''
+ def null_check_message_1(self,*k,**kw):
+ return
+ def null_check_message_2(self,*k,**kw):
+ return
+
+ v = getattr(conf.env, 'in_compound', [])
+ if v != [] and v != 0:
+ conf.env.in_compound = v + 1
+ return
+ conf.check_message_1(msg)
+ conf.saved_check_message_1 = conf.check_message_1
+ conf.check_message_1 = null_check_message_1
+ conf.saved_check_message_2 = conf.check_message_2
+ conf.check_message_2 = null_check_message_2
+ conf.env.in_compound = 1
+
+
+@conf
+def COMPOUND_END(conf, result):
+ '''start a compound test'''
+ conf.env.in_compound -= 1
+ if conf.env.in_compound != 0:
+ return
+ conf.check_message_1 = conf.saved_check_message_1
+ conf.check_message_2 = conf.saved_check_message_2
+ p = conf.check_message_2
+ if result == True:
+ p('ok ')
+ elif result == False:
+ p('not found', 'YELLOW')
+ else:
+ p(result)
+
+
+@feature('nolink')
+def nolink(self):
+ '''using the nolink type in conf.check() allows us to avoid
+ the link stage of a test, thus speeding it up for tests
+ that where linking is not needed'''
+ pass
+
+
+def CHECK_HEADER(conf, h, add_headers=False, lib=None):
+ '''check for a header'''
+ if h in missing_headers and lib is None:
+ return False
+ d = h.upper().replace('/', '_')
+ d = d.replace('.', '_')
+ d = d.replace('-', '_')
+ d = 'HAVE_%s' % d
+ if CONFIG_SET(conf, d):
+ if add_headers:
+ if not h in conf.env.hlist:
+ conf.env.hlist.append(h)
+ return True
+
+ (ccflags, ldflags) = library_flags(conf, lib)
+
+ hdrs = hlist_to_string(conf, headers=h)
+ ret = conf.check(fragment='%s\nint main(void) { return 0; }' % hdrs,
+ type='nolink',
+ execute=0,
+ ccflags=ccflags,
+ msg="Checking for header %s" % h)
+ if not ret:
+ missing_headers.add(h)
+ return False
+
+ conf.DEFINE(d, 1)
+ if add_headers and not h in conf.env.hlist:
+ conf.env.hlist.append(h)
+ return ret
+
+
+@conf
+def CHECK_HEADERS(conf, headers, add_headers=False, together=False, lib=None):
+ '''check for a list of headers
+
+ when together==True, then the headers accumulate within this test.
+ This is useful for interdependent headers
+ '''
+ ret = True
+ if not add_headers and together:
+ saved_hlist = conf.env.hlist[:]
+ set_add_headers = True
+ else:
+ set_add_headers = add_headers
+ for hdr in TO_LIST(headers):
+ if not CHECK_HEADER(conf, hdr, set_add_headers, lib=lib):
+ ret = False
+ if not add_headers and together:
+ conf.env.hlist = saved_hlist
+ return ret
+
+
+def header_list(conf, headers=None, lib=None):
+ '''form a list of headers which exist, as a string'''
+ hlist=[]
+ if headers is not None:
+ for h in TO_LIST(headers):
+ if CHECK_HEADER(conf, h, add_headers=False, lib=lib):
+ hlist.append(h)
+ return hlist_to_string(conf, headers=hlist)
+
+
+@conf
+def CHECK_TYPE(conf, t, alternate=None, headers=None, define=None, lib=None, msg=None):
+ '''check for a single type'''
+ if define is None:
+ define = 'HAVE_' + t.upper().replace(' ', '_')
+ if msg is None:
+ msg='Checking for %s' % t
+ ret = CHECK_CODE(conf, '%s _x' % t,
+ define,
+ execute=False,
+ headers=headers,
+ local_include=False,
+ msg=msg,
+ lib=lib,
+ link=False)
+ if not ret and alternate:
+ conf.DEFINE(t, alternate)
+ return ret
+
+
+@conf
+def CHECK_TYPES(conf, list, headers=None, define=None, alternate=None, lib=None):
+ '''check for a list of types'''
+ ret = True
+ for t in TO_LIST(list):
+ if not CHECK_TYPE(conf, t, headers=headers,
+ define=define, alternate=alternate, lib=lib):
+ ret = False
+ return ret
+
+
+@conf
+def CHECK_TYPE_IN(conf, t, headers=None, alternate=None, define=None):
+ '''check for a single type with a header'''
+ return CHECK_TYPE(conf, t, headers=headers, alternate=alternate, define=define)
+
+
+@conf
+def CHECK_VARIABLE(conf, v, define=None, always=False,
+ headers=None, msg=None, lib=None):
+ '''check for a variable declaration (or define)'''
+ if define is None:
+ define = 'HAVE_%s' % v.upper()
+
+ if msg is None:
+ msg="Checking for variable %s" % v
+
+ return CHECK_CODE(conf,
+ # we need to make sure the compiler doesn't
+ # optimize it out...
+ '''
+ #ifndef %s
+ void *_x; _x=(void *)&%s; return (int)_x;
+ #endif
+ return 0
+ ''' % (v, v),
+ execute=False,
+ link=False,
+ msg=msg,
+ local_include=False,
+ lib=lib,
+ headers=headers,
+ define=define,
+ always=always)
+
+
+@conf
+def CHECK_DECLS(conf, vars, reverse=False, headers=None, always=False):
+ '''check a list of variable declarations, using the HAVE_DECL_xxx form
+ of define
+
+ When reverse==True then use HAVE_xxx_DECL instead of HAVE_DECL_xxx
+ '''
+ ret = True
+ for v in TO_LIST(vars):
+ if not reverse:
+ define='HAVE_DECL_%s' % v.upper()
+ else:
+ define='HAVE_%s_DECL' % v.upper()
+ if not CHECK_VARIABLE(conf, v,
+ define=define,
+ headers=headers,
+ msg='Checking for declaration of %s' % v,
+ always=always):
+ ret = False
+ return ret
+
+
+def CHECK_FUNC(conf, f, link=True, lib=None, headers=None):
+ '''check for a function'''
+ define='HAVE_%s' % f.upper()
+
+ ret = False
+
+ conf.COMPOUND_START('Checking for %s' % f)
+
+ if link is None or link == True:
+ ret = CHECK_CODE(conf,
+ # this is based on the autoconf strategy
+ '''
+ #define %s __fake__%s
+ #ifdef HAVE_LIMITS_H
+ # include <limits.h>
+ #else
+ # include <assert.h>
+ #endif
+ #undef %s
+ #if defined __stub_%s || defined __stub___%s
+ #error "bad glibc stub"
+ #endif
+ extern char %s();
+ int main() { return %s(); }
+ ''' % (f, f, f, f, f, f, f),
+ execute=False,
+ link=True,
+ addmain=False,
+ add_headers=False,
+ define=define,
+ local_include=False,
+ lib=lib,
+ headers=headers,
+ msg='Checking for %s' % f)
+
+ if not ret:
+ ret = CHECK_CODE(conf,
+ # it might be a macro
+ # we need to make sure the compiler doesn't
+ # optimize it out...
+ 'void *__x = (void *)%s; return (int)__x' % f,
+ execute=False,
+ link=True,
+ addmain=True,
+ add_headers=True,
+ define=define,
+ local_include=False,
+ lib=lib,
+ headers=headers,
+ msg='Checking for macro %s' % f)
+
+ if not ret and (link is None or link == False):
+ ret = CHECK_VARIABLE(conf, f,
+ define=define,
+ headers=headers,
+ msg='Checking for declaration of %s' % f)
+ conf.COMPOUND_END(ret)
+ return ret
+
+
+@conf
+def CHECK_FUNCS(conf, list, link=True, lib=None, headers=None):
+ '''check for a list of functions'''
+ ret = True
+ for f in TO_LIST(list):
+ if not CHECK_FUNC(conf, f, link=link, lib=lib, headers=headers):
+ ret = False
+ return ret
+
+
+@conf
+def CHECK_SIZEOF(conf, vars, headers=None, define=None):
+ '''check the size of a type'''
+ ret = True
+ for v in TO_LIST(vars):
+ v_define = define
+ if v_define is None:
+ v_define = 'SIZEOF_%s' % v.upper().replace(' ', '_')
+ if not CHECK_CODE(conf,
+ 'printf("%%u", (unsigned)sizeof(%s))' % v,
+ define=v_define,
+ execute=True,
+ define_ret=True,
+ quote=False,
+ headers=headers,
+ local_include=False,
+ msg="Checking size of %s" % v):
+ ret = False
+ return ret
+
+
+
+@conf
+def CHECK_CODE(conf, code, define,
+ always=False, execute=False, addmain=True,
+ add_headers=True, mandatory=False,
+ headers=None, msg=None, cflags='', includes='# .',
+ local_include=True, lib=None, link=True,
+ define_ret=False, quote=False,
+ on_target=True):
+ '''check if some code compiles and/or runs'''
+
+ if CONFIG_SET(conf, define):
+ return True
+
+ if headers is not None:
+ CHECK_HEADERS(conf, headers=headers, lib=lib)
+
+ if add_headers:
+ hdrs = header_list(conf, headers=headers, lib=lib)
+ else:
+ hdrs = ''
+ if execute:
+ execute = 1
+ else:
+ execute = 0
+
+ defs = conf.get_config_header()
+
+ if addmain:
+ fragment='%s\n%s\n int main(void) { %s; return 0; }\n' % (defs, hdrs, code)
+ else:
+ fragment='%s\n%s\n%s\n' % (defs, hdrs, code)
+
+ if msg is None:
+ msg="Checking for %s" % define
+
+ cflags = TO_LIST(cflags)
+
+ if local_include:
+ cflags.append('-I%s' % conf.curdir)
+
+ if not link:
+ type='nolink'
+ else:
+ type='cprogram'
+
+ uselib = TO_LIST(lib)
+
+ (ccflags, ldflags) = library_flags(conf, uselib)
+
+ cflags.extend(ccflags)
+
+ if on_target:
+ exec_args = conf.SAMBA_CROSS_ARGS(msg=msg)
+ else:
+ exec_args = []
+
+ conf.COMPOUND_START(msg)
+
+ ret = conf.check(fragment=fragment,
+ execute=execute,
+ define_name = define,
+ mandatory = mandatory,
+ ccflags=cflags,
+ ldflags=ldflags,
+ includes=includes,
+ uselib=uselib,
+ type=type,
+ msg=msg,
+ quote=quote,
+ exec_args=exec_args,
+ define_ret=define_ret)
+ if not ret and CONFIG_SET(conf, define):
+ # sometimes conf.check() returns false, but it
+ # sets the define. Maybe a waf bug?
+ ret = True
+ if ret:
+ if not define_ret:
+ conf.DEFINE(define, 1)
+ conf.COMPOUND_END(True)
+ else:
+ conf.COMPOUND_END(conf.env[define])
+ return True
+ if always:
+ conf.DEFINE(define, 0)
+ conf.COMPOUND_END(False)
+ return False
+
+
+
+@conf
+def CHECK_STRUCTURE_MEMBER(conf, structname, member,
+ always=False, define=None, headers=None):
+ '''check for a structure member'''
+ if define is None:
+ define = 'HAVE_%s' % member.upper()
+ return CHECK_CODE(conf,
+ '%s s; void *_x; _x=(void *)&s.%s' % (structname, member),
+ define,
+ execute=False,
+ link=False,
+ always=always,
+ headers=headers,
+ local_include=False,
+ msg="Checking for member %s in %s" % (member, structname))
+
+
+@conf
+def CHECK_CFLAGS(conf, cflags):
+ '''check if the given cflags are accepted by the compiler
+ '''
+ return conf.check(fragment='int main(void) { return 0; }\n',
+ execute=0,
+ type='nolink',
+ ccflags=cflags,
+ msg="Checking compiler accepts %s" % cflags)
+
+@conf
+def CHECK_LDFLAGS(conf, ldflags):
+ '''check if the given ldflags are accepted by the linker
+ '''
+ return conf.check(fragment='int main(void) { return 0; }\n',
+ execute=0,
+ ldflags=ldflags,
+ msg="Checking linker accepts %s" % ldflags)
+
+
+@conf
+def CONFIG_GET(conf, option):
+ '''return True if a configuration option was found'''
+ if (option in conf.env):
+ return conf.env[option]
+ else:
+ return None
+
+@conf
+def CONFIG_SET(conf, option):
+ '''return True if a configuration option was found'''
+ return (option in conf.env) and (conf.env[option] != ())
+Build.BuildContext.CONFIG_SET = CONFIG_SET
+Build.BuildContext.CONFIG_GET = CONFIG_GET
+
+
+def library_flags(self, libs):
+ '''work out flags from pkg_config'''
+ ccflags = []
+ ldflags = []
+ for lib in TO_LIST(libs):
+ inc_path = getattr(self.env, 'CPPPATH_%s' % lib.upper(), [])
+ lib_path = getattr(self.env, 'LIBPATH_%s' % lib.upper(), [])
+ ccflags.extend(['-I%s' % i for i in inc_path])
+ ldflags.extend(['-L%s' % l for l in lib_path])
+ extra_ccflags = TO_LIST(getattr(self.env, 'CCFLAGS_%s' % lib.upper(), []))
+ extra_ldflags = TO_LIST(getattr(self.env, 'LDFLAGS_%s' % lib.upper(), []))
+ ccflags.extend(extra_ccflags)
+ ldflags.extend(extra_ldflags)
+ if 'EXTRA_LDFLAGS' in self.env:
+ ldflags.extend(self.env['EXTRA_LDFLAGS'])
+
+ ccflags = unique_list(ccflags)
+ ldflags = unique_list(ldflags)
+ return (ccflags, ldflags)
+
+
+@conf
+def CHECK_LIB(conf, libs, mandatory=False, empty_decl=True, set_target=True, shlib=False):
+ '''check if a set of libraries exist as system libraries
+
+ returns the sublist of libs that do exist as a syslib or []
+ '''
+
+ fragment= '''
+int foo()
+{
+ int v = 2;
+ return v*2;
+}
+'''
+ ret = []
+ liblist = TO_LIST(libs)
+ for lib in liblist[:]:
+ if GET_TARGET_TYPE(conf, lib) == 'SYSLIB':
+ ret.append(lib)
+ continue
+
+ (ccflags, ldflags) = library_flags(conf, lib)
+ if shlib:
+ res = conf.check(features='cc cshlib', fragment=fragment, lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags)
+ else:
+ res = conf.check(lib=lib, uselib_store=lib, ccflags=ccflags, ldflags=ldflags)
+
+ if not res:
+ if mandatory:
+ Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
+ sys.exit(1)
+ if empty_decl:
+ # if it isn't a mandatory library, then remove it from dependency lists
+ if set_target:
+ SET_TARGET_TYPE(conf, lib, 'EMPTY')
+ else:
+ conf.define('HAVE_LIB%s' % lib.upper().replace('-','_'), 1)
+ conf.env['LIB_' + lib.upper()] = lib
+ if set_target:
+ conf.SET_TARGET_TYPE(lib, 'SYSLIB')
+ ret.append(lib)
+
+ return ret
+
+
+
+@conf
+def CHECK_FUNCS_IN(conf, list, library, mandatory=False, checklibc=False,
+ headers=None, link=True, empty_decl=True, set_target=True):
+ """
+ check that the functions in 'list' are available in 'library'
+ if they are, then make that library available as a dependency
+
+ if the library is not available and mandatory==True, then
+ raise an error.
+
+ If the library is not available and mandatory==False, then
+ add the library to the list of dependencies to remove from
+ build rules
+
+ optionally check for the functions first in libc
+ """
+ remaining = TO_LIST(list)
+ liblist = TO_LIST(library)
+
+ # check if some already found
+ for f in remaining[:]:
+ if CONFIG_SET(conf, 'HAVE_%s' % f.upper()):
+ remaining.remove(f)
+
+ # see if the functions are in libc
+ if checklibc:
+ for f in remaining[:]:
+ if CHECK_FUNC(conf, f, link=True, headers=headers):
+ remaining.remove(f)
+
+ if remaining == []:
+ for lib in liblist:
+ if GET_TARGET_TYPE(conf, lib) != 'SYSLIB' and empty_decl:
+ SET_TARGET_TYPE(conf, lib, 'EMPTY')
+ return True
+
+ checklist = conf.CHECK_LIB(liblist, empty_decl=empty_decl, set_target=set_target)
+ for lib in liblist[:]:
+ if not lib in checklist and mandatory:
+ Logs.error("Mandatory library '%s' not found for functions '%s'" % (lib, list))
+ sys.exit(1)
+
+ ret = True
+ for f in remaining:
+ if not CHECK_FUNC(conf, f, lib=' '.join(checklist), headers=headers, link=link):
+ ret = False
+
+ return ret
+
+
+@conf
+def IN_LAUNCH_DIR(conf):
+ '''return True if this rule is being run from the launch directory'''
+ return os.path.realpath(conf.curdir) == os.path.realpath(Options.launch_dir)
+Options.Handler.IN_LAUNCH_DIR = IN_LAUNCH_DIR
+
+
+@conf
+def SAMBA_CONFIG_H(conf, path=None):
+ '''write out config.h in the right directory'''
+ # we don't want to produce a config.h in places like lib/replace
+ # when we are building projects that depend on lib/replace
+ if not IN_LAUNCH_DIR(conf):
+ return
+
+ if Options.options.developer:
+ # we add these here to ensure that -Wstrict-prototypes is not set during configure
+ conf.ADD_CFLAGS('-Wall -g -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wwrite-strings -Werror-implicit-function-declaration -Wformat=2 -Wno-format-y2k -Wmissing-prototypes',
+ testflags=True)
+ if os.getenv('TOPLEVEL_BUILD'):
+ conf.ADD_CFLAGS('-Wcast-qual', testflags=True)
+ conf.env.DEVELOPER_MODE = True
+
+ if Options.options.picky_developer:
+ conf.ADD_CFLAGS('-Werror', testflags=True)
+
+ if Options.options.fatal_errors:
+ conf.ADD_CFLAGS('-Wfatal-errors', testflags=True)
+
+ if Options.options.pedantic:
+ conf.ADD_CFLAGS('-W', testflags=True)
+
+ if path is None:
+ conf.write_config_header('config.h', top=True)
+ else:
+ conf.write_config_header(path)
+ conf.SAMBA_CROSS_CHECK_COMPLETE()
+
+
+@conf
+def CONFIG_PATH(conf, name, default):
+ '''setup a configurable path'''
+ if not name in conf.env:
+ if default[0] == '/':
+ conf.env[name] = default
+ else:
+ conf.env[name] = conf.env['PREFIX'] + default
+
+@conf
+def ADD_CFLAGS(conf, flags, testflags=False):
+ '''add some CFLAGS to the command line
+ optionally set testflags to ensure all the flags work
+ '''
+ if testflags:
+ ok_flags=[]
+ for f in flags.split():
+ if CHECK_CFLAGS(conf, f):
+ ok_flags.append(f)
+ flags = ok_flags
+ if not 'EXTRA_CFLAGS' in conf.env:
+ conf.env['EXTRA_CFLAGS'] = []
+ conf.env['EXTRA_CFLAGS'].extend(TO_LIST(flags))
+
+@conf
+def ADD_LDFLAGS(conf, flags, testflags=False):
+ '''add some LDFLAGS to the command line
+ optionally set testflags to ensure all the flags work
+
+ this will return the flags that are added, if any
+ '''
+ if testflags:
+ ok_flags=[]
+ for f in flags.split():
+ if CHECK_LDFLAGS(conf, f):
+ ok_flags.append(f)
+ flags = ok_flags
+ if not 'EXTRA_LDFLAGS' in conf.env:
+ conf.env['EXTRA_LDFLAGS'] = []
+ conf.env['EXTRA_LDFLAGS'].extend(TO_LIST(flags))
+ return flags
+
+
+@conf
+def ADD_EXTRA_INCLUDES(conf, includes):
+ '''add some extra include directories to all builds'''
+ if not 'EXTRA_INCLUDES' in conf.env:
+ conf.env['EXTRA_INCLUDES'] = []
+ conf.env['EXTRA_INCLUDES'].extend(TO_LIST(includes))
+
+
+
+def CURRENT_CFLAGS(bld, target, cflags, hide_symbols=False):
+ '''work out the current flags. local flags are added first'''
+ if not 'EXTRA_CFLAGS' in bld.env:
+ list = []
+ else:
+ list = bld.env['EXTRA_CFLAGS'];
+ ret = TO_LIST(cflags)
+ ret.extend(list)
+ if hide_symbols and bld.env.HAVE_VISIBILITY_ATTR:
+ ret.append('-fvisibility=hidden')
+ return ret
+
+
+@conf
+def CHECK_CC_ENV(conf):
+ """trim whitespaces from 'CC'.
+ The build farm sometimes puts a space at the start"""
+ if os.environ.get('CC'):
+ conf.env.CC = TO_LIST(os.environ.get('CC'))
+ if len(conf.env.CC) == 1:
+ # make for nicer logs if just a single command
+ conf.env.CC = conf.env.CC[0]
+
+
+@conf
+def SETUP_CONFIGURE_CACHE(conf, enable):
+ '''enable/disable cache of configure results'''
+ if enable:
+ # when -C is chosen, we will use a private cache and will
+ # not look into system includes. This roughtly matches what
+ # autoconf does with -C
+ cache_path = os.path.join(conf.blddir, '.confcache')
+ mkdir_p(cache_path)
+ Options.cache_global = os.environ['WAFCACHE'] = cache_path
+ else:
+ # when -C is not chosen we will not cache configure checks
+ # We set the recursion limit low to prevent waf from spending
+ # a lot of time on the signatures of the files.
+ Options.cache_global = os.environ['WAFCACHE'] = ''
+ preproc.recursion_limit = 1
+ # in either case we don't need to scan system includes
+ preproc.go_absolute = False
diff --git a/buildtools/wafsamba/samba_autoproto.py b/buildtools/wafsamba/samba_autoproto.py
new file mode 100644
index 0000000000..2d8ea546ab
--- /dev/null
+++ b/buildtools/wafsamba/samba_autoproto.py
@@ -0,0 +1,23 @@
+# waf build tool for building automatic prototypes from C source
+
+import Build
+from samba_utils import *
+
+def SAMBA_AUTOPROTO(bld, header, source):
+ '''rule for samba prototype generation'''
+ bld.SET_BUILD_GROUP('prototypes')
+ relpath = os_path_relpath(bld.curdir, bld.srcnode.abspath())
+ name = os.path.join(relpath, header)
+ SET_TARGET_TYPE(bld, name, 'PROTOTYPE')
+ t = bld(
+ name = name,
+ source = source,
+ target = header,
+ on_results=True,
+ ext_out='.c',
+ before ='cc',
+ rule = '${PERL} "${SCRIPT}/mkproto.pl" --srcdir=.. --builddir=. --public=/dev/null --private="${TGT}" ${SRC}'
+ )
+ t.env.SCRIPT = os.path.join(bld.srcnode.abspath(), 'source4/script')
+Build.BuildContext.SAMBA_AUTOPROTO = SAMBA_AUTOPROTO
+
diff --git a/buildtools/wafsamba/samba_bundled.py b/buildtools/wafsamba/samba_bundled.py
new file mode 100644
index 0000000000..39edad060d
--- /dev/null
+++ b/buildtools/wafsamba/samba_bundled.py
@@ -0,0 +1,191 @@
+# functions to support bundled libraries
+
+from Configure import conf
+import sys, Logs
+from samba_utils import *
+
+def PRIVATE_NAME(bld, name, private_extension, private_library):
+ '''possibly rename a library to include a bundled extension'''
+
+ # we now use the same private name for libraries as the public name.
+ # see http://git.samba.org/?p=tridge/junkcode.git;a=tree;f=shlib for a
+ # demonstration that this is the right thing to do
+ # also see http://lists.samba.org/archive/samba-technical/2011-January/075816.html
+ return name
+
+
+def target_in_list(target, lst, default):
+ for l in lst:
+ if target == l:
+ return True
+ if '!' + target == l:
+ return False
+ if l == 'ALL':
+ return True
+ if l == 'NONE':
+ return False
+ return default
+
+
+def BUILTIN_LIBRARY(bld, name):
+ '''return True if a library should be builtin
+ instead of being built as a shared lib'''
+ if bld.env.DISABLE_SHARED:
+ return True
+ return target_in_list(name, bld.env.BUILTIN_LIBRARIES, False)
+Build.BuildContext.BUILTIN_LIBRARY = BUILTIN_LIBRARY
+
+
+def BUILTIN_DEFAULT(opt, builtins):
+ '''set a comma separated default list of builtin libraries for this package'''
+ if 'BUILTIN_LIBRARIES_DEFAULT' in Options.options:
+ return
+ Options.options['BUILTIN_LIBRARIES_DEFAULT'] = builtins
+Options.Handler.BUILTIN_DEFAULT = BUILTIN_DEFAULT
+
+
+def PRIVATE_EXTENSION_DEFAULT(opt, extension, noextension=''):
+ '''set a default private library extension'''
+ if 'PRIVATE_EXTENSION_DEFAULT' in Options.options:
+ return
+ Options.options['PRIVATE_EXTENSION_DEFAULT'] = extension
+ Options.options['PRIVATE_EXTENSION_EXCEPTION'] = noextension
+Options.Handler.PRIVATE_EXTENSION_DEFAULT = PRIVATE_EXTENSION_DEFAULT
+
+
+def minimum_library_version(conf, libname, default):
+ '''allow override of mininum system library version'''
+
+ minlist = Options.options.MINIMUM_LIBRARY_VERSION
+ if not minlist:
+ return default
+
+ for m in minlist.split(','):
+ a = m.split(':')
+ if len(a) != 2:
+ Logs.error("Bad syntax for --minimum-library-version of %s" % m)
+ sys.exit(1)
+ if a[0] == libname:
+ return a[1]
+ return default
+
+
+@conf
+def LIB_MAY_BE_BUNDLED(conf, libname):
+ return ('NONE' not in conf.env.BUNDLED_LIBS and
+ '!%s' % libname not in conf.env.BUNDLED_LIBS)
+
+
+@conf
+def LIB_MUST_BE_BUNDLED(conf, libname):
+ return ('ALL' in conf.env.BUNDLED_LIBS or
+ libname in conf.env.BUNDLED_LIBS)
+
+
+@runonce
+@conf
+def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
+ checkfunctions=None, headers=None,
+ onlyif=None, implied_deps=None,
+ require_headers=True):
+ '''check if a library is available as a system library.
+ this first tries via pkg-config, then if that fails
+ tries by testing for a specified function in the specified lib
+ '''
+ if conf.LIB_MUST_BE_BUNDLED(libname):
+ return False
+ found = 'FOUND_SYSTEMLIB_%s' % libname
+ if found in conf.env:
+ return conf.env[found]
+
+ def check_functions_headers():
+ '''helper function for CHECK_BUNDLED_SYSTEM'''
+ if checkfunctions is None:
+ return True
+ if require_headers and headers and not conf.CHECK_HEADERS(headers, lib=libname):
+ return False
+ return conf.CHECK_FUNCS_IN(checkfunctions, libname, headers=headers,
+ empty_decl=False, set_target=False)
+
+ # see if the library should only use a system version if another dependent
+ # system version is found. That prevents possible use of mixed library
+ # versions
+ if onlyif:
+ for syslib in TO_LIST(onlyif):
+ f = 'FOUND_SYSTEMLIB_%s' % syslib
+ if not f in conf.env:
+ if not conf.LIB_MAY_BE_BUNDLED(libname):
+ Logs.error('ERROR: Use of system library %s depends on missing system library %s' % (libname, syslib))
+ sys.exit(1)
+ conf.env[found] = False
+ return False
+
+ minversion = minimum_library_version(conf, libname, minversion)
+
+ msg = 'Checking for system %s' % libname
+ if minversion != '0.0.0':
+ msg += ' >= %s' % minversion
+
+ # try pkgconfig first
+ if (conf.check_cfg(package=libname,
+ args='"%s >= %s" --cflags --libs' % (libname, minversion),
+ msg=msg) and
+ check_functions_headers()):
+ conf.SET_TARGET_TYPE(libname, 'SYSLIB')
+ conf.env[found] = True
+ if implied_deps:
+ conf.SET_SYSLIB_DEPS(libname, implied_deps)
+ return True
+ if checkfunctions is not None:
+ if check_functions_headers():
+ conf.env[found] = True
+ if implied_deps:
+ conf.SET_SYSLIB_DEPS(libname, implied_deps)
+ conf.SET_TARGET_TYPE(libname, 'SYSLIB')
+ return True
+ conf.env[found] = False
+ if not conf.LIB_MAY_BE_BUNDLED(libname):
+ Logs.error('ERROR: System library %s of version %s not found, and bundling disabled' % (libname, minversion))
+ sys.exit(1)
+ return False
+
+
+@runonce
+@conf
+def CHECK_BUNDLED_SYSTEM_PYTHON(conf, libname, modulename, minversion='0.0.0'):
+ '''check if a python module is available on the system and
+ has the specified minimum version.
+ '''
+ if conf.LIB_MUST_BE_BUNDLED(libname):
+ return False
+
+ # see if the library should only use a system version if another dependent
+ # system version is found. That prevents possible use of mixed library
+ # versions
+ minversion = minimum_library_version(conf, libname, minversion)
+
+ try:
+ m = __import__(modulename)
+ except ImportError:
+ found = False
+ else:
+ try:
+ version = m.__version__
+ except AttributeError:
+ found = False
+ else:
+ found = tuple(version.split(".")) >= tuple(minversion.split("."))
+ if not found and not conf.LIB_MAY_BE_BUNDLED(libname):
+ Logs.error('ERROR: Python module %s of version %s not found, and bundling disabled' % (libname, minversion))
+ sys.exit(1)
+ return found
+
+
+def NONSHARED_BINARY(bld, name):
+ '''return True if a binary should be built without non-system shared libs'''
+ if bld.env.DISABLE_SHARED:
+ return True
+ return target_in_list(name, bld.env.NONSHARED_BINARIES, False)
+Build.BuildContext.NONSHARED_BINARY = NONSHARED_BINARY
+
+
diff --git a/buildtools/wafsamba/samba_conftests.py b/buildtools/wafsamba/samba_conftests.py
new file mode 100644
index 0000000000..c7e596d27a
--- /dev/null
+++ b/buildtools/wafsamba/samba_conftests.py
@@ -0,0 +1,414 @@
+# a set of config tests that use the samba_autoconf functions
+# to test for commonly needed configuration options
+
+import os, Build, shutil, Utils, re
+from Configure import conf
+from samba_utils import *
+
+@conf
+def CHECK_ICONV(conf, define='HAVE_NATIVE_ICONV'):
+ '''check if the iconv library is installed
+ optionally pass a define'''
+ if conf.CHECK_FUNCS_IN('iconv_open', 'iconv', checklibc=True, headers='iconv.h'):
+ conf.DEFINE(define, 1)
+ return True
+ return False
+
+
+@conf
+def CHECK_LARGEFILE(conf, define='HAVE_LARGEFILE'):
+ '''see what we need for largefile support'''
+ if conf.CHECK_CODE('return !(sizeof(off_t) >= 8)',
+ define,
+ execute=True,
+ msg='Checking for large file support'):
+ return True
+ if conf.CHECK_CODE('return !(sizeof(off_t) >= 8)',
+ define,
+ execute=True,
+ cflags='-D_FILE_OFFSET_BITS=64',
+ msg='Checking for -D_FILE_OFFSET_BITS=64'):
+ conf.DEFINE('_FILE_OFFSET_BITS', 64)
+ return True
+ return False
+
+
+@conf
+def CHECK_C_PROTOTYPE(conf, function, prototype, define, headers=None, msg=None):
+ '''verify that a C prototype matches the one on the current system'''
+ if not conf.CHECK_DECLS(function, headers=headers):
+ return False
+ if not msg:
+ msg = 'Checking C prototype for %s' % function
+ return conf.CHECK_CODE('%s; void *_x = (void *)%s' % (prototype, function),
+ define=define,
+ local_include=False,
+ headers=headers,
+ link=False,
+ execute=False,
+ msg=msg)
+
+
+@conf
+def CHECK_CHARSET_EXISTS(conf, charset, outcharset='UCS-2LE', headers=None, define=None):
+ '''check that a named charset is able to be used with iconv_open() for conversion
+ to a target charset
+ '''
+ msg = 'Checking if can we convert from %s to %s' % (charset, outcharset)
+ if define is None:
+ define = 'HAVE_CHARSET_%s' % charset.upper().replace('-','_')
+ return conf.CHECK_CODE('''
+ iconv_t cd = iconv_open("%s", "%s");
+ if (cd == 0 || cd == (iconv_t)-1) return -1;
+ ''' % (charset, outcharset),
+ define=define,
+ execute=True,
+ msg=msg,
+ lib='iconv',
+ headers=headers)
+
+def find_config_dir(conf):
+ '''find a directory to run tests in'''
+ k = 0
+ while k < 10000:
+ dir = os.path.join(conf.blddir, '.conf_check_%d' % k)
+ try:
+ shutil.rmtree(dir)
+ except OSError:
+ pass
+ try:
+ os.stat(dir)
+ except:
+ break
+ k += 1
+
+ try:
+ os.makedirs(dir)
+ except:
+ conf.fatal('cannot create a configuration test folder %r' % dir)
+
+ try:
+ os.stat(dir)
+ except:
+ conf.fatal('cannot use the configuration test folder %r' % dir)
+ return dir
+
+@conf
+def CHECK_SHLIB_INTRASINC_NAME_FLAGS(conf, msg):
+ '''
+ check if the waf default flags for setting the name of lib
+ are ok
+ '''
+
+ snip = '''
+int foo(int v) {
+ return v * 2;
+}
+'''
+ return conf.check(features='cc cshlib',vnum="1",fragment=snip,msg=msg)
+
+@conf
+def CHECK_NEED_LC(conf, msg):
+ '''check if we need -lc'''
+
+ dir = find_config_dir(conf)
+
+ env = conf.env
+
+ bdir = os.path.join(dir, 'testbuild2')
+ if not os.path.exists(bdir):
+ os.makedirs(bdir)
+
+
+ subdir = os.path.join(dir, "liblctest")
+
+ os.makedirs(subdir)
+
+ dest = open(os.path.join(subdir, 'liblc1.c'), 'w')
+ dest.write('#include <stdio.h>\nint lib_func(void) { FILE *f = fopen("foo", "r");}\n')
+ dest.close()
+
+ bld = Build.BuildContext()
+ bld.log = conf.log
+ bld.all_envs.update(conf.all_envs)
+ bld.all_envs['default'] = env
+ bld.lst_variants = bld.all_envs.keys()
+ bld.load_dirs(dir, bdir)
+
+ bld.rescan(bld.srcnode)
+
+ bld(features='cc cshlib',
+ source='liblctest/liblc1.c',
+ ldflags=conf.env['EXTRA_LDFLAGS'],
+ target='liblc',
+ name='liblc')
+
+ try:
+ bld.compile()
+ conf.check_message(msg, '', True)
+ return True
+ except:
+ conf.check_message(msg, '', False)
+ return False
+
+
+@conf
+def CHECK_SHLIB_W_PYTHON(conf, msg):
+ '''check if we need -undefined dynamic_lookup'''
+
+ dir = find_config_dir(conf)
+
+ env = conf.env
+
+ snip = '''
+#include <Python.h>
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+
+static PyObject *ldb_module = NULL;
+int foo(int v) {
+ extern char **environ;
+ environ[0] = 1;
+ ldb_module = PyImport_ImportModule("ldb");
+ return v * 2;
+}'''
+ return conf.check(features='cc cshlib',uselib='PYEMBED',fragment=snip,msg=msg)
+
+# this one is quite complex, and should probably be broken up
+# into several parts. I'd quite like to create a set of CHECK_COMPOUND()
+# functions that make writing complex compound tests like this much easier
+@conf
+def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
+ '''see if the platform supports building libraries'''
+
+ if msg is None:
+ if rpath:
+ msg = "rpath library support"
+ else:
+ msg = "building library support"
+
+ dir = find_config_dir(conf)
+
+ bdir = os.path.join(dir, 'testbuild')
+ if not os.path.exists(bdir):
+ os.makedirs(bdir)
+
+ env = conf.env
+
+ subdir = os.path.join(dir, "libdir")
+
+ os.makedirs(subdir)
+
+ dest = open(os.path.join(subdir, 'lib1.c'), 'w')
+ dest.write('int lib_func(void) { return 42; }\n')
+ dest.close()
+
+ dest = open(os.path.join(dir, 'main.c'), 'w')
+ dest.write('int main(void) {return !(lib_func() == 42);}\n')
+ dest.close()
+
+ bld = Build.BuildContext()
+ bld.log = conf.log
+ bld.all_envs.update(conf.all_envs)
+ bld.all_envs['default'] = env
+ bld.lst_variants = bld.all_envs.keys()
+ bld.load_dirs(dir, bdir)
+
+ bld.rescan(bld.srcnode)
+
+ ldflags = []
+ if version_script:
+ ldflags.append("-Wl,--version-script=%s/vscript" % bld.path.abspath())
+ dest = open(os.path.join(dir,'vscript'), 'w')
+ dest.write('TEST_1.0A2 { global: *; };\n')
+ dest.close()
+
+ bld(features='cc cshlib',
+ source='libdir/lib1.c',
+ target='libdir/lib1',
+ ldflags=ldflags,
+ name='lib1')
+
+ o = bld(features='cc cprogram',
+ source='main.c',
+ target='prog1',
+ uselib_local='lib1')
+
+ if rpath:
+ o.rpath=os.path.join(bdir, 'default/libdir')
+
+ # compile the program
+ try:
+ bld.compile()
+ except:
+ conf.check_message(msg, '', False)
+ return False
+
+ # path for execution
+ lastprog = o.link_task.outputs[0].abspath(env)
+
+ if not rpath:
+ if 'LD_LIBRARY_PATH' in os.environ:
+ old_ld_library_path = os.environ['LD_LIBRARY_PATH']
+ else:
+ old_ld_library_path = None
+ ADD_LD_LIBRARY_PATH(os.path.join(bdir, 'default/libdir'))
+
+ # we need to run the program, try to get its result
+ args = conf.SAMBA_CROSS_ARGS(msg=msg)
+ proc = Utils.pproc.Popen([lastprog] + args, stdout=Utils.pproc.PIPE, stderr=Utils.pproc.PIPE)
+ (out, err) = proc.communicate()
+ w = conf.log.write
+ w(str(out))
+ w('\n')
+ w(str(err))
+ w('\nreturncode %r\n' % proc.returncode)
+ ret = (proc.returncode == 0)
+
+ if not rpath:
+ os.environ['LD_LIBRARY_PATH'] = old_ld_library_path or ''
+
+ conf.check_message(msg, '', ret)
+ return ret
+
+
+
+@conf
+def CHECK_PERL_MANPAGE(conf, msg=None, section=None):
+ '''work out what extension perl uses for manpages'''
+
+ if msg is None:
+ if section:
+ msg = "perl man%s extension" % section
+ else:
+ msg = "perl manpage generation"
+
+ conf.check_message_1(msg)
+
+ dir = find_config_dir(conf)
+
+ bdir = os.path.join(dir, 'testbuild')
+ if not os.path.exists(bdir):
+ os.makedirs(bdir)
+
+ dest = open(os.path.join(bdir, 'Makefile.PL'), 'w')
+ dest.write("""
+use ExtUtils::MakeMaker;
+WriteMakefile(
+ 'NAME' => 'WafTest',
+ 'EXE_FILES' => [ 'WafTest' ]
+);
+""")
+ dest.close()
+ back = os.path.abspath('.')
+ os.chdir(bdir)
+ proc = Utils.pproc.Popen(['perl', 'Makefile.PL'],
+ stdout=Utils.pproc.PIPE,
+ stderr=Utils.pproc.PIPE)
+ (out, err) = proc.communicate()
+ os.chdir(back)
+
+ ret = (proc.returncode == 0)
+ if not ret:
+ conf.check_message_2('not found', color='YELLOW')
+ return
+
+ if section:
+ f = open(os.path.join(bdir,'Makefile'), 'r')
+ man = f.read()
+ f.close()
+ m = re.search('MAN%sEXT\s+=\s+(\w+)' % section, man)
+ if not m:
+ conf.check_message_2('not found', color='YELLOW')
+ return
+ ext = m.group(1)
+ conf.check_message_2(ext)
+ return ext
+
+ conf.check_message_2('ok')
+ return True
+
+
+@conf
+def CHECK_COMMAND(conf, cmd, msg=None, define=None, on_target=True, boolean=False):
+ '''run a command and return result'''
+ if msg is None:
+ msg = 'Checking %s' % ' '.join(cmd)
+ conf.COMPOUND_START(msg)
+ cmd = cmd[:]
+ if on_target:
+ cmd.extend(conf.SAMBA_CROSS_ARGS(msg=msg))
+ try:
+ ret = Utils.cmd_output(cmd)
+ except:
+ conf.COMPOUND_END(False)
+ return False
+ if boolean:
+ conf.COMPOUND_END('ok')
+ if define:
+ conf.DEFINE(define, '1')
+ else:
+ ret = ret.strip()
+ conf.COMPOUND_END(ret)
+ if define:
+ conf.DEFINE(define, ret, quote=True)
+ return ret
+
+
+@conf
+def CHECK_UNAME(conf):
+ '''setup SYSTEM_UNAME_* defines'''
+ ret = True
+ for v in "sysname machine release version".split():
+ if not conf.CHECK_CODE('''
+ struct utsname n;
+ if (uname(&n) == -1) return -1;
+ printf("%%s", n.%s);
+ ''' % v,
+ define='SYSTEM_UNAME_%s' % v.upper(),
+ execute=True,
+ define_ret=True,
+ quote=True,
+ headers='sys/utsname.h',
+ local_include=False,
+ msg="Checking uname %s type" % v):
+ ret = False
+ return ret
+
+@conf
+def CHECK_INLINE(conf):
+ '''check for the right value for inline'''
+ conf.COMPOUND_START('Checking for inline')
+ for i in ['inline', '__inline__', '__inline']:
+ ret = conf.CHECK_CODE('''
+ typedef int foo_t;
+ static %s foo_t static_foo () {return 0; }
+ %s foo_t foo () {return 0; }''' % (i, i),
+ define='INLINE_MACRO',
+ addmain=False,
+ link=False)
+ if ret:
+ if i != 'inline':
+ conf.DEFINE('inline', i, quote=False)
+ break
+ if not ret:
+ conf.COMPOUND_END(ret)
+ else:
+ conf.COMPOUND_END(i)
+ return ret
+
+@conf
+def CHECK_XSLTPROC_MANPAGES(conf):
+ '''check if xsltproc can run with the given stylesheets'''
+
+
+ if not conf.CONFIG_SET('XSLTPROC'):
+ conf.find_program('xsltproc', var='XSLTPROC')
+ if not conf.CONFIG_SET('XSLTPROC'):
+ return False
+
+ s='http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
+ conf.CHECK_COMMAND('%s --nonet %s 2> /dev/null' % (conf.env.XSLTPROC, s),
+ msg='Checking for stylesheet %s' % s,
+ define='XSLTPROC_MANPAGES', on_target=False,
+ boolean=True)
diff --git a/buildtools/wafsamba/samba_cross.py b/buildtools/wafsamba/samba_cross.py
new file mode 100644
index 0000000000..3838e34ec4
--- /dev/null
+++ b/buildtools/wafsamba/samba_cross.py
@@ -0,0 +1,134 @@
+# functions for handling cross-compilation
+
+import Utils, Logs, sys, os, Options, re
+from Configure import conf
+
+real_Popen = None
+
+ANSWER_UNKNOWN = (254, "")
+ANSWER_FAIL = (255, "")
+ANSWER_OK = (0, "")
+
+cross_answers_incomplete = False
+
+
+def add_answer(ca_file, msg, answer):
+ '''add an answer to a set of cross answers'''
+ try:
+ f = open(ca_file, 'a')
+ except:
+ Logs.error("Unable to open cross-answers file %s" % ca_file)
+ sys.exit(1)
+ if answer == ANSWER_OK:
+ f.write('%s: OK\n' % msg)
+ elif answer == ANSWER_UNKNOWN:
+ f.write('%s: UNKNOWN\n' % msg)
+ elif answer == ANSWER_FAIL:
+ f.write('%s: FAIL\n' % msg)
+ else:
+ (retcode, retstring) = answer
+ f.write('%s: (%d, "%s")' % (msg, retcode, retstring))
+ f.close()
+
+
+def cross_answer(ca_file, msg):
+ '''return a (retcode,retstring) tuple from a answers file'''
+ try:
+ f = open(ca_file, 'r')
+ except:
+ add_answer(ca_file, msg, ANSWER_UNKNOWN)
+ return ANSWER_UNKNOWN
+ for line in f:
+ line = line.strip()
+ if line == '' or line[0] == '#':
+ continue
+ if line.find(':') != -1:
+ a = line.split(':')
+ thismsg = a[0].strip()
+ if thismsg != msg:
+ continue
+ ans = a[1].strip()
+ if ans == "OK" or ans == "YES":
+ f.close()
+ return ANSWER_OK
+ elif ans == "UNKNOWN":
+ f.close()
+ return ANSWER_UNKNOWN
+ elif ans == "FAIL" or ans == "NO":
+ f.close()
+ return ANSWER_FAIL
+ elif ans[0] == '"':
+ return (0, ans.strip('"'))
+ elif ans[0] == "'":
+ return (0, ans.strip("'"))
+ else:
+ m = re.match('\(\s*(-?\d+)\s*,\s*\"(.*)\"\s*\)', ans)
+ if m:
+ f.close()
+ return (int(m.group(1)), m.group(2))
+ else:
+ raise Utils.WafError("Bad answer format '%s' in %s" % (line, ca_file))
+ f.close()
+ add_answer(ca_file, msg, ANSWER_UNKNOWN)
+ return ANSWER_UNKNOWN
+
+
+class cross_Popen(Utils.pproc.Popen):
+ '''cross-compilation wrapper for Popen'''
+ def __init__(*k, **kw):
+ (obj, args) = k
+
+ if '--cross-execute' in args:
+ # when --cross-execute is set, then change the arguments
+ # to use the cross emulator
+ i = args.index('--cross-execute')
+ newargs = args[i+1].split()
+ newargs.extend(args[0:i])
+ args = newargs
+ elif '--cross-answers' in args:
+ # when --cross-answers is set, then change the arguments
+ # to use the cross answers if available
+ i = args.index('--cross-answers')
+ ca_file = args[i+1]
+ msg = args[i+2]
+ ans = cross_answer(ca_file, msg)
+ if ans == ANSWER_UNKNOWN:
+ global cross_answers_incomplete
+ cross_answers_incomplete = True
+ (retcode, retstring) = ans
+ args = ['/bin/sh', '-c', "echo -n '%s'; exit %d" % (retstring, retcode)]
+ real_Popen.__init__(*(obj, args), **kw)
+
+
+@conf
+def SAMBA_CROSS_ARGS(conf, msg=None):
+ '''get exec_args to pass when running cross compiled binaries'''
+ if not conf.env.CROSS_COMPILE:
+ return []
+
+ global real_Popen
+ if real_Popen is None:
+ real_Popen = Utils.pproc.Popen
+ Utils.pproc.Popen = cross_Popen
+
+ ret = []
+
+ if conf.env.CROSS_EXECUTE:
+ ret.extend(['--cross-execute', conf.env.CROSS_EXECUTE])
+ elif conf.env.CROSS_ANSWERS:
+ if msg is None:
+ raise Utils.WafError("Cannot have NULL msg in cross-answers")
+ ret.extend(['--cross-answers', os.path.join(Options.launch_dir, conf.env.CROSS_ANSWERS), msg])
+
+ if ret == []:
+ raise Utils.WafError("Cannot cross-compile without either --cross-execute or --cross-answers")
+
+ return ret
+
+@conf
+def SAMBA_CROSS_CHECK_COMPLETE(conf):
+ '''check if we have some unanswered questions'''
+ global cross_answers_incomplete
+ if conf.env.CROSS_COMPILE and cross_answers_incomplete:
+ raise Utils.WafError("Cross answers file %s is incomplete" % conf.env.CROSS_ANSWERS)
+ return True
diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py
new file mode 100644
index 0000000000..adeb3645ce
--- /dev/null
+++ b/buildtools/wafsamba/samba_deps.py
@@ -0,0 +1,1184 @@
+# Samba automatic dependency handling and project rules
+
+import Build, os, sys, re, Environment, Logs, time
+from samba_utils import *
+from samba_autoconf import *
+from samba_bundled import BUILTIN_LIBRARY
+
+@conf
+def ADD_GLOBAL_DEPENDENCY(ctx, dep):
+ '''add a dependency for all binaries and libraries'''
+ if not 'GLOBAL_DEPENDENCIES' in ctx.env:
+ ctx.env.GLOBAL_DEPENDENCIES = []
+ ctx.env.GLOBAL_DEPENDENCIES.append(dep)
+
+
+@conf
+def BREAK_CIRCULAR_LIBRARY_DEPENDENCIES(ctx):
+ '''indicate that circular dependencies between libraries should be broken.'''
+ ctx.env.ALLOW_CIRCULAR_LIB_DEPENDENCIES = True
+
+
+@conf
+def SET_SYSLIB_DEPS(conf, target, deps):
+ '''setup some implied dependencies for a SYSLIB'''
+ cache = LOCAL_CACHE(conf, 'SYSLIB_DEPS')
+ cache[target] = deps
+
+
+def expand_subsystem_deps(bld):
+ '''expand the reverse dependencies resulting from subsystem
+ attributes of modules. This is walking over the complete list
+ of declared subsystems, and expands the samba_deps_extended list for any
+ module<->subsystem dependencies'''
+
+ subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ for subsystem_name in subsystem_list:
+ bld.ASSERT(subsystem_name in targets, "Subsystem target %s not declared" % subsystem_name)
+ type = targets[subsystem_name]
+ if type == 'DISABLED' or type == 'EMPTY':
+ continue
+
+ # for example,
+ # subsystem_name = dcerpc_server (a subsystem)
+ # subsystem = dcerpc_server (a subsystem object)
+ # module_name = rpc_epmapper (a module within the dcerpc_server subsystem)
+ # module = rpc_epmapper (a module object within the dcerpc_server subsystem)
+
+ subsystem = bld.name_to_obj(subsystem_name, bld.env)
+ bld.ASSERT(subsystem is not None, "Unable to find subsystem %s" % subsystem_name)
+ for d in subsystem_list[subsystem_name]:
+ module_name = d['TARGET']
+ module_type = targets[module_name]
+ if module_type in ['DISABLED', 'EMPTY']:
+ continue
+ bld.ASSERT(subsystem is not None,
+ "Subsystem target %s for %s (%s) not found" % (subsystem_name, module_name, module_type))
+ if module_type in ['SUBSYSTEM']:
+ # if a module is a plain object type (not a library) then the
+ # subsystem it is part of needs to have it as a dependency, so targets
+ # that depend on this subsystem get the modules of that subsystem
+ subsystem.samba_deps_extended.append(module_name)
+ subsystem.samba_deps_extended = unique_list(subsystem.samba_deps_extended)
+
+
+
+def build_dependencies(self):
+ '''This builds the dependency list for a target. It runs after all the targets are declared
+
+ The reason this is not just done in the SAMBA_*() rules is that we have no way of knowing
+ the full dependency list for a target until we have all of the targets declared.
+ '''
+
+ if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
+ self.uselib = list(self.final_syslibs)
+ self.uselib_local = list(self.final_libs)
+ self.add_objects = list(self.final_objects)
+
+ # extra link flags from pkg_config
+ libs = self.final_syslibs.copy()
+
+ (ccflags, ldflags) = library_flags(self, list(libs))
+ new_ldflags = getattr(self, 'samba_ldflags', [])[:]
+ new_ldflags.extend(ldflags)
+ self.ldflags = new_ldflags
+
+ if getattr(self, 'allow_undefined_symbols', False) and self.env.undefined_ldflags:
+ for f in self.env.undefined_ldflags:
+ self.ldflags.remove(f)
+
+ debug('deps: computed dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
+ self.sname, self.uselib, self.uselib_local, self.add_objects)
+
+ if self.samba_type in ['SUBSYSTEM']:
+ # this is needed for the ccflags of libs that come from pkg_config
+ self.uselib = list(self.final_syslibs)
+ self.uselib.extend(list(self.direct_syslibs))
+ for lib in self.final_libs:
+ t = self.bld.name_to_obj(lib, self.bld.env)
+ self.uselib.extend(list(t.final_syslibs))
+ self.uselib = unique_list(self.uselib)
+
+ if getattr(self, 'uselib', None):
+ up_list = []
+ for l in self.uselib:
+ up_list.append(l.upper())
+ self.uselib = up_list
+
+
+def build_includes(self):
+ '''This builds the right set of includes for a target.
+
+ One tricky part of this is that the includes= attribute for a
+ target needs to use paths which are relative to that targets
+ declaration directory (which we can get at via t.path).
+
+ The way this works is the includes list gets added as
+ samba_includes in the main build task declaration. Then this
+ function runs after all of the tasks are declared, and it
+ processes the samba_includes attribute to produce a includes=
+ attribute
+ '''
+
+ if getattr(self, 'samba_includes', None) is None:
+ return
+
+ bld = self.bld
+
+ inc_deps = includes_objects(bld, self, set(), {})
+
+ includes = []
+
+ # maybe add local includes
+ if getattr(self, 'local_include', True) == True and getattr(self, 'local_include_first', True):
+ includes.append('.')
+
+ includes.extend(self.samba_includes_extended)
+
+ if 'EXTRA_INCLUDES' in bld.env and getattr(self, 'global_include', True):
+ includes.extend(bld.env['EXTRA_INCLUDES'])
+
+ includes.append('#')
+
+ inc_set = set()
+ inc_abs = []
+
+ for d in inc_deps:
+ t = bld.name_to_obj(d, bld.env)
+ bld.ASSERT(t is not None, "Unable to find dependency %s for %s" % (d, self.sname))
+ inclist = getattr(t, 'samba_includes_extended', [])[:]
+ if getattr(t, 'local_include', True) == True:
+ inclist.append('.')
+ if inclist == []:
+ continue
+ tpath = t.samba_abspath
+ for inc in inclist:
+ npath = tpath + '/' + inc
+ if not npath in inc_set:
+ inc_abs.append(npath)
+ inc_set.add(npath)
+
+ mypath = self.path.abspath(bld.env)
+ for inc in inc_abs:
+ relpath = os_path_relpath(inc, mypath)
+ includes.append(relpath)
+
+ if getattr(self, 'local_include', True) == True and not getattr(self, 'local_include_first', True):
+ includes.append('.')
+
+ # now transform the includes list to be relative to the top directory
+ # which is represented by '#' in waf. This allows waf to cache the
+ # includes lists more efficiently
+ includes_top = []
+ for i in includes:
+ if i[0] == '#':
+ # some are already top based
+ includes_top.append(i)
+ continue
+ absinc = os.path.join(self.path.abspath(), i)
+ relinc = os_path_relpath(absinc, self.bld.srcnode.abspath())
+ includes_top.append('#' + relinc)
+
+ self.includes = unique_list(includes_top)
+ debug('deps: includes for target %s: includes=%s',
+ self.sname, self.includes)
+
+
+
+
+def add_init_functions(self):
+ '''This builds the right set of init functions'''
+
+ bld = self.bld
+
+ subsystems = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
+
+ # cope with the separated object lists from BINARY and LIBRARY targets
+ sname = self.sname
+ if sname.endswith('.objlist'):
+ sname = sname[0:-8]
+
+ modules = []
+ if sname in subsystems:
+ modules.append(sname)
+
+ m = getattr(self, 'samba_modules', None)
+ if m is not None:
+ modules.extend(TO_LIST(m))
+
+ m = getattr(self, 'samba_subsystem', None)
+ if m is not None:
+ modules.append(m)
+
+ sentinal = getattr(self, 'init_function_sentinal', 'NULL')
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+ cflags = getattr(self, 'samba_cflags', [])[:]
+
+ if modules == []:
+ sname = sname.replace('-','_')
+ sname = sname.replace('/','_')
+ cflags.append('-DSTATIC_%s_MODULES=%s' % (sname, sentinal))
+ if sentinal == 'NULL':
+ cflags.append('-DSTATIC_%s_MODULES_PROTO' % sname)
+ self.ccflags = cflags
+ return
+
+ for m in modules:
+ bld.ASSERT(m in subsystems,
+ "No init_function defined for module '%s' in target '%s'" % (m, self.sname))
+ init_fn_list = []
+ for d in subsystems[m]:
+ if targets[d['TARGET']] != 'DISABLED':
+ init_fn_list.append(d['INIT_FUNCTION'])
+ if init_fn_list == []:
+ cflags.append('-DSTATIC_%s_MODULES=%s' % (m, sentinal))
+ if sentinal == 'NULL':
+ cflags.append('-DSTATIC_%s_MODULES_PROTO' % m)
+ else:
+ cflags.append('-DSTATIC_%s_MODULES=%s' % (m, ','.join(init_fn_list) + ',' + sentinal))
+ proto=''
+ for f in init_fn_list:
+ proto = proto + '_MODULE_PROTO(%s)' % f
+ cflags.append('-DSTATIC_%s_MODULES_PROTO=%s' % (m, proto))
+ self.ccflags = cflags
+
+
+
+def check_duplicate_sources(bld, tgt_list):
+ '''see if we are compiling the same source file more than once
+ without an allow_duplicates attribute'''
+
+ debug('deps: checking for duplicate sources')
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+ ret = True
+
+ global tstart
+
+ for t in tgt_list:
+ source_list = TO_LIST(getattr(t, 'source', ''))
+ tpath = os.path.normpath(os_path_relpath(t.path.abspath(bld.env), t.env.BUILD_DIRECTORY + '/default'))
+ obj_sources = set()
+ for s in source_list:
+ p = os.path.normpath(os.path.join(tpath, s))
+ if p in obj_sources:
+ Logs.error("ERROR: source %s appears twice in target '%s'" % (p, t.sname))
+ sys.exit(1)
+ obj_sources.add(p)
+ t.samba_source_set = obj_sources
+
+ subsystems = {}
+
+ # build a list of targets that each source file is part of
+ for t in tgt_list:
+ sources = []
+ if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
+ continue
+ for obj in t.add_objects:
+ t2 = t.bld.name_to_obj(obj, bld.env)
+ source_set = getattr(t2, 'samba_source_set', set())
+ for s in source_set:
+ if not s in subsystems:
+ subsystems[s] = {}
+ if not t.sname in subsystems[s]:
+ subsystems[s][t.sname] = []
+ subsystems[s][t.sname].append(t2.sname)
+
+ for s in subsystems:
+ if len(subsystems[s]) > 1 and Options.options.SHOW_DUPLICATES:
+ Logs.warn("WARNING: source %s is in more than one target: %s" % (s, subsystems[s].keys()))
+ for tname in subsystems[s]:
+ if len(subsystems[s][tname]) > 1:
+ raise Utils.WafError("ERROR: source %s is in more than one subsystem of target '%s': %s" % (s, tname, subsystems[s][tname]))
+
+ return ret
+
+
+def check_orpaned_targets(bld, tgt_list):
+ '''check if any build targets are orphaned'''
+
+ target_dict = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ debug('deps: checking for orphaned targets')
+
+ for t in tgt_list:
+ if getattr(t, 'samba_used', False) == True:
+ continue
+ type = target_dict[t.sname]
+ if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
+ if re.search('^PIDL_', t.sname) is None:
+ Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
+
+
+def check_group_ordering(bld, tgt_list):
+ '''see if we have any dependencies that violate the group ordering
+
+ It is an error for a target to depend on a target from a later
+ build group
+ '''
+
+ def group_name(g):
+ tm = bld.task_manager
+ return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
+
+ for g in bld.task_manager.groups:
+ gname = group_name(g)
+ for t in g.tasks_gen:
+ t.samba_group = gname
+
+ grp_map = {}
+ idx = 0
+ for g in bld.task_manager.groups:
+ name = group_name(g)
+ grp_map[name] = idx
+ idx += 1
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ ret = True
+ for t in tgt_list:
+ tdeps = getattr(t, 'add_objects', []) + getattr(t, 'uselib_local', [])
+ for d in tdeps:
+ t2 = bld.name_to_obj(d, bld.env)
+ if t2 is None:
+ continue
+ map1 = grp_map[t.samba_group]
+ map2 = grp_map[t2.samba_group]
+
+ if map2 > map1:
+ Logs.error("Target %r in build group %r depends on target %r from later build group %r" % (
+ t.sname, t.samba_group, t2.sname, t2.samba_group))
+ ret = False
+
+ return ret
+
+
+def show_final_deps(bld, tgt_list):
+ '''show the final dependencies for all targets'''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ for t in tgt_list:
+ if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
+ continue
+ debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
+ t.sname, t.uselib, getattr(t, 'uselib_local', []), getattr(t, 'add_objects', []))
+
+
+def add_samba_attributes(bld, tgt_list):
+ '''ensure a target has a the required samba attributes'''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ for t in tgt_list:
+ if t.name != '':
+ t.sname = t.name
+ else:
+ t.sname = t.target
+ t.samba_type = targets[t.sname]
+ t.samba_abspath = t.path.abspath(bld.env)
+ t.samba_deps_extended = t.samba_deps[:]
+ t.samba_includes_extended = TO_LIST(t.samba_includes)[:]
+ t.ccflags = getattr(t, 'samba_cflags', '')
+
+def replace_grouping_libraries(bld, tgt_list):
+ '''replace dependencies based on grouping libraries
+
+ If a library is marked as a grouping library, then any target that
+ depends on a subsystem that is part of that grouping library gets
+ that dependency replaced with a dependency on the grouping library
+ '''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ grouping = {}
+
+ # find our list of grouping libraries, mapped from the subsystems they depend on
+ for t in tgt_list:
+ if not getattr(t, 'grouping_library', False):
+ continue
+ for dep in t.samba_deps_extended:
+ bld.ASSERT(dep in targets, "grouping library target %s not declared in %s" % (dep, t.sname))
+ if targets[dep] == 'SUBSYSTEM':
+ grouping[dep] = t.sname
+
+ # now replace any dependencies on elements of grouping libraries
+ for t in tgt_list:
+ for i in range(len(t.samba_deps_extended)):
+ dep = t.samba_deps_extended[i]
+ if dep in grouping:
+ if t.sname != grouping[dep]:
+ debug("deps: target %s: replacing dependency %s with grouping library %s" % (t.sname, dep, grouping[dep]))
+ t.samba_deps_extended[i] = grouping[dep]
+
+
+
+def build_direct_deps(bld, tgt_list):
+ '''build the direct_objects and direct_libs sets for each target'''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+ syslib_deps = LOCAL_CACHE(bld, 'SYSLIB_DEPS')
+
+ global_deps = bld.env.GLOBAL_DEPENDENCIES
+ global_deps_exclude = set()
+ for dep in global_deps:
+ t = bld.name_to_obj(dep, bld.env)
+ for d in t.samba_deps:
+ # prevent loops from the global dependencies list
+ global_deps_exclude.add(d)
+ global_deps_exclude.add(d + '.objlist')
+
+ for t in tgt_list:
+ t.direct_objects = set()
+ t.direct_libs = set()
+ t.direct_syslibs = set()
+ deps = t.samba_deps_extended[:]
+ if getattr(t, 'samba_use_global_deps', False) and not t.sname in global_deps_exclude:
+ deps.extend(global_deps)
+ for d in deps:
+ if d == t.sname: continue
+ if not d in targets:
+ Logs.error("Unknown dependency '%s' in '%s'" % (d, t.sname))
+ sys.exit(1)
+ if targets[d] in [ 'EMPTY', 'DISABLED' ]:
+ continue
+ if targets[d] == 'PYTHON' and targets[t.sname] != 'PYTHON' and t.sname.find('.objlist') == -1:
+ # this check should be more restrictive, but for now we have pidl-generated python
+ # code that directly depends on other python modules
+ Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
+ sys.exit(1)
+ if targets[d] == 'SYSLIB':
+ t.direct_syslibs.add(d)
+ if d in syslib_deps:
+ for implied in TO_LIST(syslib_deps[d]):
+ if BUILTIN_LIBRARY(bld, implied):
+ t.direct_objects.add(implied)
+ elif targets[implied] == 'SYSLIB':
+ t.direct_syslibs.add(implied)
+ elif targets[implied] in ['LIBRARY', 'MODULE']:
+ t.direct_libs.add(implied)
+ else:
+ Logs.error('Implied dependency %s in %s is of type %s' % (
+ implied, t.sname, targets[implied]))
+ sys.exit(1)
+ continue
+ t2 = bld.name_to_obj(d, bld.env)
+ if t2 is None:
+ Logs.error("no task %s of type %s in %s" % (d, targets[d], t.sname))
+ sys.exit(1)
+ if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
+ t.direct_libs.add(d)
+ elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
+ t.direct_objects.add(d)
+ debug('deps: built direct dependencies')
+
+
+def dependency_loop(loops, t, target):
+ '''add a dependency loop to the loops dictionary'''
+ if t.sname == target:
+ return
+ if not target in loops:
+ loops[target] = set()
+ if not t.sname in loops[target]:
+ loops[target].add(t.sname)
+
+
+def indirect_libs(bld, t, chain, loops):
+ '''recursively calculate the indirect library dependencies for a target
+
+ An indirect library is a library that results from a dependency on
+ a subsystem
+ '''
+
+ ret = getattr(t, 'indirect_libs', None)
+ if ret is not None:
+ return ret
+
+ ret = set()
+ for obj in t.direct_objects:
+ if obj in chain:
+ dependency_loop(loops, t, obj)
+ continue
+ chain.add(obj)
+ t2 = bld.name_to_obj(obj, bld.env)
+ r2 = indirect_libs(bld, t2, chain, loops)
+ chain.remove(obj)
+ ret = ret.union(t2.direct_libs)
+ ret = ret.union(r2)
+
+ for obj in indirect_objects(bld, t, set(), loops):
+ if obj in chain:
+ dependency_loop(loops, t, obj)
+ continue
+ chain.add(obj)
+ t2 = bld.name_to_obj(obj, bld.env)
+ r2 = indirect_libs(bld, t2, chain, loops)
+ chain.remove(obj)
+ ret = ret.union(t2.direct_libs)
+ ret = ret.union(r2)
+
+ t.indirect_libs = ret
+
+ return ret
+
+
+def indirect_objects(bld, t, chain, loops):
+ '''recursively calculate the indirect object dependencies for a target
+
+ indirect objects are the set of objects from expanding the
+ subsystem dependencies
+ '''
+
+ ret = getattr(t, 'indirect_objects', None)
+ if ret is not None: return ret
+
+ ret = set()
+ for lib in t.direct_objects:
+ if lib in chain:
+ dependency_loop(loops, t, lib)
+ continue
+ chain.add(lib)
+ t2 = bld.name_to_obj(lib, bld.env)
+ r2 = indirect_objects(bld, t2, chain, loops)
+ chain.remove(lib)
+ ret = ret.union(t2.direct_objects)
+ ret = ret.union(r2)
+
+ t.indirect_objects = ret
+ return ret
+
+
+def extended_objects(bld, t, chain):
+ '''recursively calculate the extended object dependencies for a target
+
+ extended objects are the union of:
+ - direct objects
+ - indirect objects
+ - direct and indirect objects of all direct and indirect libraries
+ '''
+
+ ret = getattr(t, 'extended_objects', None)
+ if ret is not None: return ret
+
+ ret = set()
+ ret = ret.union(t.final_objects)
+
+ for lib in t.final_libs:
+ if lib in chain:
+ continue
+ t2 = bld.name_to_obj(lib, bld.env)
+ chain.add(lib)
+ r2 = extended_objects(bld, t2, chain)
+ chain.remove(lib)
+ ret = ret.union(t2.final_objects)
+ ret = ret.union(r2)
+
+ t.extended_objects = ret
+ return ret
+
+
+def includes_objects(bld, t, chain, inc_loops):
+ '''recursively calculate the includes object dependencies for a target
+
+ includes dependencies come from either library or object dependencies
+ '''
+ ret = getattr(t, 'includes_objects', None)
+ if ret is not None:
+ return ret
+
+ ret = t.direct_objects.copy()
+ ret = ret.union(t.direct_libs)
+
+ for obj in t.direct_objects:
+ if obj in chain:
+ dependency_loop(inc_loops, t, obj)
+ continue
+ chain.add(obj)
+ t2 = bld.name_to_obj(obj, bld.env)
+ r2 = includes_objects(bld, t2, chain, inc_loops)
+ chain.remove(obj)
+ ret = ret.union(t2.direct_objects)
+ ret = ret.union(r2)
+
+ for lib in t.direct_libs:
+ if lib in chain:
+ dependency_loop(inc_loops, t, lib)
+ continue
+ chain.add(lib)
+ t2 = bld.name_to_obj(lib, bld.env)
+ if t2 is None:
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+ Logs.error('Target %s of type %s not found in direct_libs for %s' % (
+ lib, targets[lib], t.sname))
+ sys.exit(1)
+ r2 = includes_objects(bld, t2, chain, inc_loops)
+ chain.remove(lib)
+ ret = ret.union(t2.direct_objects)
+ ret = ret.union(r2)
+
+ t.includes_objects = ret
+ return ret
+
+
+def break_dependency_loops(bld, tgt_list):
+ '''find and break dependency loops'''
+ loops = {}
+ inc_loops = {}
+
+ # build up the list of loops
+ for t in tgt_list:
+ indirect_objects(bld, t, set(), loops)
+ indirect_libs(bld, t, set(), loops)
+ includes_objects(bld, t, set(), inc_loops)
+
+ # break the loops
+ for t in tgt_list:
+ if t.sname in loops:
+ for attr in ['direct_objects', 'indirect_objects', 'direct_libs', 'indirect_libs']:
+ objs = getattr(t, attr, set())
+ setattr(t, attr, objs.difference(loops[t.sname]))
+
+ for loop in loops:
+ debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
+
+ for loop in inc_loops:
+ debug('deps: Found include loops for target %s : %s', loop, inc_loops[loop])
+
+ # expand the loops mapping by one level
+ for loop in loops.copy():
+ for tgt in loops[loop]:
+ if tgt in loops:
+ loops[loop] = loops[loop].union(loops[tgt])
+
+ for loop in inc_loops.copy():
+ for tgt in inc_loops[loop]:
+ if tgt in inc_loops:
+ inc_loops[loop] = inc_loops[loop].union(inc_loops[tgt])
+
+
+ # expand indirect subsystem and library loops
+ for loop in loops.copy():
+ t = bld.name_to_obj(loop, bld.env)
+ if t.samba_type in ['SUBSYSTEM']:
+ loops[loop] = loops[loop].union(t.indirect_objects)
+ loops[loop] = loops[loop].union(t.direct_objects)
+ if t.samba_type in ['LIBRARY','PYTHON']:
+ loops[loop] = loops[loop].union(t.indirect_libs)
+ loops[loop] = loops[loop].union(t.direct_libs)
+ if loop in loops[loop]:
+ loops[loop].remove(loop)
+
+ # expand indirect includes loops
+ for loop in inc_loops.copy():
+ t = bld.name_to_obj(loop, bld.env)
+ inc_loops[loop] = inc_loops[loop].union(t.includes_objects)
+ if loop in inc_loops[loop]:
+ inc_loops[loop].remove(loop)
+
+ # add in the replacement dependencies
+ for t in tgt_list:
+ for loop in loops:
+ for attr in ['indirect_objects', 'indirect_libs']:
+ objs = getattr(t, attr, set())
+ if loop in objs:
+ diff = loops[loop].difference(objs)
+ if t.sname in diff:
+ diff.remove(t.sname)
+ if diff:
+ debug('deps: Expanded target %s of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
+ objs = objs.union(diff)
+ setattr(t, attr, objs)
+
+ for loop in inc_loops:
+ objs = getattr(t, 'includes_objects', set())
+ if loop in objs:
+ diff = inc_loops[loop].difference(objs)
+ if t.sname in diff:
+ diff.remove(t.sname)
+ if diff:
+ debug('deps: Expanded target %s includes of type %s from loop %s by %s', t.sname, t.samba_type, loop, diff)
+ objs = objs.union(diff)
+ setattr(t, 'includes_objects', objs)
+
+
+def reduce_objects(bld, tgt_list):
+ '''reduce objects by looking for indirect object dependencies'''
+ rely_on = {}
+
+ for t in tgt_list:
+ t.extended_objects = None
+
+ changed = False
+
+ for type in ['BINARY', 'PYTHON', 'LIBRARY']:
+ for t in tgt_list:
+ if t.samba_type != type: continue
+ # if we will indirectly link to a target then we don't need it
+ new = t.final_objects.copy()
+ for l in t.final_libs:
+ t2 = bld.name_to_obj(l, bld.env)
+ t2_obj = extended_objects(bld, t2, set())
+ dup = new.intersection(t2_obj)
+ if t.sname in rely_on:
+ dup = dup.difference(rely_on[t.sname])
+ if dup:
+ debug('deps: removing dups from %s of type %s: %s also in %s %s',
+ t.sname, t.samba_type, dup, t2.samba_type, l)
+ new = new.difference(dup)
+ changed = True
+ if not l in rely_on:
+ rely_on[l] = set()
+ rely_on[l] = rely_on[l].union(dup)
+ t.final_objects = new
+
+ if not changed:
+ return False
+
+ # add back in any objects that were relied upon by the reduction rules
+ for r in rely_on:
+ t = bld.name_to_obj(r, bld.env)
+ t.final_objects = t.final_objects.union(rely_on[r])
+
+ return True
+
+
+def show_library_loop(bld, lib1, lib2, path, seen):
+ '''show the detailed path of a library loop between lib1 and lib2'''
+
+ t = bld.name_to_obj(lib1, bld.env)
+ if not lib2 in getattr(t, 'final_libs', set()):
+ return
+
+ for d in t.samba_deps_extended:
+ if d in seen:
+ continue
+ seen.add(d)
+ path2 = path + '=>' + d
+ if d == lib2:
+ Logs.warn('library loop path: ' + path2)
+ return
+ show_library_loop(bld, d, lib2, path2, seen)
+ seen.remove(d)
+
+
+def calculate_final_deps(bld, tgt_list, loops):
+ '''calculate the final library and object dependencies'''
+ for t in tgt_list:
+ # start with the maximum possible list
+ t.final_libs = t.direct_libs.union(indirect_libs(bld, t, set(), loops))
+ t.final_objects = t.direct_objects.union(indirect_objects(bld, t, set(), loops))
+
+ for t in tgt_list:
+ # don't depend on ourselves
+ if t.sname in t.final_libs:
+ t.final_libs.remove(t.sname)
+ if t.sname in t.final_objects:
+ t.final_objects.remove(t.sname)
+
+ # handle any non-shared binaries
+ for t in tgt_list:
+ if t.samba_type == 'BINARY' and bld.NONSHARED_BINARY(t.sname):
+ subsystem_list = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ # replace lib deps with objlist deps
+ for l in t.final_libs:
+ objname = l + '.objlist'
+ t2 = bld.name_to_obj(objname, bld.env)
+ if t2 is None:
+ Logs.error('ERROR: subsystem %s not found' % objname)
+ sys.exit(1)
+ t.final_objects.add(objname)
+ t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
+ if l in subsystem_list:
+ # its a subsystem - we also need the contents of any modules
+ for d in subsystem_list[l]:
+ module_name = d['TARGET']
+ if targets[module_name] == 'LIBRARY':
+ objname = module_name + '.objlist'
+ elif targets[module_name] == 'SUBSYSTEM':
+ objname = module_name
+ else:
+ continue
+ t2 = bld.name_to_obj(objname, bld.env)
+ if t2 is None:
+ Logs.error('ERROR: subsystem %s not found' % objname)
+ sys.exit(1)
+ t.final_objects.add(objname)
+ t.final_objects = t.final_objects.union(extended_objects(bld, t2, set()))
+ t.final_libs = set()
+
+ # find any library loops
+ for t in tgt_list:
+ if t.samba_type in ['LIBRARY', 'PYTHON']:
+ for l in t.final_libs.copy():
+ t2 = bld.name_to_obj(l, bld.env)
+ if t.sname in t2.final_libs:
+ if getattr(bld.env, "ALLOW_CIRCULAR_LIB_DEPENDENCIES", False):
+ # we could break this in either direction. If one of the libraries
+ # has a version number, and will this be distributed publicly, then
+ # we should make it the lower level library in the DAG
+ Logs.warn('deps: removing library loop %s from %s' % (t.sname, t2.sname))
+ dependency_loop(loops, t, t2.sname)
+ t2.final_libs.remove(t.sname)
+ else:
+ Logs.error('ERROR: circular library dependency between %s and %s'
+ % (t.sname, t2.sname))
+ show_library_loop(bld, t.sname, t2.sname, t.sname, set())
+ show_library_loop(bld, t2.sname, t.sname, t2.sname, set())
+ sys.exit(1)
+
+ for loop in loops:
+ debug('deps: Found dependency loops for target %s : %s', loop, loops[loop])
+
+ # we now need to make corrections for any library loops we broke up
+ # any target that depended on the target of the loop and doesn't
+ # depend on the source of the loop needs to get the loop source added
+ for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
+ for t in tgt_list:
+ if t.samba_type != type: continue
+ for loop in loops:
+ if loop in t.final_libs:
+ diff = loops[loop].difference(t.final_libs)
+ if t.sname in diff:
+ diff.remove(t.sname)
+ if t.sname in diff:
+ diff.remove(t.sname)
+ # make sure we don't recreate the loop again!
+ for d in diff.copy():
+ t2 = bld.name_to_obj(d, bld.env)
+ if t2.samba_type == 'LIBRARY':
+ if t.sname in t2.final_libs:
+ debug('deps: removing expansion %s from %s', d, t.sname)
+ diff.remove(d)
+ if diff:
+ debug('deps: Expanded target %s by loop %s libraries (loop %s) %s', t.sname, loop,
+ loops[loop], diff)
+ t.final_libs = t.final_libs.union(diff)
+
+ # remove objects that are also available in linked libs
+ count = 0
+ while reduce_objects(bld, tgt_list):
+ count += 1
+ if count > 100:
+ Logs.warn("WARNING: Unable to remove all inter-target object duplicates")
+ break
+ debug('deps: Object reduction took %u iterations', count)
+
+ # add in any syslib dependencies
+ for t in tgt_list:
+ if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
+ continue
+ syslibs = set()
+ for d in t.final_objects:
+ t2 = bld.name_to_obj(d, bld.env)
+ syslibs = syslibs.union(t2.direct_syslibs)
+ # this adds the indirect syslibs as well, which may not be needed
+ # depending on the linker flags
+ for d in t.final_libs:
+ t2 = bld.name_to_obj(d, bld.env)
+ syslibs = syslibs.union(t2.direct_syslibs)
+ t.final_syslibs = syslibs
+
+
+ # find any unresolved library loops
+ lib_loop_error = False
+ for t in tgt_list:
+ if t.samba_type in ['LIBRARY', 'PYTHON']:
+ for l in t.final_libs.copy():
+ t2 = bld.name_to_obj(l, bld.env)
+ if t.sname in t2.final_libs:
+ Logs.error('ERROR: Unresolved library loop %s from %s' % (t.sname, t2.sname))
+ lib_loop_error = True
+ if lib_loop_error:
+ sys.exit(1)
+
+ debug('deps: removed duplicate dependencies')
+
+
+def show_dependencies(bld, target, seen):
+ '''recursively show the dependencies of target'''
+
+ if target in seen:
+ return
+
+ t = bld.name_to_obj(target, bld.env)
+ if t is None:
+ Logs.error("ERROR: Unable to find target '%s'" % target)
+ sys.exit(1)
+
+ Logs.info('%s(OBJECTS): %s' % (target, t.direct_objects))
+ Logs.info('%s(LIBS): %s' % (target, t.direct_libs))
+ Logs.info('%s(SYSLIBS): %s' % (target, t.direct_syslibs))
+
+ seen.add(target)
+
+ for t2 in t.direct_objects:
+ show_dependencies(bld, t2, seen)
+
+
+def show_object_duplicates(bld, tgt_list):
+ '''show a list of object files that are included in more than
+ one library or binary'''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ used_by = {}
+
+ Logs.info("showing duplicate objects")
+
+ for t in tgt_list:
+ if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
+ continue
+ for n in getattr(t, 'final_objects', set()):
+ t2 = bld.name_to_obj(n, bld.env)
+ if not n in used_by:
+ used_by[n] = set()
+ used_by[n].add(t.sname)
+
+ for n in used_by:
+ if len(used_by[n]) > 1:
+ Logs.info("target '%s' is used by %s" % (n, used_by[n]))
+
+ Logs.info("showing indirect dependency counts (sorted by count)")
+
+ def indirect_count(t1, t2):
+ return len(t2.indirect_objects) - len(t1.indirect_objects)
+
+ sorted_list = sorted(tgt_list, cmp=indirect_count)
+ for t in sorted_list:
+ if len(t.indirect_objects) > 1:
+ Logs.info("%s depends on %u indirect objects" % (t.sname, len(t.indirect_objects)))
+
+
+######################################################################
+# this provides a way to save our dependency calculations between runs
+savedeps_version = 3
+savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
+ 'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
+ 'use_global_deps', 'global_include' ]
+savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags', 'samba_deps_extended']
+savedeps_outenv = ['INC_PATHS']
+savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
+savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
+savedeps_files = ['buildtools/wafsamba/samba_deps.py']
+
+def save_samba_deps(bld, tgt_list):
+ '''save the dependency calculations between builds, to make
+ further builds faster'''
+ denv = Environment.Environment()
+
+ denv.version = savedeps_version
+ denv.savedeps_inputs = savedeps_inputs
+ denv.savedeps_outputs = savedeps_outputs
+ denv.input = {}
+ denv.output = {}
+ denv.outenv = {}
+ denv.caches = {}
+ denv.envvar = {}
+ denv.files = {}
+
+ for f in savedeps_files:
+ denv.files[f] = os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime
+
+ for c in savedeps_caches:
+ denv.caches[c] = LOCAL_CACHE(bld, c)
+
+ for e in savedeps_envvars:
+ denv.envvar[e] = bld.env[e]
+
+ for t in tgt_list:
+ # save all the input attributes for each target
+ tdeps = {}
+ for attr in savedeps_inputs:
+ v = getattr(t, attr, None)
+ if v is not None:
+ tdeps[attr] = v
+ if tdeps != {}:
+ denv.input[t.sname] = tdeps
+
+ # save all the output attributes for each target
+ tdeps = {}
+ for attr in savedeps_outputs:
+ v = getattr(t, attr, None)
+ if v is not None:
+ tdeps[attr] = v
+ if tdeps != {}:
+ denv.output[t.sname] = tdeps
+
+ tdeps = {}
+ for attr in savedeps_outenv:
+ if attr in t.env:
+ tdeps[attr] = t.env[attr]
+ if tdeps != {}:
+ denv.outenv[t.sname] = tdeps
+
+ depsfile = os.path.join(bld.bdir, "sambadeps")
+ denv.store(depsfile)
+
+
+
+def load_samba_deps(bld, tgt_list):
+ '''load a previous set of build dependencies if possible'''
+ depsfile = os.path.join(bld.bdir, "sambadeps")
+ denv = Environment.Environment()
+ try:
+ debug('deps: checking saved dependencies')
+ denv.load(depsfile)
+ if (denv.version != savedeps_version or
+ denv.savedeps_inputs != savedeps_inputs or
+ denv.savedeps_outputs != savedeps_outputs):
+ return False
+ except:
+ return False
+
+ # check if critical files have changed
+ for f in savedeps_files:
+ if f not in denv.files:
+ return False
+ if denv.files[f] != os.stat(os.path.join(bld.srcnode.abspath(), f)).st_mtime:
+ return False
+
+ # check if caches are the same
+ for c in savedeps_caches:
+ if c not in denv.caches or denv.caches[c] != LOCAL_CACHE(bld, c):
+ return False
+
+ # check if caches are the same
+ for e in savedeps_envvars:
+ if e not in denv.envvar or denv.envvar[e] != bld.env[e]:
+ return False
+
+ # check inputs are the same
+ for t in tgt_list:
+ tdeps = {}
+ for attr in savedeps_inputs:
+ v = getattr(t, attr, None)
+ if v is not None:
+ tdeps[attr] = v
+ if t.sname in denv.input:
+ olddeps = denv.input[t.sname]
+ else:
+ olddeps = {}
+ if tdeps != olddeps:
+ #print '%s: \ntdeps=%s \nodeps=%s' % (t.sname, tdeps, olddeps)
+ return False
+
+ # put outputs in place
+ for t in tgt_list:
+ if not t.sname in denv.output: continue
+ tdeps = denv.output[t.sname]
+ for a in tdeps:
+ setattr(t, a, tdeps[a])
+
+ # put output env vars in place
+ for t in tgt_list:
+ if not t.sname in denv.outenv: continue
+ tdeps = denv.outenv[t.sname]
+ for a in tdeps:
+ t.env[a] = tdeps[a]
+
+ debug('deps: loaded saved dependencies')
+ return True
+
+
+
+def check_project_rules(bld):
+ '''check the project rules - ensuring the targets are sane'''
+
+ loops = {}
+ inc_loops = {}
+
+ tgt_list = get_tgt_list(bld)
+
+ add_samba_attributes(bld, tgt_list)
+
+ force_project_rules = (Options.options.SHOWDEPS or
+ Options.options.SHOW_DUPLICATES)
+
+ if not force_project_rules and load_samba_deps(bld, tgt_list):
+ return
+
+ global tstart
+ tstart = time.clock()
+
+ bld.new_rules = True
+ Logs.info("Checking project rules ...")
+
+ debug('deps: project rules checking started')
+
+ expand_subsystem_deps(bld)
+
+ debug("deps: expand_subsystem_deps: %f" % (time.clock() - tstart))
+
+ replace_grouping_libraries(bld, tgt_list)
+
+ debug("deps: replace_grouping_libraries: %f" % (time.clock() - tstart))
+
+ build_direct_deps(bld, tgt_list)
+
+ debug("deps: build_direct_deps: %f" % (time.clock() - tstart))
+
+ break_dependency_loops(bld, tgt_list)
+
+ debug("deps: break_dependency_loops: %f" % (time.clock() - tstart))
+
+ if Options.options.SHOWDEPS:
+ show_dependencies(bld, Options.options.SHOWDEPS, set())
+
+ calculate_final_deps(bld, tgt_list, loops)
+
+ debug("deps: calculate_final_deps: %f" % (time.clock() - tstart))
+
+ if Options.options.SHOW_DUPLICATES:
+ show_object_duplicates(bld, tgt_list)
+
+ # run the various attribute generators
+ for f in [ build_dependencies, build_includes, add_init_functions ]:
+ debug('deps: project rules checking %s', f)
+ for t in tgt_list: f(t)
+ debug("deps: %s: %f" % (f, time.clock() - tstart))
+
+ debug('deps: project rules stage1 completed')
+
+ #check_orpaned_targets(bld, tgt_list)
+
+ if not check_duplicate_sources(bld, tgt_list):
+ Logs.error("Duplicate sources present - aborting")
+ sys.exit(1)
+
+ debug("deps: check_duplicate_sources: %f" % (time.clock() - tstart))
+
+ if not check_group_ordering(bld, tgt_list):
+ Logs.error("Bad group ordering - aborting")
+ sys.exit(1)
+
+ debug("deps: check_group_ordering: %f" % (time.clock() - tstart))
+
+ show_final_deps(bld, tgt_list)
+
+ debug("deps: show_final_deps: %f" % (time.clock() - tstart))
+
+ debug('deps: project rules checking completed - %u targets checked',
+ len(tgt_list))
+
+ if not bld.is_install:
+ save_samba_deps(bld, tgt_list)
+
+ debug("deps: save_samba_deps: %f" % (time.clock() - tstart))
+
+ Logs.info("Project rules pass")
+
+
+def CHECK_PROJECT_RULES(bld):
+ '''enable checking of project targets for sanity'''
+ if bld.env.added_project_rules:
+ return
+ bld.env.added_project_rules = True
+ bld.add_pre_fun(check_project_rules)
+Build.BuildContext.CHECK_PROJECT_RULES = CHECK_PROJECT_RULES
+
+
diff --git a/buildtools/wafsamba/samba_dist.py b/buildtools/wafsamba/samba_dist.py
new file mode 100644
index 0000000000..a11a37cc1b
--- /dev/null
+++ b/buildtools/wafsamba/samba_dist.py
@@ -0,0 +1,204 @@
+# customised version of 'waf dist' for Samba tools
+# uses git ls-files to get file lists
+
+import Utils, os, sys, tarfile, stat, Scripting, Logs, Options
+from samba_utils import *
+
+dist_dirs = None
+dist_blacklist = ""
+
+def add_symlink(tar, fname, abspath, basedir):
+ '''handle symlinks to directories that may move during packaging'''
+ if not os.path.islink(abspath):
+ return False
+ tinfo = tar.gettarinfo(name=abspath, arcname=fname)
+ tgt = os.readlink(abspath)
+
+ if dist_dirs:
+ # we need to find the target relative to the main directory
+ # this is here to cope with symlinks into the buildtools
+ # directory from within the standalone libraries in Samba. For example,
+ # a symlink to ../../builtools/scripts/autogen-waf.sh needs
+ # to be rewritten as a symlink to buildtools/scripts/autogen-waf.sh
+ # when the tarball for talloc is built
+
+ # the filename without the appname-version
+ rel_fname = '/'.join(fname.split('/')[1:])
+
+ # join this with the symlink target
+ tgt_full = os.path.join(os.path.dirname(rel_fname), tgt)
+
+ # join with the base directory
+ tgt_base = os.path.normpath(os.path.join(basedir, tgt_full))
+
+ # see if this is inside one of our dist_dirs
+ for dir in dist_dirs.split():
+ if dir.find(':') != -1:
+ destdir=dir.split(':')[1]
+ dir=dir.split(':')[0]
+ else:
+ destdir = '.'
+ if dir == basedir:
+ # internal links don't get rewritten
+ continue
+ if dir == tgt_base[0:len(dir)] and tgt_base[len(dir)] == '/':
+ new_tgt = destdir + tgt_base[len(dir):]
+ tinfo.linkname = new_tgt
+ break
+
+ tinfo.uid = 0
+ tinfo.gid = 0
+ tinfo.uname = 'root'
+ tinfo.gname = 'root'
+ tar.addfile(tinfo)
+ return True
+
+def add_tarfile(tar, fname, abspath, basedir):
+ '''add a file to the tarball'''
+ if add_symlink(tar, fname, abspath, basedir):
+ return
+ try:
+ tinfo = tar.gettarinfo(name=abspath, arcname=fname)
+ except OSError:
+ Logs.error('Unable to find file %s - missing from git checkout?' % abspath)
+ sys.exit(1)
+ tinfo.uid = 0
+ tinfo.gid = 0
+ tinfo.uname = 'root'
+ tinfo.gname = 'root'
+ fh = open(abspath)
+ tar.addfile(tinfo, fileobj=fh)
+ fh.close()
+
+
+def vcs_dir_contents(path):
+ """Return the versioned files under a path.
+
+ :return: List of paths relative to path
+ """
+ repo = path
+ while repo != "/":
+ if os.path.isdir(os.path.join(repo, ".git")):
+ ls_files_cmd = [ 'git', 'ls-files', '--full-name',
+ os_path_relpath(path, repo) ]
+ cwd = None
+ env = dict(os.environ)
+ env["GIT_DIR"] = os.path.join(repo, ".git")
+ break
+ elif os.path.isdir(os.path.join(repo, ".bzr")):
+ ls_files_cmd = [ 'bzr', 'ls', '--recursive', '--versioned',
+ os_path_relpath(path, repo)]
+ cwd = repo
+ env = None
+ break
+ repo = os.path.dirname(repo)
+ if repo == "/":
+ raise Exception("unsupported or no vcs for %s" % path)
+ return Utils.cmd_output(ls_files_cmd, cwd=cwd, env=env).split()
+
+
+def dist(appname='',version=''):
+ if not isinstance(appname, str) or not appname:
+ # this copes with a mismatch in the calling arguments for dist()
+ appname = Utils.g_module.APPNAME
+ version = Utils.g_module.VERSION
+ if not version:
+ version = Utils.g_module.VERSION
+
+ srcdir = os.path.normpath(os.path.join(os.path.dirname(Utils.g_module.root_path), Utils.g_module.srcdir))
+
+ if not dist_dirs:
+ Logs.error('You must use samba_dist.DIST_DIRS() to set which directories to package')
+ sys.exit(1)
+
+ dist_base = '%s-%s' % (appname, version)
+
+ if Options.options.SIGN_RELEASE:
+ dist_name = '%s.tar' % (dist_base)
+ tar = tarfile.open(dist_name, 'w')
+ else:
+ dist_name = '%s.tar.gz' % (dist_base)
+ tar = tarfile.open(dist_name, 'w:gz')
+
+ blacklist = dist_blacklist.split()
+
+ for dir in dist_dirs.split():
+ if dir.find(':') != -1:
+ destdir=dir.split(':')[1]
+ dir=dir.split(':')[0]
+ else:
+ destdir = '.'
+ absdir = os.path.join(srcdir, dir)
+ try:
+ files = vcs_dir_contents(absdir)
+ except Exception, e:
+ Logs.error('unable to get contents of %s: %s' % (absdir, e))
+ sys.exit(1)
+ for f in files:
+ abspath = os.path.join(srcdir, f)
+
+ if dir != '.':
+ f = f[len(dir)+1:]
+
+ # Remove files in the blacklist
+ if f in dist_blacklist:
+ continue
+ blacklisted = False
+ # Remove directories in the blacklist
+ for d in blacklist:
+ if f.startswith(d):
+ blacklisted = True
+ if blacklisted:
+ continue
+ if os.path.isdir(abspath):
+ continue
+ if destdir != '.':
+ f = destdir + '/' + f
+ fname = dist_base + '/' + f
+ add_tarfile(tar, fname, abspath, dir)
+
+ tar.close()
+
+ if Options.options.SIGN_RELEASE:
+ import gzip
+ try:
+ os.unlink(dist_name + '.asc')
+ except OSError:
+ pass
+
+ cmd = "gpg --detach-sign --armor " + dist_name
+ os.system(cmd)
+ uncompressed_tar = open(dist_name, 'rb')
+ compressed_tar = gzip.open(dist_name + '.gz', 'wb')
+ while 1:
+ buffer = uncompressed_tar.read(1048576)
+ if buffer:
+ compressed_tar.write(buffer)
+ else:
+ break
+ uncompressed_tar.close()
+ compressed_tar.close()
+ os.unlink(dist_name)
+ Logs.info('Created %s.gz %s.asc' % (dist_name, dist_name))
+ dist_name = dist_name + '.gz'
+ else:
+ Logs.info('Created %s' % dist_name)
+
+ return dist_name
+
+
+@conf
+def DIST_DIRS(dirs):
+ '''set the directories to package, relative to top srcdir'''
+ global dist_dirs
+ if not dist_dirs:
+ dist_dirs = dirs
+
+@conf
+def DIST_BLACKLIST(blacklist):
+ '''set the files to exclude from packaging, relative to top srcdir'''
+ global dist_blacklist
+ if not dist_blacklist:
+ dist_blacklist = blacklist
+
+Scripting.dist = dist
diff --git a/buildtools/wafsamba/samba_headers.py b/buildtools/wafsamba/samba_headers.py
new file mode 100644
index 0000000000..cca6420b6c
--- /dev/null
+++ b/buildtools/wafsamba/samba_headers.py
@@ -0,0 +1,180 @@
+# specialist handling of header files for Samba
+
+import Build, re, Task, TaskGen, shutil, sys, Logs
+from samba_utils import *
+
+
+def header_install_path(header, header_path):
+ '''find the installation path for a header, given a header_path option'''
+ if not header_path:
+ return ''
+ if not isinstance(header_path, list):
+ return header_path
+ for (p1, dir) in header_path:
+ for p2 in TO_LIST(p1):
+ if fnmatch.fnmatch(header, p2):
+ return dir
+ # default to current path
+ return ''
+
+
+re_header = re.compile('^\s*#\s*include[ \t]*"([^"]+)"', re.I | re.M)
+
+# a dictionary mapping source header paths to public header paths
+header_map = {}
+
+def find_suggested_header(hpath):
+ '''find a suggested header path to use'''
+ base = os.path.basename(hpath)
+ ret = []
+ for h in header_map:
+ if os.path.basename(h) == base:
+ ret.append('<%s>' % header_map[h])
+ ret.append('"%s"' % h)
+ return ret
+
+def create_public_header(task):
+ '''create a public header from a private one, output within the build tree'''
+ src = task.inputs[0].abspath(task.env)
+ tgt = task.outputs[0].bldpath(task.env)
+
+ if os.path.exists(tgt):
+ os.unlink(tgt)
+
+ relsrc = os_path_relpath(src, task.env.TOPDIR)
+
+ infile = open(src, mode='r')
+ outfile = open(tgt, mode='w')
+ linenumber = 0
+
+ search_paths = [ '', task.env.RELPATH ]
+ for i in task.env.EXTRA_INCLUDES:
+ if i.startswith('#'):
+ search_paths.append(i[1:])
+
+ for line in infile:
+ linenumber += 1
+
+ # allow some straight substitutions
+ if task.env.public_headers_replace and line.strip() in task.env.public_headers_replace:
+ outfile.write(task.env.public_headers_replace[line.strip()] + '\n')
+ continue
+
+ # see if its an include line
+ m = re_header.match(line)
+ if m is None:
+ outfile.write(line)
+ continue
+
+ # its an include, get the header path
+ hpath = m.group(1)
+ if hpath.startswith("bin/default/"):
+ hpath = hpath[12:]
+
+ # some are always allowed
+ if task.env.public_headers_skip and hpath in task.env.public_headers_skip:
+ outfile.write(line)
+ continue
+
+ # work out the header this refers to
+ found = False
+ for s in search_paths:
+ p = os.path.normpath(os.path.join(s, hpath))
+ if p in header_map:
+ outfile.write("#include <%s>\n" % header_map[p])
+ found = True
+ break
+ if found:
+ continue
+
+ if task.env.public_headers_allow_broken:
+ Logs.warn("Broken public header include '%s' in '%s'" % (hpath, relsrc))
+ outfile.write(line)
+ continue
+
+ # try to be nice to the developer by suggesting an alternative
+ suggested = find_suggested_header(hpath)
+ outfile.close()
+ os.unlink(tgt)
+ sys.stderr.write("%s:%u:Error: unable to resolve public header %s (maybe try one of %s)\n" % (
+ os.path.relpath(src, os.getcwd()), linenumber, hpath, suggested))
+ raise Utils.WafError("Unable to resolve header path '%s' in public header '%s' in directory %s" % (
+ hpath, relsrc, task.env.RELPATH))
+ infile.close()
+ outfile.close()
+
+
+def public_headers_simple(bld, public_headers, header_path=None, public_headers_install=True):
+ '''install some headers - simple version, no munging needed
+ '''
+ if not public_headers_install:
+ return
+ for h in TO_LIST(public_headers):
+ inst_path = header_install_path(h, header_path)
+ if h.find(':') != -1:
+ s = h.split(":")
+ h_name = s[0]
+ inst_name = s[1]
+ else:
+ h_name = h
+ inst_name = os.path.basename(h)
+ bld.INSTALL_FILES('${INCLUDEDIR}', h_name, destname=inst_name)
+
+
+
+def PUBLIC_HEADERS(bld, public_headers, header_path=None, public_headers_install=True):
+ '''install some headers
+
+ header_path may either be a string that is added to the INCLUDEDIR,
+ or it can be a dictionary of wildcard patterns which map to destination
+ directories relative to INCLUDEDIR
+ '''
+ bld.SET_BUILD_GROUP('final')
+
+ if not bld.env.build_public_headers:
+ # in this case no header munging neeeded. Used for tdb, talloc etc
+ public_headers_simple(bld, public_headers, header_path=header_path,
+ public_headers_install=public_headers_install)
+ return
+
+ # create the public header in the given path
+ # in the build tree
+ for h in TO_LIST(public_headers):
+ inst_path = header_install_path(h, header_path)
+ if h.find(':') != -1:
+ s = h.split(":")
+ h_name = s[0]
+ inst_name = s[1]
+ else:
+ h_name = h
+ inst_name = os.path.basename(h)
+ relpath1 = os_path_relpath(bld.srcnode.abspath(), bld.curdir)
+ relpath2 = os_path_relpath(bld.curdir, bld.srcnode.abspath())
+ targetdir = os.path.normpath(os.path.join(relpath1, bld.env.build_public_headers, inst_path))
+ if not os.path.exists(os.path.join(bld.curdir, targetdir)):
+ raise Utils.WafError("missing source directory %s for public header %s" % (targetdir, inst_name))
+ target = os.path.join(targetdir, inst_name)
+
+ # the source path of the header, relative to the top of the source tree
+ src_path = os.path.normpath(os.path.join(relpath2, h_name))
+
+ # the install path of the header, relative to the public include directory
+ target_path = os.path.normpath(os.path.join(inst_path, inst_name))
+
+ header_map[src_path] = target_path
+
+ t = bld.SAMBA_GENERATOR('HEADER_%s/%s/%s' % (relpath2, inst_path, inst_name),
+ group='headers',
+ rule=create_public_header,
+ source=h_name,
+ target=target)
+ t.env.RELPATH = relpath2
+ t.env.TOPDIR = bld.srcnode.abspath()
+ if not bld.env.public_headers_list:
+ bld.env.public_headers_list = []
+ bld.env.public_headers_list.append(os.path.join(inst_path, inst_name))
+ if public_headers_install:
+ bld.INSTALL_FILES('${INCLUDEDIR}',
+ target,
+ destname=os.path.join(inst_path, inst_name), flat=True)
+Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
diff --git a/buildtools/wafsamba/samba_install.py b/buildtools/wafsamba/samba_install.py
new file mode 100644
index 0000000000..d755d01078
--- /dev/null
+++ b/buildtools/wafsamba/samba_install.py
@@ -0,0 +1,227 @@
+###########################
+# this handles the magic we need to do for installing
+# with all the configure options that affect rpath and shared
+# library use
+
+import Options
+from TaskGen import feature, before, after
+from samba_utils import *
+
+@feature('install_bin')
+@after('apply_core')
+@before('apply_link', 'apply_obj_vars')
+def install_binary(self):
+ '''install a binary, taking account of the different rpath varients'''
+ bld = self.bld
+
+ # get the ldflags we will use for install and build
+ install_ldflags = install_rpath(self)
+ build_ldflags = build_rpath(bld)
+
+ if not Options.is_install:
+ # just need to set rpath if we are not installing
+ self.env.RPATH = build_ldflags
+ return
+
+ # work out the install path, expanding variables
+ install_path = getattr(self, 'samba_inst_path', None) or '${BINDIR}'
+ install_path = bld.EXPAND_VARIABLES(install_path)
+
+ orig_target = os.path.basename(self.target)
+
+ if install_ldflags != build_ldflags:
+ # we will be creating a new target name, and using that for the
+ # install link. That stops us from overwriting the existing build
+ # target, which has different ldflags
+ self.target += '.inst'
+
+ # setup the right rpath link flags for the install
+ self.env.RPATH = install_ldflags
+
+ if not self.samba_install:
+ # this binary is marked not to be installed
+ return
+
+ # tell waf to install the right binary
+ bld.install_as(os.path.join(install_path, orig_target),
+ os.path.join(self.path.abspath(bld.env), self.target),
+ chmod=MODE_755)
+
+
+
+@feature('install_lib')
+@after('apply_core')
+@before('apply_link', 'apply_obj_vars')
+def install_library(self):
+ '''install a library, taking account of the different rpath varients'''
+ if getattr(self, 'done_install_library', False):
+ return
+
+ bld = self.bld
+
+ install_ldflags = install_rpath(self)
+ build_ldflags = build_rpath(bld)
+
+ if not Options.is_install or not getattr(self, 'samba_install', True):
+ # just need to set the build rpath if we are not installing
+ self.env.RPATH = build_ldflags
+ return
+
+ # setup the install path, expanding variables
+ install_path = getattr(self, 'samba_inst_path', None)
+ if install_path is None:
+ if getattr(self, 'private_library', False):
+ install_path = '${PRIVATELIBDIR}'
+ else:
+ install_path = '${LIBDIR}'
+ install_path = bld.EXPAND_VARIABLES(install_path)
+
+ target_name = self.target
+
+ if install_ldflags != build_ldflags:
+ # we will be creating a new target name, and using that for the
+ # install link. That stops us from overwriting the existing build
+ # target, which has different ldflags
+ self.done_install_library = True
+ t = self.clone('default')
+ t.posted = False
+ t.target += '.inst'
+ self.env.RPATH = build_ldflags
+ else:
+ t = self
+
+ t.env.RPATH = install_ldflags
+
+ dev_link = None
+
+ # in the following the names are:
+ # - inst_name is the name with .inst. in it, in the build
+ # directory
+ # - install_name is the name in the install directory
+ # - install_link is a symlink in the install directory, to install_name
+
+ if getattr(self, 'samba_realname', None):
+ install_name = self.samba_realname
+ install_link = None
+ if getattr(self, 'samba_type', None) == 'PYTHON':
+ inst_name = bld.make_libname(t.target, nolibprefix=True, python=True)
+ else:
+ inst_name = bld.make_libname(t.target)
+ elif self.vnum:
+ vnum_base = self.vnum.split('.')[0]
+ install_name = bld.make_libname(target_name, version=self.vnum)
+ install_link = bld.make_libname(target_name, version=vnum_base)
+ inst_name = bld.make_libname(t.target)
+ if not self.private_library:
+ # only generate the dev link for non-bundled libs
+ dev_link = bld.make_libname(target_name)
+ elif getattr(self, 'soname', ''):
+ install_name = bld.make_libname(target_name)
+ install_link = self.soname
+ inst_name = bld.make_libname(t.target)
+ else:
+ install_name = bld.make_libname(target_name)
+ install_link = None
+ inst_name = bld.make_libname(t.target)
+
+ if t.env.SONAME_ST:
+ # ensure we get the right names in the library
+ if install_link:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
+ else:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
+ t.env.SONAME_ST = ''
+
+ # tell waf to install the library
+ bld.install_as(os.path.join(install_path, install_name),
+ os.path.join(self.path.abspath(bld.env), inst_name))
+ if install_link and install_link != install_name:
+ # and the symlink if needed
+ bld.symlink_as(os.path.join(install_path, install_link), install_name)
+ if dev_link:
+ bld.symlink_as(os.path.join(install_path, dev_link), install_name)
+
+
+@feature('cshlib')
+@after('apply_implib')
+@before('apply_vnum')
+def apply_soname(self):
+ '''install a library, taking account of the different rpath varients'''
+
+ if self.env.SONAME_ST and getattr(self, 'soname', ''):
+ self.env.append_value('LINKFLAGS', self.env.SONAME_ST % self.soname)
+ self.env.SONAME_ST = ''
+
+@feature('cshlib')
+@after('apply_implib')
+@before('apply_vnum')
+def apply_vscript(self):
+ '''add version-script arguments to library build'''
+
+ if self.env.HAVE_LD_VERSION_SCRIPT and getattr(self, 'version_script', ''):
+ self.env.append_value('LINKFLAGS', "-Wl,--version-script=%s" %
+ self.version_script)
+ self.version_script = None
+
+
+##############################
+# handle the creation of links for libraries and binaries in the build tree
+
+@feature('symlink_lib')
+@after('apply_link')
+def symlink_lib(self):
+ '''symlink a shared lib'''
+
+ if self.target.endswith('.inst'):
+ return
+
+ blddir = os.path.dirname(self.bld.srcnode.abspath(self.bld.env))
+ libpath = self.link_task.outputs[0].abspath(self.env)
+
+ # calculat the link target and put it in the environment
+ soext=""
+ vnum = getattr(self, 'vnum', None)
+ if vnum is not None:
+ soext = '.' + vnum.split('.')[0]
+
+ link_target = getattr(self, 'link_name', '')
+ if link_target == '':
+ basename = os.path.basename(self.bld.make_libname(self.target, version=soext))
+ if getattr(self, "private_library", False):
+ link_target = '%s/private/%s' % (LIB_PATH, basename)
+ else:
+ link_target = '%s/%s' % (LIB_PATH, basename)
+
+ link_target = os.path.join(blddir, link_target)
+
+ if os.path.lexists(link_target):
+ if os.path.islink(link_target) and os.readlink(link_target) == libpath:
+ return
+ os.unlink(link_target)
+
+ link_container = os.path.dirname(link_target)
+ if not os.path.isdir(link_container):
+ os.makedirs(link_container)
+
+ os.symlink(libpath, link_target)
+
+
+@feature('symlink_bin')
+@after('apply_link')
+def symlink_bin(self):
+ '''symlink a binary into the build directory'''
+
+ if self.target.endswith('.inst'):
+ return
+
+ blddir = os.path.dirname(self.bld.srcnode.abspath(self.bld.env))
+ if not self.link_task.outputs or not self.link_task.outputs[0]:
+ raise Utils.WafError('no outputs found for %s in symlink_bin' % self.name)
+ binpath = self.link_task.outputs[0].abspath(self.env)
+ bldpath = os.path.join(self.bld.env.BUILD_DIRECTORY, self.link_task.outputs[0].name)
+
+ if os.path.lexists(bldpath):
+ if os.path.islink(bldpath) and os.readlink(bldpath) == binpath:
+ return
+ os.unlink(bldpath)
+ os.symlink(binpath, bldpath)
diff --git a/buildtools/wafsamba/samba_optimisation.py b/buildtools/wafsamba/samba_optimisation.py
new file mode 100644
index 0000000000..951fd4c1f6
--- /dev/null
+++ b/buildtools/wafsamba/samba_optimisation.py
@@ -0,0 +1,165 @@
+# This file contains waf optimisations for Samba
+
+# most of these optimisations are possible because of the restricted build environment
+# that Samba has. For example, Samba doesn't attempt to cope with Win32 paths during the
+# build, and Samba doesn't need build varients
+
+# overall this makes some build tasks quite a bit faster
+
+from TaskGen import feature, after
+import preproc, Task
+
+@feature('cc', 'cxx')
+@after('apply_type_vars', 'apply_lib_vars', 'apply_core')
+def apply_incpaths(self):
+ lst = []
+
+ try:
+ kak = self.bld.kak
+ except AttributeError:
+ kak = self.bld.kak = {}
+
+ # TODO move the uselib processing out of here
+ for lib in self.to_list(self.uselib):
+ for path in self.env['CPPPATH_' + lib]:
+ if not path in lst:
+ lst.append(path)
+ if preproc.go_absolute:
+ for path in preproc.standard_includes:
+ if not path in lst:
+ lst.append(path)
+
+ for path in self.to_list(self.includes):
+ if not path in lst:
+ if preproc.go_absolute or path[0] != '/': #os.path.isabs(path):
+ lst.append(path)
+ else:
+ self.env.prepend_value('CPPPATH', path)
+
+ for path in lst:
+ node = None
+ if path[0] == '/': # os.path.isabs(path):
+ if preproc.go_absolute:
+ node = self.bld.root.find_dir(path)
+ elif path[0] == '#':
+ node = self.bld.srcnode
+ if len(path) > 1:
+ try:
+ node = kak[path]
+ except KeyError:
+ kak[path] = node = node.find_dir(path[1:])
+ else:
+ try:
+ node = kak[(self.path.id, path)]
+ except KeyError:
+ kak[(self.path.id, path)] = node = self.path.find_dir(path)
+
+ if node:
+ self.env.append_value('INC_PATHS', node)
+
+@feature('cc')
+@after('apply_incpaths')
+def apply_obj_vars_cc(self):
+ """after apply_incpaths for INC_PATHS"""
+ env = self.env
+ app = env.append_unique
+ cpppath_st = env['CPPPATH_ST']
+
+ lss = env['_CCINCFLAGS']
+
+ try:
+ cac = self.bld.cac
+ except AttributeError:
+ cac = self.bld.cac = {}
+
+ # local flags come first
+ # set the user-defined includes paths
+ for i in env['INC_PATHS']:
+
+ try:
+ lss.extend(cac[i.id])
+ except KeyError:
+
+ cac[i.id] = [cpppath_st % i.bldpath(env), cpppath_st % i.srcpath(env)]
+ lss.extend(cac[i.id])
+
+ env['_CCINCFLAGS'] = lss
+ # set the library include paths
+ for i in env['CPPPATH']:
+ app('_CCINCFLAGS', cpppath_st % i)
+
+import Node, Environment
+
+def vari(self):
+ return "default"
+Environment.Environment.variant = vari
+
+def variant(self, env):
+ if not env: return 0
+ elif self.id & 3 == Node.FILE: return 0
+ else: return "default"
+Node.Node.variant = variant
+
+
+import TaskGen, Task
+
+def create_task(self, name, src=None, tgt=None):
+ task = Task.TaskBase.classes[name](self.env, generator=self)
+ if src:
+ task.set_inputs(src)
+ if tgt:
+ task.set_outputs(tgt)
+ return task
+TaskGen.task_gen.create_task = create_task
+
+def hash_constraints(self):
+ a = self.attr
+ sum = hash((str(a('before', '')),
+ str(a('after', '')),
+ str(a('ext_in', '')),
+ str(a('ext_out', '')),
+ self.__class__.maxjobs))
+ return sum
+Task.TaskBase.hash_constraints = hash_constraints
+
+
+# import cc
+# from TaskGen import extension
+# import Utils
+
+# @extension(cc.EXT_CC)
+# def c_hook(self, node):
+# task = self.create_task('cc', node, node.change_ext('.o'))
+# try:
+# self.compiled_tasks.append(task)
+# except AttributeError:
+# raise Utils.WafError('Have you forgotten to set the feature "cc" on %s?' % str(self))
+
+# bld = self.bld
+# try:
+# dc = bld.dc
+# except AttributeError:
+# dc = bld.dc = {}
+
+# if task.outputs[0].id in dc:
+# raise Utils.WafError('Samba, you are doing it wrong %r %s %s' % (task.outputs, task.generator, dc[task.outputs[0].id].generator))
+# else:
+# dc[task.outputs[0].id] = task
+
+# return task
+
+
+def suncc_wrap(cls):
+ '''work around a problem with cc on solaris not handling module aliases
+ which have empty libs'''
+ if getattr(cls, 'solaris_wrap', False):
+ return
+ cls.solaris_wrap = True
+ oldrun = cls.run
+ def run(self):
+ if self.env.CC_NAME == "sun" and not self.inputs:
+ self.env = self.env.copy()
+ self.env.append_value('LINKFLAGS', '-')
+ return oldrun(self)
+ cls.run = run
+suncc_wrap(Task.TaskBase.classes['cc_link'])
diff --git a/buildtools/wafsamba/samba_patterns.py b/buildtools/wafsamba/samba_patterns.py
new file mode 100644
index 0000000000..37ef4198a6
--- /dev/null
+++ b/buildtools/wafsamba/samba_patterns.py
@@ -0,0 +1,29 @@
+# a waf tool to add extension based build patterns for Samba
+
+import Task
+from TaskGen import extension
+from samba_utils import *
+from wafsamba import samba_version_file
+
+def write_version_header(task):
+ '''print version.h contents'''
+ src = task.inputs[0].srcpath(task.env)
+ tgt = task.outputs[0].bldpath(task.env)
+
+ version = samba_version_file(src, task.env.srcdir, env=task.env)
+ string = str(version)
+
+ f = open(tgt, 'w')
+ s = f.write(string)
+ f.close()
+ return 0
+
+
+def SAMBA_MKVERSION(bld, target):
+ '''generate the version.h header for Samba'''
+ t = bld.SAMBA_GENERATOR('VERSION',
+ rule=write_version_header,
+ source= 'VERSION',
+ target=target,
+ always=True)
+Build.BuildContext.SAMBA_MKVERSION = SAMBA_MKVERSION
diff --git a/buildtools/wafsamba/samba_pidl.py b/buildtools/wafsamba/samba_pidl.py
new file mode 100644
index 0000000000..f40066eb69
--- /dev/null
+++ b/buildtools/wafsamba/samba_pidl.py
@@ -0,0 +1,167 @@
+# waf build tool for building IDL files with pidl
+
+from TaskGen import before
+import Build, os, sys, Logs
+from samba_utils import *
+
+def SAMBA_PIDL(bld, pname, source,
+ options='',
+ output_dir='.',
+ symlink=False,
+ generate_tables=True):
+ '''Build a IDL file using pidl.
+ This will produce up to 13 output files depending on the options used'''
+
+ bname = source[0:-4]; # strip off the .idl suffix
+ bname = os.path.basename(bname)
+ name = "%s_%s" % (pname, bname.upper())
+
+ if not SET_TARGET_TYPE(bld, name, 'PIDL'):
+ return
+
+ bld.SET_BUILD_GROUP('build_source')
+
+ # the output files depend on the options used. Use this dictionary
+ # to map between the options and the resulting file names
+ options_map = { '--header' : '%s.h',
+ '--ndr-parser' : 'ndr_%s.c ndr_%s.h',
+ '--samba3-ndr-server' : 'srv_%s.c srv_%s.h',
+ '--samba3-ndr-client' : 'cli_%s.c cli_%s.h',
+ '--server' : 'ndr_%s_s.c',
+ '--client' : 'ndr_%s_c.c ndr_%s_c.h',
+ '--python' : 'py_%s.c',
+ '--tdr-parser' : 'tdr_%s.c tdr_%s.h',
+ '--dcom-proxy' : '%s_p.c',
+ '--com-header' : 'com_%s.h'
+ }
+
+ table_header_idx = None
+ out_files = []
+ options_list = TO_LIST(options)
+
+ for o in options_list:
+ if o in options_map:
+ ofiles = TO_LIST(options_map[o])
+ for f in ofiles:
+ out_files.append(os.path.join(output_dir, f % bname))
+ if f == 'ndr_%s.h':
+ # remember this one for the tables generation
+ table_header_idx = len(out_files) - 1
+
+ # depend on the full pidl sources
+ source = TO_LIST(source)
+ try:
+ pidl_src_nodes = bld.pidl_files_cache
+ except AttributeError:
+ bld.pidl_files_cache = bld.srcnode.ant_glob('pidl/lib/Parse/**/*.pm', flat=False)
+ bld.pidl_files_cache.extend(bld.srcnode.ant_glob('pidl', flat=False))
+ pidl_src_nodes = bld.pidl_files_cache
+
+ # the cd .. is needed because pidl currently is sensitive to the directory it is run in
+ cpp = ""
+ cc = ""
+ if bld.CONFIG_SET("CPP"):
+ if isinstance(bld.CONFIG_GET("CPP"), list):
+ cpp = 'CPP="%s"' % bld.CONFIG_GET("CPP")[0]
+ else:
+ cpp = 'CPP="%s"' % bld.CONFIG_GET("CPP")
+
+ if cpp == "CPP=xlc_r":
+ cpp = ""
+
+
+ if bld.CONFIG_SET("CC"):
+ if isinstance(bld.CONFIG_GET("CC"), list):
+ cc = 'CC="%s"' % bld.CONFIG_GET("CC")[0]
+ else:
+ cc = 'CC="%s"' % bld.CONFIG_GET("CC")
+
+ t = bld(rule='cd .. && %s %s ${PERL} "${PIDL}" --quiet ${OPTIONS} --outputdir ${OUTPUTDIR} -- "${SRC[0].abspath(env)}"' % (cpp, cc),
+ ext_out = '.c',
+ before = 'cc',
+ on_results = True,
+ shell = True,
+ source = source,
+ target = out_files,
+ name = name,
+ samba_type = 'PIDL')
+
+ # prime the list of nodes we are dependent on with the cached pidl sources
+ t.allnodes = pidl_src_nodes
+
+ t.env.PIDL = os.path.join(bld.srcnode.abspath(), 'pidl/pidl')
+ t.env.OPTIONS = TO_LIST(options)
+
+ # this rather convoluted set of path calculations is to cope with the possibility
+ # that gen_ndr is a symlink into the source tree. By doing this for the source3
+ # gen_ndr directory we end up generating identical output in gen_ndr for the old
+ # build system and the new one. That makes keeping things in sync much easier.
+ # eventually we should drop the gen_ndr files in git, but in the meanwhile this works
+
+ found_dir = bld.path.find_dir(output_dir)
+ if not 'abspath' in dir(found_dir):
+ Logs.error('Unable to find pidl output directory %s' %
+ os.path.normpath(os.path.join(bld.curdir, output_dir)))
+ sys.exit(1)
+
+ outdir = bld.path.find_dir(output_dir).abspath(t.env)
+
+ if symlink and not os.path.lexists(outdir):
+ link_source = os.path.normpath(os.path.join(bld.curdir,output_dir))
+ os.symlink(link_source, outdir)
+
+ real_outputdir = os.path.realpath(outdir)
+ t.env.OUTPUTDIR = os_path_relpath(real_outputdir, os.path.dirname(bld.env.BUILD_DIRECTORY))
+
+ if generate_tables and table_header_idx is not None:
+ pidl_headers = LOCAL_CACHE(bld, 'PIDL_HEADERS')
+ pidl_headers[name] = [bld.path.find_or_declare(out_files[table_header_idx])]
+
+ t.more_includes = '#' + bld.path.relpath_gen(bld.srcnode)
+Build.BuildContext.SAMBA_PIDL = SAMBA_PIDL
+
+
+def SAMBA_PIDL_LIST(bld, name, source,
+ options='',
+ output_dir='.',
+ symlink=False,
+ generate_tables=True):
+ '''A wrapper for building a set of IDL files'''
+ for p in TO_LIST(source):
+ bld.SAMBA_PIDL(name, p, options=options, output_dir=output_dir, symlink=symlink, generate_tables=generate_tables)
+Build.BuildContext.SAMBA_PIDL_LIST = SAMBA_PIDL_LIST
+
+
+#################################################################
+# the rule for generating the NDR tables
+from TaskGen import feature, before
+@feature('collect')
+@before('exec_rule')
+def collect(self):
+ pidl_headers = LOCAL_CACHE(self.bld, 'PIDL_HEADERS')
+ for (name, hd) in pidl_headers.items():
+ y = self.bld.name_to_obj(name, self.env)
+ self.bld.ASSERT(y is not None, 'Failed to find PIDL header %s' % name)
+ y.post()
+ for node in hd:
+ self.bld.ASSERT(node is not None, 'Got None as build node generating PIDL table for %s' % name)
+ self.source += " " + node.relpath_gen(self.path)
+
+
+def SAMBA_PIDL_TABLES(bld, name, target):
+ '''generate the pidl NDR tables file'''
+ headers = bld.env.PIDL_HEADERS
+ bld.SET_BUILD_GROUP('main')
+ t = bld(
+ features = 'collect',
+ rule = '${PERL} ${SRC} --output ${TGT} | sed "s|default/||" > ${TGT}',
+ ext_out = '.c',
+ before = 'cc',
+ on_results = True,
+ shell = True,
+ source = '../../librpc/tables.pl',
+ target = target,
+ name = name)
+ t.env.LIBRPC = os.path.join(bld.srcnode.abspath(), 'librpc')
+Build.BuildContext.SAMBA_PIDL_TABLES = SAMBA_PIDL_TABLES
+
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
new file mode 100644
index 0000000000..e9afa939a3
--- /dev/null
+++ b/buildtools/wafsamba/samba_python.py
@@ -0,0 +1,69 @@
+# waf build tool for building IDL files with pidl
+
+import Build
+from samba_utils import *
+from samba_autoconf import *
+
+from Configure import conf
+@conf
+def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
+ if conf.env["python_headers_checked"] == []:
+ conf.check_python_headers(mandatory)
+ conf.env["python_headers_checked"] = "yes"
+ else:
+ conf.msg("python headers", "using cache")
+
+
+def SAMBA_PYTHON(bld, name,
+ source='',
+ deps='',
+ public_deps='',
+ realname=None,
+ cflags='',
+ includes='',
+ init_function_sentinal=None,
+ local_include=True,
+ vars=None,
+ enabled=True):
+ '''build a python extension for Samba'''
+
+ # when we support static python modules we'll need to gather
+ # the list from all the SAMBA_PYTHON() targets
+ if init_function_sentinal is not None:
+ cflags += '-DSTATIC_LIBPYTHON_MODULES=%s' % init_function_sentinal
+
+ source = bld.EXPAND_VARIABLES(source, vars=vars)
+
+ if realname is None:
+ # a SAMBA_PYTHON target without a realname is just a
+ # library with pyembed=True
+ bld.SAMBA_LIBRARY(name,
+ source=source,
+ deps=deps,
+ public_deps=public_deps,
+ includes=includes,
+ cflags=cflags,
+ local_include=local_include,
+ vars=vars,
+ pyembed=True,
+ enabled=enabled)
+ return
+
+ link_name = 'python/%s' % realname
+
+ bld.SAMBA_LIBRARY(name,
+ source=source,
+ deps=deps,
+ public_deps=public_deps,
+ includes=includes,
+ cflags=cflags,
+ realname=realname,
+ local_include=local_include,
+ vars=vars,
+ link_name=link_name,
+ pyembed=True,
+ target_type='PYTHON',
+ install_path='${PYTHONARCHDIR}',
+ enabled=enabled)
+
+Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
new file mode 100644
index 0000000000..3adf533b0e
--- /dev/null
+++ b/buildtools/wafsamba/samba_utils.py
@@ -0,0 +1,620 @@
+# a waf tool to add autoconf-like macros to the configure section
+# and for SAMBA_ macros for building libraries, binaries etc
+
+import Build, os, sys, Options, Utils, Task, re, fnmatch, Logs
+from TaskGen import feature, before
+from Configure import conf
+from Logs import debug
+import shlex
+
+# TODO: make this a --option
+LIB_PATH="shared"
+
+
+# sigh, python octal constants are a mess
+MODE_644 = int('644', 8)
+MODE_755 = int('755', 8)
+
+@conf
+def SET_TARGET_TYPE(ctx, target, value):
+ '''set the target type of a target'''
+ cache = LOCAL_CACHE(ctx, 'TARGET_TYPE')
+ if target in cache and cache[target] != 'EMPTY':
+ Logs.error("ERROR: Target '%s' in directory %s re-defined as %s - was %s" % (target, ctx.curdir, value, cache[target]))
+ sys.exit(1)
+ LOCAL_CACHE_SET(ctx, 'TARGET_TYPE', target, value)
+ debug("task_gen: Target '%s' created of type '%s' in %s" % (target, value, ctx.curdir))
+ return True
+
+
+def GET_TARGET_TYPE(ctx, target):
+ '''get target type from cache'''
+ cache = LOCAL_CACHE(ctx, 'TARGET_TYPE')
+ if not target in cache:
+ return None
+ return cache[target]
+
+
+######################################################
+# this is used as a decorator to make functions only
+# run once. Based on the idea from
+# http://stackoverflow.com/questions/815110/is-there-a-decorator-to-simply-cache-function-return-values
+runonce_ret = {}
+def runonce(function):
+ def runonce_wrapper(*args):
+ if args in runonce_ret:
+ return runonce_ret[args]
+ else:
+ ret = function(*args)
+ runonce_ret[args] = ret
+ return ret
+ return runonce_wrapper
+
+
+def ADD_LD_LIBRARY_PATH(path):
+ '''add something to LD_LIBRARY_PATH'''
+ if 'LD_LIBRARY_PATH' in os.environ:
+ oldpath = os.environ['LD_LIBRARY_PATH']
+ else:
+ oldpath = ''
+ newpath = oldpath.split(':')
+ if not path in newpath:
+ newpath.append(path)
+ os.environ['LD_LIBRARY_PATH'] = ':'.join(newpath)
+
+
+def needs_private_lib(bld, target):
+ '''return True if a target links to a private library'''
+ for lib in getattr(target, "uselib_local", []):
+ t = bld.name_to_obj(lib, bld.env)
+ if t and getattr(t, 'private_library', False):
+ return True
+ return False
+
+
+def install_rpath(target):
+ '''the rpath value for installation'''
+ bld = target.bld
+ bld.env['RPATH'] = []
+ ret = set()
+ if bld.env.RPATH_ON_INSTALL:
+ ret.add(bld.EXPAND_VARIABLES(bld.env.LIBDIR))
+ if bld.env.RPATH_ON_INSTALL_PRIVATE and needs_private_lib(bld, target):
+ ret.add(bld.EXPAND_VARIABLES(bld.env.PRIVATELIBDIR))
+ return list(ret)
+
+
+def build_rpath(bld):
+ '''the rpath value for build'''
+ rpaths = [os.path.normpath('%s/%s' % (bld.env.BUILD_DIRECTORY, d)) for d in ("shared", "shared/private")]
+ bld.env['RPATH'] = []
+ if bld.env.RPATH_ON_BUILD:
+ return rpaths
+ for rpath in rpaths:
+ ADD_LD_LIBRARY_PATH(rpath)
+ return []
+
+
+@conf
+def LOCAL_CACHE(ctx, name):
+ '''return a named build cache dictionary, used to store
+ state inside other functions'''
+ if name in ctx.env:
+ return ctx.env[name]
+ ctx.env[name] = {}
+ return ctx.env[name]
+
+
+@conf
+def LOCAL_CACHE_SET(ctx, cachename, key, value):
+ '''set a value in a local cache'''
+ cache = LOCAL_CACHE(ctx, cachename)
+ cache[key] = value
+
+
+@conf
+def ASSERT(ctx, expression, msg):
+ '''a build assert call'''
+ if not expression:
+ raise Utils.WafError("ERROR: %s\n" % msg)
+Build.BuildContext.ASSERT = ASSERT
+
+
+def SUBDIR(bld, subdir, list):
+ '''create a list of files by pre-pending each with a subdir name'''
+ ret = ''
+ for l in TO_LIST(list):
+ ret = ret + os.path.normpath(os.path.join(subdir, l)) + ' '
+ return ret
+Build.BuildContext.SUBDIR = SUBDIR
+
+
+def dict_concat(d1, d2):
+ '''concatenate two dictionaries d1 += d2'''
+ for t in d2:
+ if t not in d1:
+ d1[t] = d2[t]
+
+
+def exec_command(self, cmd, **kw):
+ '''this overrides the 'waf -v' debug output to be in a nice
+ unix like format instead of a python list.
+ Thanks to ita on #waf for this'''
+ import Utils, Logs
+ _cmd = cmd
+ if isinstance(cmd, list):
+ _cmd = ' '.join(cmd)
+ debug('runner: %s' % _cmd)
+ if self.log:
+ self.log.write('%s\n' % cmd)
+ kw['log'] = self.log
+ try:
+ if not kw.get('cwd', None):
+ kw['cwd'] = self.cwd
+ except AttributeError:
+ self.cwd = kw['cwd'] = self.bldnode.abspath()
+ return Utils.exec_command(cmd, **kw)
+Build.BuildContext.exec_command = exec_command
+
+
+def ADD_COMMAND(opt, name, function):
+ '''add a new top level command to waf'''
+ Utils.g_module.__dict__[name] = function
+ opt.name = function
+Options.Handler.ADD_COMMAND = ADD_COMMAND
+
+
+@feature('cc', 'cshlib', 'cprogram')
+@before('apply_core','exec_rule')
+def process_depends_on(self):
+ '''The new depends_on attribute for build rules
+ allow us to specify a dependency on output from
+ a source generation rule'''
+ if getattr(self , 'depends_on', None):
+ lst = self.to_list(self.depends_on)
+ for x in lst:
+ y = self.bld.name_to_obj(x, self.env)
+ self.bld.ASSERT(y is not None, "Failed to find dependency %s of %s" % (x, self.name))
+ y.post()
+ if getattr(y, 'more_includes', None):
+ self.includes += " " + y.more_includes
+
+
+os_path_relpath = getattr(os.path, 'relpath', None)
+if os_path_relpath is None:
+ # Python < 2.6 does not have os.path.relpath, provide a replacement
+ # (imported from Python2.6.5~rc2)
+ def os_path_relpath(path, start):
+ """Return a relative version of a path"""
+ start_list = os.path.abspath(start).split("/")
+ path_list = os.path.abspath(path).split("/")
+
+ # Work out how much of the filepath is shared by start and path.
+ i = len(os.path.commonprefix([start_list, path_list]))
+
+ rel_list = ['..'] * (len(start_list)-i) + path_list[i:]
+ if not rel_list:
+ return start
+ return os.path.join(*rel_list)
+
+
+def unique_list(seq):
+ '''return a uniquified list in the same order as the existing list'''
+ seen = {}
+ result = []
+ for item in seq:
+ if item in seen: continue
+ seen[item] = True
+ result.append(item)
+ return result
+
+
+def TO_LIST(str, delimiter=None):
+ '''Split a list, preserving quoted strings and existing lists'''
+ if str is None:
+ return []
+ if isinstance(str, list):
+ return str
+ lst = str.split(delimiter)
+ # the string may have had quotes in it, now we
+ # check if we did have quotes, and use the slower shlex
+ # if we need to
+ for e in lst:
+ if e[0] == '"':
+ return shlex.split(str)
+ return lst
+
+
+def subst_vars_error(string, env):
+ '''substitute vars, throw an error if a variable is not defined'''
+ lst = re.split('(\$\{\w+\})', string)
+ out = []
+ for v in lst:
+ if re.match('\$\{\w+\}', v):
+ vname = v[2:-1]
+ if not vname in env:
+ Logs.error("Failed to find variable %s in %s" % (vname, string))
+ sys.exit(1)
+ v = env[vname]
+ out.append(v)
+ return ''.join(out)
+
+
+@conf
+def SUBST_ENV_VAR(ctx, varname):
+ '''Substitute an environment variable for any embedded variables'''
+ return subst_vars_error(ctx.env[varname], ctx.env)
+Build.BuildContext.SUBST_ENV_VAR = SUBST_ENV_VAR
+
+
+def ENFORCE_GROUP_ORDERING(bld):
+ '''enforce group ordering for the project. This
+ makes the group ordering apply only when you specify
+ a target with --target'''
+ if Options.options.compile_targets:
+ @feature('*')
+ @before('exec_rule', 'apply_core', 'collect')
+ def force_previous_groups(self):
+ if getattr(self.bld, 'enforced_group_ordering', False) == True:
+ return
+ self.bld.enforced_group_ordering = True
+
+ def group_name(g):
+ tm = self.bld.task_manager
+ return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
+
+ my_id = id(self)
+ bld = self.bld
+ stop = None
+ for g in bld.task_manager.groups:
+ for t in g.tasks_gen:
+ if id(t) == my_id:
+ stop = id(g)
+ debug('group: Forcing up to group %s for target %s',
+ group_name(g), self.name or self.target)
+ break
+ if stop != None:
+ break
+ if stop is None:
+ return
+
+ for i in xrange(len(bld.task_manager.groups)):
+ g = bld.task_manager.groups[i]
+ bld.task_manager.current_group = i
+ if id(g) == stop:
+ break
+ debug('group: Forcing group %s', group_name(g))
+ for t in g.tasks_gen:
+ if not getattr(t, 'forced_groups', False):
+ debug('group: Posting %s', t.name or t.target)
+ t.forced_groups = True
+ t.post()
+Build.BuildContext.ENFORCE_GROUP_ORDERING = ENFORCE_GROUP_ORDERING
+
+
+def recursive_dirlist(dir, relbase, pattern=None):
+ '''recursive directory list'''
+ ret = []
+ for f in os.listdir(dir):
+ f2 = dir + '/' + f
+ if os.path.isdir(f2):
+ ret.extend(recursive_dirlist(f2, relbase))
+ else:
+ if pattern and not fnmatch.fnmatch(f, pattern):
+ continue
+ ret.append(os_path_relpath(f2, relbase))
+ return ret
+
+
+def mkdir_p(dir):
+ '''like mkdir -p'''
+ if not dir:
+ return
+ if dir.endswith("/"):
+ mkdir_p(dir[:-1])
+ return
+ if os.path.isdir(dir):
+ return
+ mkdir_p(os.path.dirname(dir))
+ os.mkdir(dir)
+
+
+def SUBST_VARS_RECURSIVE(string, env):
+ '''recursively expand variables'''
+ if string is None:
+ return string
+ limit=100
+ while (string.find('${') != -1 and limit > 0):
+ string = subst_vars_error(string, env)
+ limit -= 1
+ return string
+
+
+@conf
+def EXPAND_VARIABLES(ctx, varstr, vars=None):
+ '''expand variables from a user supplied dictionary
+
+ This is most useful when you pass vars=locals() to expand
+ all your local variables in strings
+ '''
+
+ if isinstance(varstr, list):
+ ret = []
+ for s in varstr:
+ ret.append(EXPAND_VARIABLES(ctx, s, vars=vars))
+ return ret
+
+ if not isinstance(varstr, str):
+ return varstr
+
+ import Environment
+ env = Environment.Environment()
+ ret = varstr
+ # substitute on user supplied dict if avaiilable
+ if vars is not None:
+ for v in vars.keys():
+ env[v] = vars[v]
+ ret = SUBST_VARS_RECURSIVE(ret, env)
+
+ # if anything left, subst on the environment as well
+ if ret.find('${') != -1:
+ ret = SUBST_VARS_RECURSIVE(ret, ctx.env)
+ # make sure there is nothing left. Also check for the common
+ # typo of $( instead of ${
+ if ret.find('${') != -1 or ret.find('$(') != -1:
+ Logs.error('Failed to substitute all variables in varstr=%s' % ret)
+ sys.exit(1)
+ return ret
+Build.BuildContext.EXPAND_VARIABLES = EXPAND_VARIABLES
+
+
+def RUN_COMMAND(cmd,
+ env=None,
+ shell=False):
+ '''run a external command, return exit code or signal'''
+ if env:
+ cmd = SUBST_VARS_RECURSIVE(cmd, env)
+
+ status = os.system(cmd)
+ if os.WIFEXITED(status):
+ return os.WEXITSTATUS(status)
+ if os.WIFSIGNALED(status):
+ return - os.WTERMSIG(status)
+ Logs.error("Unknown exit reason %d for command: %s" (status, cmd))
+ return -1
+
+
+# make sure we have md5. some systems don't have it
+try:
+ from hashlib import md5
+except:
+ try:
+ import md5
+ except:
+ import Constants
+ Constants.SIG_NIL = hash('abcd')
+ class replace_md5(object):
+ def __init__(self):
+ self.val = None
+ def update(self, val):
+ self.val = hash((self.val, val))
+ def digest(self):
+ return str(self.val)
+ def hexdigest(self):
+ return self.digest().encode('hex')
+ def replace_h_file(filename):
+ f = open(filename, 'rb')
+ m = replace_md5()
+ while (filename):
+ filename = f.read(100000)
+ m.update(filename)
+ f.close()
+ return m.digest()
+ Utils.md5 = replace_md5
+ Task.md5 = replace_md5
+ Utils.h_file = replace_h_file
+
+
+def LOAD_ENVIRONMENT():
+ '''load the configuration environment, allowing access to env vars
+ from new commands'''
+ import Environment
+ env = Environment.Environment()
+ try:
+ env.load('.lock-wscript')
+ env.load(env.blddir + '/c4che/default.cache.py')
+ except:
+ pass
+ return env
+
+
+def IS_NEWER(bld, file1, file2):
+ '''return True if file1 is newer than file2'''
+ t1 = os.stat(os.path.join(bld.curdir, file1)).st_mtime
+ t2 = os.stat(os.path.join(bld.curdir, file2)).st_mtime
+ return t1 > t2
+Build.BuildContext.IS_NEWER = IS_NEWER
+
+
+@conf
+def RECURSE(ctx, directory):
+ '''recurse into a directory, relative to the curdir or top level'''
+ try:
+ visited_dirs = ctx.visited_dirs
+ except:
+ visited_dirs = ctx.visited_dirs = set()
+ d = os.path.join(ctx.curdir, directory)
+ if os.path.exists(d):
+ abspath = os.path.abspath(d)
+ else:
+ abspath = os.path.abspath(os.path.join(Utils.g_module.srcdir, directory))
+ ctxclass = ctx.__class__.__name__
+ key = ctxclass + ':' + abspath
+ if key in visited_dirs:
+ # already done it
+ return
+ visited_dirs.add(key)
+ relpath = os_path_relpath(abspath, ctx.curdir)
+ if ctxclass == 'Handler':
+ return ctx.sub_options(relpath)
+ if ctxclass == 'ConfigurationContext':
+ return ctx.sub_config(relpath)
+ if ctxclass == 'BuildContext':
+ return ctx.add_subdirs(relpath)
+ Logs.error('Unknown RECURSE context class', ctxclass)
+ raise
+Options.Handler.RECURSE = RECURSE
+Build.BuildContext.RECURSE = RECURSE
+
+
+def CHECK_MAKEFLAGS(bld):
+ '''check for MAKEFLAGS environment variable in case we are being
+ called from a Makefile try to honor a few make command line flags'''
+ if not 'WAF_MAKE' in os.environ:
+ return
+ makeflags = os.environ.get('MAKEFLAGS')
+ if makeflags is None:
+ return
+ jobs_set = False
+ # we need to use shlex.split to cope with the escaping of spaces
+ # in makeflags
+ for opt in shlex.split(makeflags):
+ # options can come either as -x or as x
+ if opt[0:2] == 'V=':
+ Options.options.verbose = Logs.verbose = int(opt[2:])
+ if Logs.verbose > 0:
+ Logs.zones = ['runner']
+ if Logs.verbose > 2:
+ Logs.zones = ['*']
+ elif opt[0].isupper() and opt.find('=') != -1:
+ loc = opt.find('=')
+ setattr(Options.options, opt[0:loc], opt[loc+1:])
+ elif opt[0] != '-':
+ for v in opt:
+ if v == 'j':
+ jobs_set = True
+ elif v == 'k':
+ Options.options.keep = True
+ elif opt == '-j':
+ jobs_set = True
+ elif opt == '-k':
+ Options.options.keep = True
+ if not jobs_set:
+ # default to one job
+ Options.options.jobs = 1
+
+Build.BuildContext.CHECK_MAKEFLAGS = CHECK_MAKEFLAGS
+
+option_groups = {}
+
+def option_group(opt, name):
+ '''find or create an option group'''
+ global option_groups
+ if name in option_groups:
+ return option_groups[name]
+ gr = opt.add_option_group(name)
+ option_groups[name] = gr
+ return gr
+Options.Handler.option_group = option_group
+
+
+def save_file(filename, contents, create_dir=False):
+ '''save data to a file'''
+ if create_dir:
+ mkdir_p(os.path.dirname(filename))
+ try:
+ f = open(filename, 'w')
+ f.write(contents)
+ f.close()
+ except:
+ return False
+ return True
+
+
+def load_file(filename):
+ '''return contents of a file'''
+ try:
+ f = open(filename, 'r')
+ r = f.read()
+ f.close()
+ except:
+ return None
+ return r
+
+
+def reconfigure(ctx):
+ '''rerun configure if necessary'''
+ import Configure, samba_wildcard, Scripting
+ if not os.path.exists(".lock-wscript"):
+ raise Utils.WafError('configure has not been run')
+ bld = samba_wildcard.fake_build_environment()
+ Configure.autoconfig = True
+ Scripting.check_configured(bld)
+
+
+def map_shlib_extension(ctx, name, python=False):
+ '''map a filename with a shared library extension of .so to the real shlib name'''
+ if name is None:
+ return None
+ if name[-1:].isdigit():
+ # some libraries have specified versions in the wscript rule
+ return name
+ (root1, ext1) = os.path.splitext(name)
+ if python:
+ (root2, ext2) = os.path.splitext(ctx.env.pyext_PATTERN)
+ else:
+ (root2, ext2) = os.path.splitext(ctx.env.shlib_PATTERN)
+ return root1+ext2
+Build.BuildContext.map_shlib_extension = map_shlib_extension
+
+def apply_pattern(filename, pattern):
+ '''apply a filename pattern to a filename that may have a directory component'''
+ dirname = os.path.dirname(filename)
+ if not dirname:
+ return pattern % filename
+ basename = os.path.basename(filename)
+ return os.path.join(dirname, pattern % basename)
+
+def make_libname(ctx, name, nolibprefix=False, version=None, python=False):
+ """make a library filename
+ Options:
+ nolibprefix: don't include the lib prefix
+ version : add a version number
+ python : if we should use python module name conventions"""
+
+ if python:
+ libname = apply_pattern(name, ctx.env.pyext_PATTERN)
+ else:
+ libname = apply_pattern(name, ctx.env.shlib_PATTERN)
+ if nolibprefix and libname[0:3] == 'lib':
+ libname = libname[3:]
+ if version:
+ if version[0] == '.':
+ version = version[1:]
+ (root, ext) = os.path.splitext(libname)
+ if ext == ".dylib":
+ # special case - version goes before the prefix
+ libname = "%s.%s%s" % (root, version, ext)
+ else:
+ libname = "%s%s.%s" % (root, ext, version)
+ return libname
+Build.BuildContext.make_libname = make_libname
+
+
+def get_tgt_list(bld):
+ '''return a list of build objects for samba'''
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ # build a list of task generators we are interested in
+ tgt_list = []
+ for tgt in targets:
+ type = targets[tgt]
+ if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
+ continue
+ t = bld.name_to_obj(tgt, bld.env)
+ if t is None:
+ Logs.error("Target %s of type %s has no task generator" % (tgt, type))
+ sys.exit(1)
+ tgt_list.append(t)
+ return tgt_list
diff --git a/buildtools/wafsamba/samba_version.py b/buildtools/wafsamba/samba_version.py
new file mode 100644
index 0000000000..0b0c159f55
--- /dev/null
+++ b/buildtools/wafsamba/samba_version.py
@@ -0,0 +1,269 @@
+import os
+import Utils
+import samba_utils
+import sys
+
+def bzr_version_summary(path):
+ try:
+ import bzrlib
+ except ImportError:
+ return ("BZR-UNKNOWN", {})
+
+ import bzrlib.ui
+ bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
+ sys.stdin, sys.stdout, sys.stderr)
+ from bzrlib import branch, osutils, workingtree
+ from bzrlib.plugin import load_plugins
+ load_plugins()
+
+ b = branch.Branch.open(path)
+ (revno, revid) = b.last_revision_info()
+ rev = b.repository.get_revision(revid)
+
+ fields = {
+ "BZR_REVISION_ID": revid,
+ "BZR_REVNO": revno,
+ "COMMIT_DATE": osutils.format_date_with_offset_in_original_timezone(rev.timestamp,
+ rev.timezone or 0),
+ "COMMIT_TIME": int(rev.timestamp),
+ "BZR_BRANCH": rev.properties.get("branch-nick", ""),
+ }
+
+ # If possible, retrieve the git sha
+ try:
+ from bzrlib.plugins.git.object_store import get_object_store
+ except ImportError:
+ # No git plugin
+ ret = "BZR-%d" % revno
+ else:
+ store = get_object_store(b.repository)
+ full_rev = store._lookup_revision_sha1(revid)
+ fields["GIT_COMMIT_ABBREV"] = full_rev[:7]
+ fields["GIT_COMMIT_FULLREV"] = full_rev
+ ret = "GIT-" + fields["GIT_COMMIT_ABBREV"]
+
+ if workingtree.WorkingTree.open(path).has_changes():
+ fields["COMMIT_IS_CLEAN"] = 0
+ ret += "+"
+ else:
+ fields["COMMIT_IS_CLEAN"] = 1
+ return (ret, fields)
+
+
+def git_version_summary(path, env=None):
+ # Get version from GIT
+ if not 'GIT' in env and os.path.exists("/usr/bin/git"):
+ # this is useful when doing make dist without configuring
+ env.GIT = "/usr/bin/git"
+
+ if not 'GIT' in env:
+ return ("GIT-UNKNOWN", {})
+
+ environ = dict(os.environ)
+ environ["GIT_DIR"] = '%s/.git' % path
+ environ["GIT_WORK_TREE"] = path
+ git = Utils.cmd_output(env.GIT + ' show --pretty=format:"%h%n%ct%n%H%n%cd" --stat HEAD', silent=True, env=environ)
+
+ lines = git.splitlines()
+ if not lines or len(lines) < 4:
+ return ("GIT-UNKNOWN", {})
+
+ fields = {
+ "GIT_COMMIT_ABBREV": lines[0],
+ "GIT_COMMIT_FULLREV": lines[2],
+ "COMMIT_TIME": int(lines[1]),
+ "COMMIT_DATE": lines[3],
+ }
+
+ ret = "GIT-" + fields["GIT_COMMIT_ABBREV"]
+
+ if env.GIT_LOCAL_CHANGES:
+ clean = Utils.cmd_output('%s diff HEAD | wc -l' % env.GIT, silent=True).strip()
+ if clean == "0":
+ fields["COMMIT_IS_CLEAN"] = 1
+ else:
+ fields["COMMIT_IS_CLEAN"] = 0
+ ret += "+"
+
+ return (ret, fields)
+
+
+class SambaVersion(object):
+
+ def __init__(self, version_dict, path, env=None):
+ '''Determine the version number of samba
+
+See VERSION for the format. Entries on that file are
+also accepted as dictionary entries here
+ '''
+
+ self.MAJOR=None
+ self.MINOR=None
+ self.RELEASE=None
+ self.REVISION=None
+ self.TP_RELEASE=None
+ self.ALPHA_RELEASE=None
+ self.PRE_RELEASE=None
+ self.RC_RELEASE=None
+ self.IS_SNAPSHOT=True
+ self.RELEASE_NICKNAME=None
+ self.VENDOR_SUFFIX=None
+ self.VENDOR_PATCH=None
+
+ for a, b in version_dict.iteritems():
+ if a.startswith("SAMBA_VERSION_"):
+ setattr(self, a[14:], b)
+ else:
+ setattr(self, a, b)
+
+ if self.IS_GIT_SNAPSHOT == "yes":
+ self.IS_SNAPSHOT=True
+ elif self.IS_GIT_SNAPSHOT == "no":
+ self.IS_SNAPSHOT=False
+ else:
+ raise Exception("Unknown value for IS_GIT_SNAPSHOT: %s" % self.IS_GIT_SNAPSHOT)
+
+ ##
+ ## start with "3.0.22"
+ ##
+ self.MAJOR=int(self.MAJOR)
+ self.MINOR=int(self.MINOR)
+ self.RELEASE=int(self.RELEASE)
+
+ SAMBA_VERSION_STRING = ("%u.%u.%u" % (self.MAJOR, self.MINOR, self.RELEASE))
+
+##
+## maybe add "3.0.22a" or "4.0.0tp11" or "4.0.0alpha1" or "3.0.22pre1" or "3.0.22rc1"
+## We do not do pre or rc version on patch/letter releases
+##
+ if self.REVISION is not None:
+ SAMBA_VERSION_STRING += self.REVISION
+ if self.TP_RELEASE is not None:
+ self.TP_RELEASE = int(self.TP_RELEASE)
+ SAMBA_VERSION_STRING += "tp%u" % self.TP_RELEASE
+ if self.ALPHA_RELEASE is not None:
+ self.ALPHA_RELEASE = int(self.ALPHA_RELEASE)
+ SAMBA_VERSION_STRING += ("alpha%u" % self.ALPHA_RELEASE)
+ if self.PRE_RELEASE is not None:
+ self.PRE_RELEASE = int(self.PRE_RELEASE)
+ SAMBA_VERSION_STRING += ("pre%u" % self.PRE_RELEASE)
+ if self.RC_RELEASE is not None:
+ self.RC_RELEASE = int(self.RC_RELEASE)
+ SAMBA_VERSION_STRING += ("rc%u" % self.RC_RELEASE)
+
+ if self.IS_SNAPSHOT:
+ if os.path.exists(os.path.join(path, ".git")):
+ suffix, self.vcs_fields = git_version_summary(path, env=env)
+ elif os.path.exists(os.path.join(path, ".bzr")):
+ suffix, self.vcs_fields = bzr_version_summary(path)
+ else:
+ suffix = "UNKNOWN"
+ self.vcs_fields = {}
+ SAMBA_VERSION_STRING += "-" + suffix
+ else:
+ self.vcs_fields = {}
+
+ self.OFFICIAL_STRING = SAMBA_VERSION_STRING
+
+ if self.VENDOR_SUFFIX is not None:
+ SAMBA_VERSION_STRING += ("-" + self.VENDOR_SUFFIX)
+ self.VENDOR_SUFFIX = self.VENDOR_SUFFIX
+
+ if self.VENDOR_PATCH is not None:
+ SAMBA_VERSION_STRING += ("-" + self.VENDOR_PATCH)
+ self.VENDOR_PATCH = self.VENDOR_PATCH
+
+ self.STRING = SAMBA_VERSION_STRING
+
+ if self.RELEASE_NICKNAME is not None:
+ self.STRING_WITH_NICKNAME = "%s (%s)" % (self.STRING, self.RELEASE_NICKNAME)
+ else:
+ self.STRING_WITH_NICKNAME = self.STRING
+
+ def __str__(self):
+ string="/* Autogenerated by waf */\n"
+ string+="#define SAMBA_VERSION_MAJOR %u\n" % self.MAJOR
+ string+="#define SAMBA_VERSION_MINOR %u\n" % self.MINOR
+ string+="#define SAMBA_VERSION_RELEASE %u\n" % self.RELEASE
+ if self.REVISION is not None:
+ string+="#define SAMBA_VERSION_REVISION %u\n" % self.REVISION
+
+ if self.TP_RELEASE is not None:
+ string+="#define SAMBA_VERSION_TP_RELEASE %u\n" % self.TP_RELEASE
+
+ if self.ALPHA_RELEASE is not None:
+ string+="#define SAMBA_VERSION_ALPHA_RELEASE %u\n" % self.ALPHA_RELEASE
+
+ if self.PRE_RELEASE is not None:
+ string+="#define SAMBA_VERSION_PRE_RELEASE %u\n" % self.PRE_RELEASE
+
+ if self.RC_RELEASE is not None:
+ string+="#define SAMBA_VERSION_RC_RELEASE %u\n" % self.RC_RELEASE
+
+ for name in sorted(self.vcs_fields.keys()):
+ string+="#define SAMBA_VERSION_%s " % name
+ value = self.vcs_fields[name]
+ if isinstance(value, basestring):
+ string += "\"%s\"" % value
+ elif type(value) is int:
+ string += "%d" % value
+ else:
+ raise Exception("Unknown type for %s: %r" % (name, value))
+ string += "\n"
+
+ string+="#define SAMBA_VERSION_OFFICIAL_STRING \"" + self.OFFICIAL_STRING + "\"\n"
+
+ if self.VENDOR_SUFFIX is not None:
+ string+="#define SAMBA_VERSION_VENDOR_SUFFIX " + self.VENDOR_SUFFIX + "\n"
+ if self.VENDOR_PATCH is not None:
+ string+="#define SAMBA_VERSION_VENDOR_PATCH " + self.VENDOR_PATCH + "\n"
+
+ if self.RELEASE_NICKNAME is not None:
+ string+="#define SAMBA_VERSION_RELEASE_NICKNAME " + self.RELEASE_NICKNAME + "\n"
+
+ # We need to put this #ifdef in to the headers so that vendors can override the version with a function
+ string+='''
+#ifdef SAMBA_VERSION_VENDOR_FUNCTION
+# define SAMBA_VERSION_STRING SAMBA_VERSION_VENDOR_FUNCTION
+#else /* SAMBA_VERSION_VENDOR_FUNCTION */
+# define SAMBA_VERSION_STRING "''' + self.STRING_WITH_NICKNAME + '''"
+#endif
+'''
+ string+="/* Version for mkrelease.sh: \nSAMBA_VERSION_STRING=" + self.STRING_WITH_NICKNAME + "\n */\n"
+
+ return string
+
+
+def samba_version_file(version_file, path, env=None):
+ '''Parse the version information from a VERSION file'''
+
+ f = open(version_file, 'r')
+ version_dict = {}
+ for line in f:
+ line = line.strip()
+ if line == '':
+ continue
+ if line.startswith("#"):
+ continue
+ try:
+ split_line = line.split("=")
+ if split_line[1] != "":
+ value = split_line[1].strip('"')
+ version_dict[split_line[0]] = value
+ except:
+ print("Failed to parse line %s from %s" % (line, version_file))
+ raise
+
+ return SambaVersion(version_dict, path, env=env)
+
+
+
+def load_version(env=None):
+ '''load samba versions either from ./VERSION or git
+ return a version object for detailed breakdown'''
+ if not env:
+ env = samba_utils.LOAD_ENVIRONMENT()
+
+ version = samba_version_file("./VERSION", ".", env)
+ Utils.g_module.VERSION = version.STRING
+ return version
diff --git a/buildtools/wafsamba/samba_wildcard.py b/buildtools/wafsamba/samba_wildcard.py
new file mode 100644
index 0000000000..5bf12672a9
--- /dev/null
+++ b/buildtools/wafsamba/samba_wildcard.py
@@ -0,0 +1,128 @@
+#! /usr/bin/env python
+
+# based on playground/evil in the waf svn tree
+
+import os, datetime
+import Scripting, Utils, Options, Logs, Environment, fnmatch
+from Constants import *
+from samba_utils import *
+
+def run_task(t, k):
+ '''run a single build task'''
+ ret = t.run()
+ if ret:
+ raise Utils.WafError("Failed to build %s: %u" % (k, ret))
+
+
+def run_named_build_task(cmd):
+ '''run a named build task, matching the cmd name using fnmatch
+ wildcards against inputs and outputs of all build tasks'''
+ bld = fake_build_environment()
+ found = False
+ cwd_node = bld.root.find_dir(os.getcwd())
+ top_node = bld.root.find_dir(bld.srcnode.abspath())
+
+ cmd = os.path.normpath(cmd)
+
+ # cope with builds of bin/*/*
+ if os.path.islink(cmd):
+ cmd = os_path_relpath(os.readlink(cmd), os.getcwd())
+
+ if cmd[0:12] == "bin/default/":
+ cmd = cmd[12:]
+
+ for g in bld.task_manager.groups:
+ for attr in ['outputs', 'inputs']:
+ for t in g.tasks:
+ s = getattr(t, attr, [])
+ for k in s:
+ relpath1 = k.relpath_gen(cwd_node)
+ relpath2 = k.relpath_gen(top_node)
+ if (fnmatch.fnmatch(relpath1, cmd) or
+ fnmatch.fnmatch(relpath2, cmd)):
+ t.position = [0,0]
+ print(t.display())
+ run_task(t, k)
+ found = True
+
+
+ if not found:
+ raise Utils.WafError("Unable to find build target matching %s" % cmd)
+
+
+
+def wildcard_main(missing_cmd_fn):
+ '''this replaces main from Scripting, allowing us to override the
+ behaviour for unknown commands
+
+ If a unknown command is found, then missing_cmd_fn() is called with
+ the name of the requested command
+ '''
+ Scripting.commands = Options.arg_line[:]
+
+ while Scripting.commands:
+ x = Scripting.commands.pop(0)
+
+ ini = datetime.datetime.now()
+ if x == 'configure':
+ fun = Scripting.configure
+ elif x == 'build':
+ fun = Scripting.build
+ else:
+ fun = getattr(Utils.g_module, x, None)
+
+ # this is the new addition on top of main from Scripting.py
+ if not fun:
+ missing_cmd_fn(x)
+ break
+
+ ctx = getattr(Utils.g_module, x + '_context', Utils.Context)()
+
+ if x in ['init', 'shutdown', 'dist', 'distclean', 'distcheck']:
+ try:
+ fun(ctx)
+ except TypeError:
+ fun()
+ else:
+ fun(ctx)
+
+ ela = ''
+ if not Options.options.progress_bar:
+ ela = ' (%s)' % Utils.get_elapsed_time(ini)
+
+ if x != 'init' and x != 'shutdown':
+ Logs.info('%r finished successfully%s' % (x, ela))
+
+ if not Scripting.commands and x != 'shutdown':
+ Scripting.commands.append('shutdown')
+
+
+
+
+def fake_build_environment():
+ """create all the tasks for the project, but do not run the build
+ return the build context in use"""
+ bld = getattr(Utils.g_module, 'build_context', Utils.Context)()
+ bld = Scripting.check_configured(bld)
+
+ Options.commands['install'] = False
+ Options.commands['uninstall'] = False
+ Options.is_install = False
+
+ bld.is_install = 0 # False
+
+ try:
+ proj = Environment.Environment(Options.lockfile)
+ except IOError:
+ raise Utils.WafError("Project not configured (run 'waf configure' first)")
+
+ bld.load_dirs(proj[SRCDIR], proj[BLDDIR])
+ bld.load_envs()
+
+ Logs.info("Waf: Entering directory `%s'" % bld.bldnode.abspath())
+ bld.add_subdirs([os.path.split(Utils.g_module.root_path)[0]])
+
+ bld.pre_build()
+ bld.flush()
+ return bld
+
diff --git a/buildtools/wafsamba/stale_files.py b/buildtools/wafsamba/stale_files.py
new file mode 100644
index 0000000000..2b94f0823e
--- /dev/null
+++ b/buildtools/wafsamba/stale_files.py
@@ -0,0 +1,98 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2006-2010 (ita)
+
+"""
+Add a pre-build hook to remove all build files
+which do not have a corresponding target
+
+This can be used for example to remove the targets
+that have changed name without performing
+a full 'waf clean'
+
+Of course, it will only work if there are no dynamically generated
+nodes/tasks, in which case the method will have to be modified
+to exclude some folders for example.
+"""
+
+import Logs, Build, os, samba_utils, Options, Utils
+from Runner import Parallel
+
+old_refill_task_list = Parallel.refill_task_list
+def replace_refill_task_list(self):
+ '''replacement for refill_task_list() that deletes stale files'''
+
+ iit = old_refill_task_list(self)
+ bld = self.bld
+
+ if not getattr(bld, 'new_rules', False):
+ # we only need to check for stale files if the build rules changed
+ return iit
+
+ if Options.options.compile_targets:
+ # not safe when --target is used
+ return iit
+
+ # execute only once
+ if getattr(self, 'cleanup_done', False):
+ return iit
+ self.cleanup_done = True
+
+ def group_name(g):
+ tm = self.bld.task_manager
+ return [x for x in tm.groups_names if id(tm.groups_names[x]) == id(g)][0]
+
+ bin_base = bld.bldnode.abspath()
+ bin_base_len = len(bin_base)
+
+ # paranoia
+ if bin_base[-4:] != '/bin':
+ raise Utils.WafError("Invalid bin base: %s" % bin_base)
+
+ # obtain the expected list of files
+ expected = []
+ for i in range(len(bld.task_manager.groups)):
+ g = bld.task_manager.groups[i]
+ tasks = g.tasks_gen
+ for x in tasks:
+ try:
+ if getattr(x, 'target'):
+ tlist = samba_utils.TO_LIST(getattr(x, 'target'))
+ for t in tlist:
+ p = os.path.join(x.path.abspath(bld.env), t)
+ p = os.path.normpath(p)
+ expected.append(p)
+ for n in x.allnodes:
+ p = n.abspath(bld.env)
+ if p[0:bin_base_len] == bin_base:
+ expected.append(p)
+ except:
+ pass
+
+ for root, dirs, files in os.walk(bin_base):
+ for f in files:
+ p = root + '/' + f
+ if os.path.islink(p):
+ link = os.readlink(p)
+ if link[0:bin_base_len] == bin_base:
+ p = link
+ if f in ['config.h']:
+ continue
+ if f[-2:] not in [ '.c', '.h' ]:
+ continue
+ if f[-7:] == '.inst.h':
+ continue
+ if p.find("/.conf") != -1:
+ continue
+ if not p in expected:
+ Logs.warn("Removing stale file: %s" % p)
+ os.unlink(p)
+ return iit
+
+
+def AUTOCLEANUP_STALE_FILES(bld):
+ """automatically clean up any files in bin that shouldn't be there"""
+ old_refill_task_list = Parallel.refill_task_list
+ Parallel.refill_task_list = replace_refill_task_list
+ Parallel.bld = bld
+Build.BuildContext.AUTOCLEANUP_STALE_FILES = AUTOCLEANUP_STALE_FILES
diff --git a/buildtools/wafsamba/symbols.py b/buildtools/wafsamba/symbols.py
new file mode 100644
index 0000000000..0d0af79d06
--- /dev/null
+++ b/buildtools/wafsamba/symbols.py
@@ -0,0 +1,496 @@
+# a waf tool to extract symbols from object files or libraries
+# using nm, producing a set of exposed defined/undefined symbols
+
+import Utils, Build, subprocess, Logs
+from samba_wildcard import fake_build_environment
+from samba_utils import *
+
+# these are the data structures used in symbols.py:
+#
+# bld.env.symbol_map : dictionary mapping public symbol names to list of
+# subsystem names where that symbol exists
+#
+# t.in_library : list of libraries that t is in
+#
+# bld.env.public_symbols: set of public symbols for each subsystem
+# bld.env.used_symbols : set of used symbols for each subsystem
+#
+# bld.env.syslib_symbols: dictionary mapping system library name to set of symbols
+# for that library
+#
+# LOCAL_CACHE(bld, 'TARGET_TYPE') : dictionary mapping subsystem name to target type
+
+def symbols_extract(objfiles, dynamic=False):
+ '''extract symbols from objfile, returning a dictionary containing
+ the set of undefined and public symbols for each file'''
+
+ ret = {}
+
+ cmd = ["nm"]
+ if dynamic:
+ # needed for some .so files
+ cmd.append("-D")
+ cmd.extend(objfiles)
+
+ nmpipe = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
+ if len(objfiles) == 1:
+ filename = objfiles[0]
+ ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set()}
+
+ for line in nmpipe:
+ line = line.strip()
+ if line.endswith(':'):
+ filename = line[:-1]
+ ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set() }
+ continue
+ cols = line.split(" ")
+ if cols == ['']:
+ continue
+ # see if the line starts with an address
+ if len(cols) == 3:
+ symbol_type = cols[1]
+ symbol = cols[2]
+ else:
+ symbol_type = cols[0]
+ symbol = cols[1]
+ if symbol_type in "BDGTRVWSi":
+ # its a public symbol
+ ret[filename]["PUBLIC"].add(symbol)
+ elif symbol_type in "U":
+ ret[filename]["UNDEFINED"].add(symbol)
+
+ return ret
+
+
+def real_name(name):
+ if name.find(".objlist") != -1:
+ name = name[:-8]
+ return name
+
+
+def find_syslib_path(bld, libname, deps):
+ '''find the path to the syslib we will link against'''
+ # the strategy is to use the targets that depend on the library, and run ldd
+ # on it to find the real location of the library that is used
+
+ linkpath = deps[0].link_task.outputs[0].abspath(bld.env)
+
+ if libname == "python":
+ libname += bld.env.PYTHON_VERSION
+
+ ret = None
+
+ lddpipe = subprocess.Popen(['ldd', linkpath], stdout=subprocess.PIPE).stdout
+ for line in lddpipe:
+ line = line.strip()
+ cols = line.split(" ")
+ if len(cols) < 3 or cols[1] != "=>":
+ continue
+ if cols[0].startswith("lib%s." % libname.lower()):
+ ret = cols[2]
+ if cols[0].startswith("libc."):
+ # save this one too
+ bld.env.libc_path = cols[2]
+ return ret
+
+
+def build_symbol_sets(bld, tgt_list):
+ '''build the public_symbols and undefined_symbols attributes for each target'''
+
+ if bld.env.public_symbols:
+ return
+
+ objlist = [] # list of object file
+ objmap = {} # map from object filename to target (subsystem) name
+
+ for t in tgt_list:
+ t.public_symbols = set()
+ t.undefined_symbols = set()
+ t.used_symbols = set()
+ for tsk in getattr(t, 'compiled_tasks', []):
+ for output in tsk.outputs:
+ objpath = output.abspath(bld.env)
+ objlist.append(objpath)
+ objmap[objpath] = t
+
+ symbols = symbols_extract(objlist)
+ for obj in objlist:
+ t = objmap[obj]
+ t.public_symbols = t.public_symbols.union(symbols[obj]["PUBLIC"])
+ t.undefined_symbols = t.undefined_symbols.union(symbols[obj]["UNDEFINED"])
+ t.used_symbols = t.used_symbols.union(symbols[obj]["UNDEFINED"])
+
+ t.undefined_symbols = t.undefined_symbols.difference(t.public_symbols)
+
+ # and the reverse map of public symbols to subsystem name
+ bld.env.symbol_map = {}
+
+ for t in tgt_list:
+ for s in t.public_symbols:
+ if not s in bld.env.symbol_map:
+ bld.env.symbol_map[s] = []
+ bld.env.symbol_map[s].append(real_name(t.sname))
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ bld.env.public_symbols = {}
+ for t in tgt_list:
+ name = real_name(t.sname)
+ if name in bld.env.public_symbols:
+ bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t.public_symbols)
+ else:
+ bld.env.public_symbols[name] = t.public_symbols
+ if t.samba_type == 'LIBRARY':
+ for dep in t.add_objects:
+ t2 = bld.name_to_obj(dep, bld.env)
+ bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
+ bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t2.public_symbols)
+
+ bld.env.used_symbols = {}
+ for t in tgt_list:
+ name = real_name(t.sname)
+ if name in bld.env.used_symbols:
+ bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t.used_symbols)
+ else:
+ bld.env.used_symbols[name] = t.used_symbols
+ if t.samba_type == 'LIBRARY':
+ for dep in t.add_objects:
+ t2 = bld.name_to_obj(dep, bld.env)
+ bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
+ bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols)
+
+
+def build_syslib_sets(bld, tgt_list):
+ '''build the public_symbols for all syslibs'''
+
+ if bld.env.syslib_symbols:
+ return
+
+ # work out what syslibs we depend on, and what targets those are used in
+ syslibs = {}
+ objmap = {}
+ for t in tgt_list:
+ if getattr(t, 'uselib', []) and t.samba_type in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
+ for lib in t.uselib:
+ if lib in ['PYEMBED', 'PYEXT']:
+ lib = "python"
+ if not lib in syslibs:
+ syslibs[lib] = []
+ syslibs[lib].append(t)
+
+ # work out the paths to each syslib
+ syslib_paths = []
+ for lib in syslibs:
+ path = find_syslib_path(bld, lib, syslibs[lib])
+ if path is None:
+ Logs.warn("Unable to find syslib path for %s" % lib)
+ if path is not None:
+ syslib_paths.append(path)
+ objmap[path] = lib.lower()
+
+ # add in libc
+ syslib_paths.append(bld.env.libc_path)
+ objmap[bld.env.libc_path] = 'c'
+
+ symbols = symbols_extract(syslib_paths, dynamic=True)
+
+ # keep a map of syslib names to public symbols
+ bld.env.syslib_symbols = {}
+ for lib in symbols:
+ bld.env.syslib_symbols[lib] = symbols[lib]["PUBLIC"]
+
+ # add to the map of symbols to dependencies
+ for lib in symbols:
+ for sym in symbols[lib]["PUBLIC"]:
+ if not sym in bld.env.symbol_map:
+ bld.env.symbol_map[sym] = []
+ bld.env.symbol_map[sym].append(objmap[lib])
+
+ # keep the libc symbols as well, as these are useful for some of the
+ # sanity checks
+ bld.env.libc_symbols = symbols[bld.env.libc_path]["PUBLIC"]
+
+ # add to the combined map of dependency name to public_symbols
+ for lib in bld.env.syslib_symbols:
+ bld.env.public_symbols[objmap[lib]] = bld.env.syslib_symbols[lib]
+
+
+def build_autodeps(bld, t):
+ '''build the set of dependencies for a target'''
+ deps = set()
+ name = real_name(t.sname)
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ for sym in t.undefined_symbols:
+ if sym in t.public_symbols:
+ continue
+ if sym in bld.env.symbol_map:
+ depname = bld.env.symbol_map[sym]
+ if depname == [ name ]:
+ # self dependencies aren't interesting
+ continue
+ if t.in_library == depname:
+ # no need to depend on the library we are part of
+ continue
+ if depname[0] in ['c', 'python']:
+ # these don't go into autodeps
+ continue
+ if targets[depname[0]] in [ 'SYSLIB' ]:
+ deps.add(depname[0])
+ continue
+ t2 = bld.name_to_obj(depname[0], bld.env)
+ if len(t2.in_library) != 1:
+ deps.add(depname[0])
+ continue
+ if t2.in_library == t.in_library:
+ # if we're part of the same library, we don't need to autodep
+ continue
+ deps.add(t2.in_library[0])
+ t.autodeps = deps
+
+
+def build_library_names(bld, tgt_list):
+ '''add a in_library attribute to all targets that are part of a library'''
+
+ if bld.env.done_build_library_names:
+ return
+
+ for t in tgt_list:
+ t.in_library = []
+
+ for t in tgt_list:
+ if t.samba_type in [ 'LIBRARY' ]:
+ for obj in t.samba_deps_extended:
+ t2 = bld.name_to_obj(obj, bld.env)
+ if t2 and t2.samba_type in [ 'SUBSYSTEM', 'ASN1' ]:
+ if not t.sname in t2.in_library:
+ t2.in_library.append(t.sname)
+ bld.env.done_build_library_names = True
+
+
+def check_library_deps(bld, t):
+ '''check that all the autodeps that have mutual dependency of this
+ target are in the same library as the target'''
+
+ name = real_name(t.sname)
+
+ if len(t.in_library) > 1:
+ Logs.warn("WARNING: Target '%s' in multiple libraries: %s" % (t.sname, t.in_library))
+
+ for dep in t.autodeps:
+ t2 = bld.name_to_obj(dep, bld.env)
+ if t2 is None:
+ continue
+ for dep2 in t2.autodeps:
+ if dep2 == name and t.in_library != t2.in_library:
+ Logs.warn("WARNING: mutual dependency %s <=> %s" % (name, real_name(t2.sname)))
+ Logs.warn("Libraries should match. %s != %s" % (t.in_library, t2.in_library))
+ # raise Utils.WafError("illegal mutual dependency")
+
+
+def check_syslib_collisions(bld, tgt_list):
+ '''check if a target has any symbol collisions with a syslib
+
+ We do not want any code in Samba to use a symbol name from a
+ system library. The chance of that causing problems is just too
+ high. Note that libreplace uses a rep_XX approach of renaming
+ symbols via macros
+ '''
+
+ has_error = False
+ for t in tgt_list:
+ for lib in bld.env.syslib_symbols:
+ common = t.public_symbols.intersection(bld.env.syslib_symbols[lib])
+ if common:
+ Logs.error("ERROR: Target '%s' has symbols '%s' which is also in syslib '%s'" % (t.sname, common, lib))
+ has_error = True
+ if has_error:
+ raise Utils.WafError("symbols in common with system libraries")
+
+
+def check_dependencies(bld, t):
+ '''check for depenencies that should be changed'''
+
+ if bld.name_to_obj(t.sname + ".objlist", bld.env):
+ return
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ remaining = t.undefined_symbols.copy()
+ remaining = remaining.difference(t.public_symbols)
+
+ sname = real_name(t.sname)
+
+ deps = set(t.samba_deps)
+ for d in t.samba_deps:
+ if targets[d] in [ 'EMPTY', 'DISABLED', 'SYSLIB' ]:
+ continue
+ bld.ASSERT(d in bld.env.public_symbols, "Failed to find symbol list for dependency '%s'" % d)
+ diff = remaining.intersection(bld.env.public_symbols[d])
+ if not diff and targets[sname] != 'LIBRARY':
+ Logs.info("Target '%s' has no dependency on %s" % (sname, d))
+ else:
+ remaining = remaining.difference(diff)
+
+ t.unsatisfied_symbols = set()
+ needed = {}
+ for sym in remaining:
+ if sym in bld.env.symbol_map:
+ dep = bld.env.symbol_map[sym]
+ if not dep[0] in needed:
+ needed[dep[0]] = set()
+ needed[dep[0]].add(sym)
+ else:
+ t.unsatisfied_symbols.add(sym)
+
+ for dep in needed:
+ Logs.info("Target '%s' should add dep '%s' for symbols %s" % (sname, dep, " ".join(needed[dep])))
+
+
+
+def check_syslib_dependencies(bld, t):
+ '''check for syslib depenencies'''
+
+ if bld.name_to_obj(t.sname + ".objlist", bld.env):
+ return
+
+ sname = real_name(t.sname)
+
+ remaining = set()
+
+ features = TO_LIST(t.features)
+ if 'pyembed' in features or 'pyext' in features:
+ t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python'])
+
+ needed = {}
+ for sym in t.unsatisfied_symbols:
+ if sym in bld.env.symbol_map:
+ dep = bld.env.symbol_map[sym][0]
+ if dep == 'c':
+ continue
+ if not dep in needed:
+ needed[dep] = set()
+ needed[dep].add(sym)
+ else:
+ remaining.add(sym)
+
+ for dep in needed:
+ Logs.info("Target '%s' should add syslib dep '%s' for symbols %s" % (sname, dep, " ".join(needed[dep])))
+
+ if remaining:
+ debug("deps: Target '%s' has unsatisfied symbols: %s" % (sname, " ".join(remaining)))
+
+
+
+def symbols_symbolcheck(task):
+ '''check the internal dependency lists'''
+ bld = task.env.bld
+ tgt_list = get_tgt_list(bld)
+
+ build_symbol_sets(bld, tgt_list)
+ build_library_names(bld, tgt_list)
+
+ for t in tgt_list:
+ t.autodeps = set()
+ if getattr(t, 'source', ''):
+ build_autodeps(bld, t)
+
+ for t in tgt_list:
+ check_dependencies(bld, t)
+
+ for t in tgt_list:
+ check_library_deps(bld, t)
+
+def symbols_syslibcheck(task):
+ '''check the syslib dependencies'''
+ bld = task.env.bld
+ tgt_list = get_tgt_list(bld)
+
+ build_syslib_sets(bld, tgt_list)
+ check_syslib_collisions(bld, tgt_list)
+
+ for t in tgt_list:
+ check_syslib_dependencies(bld, t)
+
+
+def symbols_whyneeded(task):
+ """check why 'target' needs to link to 'subsystem'"""
+ bld = task.env.bld
+ tgt_list = get_tgt_list(bld)
+
+ why = Options.options.WHYNEEDED.split(":")
+ if len(why) != 2:
+ raise Utils.WafError("usage: WHYNEEDED=TARGET:DEPENDENCY")
+ target = why[0]
+ subsystem = why[1]
+
+ build_symbol_sets(bld, tgt_list)
+ build_library_names(bld, tgt_list)
+ build_syslib_sets(bld, tgt_list)
+
+ Logs.info("Checking why %s needs to link to %s" % (target, subsystem))
+ if not target in bld.env.used_symbols:
+ Logs.warn("unable to find target '%s' in used_symbols dict" % target)
+ return
+ if not subsystem in bld.env.public_symbols:
+ Logs.warn("unable to find subsystem '%s' in public_symbols dict" % subsystem)
+ return
+ overlap = bld.env.used_symbols[target].intersection(bld.env.public_symbols[subsystem])
+ if not overlap:
+ Logs.info("target '%s' doesn't use any public symbols from '%s'" % (target, subsystem))
+ else:
+ Logs.info("target '%s' uses symbols %s from '%s'" % (target, overlap, subsystem))
+
+
+
+def symbols_dupcheck(task):
+ '''check for symbols defined in two different subsystems'''
+ bld = task.env.bld
+ tgt_list = get_tgt_list(bld)
+
+ targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
+
+ Logs.info("Checking for duplicate symbols")
+ for sym in bld.env.symbol_map:
+ subsystems = set(bld.env.symbol_map[sym])
+ if len(subsystems) == 1:
+ continue
+
+ if sym in ['main', '_init', '_fini', 'init_samba_module', 'samba_init_module', 'ldb_init_module' ]:
+ # these are expected to be in many subsystems
+ continue
+
+ # if all of them are in system libraries, we can ignore them. This copes
+ # with the duplication between libc, libpthread and libattr
+ all_syslib = True
+ for s in subsystems:
+ if s != 'c' and (not s in targets or targets[s] != 'SYSLIB'):
+ all_syslib = False
+ if all_syslib:
+ continue
+ Logs.info("symbol %s appears in %s" % (sym, subsystems))
+
+
+def SYMBOL_CHECK(bld):
+ '''check our dependency lists'''
+ if Options.options.SYMBOLCHECK:
+ bld.SET_BUILD_GROUP('symbolcheck')
+ task = bld(rule=symbols_symbolcheck, always=True, name='symbol checking')
+ task.env.bld = bld
+
+ bld.SET_BUILD_GROUP('syslibcheck')
+ task = bld(rule=symbols_syslibcheck, always=True, name='syslib checking')
+ task.env.bld = bld
+
+ bld.SET_BUILD_GROUP('syslibcheck')
+ task = bld(rule=symbols_dupcheck, always=True, name='symbol duplicate checking')
+ task.env.bld = bld
+
+ if Options.options.WHYNEEDED:
+ bld.SET_BUILD_GROUP('syslibcheck')
+ task = bld(rule=symbols_whyneeded, always=True, name='check why a dependency is needed')
+ task.env.bld = bld
+
+
+Build.BuildContext.SYMBOL_CHECK = SYMBOL_CHECK
diff --git a/buildtools/wafsamba/tru64cc.py b/buildtools/wafsamba/tru64cc.py
new file mode 100644
index 0000000000..7e85701536
--- /dev/null
+++ b/buildtools/wafsamba/tru64cc.py
@@ -0,0 +1,77 @@
+
+# compiler definition for tru64/OSF1 cc compiler
+# based on suncc.py from waf
+
+import os, optparse
+import Utils, Options, Configure
+import ccroot, ar
+from Configure import conftest
+
+from compiler_cc import c_compiler
+
+c_compiler['osf1V'] = ['gcc', 'tru64cc']
+
+@conftest
+def find_tru64cc(conf):
+ v = conf.env
+ cc = None
+ if v['CC']: cc = v['CC']
+ elif 'CC' in conf.environ: cc = conf.environ['CC']
+ if not cc: cc = conf.find_program('cc', var='CC')
+ if not cc: conf.fatal('tru64cc was not found')
+ cc = conf.cmd_to_list(cc)
+
+ try:
+ if not Utils.cmd_output(cc + ['-V']):
+ conf.fatal('tru64cc %r was not found' % cc)
+ except ValueError:
+ conf.fatal('tru64cc -V could not be executed')
+
+ v['CC'] = cc
+ v['CC_NAME'] = 'tru64'
+
+@conftest
+def tru64cc_common_flags(conf):
+ v = conf.env
+
+ v['CC_SRC_F'] = ''
+ v['CC_TGT_F'] = ['-c', '-o', '']
+ v['CPPPATH_ST'] = '-I%s' # template for adding include paths
+
+ # linker
+ if not v['LINK_CC']: v['LINK_CC'] = v['CC']
+ v['CCLNK_SRC_F'] = ''
+ v['CCLNK_TGT_F'] = ['-o', '']
+
+ v['LIB_ST'] = '-l%s' # template for adding libs
+ v['LIBPATH_ST'] = '-L%s' # template for adding libpaths
+ v['STATICLIB_ST'] = '-l%s'
+ v['STATICLIBPATH_ST'] = '-L%s'
+ v['CCDEFINES_ST'] = '-D%s'
+
+# v['SONAME_ST'] = '-Wl,-h -Wl,%s'
+# v['SHLIB_MARKER'] = '-Bdynamic'
+# v['STATICLIB_MARKER'] = '-Bstatic'
+
+ # program
+ v['program_PATTERN'] = '%s'
+
+ # shared library
+# v['shlib_CCFLAGS'] = ['-Kpic', '-DPIC']
+ v['shlib_LINKFLAGS'] = ['-shared']
+ v['shlib_PATTERN'] = 'lib%s.so'
+
+ # static lib
+# v['staticlib_LINKFLAGS'] = ['-Bstatic']
+# v['staticlib_PATTERN'] = 'lib%s.a'
+
+detect = '''
+find_tru64cc
+find_cpp
+find_ar
+tru64cc_common_flags
+cc_load_tools
+cc_add_flags
+link_add_flags
+'''
+
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
new file mode 100644
index 0000000000..2a1c82a307
--- /dev/null
+++ b/buildtools/wafsamba/wafsamba.py
@@ -0,0 +1,825 @@
+# a waf tool to add autoconf-like macros to the configure section
+# and for SAMBA_ macros for building libraries, binaries etc
+
+import Build, os, sys, Options, Task, Utils, cc, TaskGen, fnmatch, re, shutil, Logs, Constants
+from Configure import conf
+from Logs import debug
+from samba_utils import SUBST_VARS_RECURSIVE
+TaskGen.task_gen.apply_verif = Utils.nada
+
+# bring in the other samba modules
+from samba_optimisation import *
+from samba_utils import *
+from samba_version import *
+from samba_autoconf import *
+from samba_patterns import *
+from samba_pidl import *
+from samba_autoproto import *
+from samba_python import *
+from samba_deps import *
+from samba_bundled import *
+import samba_install
+import samba_conftests
+import samba_abi
+import samba_headers
+import tru64cc
+import irixcc
+import hpuxcc
+import generic_cc
+import samba_dist
+import samba_wildcard
+import stale_files
+import symbols
+import pkgconfig
+
+# some systems have broken threading in python
+if os.environ.get('WAF_NOTHREADS') == '1':
+ import nothreads
+
+LIB_PATH="shared"
+
+os.environ['PYTHONUNBUFFERED'] = '1'
+
+
+if Constants.HEXVERSION < 0x105019:
+ Logs.error('''
+Please use the version of waf that comes with Samba, not
+a system installed version. See http://wiki.samba.org/index.php/Waf
+for details.
+
+Alternatively, please run ./configure and make as usual. That will
+call the right version of waf.''')
+ sys.exit(1)
+
+
+@conf
+def SAMBA_BUILD_ENV(conf):
+ '''create the samba build environment'''
+ conf.env.BUILD_DIRECTORY = conf.blddir
+ mkdir_p(os.path.join(conf.blddir, LIB_PATH))
+ mkdir_p(os.path.join(conf.blddir, LIB_PATH, "private"))
+ mkdir_p(os.path.join(conf.blddir, "modules"))
+ mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
+ # this allows all of the bin/shared and bin/python targets
+ # to be expressed in terms of build directory paths
+ mkdir_p(os.path.join(conf.blddir, 'default'))
+ for p in ['python','shared', 'modules']:
+ link_target = os.path.join(conf.blddir, 'default/' + p)
+ if not os.path.lexists(link_target):
+ os.symlink('../' + p, link_target)
+
+ # get perl to put the blib files in the build directory
+ blib_bld = os.path.join(conf.blddir, 'default/pidl/blib')
+ blib_src = os.path.join(conf.srcdir, 'pidl/blib')
+ mkdir_p(blib_bld + '/man1')
+ mkdir_p(blib_bld + '/man3')
+ if os.path.islink(blib_src):
+ os.unlink(blib_src)
+ elif os.path.exists(blib_src):
+ shutil.rmtree(blib_src)
+
+
+def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
+ '''add an init_function to the list for a subsystem'''
+ if init_function is None:
+ return
+ bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
+ cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
+ if not subsystem in cache:
+ cache[subsystem] = []
+ cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
+Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
+
+
+
+#################################################################
+def SAMBA_LIBRARY(bld, libname, source,
+ deps='',
+ public_deps='',
+ includes='',
+ public_headers=None,
+ public_headers_install=True,
+ header_path=None,
+ pc_files=None,
+ vnum=None,
+ soname=None,
+ cflags='',
+ ldflags='',
+ external_library=False,
+ realname=None,
+ autoproto=None,
+ group='libraries',
+ depends_on='',
+ local_include=True,
+ global_include=True,
+ vars=None,
+ subdir=None,
+ install_path=None,
+ install=True,
+ pyembed=False,
+ pyext=False,
+ target_type='LIBRARY',
+ bundled_extension=True,
+ link_name=None,
+ abi_directory=None,
+ abi_match=None,
+ hide_symbols=False,
+ manpages=None,
+ private_library=False,
+ grouping_library=False,
+ allow_undefined_symbols=False,
+ enabled=True):
+ '''define a Samba library'''
+
+ if not enabled:
+ SET_TARGET_TYPE(bld, libname, 'DISABLED')
+ return
+
+ source = bld.EXPAND_VARIABLES(source, vars=vars)
+ if subdir:
+ source = bld.SUBDIR(subdir, source)
+
+ # remember empty libraries, so we can strip the dependencies
+ if ((source == '') or (source == [])) and deps == '' and public_deps == '':
+ SET_TARGET_TYPE(bld, libname, 'EMPTY')
+ return
+
+ if BUILTIN_LIBRARY(bld, libname):
+ obj_target = libname
+ else:
+ obj_target = libname + '.objlist'
+
+ if group == 'libraries':
+ subsystem_group = 'main'
+ else:
+ subsystem_group = group
+
+ # first create a target for building the object files for this library
+ # by separating in this way, we avoid recompiling the C files
+ # separately for the install library and the build library
+ bld.SAMBA_SUBSYSTEM(obj_target,
+ source = source,
+ deps = deps,
+ public_deps = public_deps,
+ includes = includes,
+ public_headers = public_headers,
+ public_headers_install = public_headers_install,
+ header_path = header_path,
+ cflags = cflags,
+ group = subsystem_group,
+ autoproto = autoproto,
+ depends_on = depends_on,
+ hide_symbols = hide_symbols,
+ pyext = pyext or (target_type == "PYTHON"),
+ local_include = local_include,
+ global_include = global_include)
+
+ if BUILTIN_LIBRARY(bld, libname):
+ return
+
+ if not SET_TARGET_TYPE(bld, libname, target_type):
+ return
+
+ # the library itself will depend on that object target
+ deps += ' ' + public_deps
+ deps = TO_LIST(deps)
+ deps.append(obj_target)
+
+ realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
+ link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
+
+ # we don't want any public libraries without version numbers
+ if not private_library and vnum is None and soname is None and target_type != 'PYTHON' and not realname:
+ raise Utils.WafError("public library '%s' must have a vnum" % libname)
+
+ if target_type == 'PYTHON' or realname or not private_library:
+ bundled_name = libname.replace('_', '-')
+ else:
+ bundled_name = PRIVATE_NAME(bld, libname, bundled_extension, private_library)
+
+ ldflags = TO_LIST(ldflags)
+
+ features = 'cc cshlib symlink_lib install_lib'
+ if target_type == 'PYTHON':
+ features += ' pyext'
+ if pyext or pyembed:
+ # this is quite strange. we should add pyext feature for pyext
+ # but that breaks the build. This may be a bug in the waf python tool
+ features += ' pyembed'
+
+ if abi_directory:
+ features += ' abi_check'
+
+ vscript = None
+ if bld.env.HAVE_LD_VERSION_SCRIPT:
+ if private_library:
+ version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
+ elif vnum:
+ version = "%s_%s" % (libname, vnum)
+ else:
+ version = None
+ if version:
+ vscript = "%s.vscript" % libname
+ bld.ABI_VSCRIPT(libname, abi_directory, version, vscript,
+ abi_match)
+ fullname = apply_pattern(bundled_name, bld.env.shlib_PATTERN)
+ fullpath = bld.path.find_or_declare(fullname)
+ vscriptpath = bld.path.find_or_declare(vscript)
+ if not fullpath:
+ raise Utils.WafError("unable to find fullpath for %s" % fullname)
+ if not vscriptpath:
+ raise Utils.WafError("unable to find vscript path for %s" % vscript)
+ bld.add_manual_dependency(fullpath, vscriptpath)
+ if Options.is_install:
+ # also make the .inst file depend on the vscript
+ instname = apply_pattern(bundled_name + '.inst', bld.env.shlib_PATTERN)
+ bld.add_manual_dependency(bld.path.find_or_declare(instname), bld.path.find_or_declare(vscript))
+ vscript = os.path.join(bld.path.abspath(bld.env), vscript)
+
+ bld.SET_BUILD_GROUP(group)
+ t = bld(
+ features = features,
+ source = [],
+ target = bundled_name,
+ depends_on = depends_on,
+ samba_ldflags = ldflags,
+ samba_deps = deps,
+ samba_includes = includes,
+ version_script = vscript,
+ local_include = local_include,
+ global_include = global_include,
+ vnum = vnum,
+ soname = soname,
+ install_path = None,
+ samba_inst_path = install_path,
+ name = libname,
+ samba_realname = realname,
+ samba_install = install,
+ abi_directory = "%s/%s" % (bld.path.abspath(), abi_directory),
+ abi_match = abi_match,
+ private_library = private_library,
+ grouping_library=grouping_library,
+ allow_undefined_symbols=allow_undefined_symbols
+ )
+
+ if realname and not link_name:
+ link_name = 'shared/%s' % realname
+
+ if link_name:
+ t.link_name = link_name
+
+ if pc_files is not None:
+ bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
+
+ if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
+ bld.MANPAGES(manpages)
+
+
+Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
+
+
+#################################################################
+def SAMBA_BINARY(bld, binname, source,
+ deps='',
+ includes='',
+ public_headers=None,
+ header_path=None,
+ modules=None,
+ ldflags=None,
+ cflags='',
+ autoproto=None,
+ use_hostcc=False,
+ use_global_deps=True,
+ compiler=None,
+ group='binaries',
+ manpages=None,
+ local_include=True,
+ global_include=True,
+ subsystem_name=None,
+ pyembed=False,
+ vars=None,
+ subdir=None,
+ install=True,
+ install_path=None,
+ enabled=True):
+ '''define a Samba binary'''
+
+ if not enabled:
+ SET_TARGET_TYPE(bld, binname, 'DISABLED')
+ return
+
+ if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
+ return
+
+ features = 'cc cprogram symlink_bin install_bin'
+ if pyembed:
+ features += ' pyembed'
+
+ obj_target = binname + '.objlist'
+
+ source = bld.EXPAND_VARIABLES(source, vars=vars)
+ if subdir:
+ source = bld.SUBDIR(subdir, source)
+ source = unique_list(TO_LIST(source))
+
+ if group == 'binaries':
+ subsystem_group = 'main'
+ else:
+ subsystem_group = group
+
+ # first create a target for building the object files for this binary
+ # by separating in this way, we avoid recompiling the C files
+ # separately for the install binary and the build binary
+ bld.SAMBA_SUBSYSTEM(obj_target,
+ source = source,
+ deps = deps,
+ includes = includes,
+ cflags = cflags,
+ group = subsystem_group,
+ autoproto = autoproto,
+ subsystem_name = subsystem_name,
+ local_include = local_include,
+ global_include = global_include,
+ use_hostcc = use_hostcc,
+ pyext = pyembed,
+ use_global_deps= use_global_deps)
+
+ bld.SET_BUILD_GROUP(group)
+
+ # the binary itself will depend on that object target
+ deps = TO_LIST(deps)
+ deps.append(obj_target)
+
+ t = bld(
+ features = features,
+ source = [],
+ target = binname,
+ samba_deps = deps,
+ samba_includes = includes,
+ local_include = local_include,
+ global_include = global_include,
+ samba_modules = modules,
+ top = True,
+ samba_subsystem= subsystem_name,
+ install_path = None,
+ samba_inst_path= install_path,
+ samba_install = install,
+ samba_ldflags = TO_LIST(ldflags)
+ )
+
+ if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
+ bld.MANPAGES(manpages)
+
+Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
+
+
+#################################################################
+def SAMBA_MODULE(bld, modname, source,
+ deps='',
+ includes='',
+ subsystem=None,
+ init_function=None,
+ module_init_name='samba_init_module',
+ autoproto=None,
+ autoproto_extra_source='',
+ cflags='',
+ internal_module=True,
+ local_include=True,
+ global_include=True,
+ vars=None,
+ subdir=None,
+ enabled=True,
+ pyembed=False,
+ allow_undefined_symbols=False
+ ):
+ '''define a Samba module.'''
+
+ source = bld.EXPAND_VARIABLES(source, vars=vars)
+ if subdir:
+ source = bld.SUBDIR(subdir, source)
+
+ if internal_module or BUILTIN_LIBRARY(bld, modname):
+ bld.SAMBA_SUBSYSTEM(modname, source,
+ deps=deps,
+ includes=includes,
+ autoproto=autoproto,
+ autoproto_extra_source=autoproto_extra_source,
+ cflags=cflags,
+ local_include=local_include,
+ global_include=global_include,
+ enabled=enabled)
+
+ bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
+ return
+
+ if not enabled:
+ SET_TARGET_TYPE(bld, modname, 'DISABLED')
+ return
+
+ obj_target = modname + '.objlist'
+
+ realname = modname
+ if subsystem is not None:
+ deps += ' ' + subsystem
+ while realname.startswith("lib"+subsystem+"_"):
+ realname = realname[len("lib"+subsystem+"_"):]
+ while realname.startswith(subsystem+"_"):
+ realname = realname[len(subsystem+"_"):]
+
+ realname = bld.make_libname(realname)
+ while realname.startswith("lib"):
+ realname = realname[len("lib"):]
+
+ build_link_name = "modules/%s/%s" % (subsystem, realname)
+
+ if init_function:
+ cflags += " -D%s=%s" % (init_function, module_init_name)
+
+ bld.SAMBA_LIBRARY(modname,
+ source,
+ deps=deps,
+ includes=includes,
+ cflags=cflags,
+ realname = realname,
+ autoproto = autoproto,
+ local_include=local_include,
+ global_include=global_include,
+ vars=vars,
+ link_name=build_link_name,
+ install_path="${MODULESDIR}/%s" % subsystem,
+ pyembed=pyembed,
+ allow_undefined_symbols=allow_undefined_symbols
+ )
+
+
+Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
+
+
+#################################################################
+def SAMBA_SUBSYSTEM(bld, modname, source,
+ deps='',
+ public_deps='',
+ includes='',
+ public_headers=None,
+ public_headers_install=True,
+ header_path=None,
+ cflags='',
+ cflags_end=None,
+ group='main',
+ init_function_sentinal=None,
+ autoproto=None,
+ autoproto_extra_source='',
+ depends_on='',
+ local_include=True,
+ local_include_first=True,
+ global_include=True,
+ subsystem_name=None,
+ enabled=True,
+ use_hostcc=False,
+ use_global_deps=True,
+ vars=None,
+ subdir=None,
+ hide_symbols=False,
+ pyext=False):
+ '''define a Samba subsystem'''
+
+ if not enabled:
+ SET_TARGET_TYPE(bld, modname, 'DISABLED')
+ return
+
+ # remember empty subsystems, so we can strip the dependencies
+ if ((source == '') or (source == [])) and deps == '' and public_deps == '':
+ SET_TARGET_TYPE(bld, modname, 'EMPTY')
+ return
+
+ if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
+ return
+
+ source = bld.EXPAND_VARIABLES(source, vars=vars)
+ if subdir:
+ source = bld.SUBDIR(subdir, source)
+ source = unique_list(TO_LIST(source))
+
+ deps += ' ' + public_deps
+
+ bld.SET_BUILD_GROUP(group)
+
+ features = 'cc'
+ if pyext:
+ features += ' pyext'
+
+ t = bld(
+ features = features,
+ source = source,
+ target = modname,
+ samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
+ depends_on = depends_on,
+ samba_deps = TO_LIST(deps),
+ samba_includes = includes,
+ local_include = local_include,
+ local_include_first = local_include_first,
+ global_include = global_include,
+ samba_subsystem= subsystem_name,
+ samba_use_hostcc = use_hostcc,
+ samba_use_global_deps = use_global_deps
+ )
+
+ if cflags_end is not None:
+ t.samba_cflags.extend(TO_LIST(cflags_end))
+
+ if autoproto is not None:
+ bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
+ if public_headers is not None:
+ bld.PUBLIC_HEADERS(public_headers, header_path=header_path,
+ public_headers_install=public_headers_install)
+ return t
+
+
+Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
+
+
+def SAMBA_GENERATOR(bld, name, rule, source='', target='',
+ group='generators', enabled=True,
+ public_headers=None,
+ public_headers_install=True,
+ header_path=None,
+ vars=None,
+ always=False):
+ '''A generic source generator target'''
+
+ if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
+ return
+
+ if not enabled:
+ return
+
+ bld.SET_BUILD_GROUP(group)
+ t = bld(
+ rule=rule,
+ source=bld.EXPAND_VARIABLES(source, vars=vars),
+ target=target,
+ shell=isinstance(rule, str),
+ on_results=True,
+ before='cc',
+ ext_out='.c',
+ samba_type='GENERATOR',
+ dep_vars = [rule] + (vars or []),
+ name=name)
+
+ if always:
+ t.always = True
+
+ if public_headers is not None:
+ bld.PUBLIC_HEADERS(public_headers, header_path=header_path,
+ public_headers_install=public_headers_install)
+ return t
+Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
+
+
+
+@runonce
+def SETUP_BUILD_GROUPS(bld):
+ '''setup build groups used to ensure that the different build
+ phases happen consecutively'''
+ bld.p_ln = bld.srcnode # we do want to see all targets!
+ bld.env['USING_BUILD_GROUPS'] = True
+ bld.add_group('setup')
+ bld.add_group('build_compiler_source')
+ bld.add_group('vscripts')
+ bld.add_group('base_libraries')
+ bld.add_group('generators')
+ bld.add_group('compiler_prototypes')
+ bld.add_group('compiler_libraries')
+ bld.add_group('build_compilers')
+ bld.add_group('build_source')
+ bld.add_group('prototypes')
+ bld.add_group('headers')
+ bld.add_group('main')
+ bld.add_group('symbolcheck')
+ bld.add_group('libraries')
+ bld.add_group('binaries')
+ bld.add_group('syslibcheck')
+ bld.add_group('final')
+Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
+
+
+def SET_BUILD_GROUP(bld, group):
+ '''set the current build group'''
+ if not 'USING_BUILD_GROUPS' in bld.env:
+ return
+ bld.set_group(group)
+Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
+
+
+
+@conf
+def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
+ """use timestamps instead of file contents for deps
+ this currently doesn't work"""
+ def h_file(filename):
+ import stat
+ st = os.stat(filename)
+ if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
+ m = Utils.md5()
+ m.update(str(st.st_mtime))
+ m.update(str(st.st_size))
+ m.update(filename)
+ return m.digest()
+ Utils.h_file = h_file
+
+
+
+t = Task.simple_task_type('copy_script', 'rm -f "${LINK_TARGET}" && ln -s "${SRC[0].abspath(env)}" ${LINK_TARGET}',
+ shell=True, color='PINK', ext_in='.bin')
+t.quiet = True
+
+@feature('copy_script')
+@before('apply_link')
+def copy_script(self):
+ tsk = self.create_task('copy_script', self.allnodes[0])
+ tsk.env.TARGET = self.target
+
+def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
+ '''used to copy scripts from the source tree into the build directory
+ for use by selftest'''
+
+ source = bld.path.ant_glob(pattern)
+
+ bld.SET_BUILD_GROUP('build_source')
+ for s in TO_LIST(source):
+ iname = s
+ if installname != None:
+ iname = installname
+ target = os.path.join(installdir, iname)
+ tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
+ mkdir_p(tgtdir)
+ t = bld(features='copy_script',
+ source = s,
+ target = target,
+ always = True,
+ install_path = None)
+ t.env.LINK_TARGET = target
+
+Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
+
+def copy_and_fix_python_path(task):
+ pattern='sys.path.insert(0, "bin/python")'
+ if task.env["PYTHONARCHDIR"] in sys.path and task.env["PYTHONDIR"] in sys.path:
+ replacement = ""
+ elif task.env["PYTHONARCHDIR"] == task.env["PYTHONDIR"]:
+ replacement="""sys.path.insert(0, "%s")""" % task.env["PYTHONDIR"]
+ else:
+ replacement="""sys.path.insert(0, "%s")
+sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
+
+ installed_location=task.outputs[0].bldpath(task.env)
+ source_file = open(task.inputs[0].srcpath(task.env))
+ installed_file = open(installed_location, 'w')
+ for line in source_file:
+ newline = line
+ if pattern in line:
+ newline = line.replace(pattern, replacement)
+ installed_file.write(newline)
+ installed_file.close()
+ os.chmod(installed_location, 0755)
+ return 0
+
+
+def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
+ python_fixup=False, destname=None, base_name=None):
+ '''install a file'''
+ destdir = bld.EXPAND_VARIABLES(destdir)
+ if not destname:
+ destname = file
+ if flat:
+ destname = os.path.basename(destname)
+ dest = os.path.join(destdir, destname)
+ if python_fixup:
+ # fixup the python path it will use to find Samba modules
+ inst_file = file + '.inst'
+ bld.SAMBA_GENERATOR('python_%s' % destname,
+ rule=copy_and_fix_python_path,
+ source=file,
+ target=inst_file)
+ file = inst_file
+ if base_name:
+ file = os.path.join(base_name, file)
+ bld.install_as(dest, file, chmod=chmod)
+
+
+def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
+ python_fixup=False, destname=None, base_name=None):
+ '''install a set of files'''
+ for f in TO_LIST(files):
+ install_file(bld, destdir, f, chmod=chmod, flat=flat,
+ python_fixup=python_fixup, destname=destname,
+ base_name=base_name)
+Build.BuildContext.INSTALL_FILES = INSTALL_FILES
+
+
+def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
+ python_fixup=False, exclude=None, trim_path=None):
+ '''install a set of files matching a wildcard pattern'''
+ files=TO_LIST(bld.path.ant_glob(pattern))
+ if trim_path:
+ files2 = []
+ for f in files:
+ files2.append(os_path_relpath(f, trim_path))
+ files = files2
+
+ if exclude:
+ for f in files[:]:
+ if fnmatch.fnmatch(f, exclude):
+ files.remove(f)
+ INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
+ python_fixup=python_fixup, base_name=trim_path)
+Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
+
+
+def INSTALL_DIRS(bld, destdir, dirs):
+ '''install a set of directories'''
+ destdir = bld.EXPAND_VARIABLES(destdir)
+ dirs = bld.EXPAND_VARIABLES(dirs)
+ for d in TO_LIST(dirs):
+ bld.install_dir(os.path.join(destdir, d))
+Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
+
+
+def MANPAGES(bld, manpages):
+ '''build and install manual pages'''
+ bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
+ for m in manpages.split():
+ source = m + '.xml'
+ bld.SAMBA_GENERATOR(m,
+ source=source,
+ target=m,
+ group='final',
+ rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
+ )
+ bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
+Build.BuildContext.MANPAGES = MANPAGES
+
+
+#############################################################
+# give a nicer display when building different types of files
+def progress_display(self, msg, fname):
+ col1 = Logs.colors(self.color)
+ col2 = Logs.colors.NORMAL
+ total = self.position[1]
+ n = len(str(total))
+ fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
+ return fs % (self.position[0], self.position[1], col1, fname, col2)
+
+def link_display(self):
+ if Options.options.progress_bar != 0:
+ return Task.Task.old_display(self)
+ fname = self.outputs[0].bldpath(self.env)
+ return progress_display(self, 'Linking', fname)
+Task.TaskBase.classes['cc_link'].display = link_display
+
+def samba_display(self):
+ if Options.options.progress_bar != 0:
+ return Task.Task.old_display(self)
+
+ targets = LOCAL_CACHE(self, 'TARGET_TYPE')
+ if self.name in targets:
+ target_type = targets[self.name]
+ type_map = { 'GENERATOR' : 'Generating',
+ 'PROTOTYPE' : 'Generating'
+ }
+ if target_type in type_map:
+ return progress_display(self, type_map[target_type], self.name)
+
+ if len(self.inputs) == 0:
+ return Task.Task.old_display(self)
+
+ fname = self.inputs[0].bldpath(self.env)
+ if fname[0:3] == '../':
+ fname = fname[3:]
+ ext_loc = fname.rfind('.')
+ if ext_loc == -1:
+ return Task.Task.old_display(self)
+ ext = fname[ext_loc:]
+
+ ext_map = { '.idl' : 'Compiling IDL',
+ '.et' : 'Compiling ERRTABLE',
+ '.asn1': 'Compiling ASN1',
+ '.c' : 'Compiling' }
+ if ext in ext_map:
+ return progress_display(self, ext_map[ext], fname)
+ return Task.Task.old_display(self)
+
+Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
+Task.TaskBase.classes['Task'].display = samba_display
+
+
+@after('apply_link')
+@feature('cshlib')
+def apply_bundle_remove_dynamiclib_patch(self):
+ if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
+ if not getattr(self,'vnum',None):
+ try:
+ self.env['LINKFLAGS'].remove('-dynamiclib')
+ self.env['LINKFLAGS'].remove('-single_module')
+ except ValueError:
+ pass
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
new file mode 100755
index 0000000000..ecc2ae51f6
--- /dev/null
+++ b/buildtools/wafsamba/wscript
@@ -0,0 +1,405 @@
+#!/usr/bin/env python
+
+# this is a base set of waf rules that everything else pulls in first
+
+import sys, wafsamba, Configure, Logs
+import Options, os, preproc
+from samba_utils import *
+from optparse import SUPPRESS_HELP
+
+# this forces configure to be re-run if any of the configure
+# sections of the build scripts change. We have to check
+# for this in sys.argv as options have not yet been parsed when
+# we need to set this. This is off by default until some issues
+# are resolved related to WAFCACHE. It will need a lot of testing
+# before it is enabled by default.
+if '--enable-auto-reconfigure' in sys.argv:
+ Configure.autoconfig = True
+
+def set_options(opt):
+ opt.tool_options('compiler_cc')
+
+ opt.tool_options('gnu_dirs')
+
+ gr = opt.option_group('library handling options')
+
+ gr.add_option('--bundled-libraries',
+ help=("comma separated list of bundled libraries. May include !LIBNAME to disable bundling a library. Can be 'NONE' or 'ALL' [auto]"),
+ action="store", dest='BUNDLED_LIBS', default='')
+
+ extension_default = Options.options['PRIVATE_EXTENSION_DEFAULT']
+ gr.add_option('--private-library-extension',
+ help=("name extension for private libraries [%s]" % extension_default),
+ action="store", dest='PRIVATE_EXTENSION', default=extension_default)
+
+ extension_exception = Options.options['PRIVATE_EXTENSION_EXCEPTION']
+ gr.add_option('--private-extension-exception',
+ help=("comma separated list of libraries to not apply extension to [%s]" % extension_exception),
+ action="store", dest='PRIVATE_EXTENSION_EXCEPTION', default=extension_exception)
+
+ builtin_defauilt = Options.options['BUILTIN_LIBRARIES_DEFAULT']
+ gr.add_option('--builtin-libraries',
+ help=("command separated list of libraries to build directly into binaries [%s]" % builtin_defauilt),
+ action="store", dest='BUILTIN_LIBRARIES', default=builtin_defauilt)
+
+ gr.add_option('--minimum-library-version',
+ help=("list of minimum system library versions (LIBNAME1:version,LIBNAME2:version)"),
+ action="store", dest='MINIMUM_LIBRARY_VERSION', default='')
+
+ gr.add_option('--disable-shared',
+ help=("Disable all use of shared libraries"),
+ action="store_true", dest='disable_shared', default=False)
+ gr.add_option('--disable-rpath',
+ help=("Disable use of rpath for build binaries"),
+ action="store_true", dest='disable_rpath_build', default=False)
+ gr.add_option('--disable-rpath-install',
+ help=("Disable use of rpath for library path in installed files"),
+ action="store_true", dest='disable_rpath_install', default=False)
+ gr.add_option('--disable-rpath-private-install',
+ help=("Disable use of rpath for private library path in installed files"),
+ action="store_true", dest='disable_rpath_private_install', default=False)
+ gr.add_option('--nonshared-binary',
+ help=("Disable use of shared libs for the listed binaries"),
+ action="store", dest='NONSHARED_BINARIES', default='')
+ gr.add_option('--disable-symbol-versions',
+ help=("Disable use of the --version-script linker option"),
+ action="store_true", dest='disable_symbol_versions', default=False)
+
+ opt.add_option('--with-modulesdir',
+ help=("modules directory [PREFIX/modules]"),
+ action="store", dest='MODULESDIR', default='${PREFIX}/modules')
+
+ opt.add_option('--with-privatelibdir',
+ help=("private library directory [PREFIX/lib/%s]" % Utils.g_module.APPNAME),
+ action="store", dest='PRIVATELIBDIR', default=None)
+
+ gr = opt.option_group('developer options')
+
+ gr.add_option('-C',
+ help='enable configure cacheing',
+ action='store_true', dest='enable_configure_cache')
+ gr.add_option('--enable-auto-reconfigure',
+ help='enable automatic reconfigure on build',
+ action='store_true', dest='enable_auto_reconfigure')
+ gr.add_option('--enable-developer',
+ help=("Turn on developer warnings and debugging"),
+ action="store_true", dest='developer', default=False)
+ gr.add_option('--picky-developer',
+ help=("Treat all warnings as errors (enable -Werror)"),
+ action="store_true", dest='picky_developer', default=False)
+ gr.add_option('--fatal-errors',
+ help=("Stop compilation on first error (enable -Wfatal-errors)"),
+ action="store_true", dest='fatal_errors', default=False)
+ gr.add_option('--enable-gccdeps',
+ help=("Enable use of gcc -MD dependency module"),
+ action="store_true", dest='enable_gccdeps', default=True)
+ gr.add_option('--timestamp-dependencies',
+ help=("use file timestamps instead of content for build dependencies (BROKEN)"),
+ action="store_true", dest='timestamp_dependencies', default=False)
+ gr.add_option('--pedantic',
+ help=("Enable even more compiler warnings"),
+ action='store_true', dest='pedantic', default=False)
+ gr.add_option('--git-local-changes',
+ help=("mark version with + if local git changes"),
+ action='store_true', dest='GIT_LOCAL_CHANGES', default=False)
+
+ gr.add_option('--abi-check',
+ help=("Check ABI signatures for libraries"),
+ action='store_true', dest='ABI_CHECK', default=False)
+ gr.add_option('--abi-check-disable',
+ help=("Disable ABI checking (used with --enable-developer)"),
+ action='store_true', dest='ABI_CHECK_DISABLE', default=False)
+ gr.add_option('--abi-update',
+ help=("Update ABI signature files for libraries"),
+ action='store_true', dest='ABI_UPDATE', default=False)
+
+ gr.add_option('--show-deps',
+ help=("Show dependency tree for the given target"),
+ dest='SHOWDEPS', default='')
+
+ gr.add_option('--symbol-check',
+ help=("check symbols in object files against project rules"),
+ action='store_true', dest='SYMBOLCHECK', default=False)
+
+ gr.add_option('--why-needed',
+ help=("TARGET:DEPENDENCY check why TARGET needs DEPENDENCY"),
+ action='store', type='str', dest='WHYNEEDED', default=None)
+
+ gr.add_option('--show-duplicates',
+ help=("Show objects which are included in multiple binaries or libraries"),
+ action='store_true', dest='SHOW_DUPLICATES', default=False)
+
+ gr = opt.add_option_group('cross compilation options')
+
+ gr.add_option('--cross-compile',
+ help=("configure for cross-compilation"),
+ action='store_true', dest='CROSS_COMPILE', default=False)
+ gr.add_option('--cross-execute',
+ help=("command prefix to use for cross-execution in configure"),
+ action='store', dest='CROSS_EXECUTE', default='')
+ gr.add_option('--cross-answers',
+ help=("answers to cross-compilation configuration (auto modified)"),
+ action='store', dest='CROSS_ANSWERS', default='')
+ gr.add_option('--hostcc',
+ help=("set host compiler when cross compiling"),
+ action='store', dest='HOSTCC', default=False)
+
+ # we use SUPPRESS_HELP for these, as they are ignored, and are there only
+ # to allow existing RPM spec files to work
+ opt.add_option('--build',
+ help=SUPPRESS_HELP,
+ action='store', dest='AUTOCONF_BUILD', default='')
+ opt.add_option('--host',
+ help=SUPPRESS_HELP,
+ action='store', dest='AUTOCONF_HOST', default='')
+ opt.add_option('--program-prefix',
+ help=SUPPRESS_HELP,
+ action='store', dest='AUTOCONF_PROGRAM_PREFIX', default='')
+ opt.add_option('--disable-dependency-tracking',
+ help=SUPPRESS_HELP,
+ action='store_true', dest='AUTOCONF_DISABLE_DEPENDENCY_TRACKING', default=False)
+
+ gr = opt.option_group('dist options')
+ gr.add_option('--sign-release',
+ help='sign the release tarball created by waf dist',
+ action='store_true', dest='SIGN_RELEASE')
+ gr.add_option('--tag',
+ help='tag release in git at the same time',
+ type='string', action='store', dest='TAG_RELEASE')
+
+
+@wafsamba.runonce
+def configure(conf):
+ conf.env.hlist = []
+ conf.env.srcdir = conf.srcdir
+
+ if Options.options.timestamp_dependencies:
+ conf.ENABLE_TIMESTAMP_DEPENDENCIES()
+
+ conf.SETUP_CONFIGURE_CACHE(Options.options.enable_configure_cache)
+
+ # load our local waf extensions
+ conf.check_tool('gnu_dirs')
+ conf.check_tool('wafsamba')
+
+ conf.CHECK_CC_ENV()
+
+ conf.check_tool('compiler_cc')
+
+ # we need git for 'waf dist'
+ conf.find_program('git', var='GIT')
+
+ # older gcc versions (< 4.4) does not work with gccdeps, so we have to see if the .d file is generated
+ if Options.options.enable_gccdeps:
+ from TaskGen import feature, after
+ @feature('testd')
+ @after('apply_core')
+ def check_d(self):
+ tsk = self.compiled_tasks[0]
+ tsk.outputs.append(tsk.outputs[0].change_ext('.d'))
+
+ import Task
+ cc = Task.TaskBase.classes['cc']
+ oldmeth = cc.run
+
+ cc.run = Task.compile_fun_noshell('cc', '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath(env)}')[0]
+ try:
+ try:
+ conf.check(features='cc testd', fragment='int main() {return 0;}\n', ccflags=['-MD'], mandatory=True, msg='Check for -MD')
+ except:
+ pass
+ else:
+ conf.check_tool('gccdeps', tooldir=conf.srcdir + "/buildtools/wafsamba")
+ finally:
+ cc.run = oldmeth
+
+ # make the install paths available in environment
+ conf.env.LIBDIR = Options.options.LIBDIR or '${PREFIX}/lib'
+ conf.env.BINDIR = Options.options.BINDIR or '${PREFIX}/bin'
+ conf.env.SBINDIR = Options.options.SBINDIR or '${PREFIX}/sbin'
+ conf.env.MODULESDIR = Options.options.MODULESDIR
+ conf.env.PRIVATELIBDIR = Options.options.PRIVATELIBDIR
+ conf.env.BUNDLED_LIBS = Options.options.BUNDLED_LIBS.split(',')
+ conf.env.BUILTIN_LIBRARIES = Options.options.BUILTIN_LIBRARIES.split(',')
+ conf.env.DISABLE_SHARED = Options.options.disable_shared
+ conf.env.NONSHARED_BINARIES = Options.options.NONSHARED_BINARIES.split(',')
+
+ conf.env.PRIVATE_EXTENSION = Options.options.PRIVATE_EXTENSION
+ conf.env.PRIVATE_EXTENSION_EXCEPTION = Options.options.PRIVATE_EXTENSION_EXCEPTION.split(',')
+
+ conf.env.CROSS_COMPILE = Options.options.CROSS_COMPILE
+ conf.env.CROSS_EXECUTE = Options.options.CROSS_EXECUTE
+ conf.env.CROSS_ANSWERS = Options.options.CROSS_ANSWERS
+ conf.env.HOSTCC = Options.options.HOSTCC
+
+ conf.env.AUTOCONF_BUILD = Options.options.AUTOCONF_BUILD
+ conf.env.AUTOCONF_HOST = Options.options.AUTOCONF_HOST
+ conf.env.AUTOCONF_PROGRAM_PREFIX = Options.options.AUTOCONF_PROGRAM_PREFIX
+
+ if (conf.env.AUTOCONF_HOST and
+ conf.env.AUTOCONF_BUILD and
+ conf.env.AUTOCONF_BUILD != conf.env.AUTOCONF_HOST):
+ Logs.error('ERROR: Mismatch between --build and --host. Please use --cross-compile instead')
+ sys.exit(1)
+ if conf.env.AUTOCONF_PROGRAM_PREFIX:
+ Logs.error('ERROR: --program-prefix not supported')
+ sys.exit(1)
+
+ # enable ABI checking for developers
+ conf.env.ABI_CHECK = Options.options.ABI_CHECK or Options.options.developer
+ if Options.options.ABI_CHECK_DISABLE:
+ conf.env.ABI_CHECK = False
+ try:
+ conf.find_program('gdb', mandatory=True)
+ except:
+ conf.env.ABI_CHECK = False
+
+ conf.env.GIT_LOCAL_CHANGES = Options.options.GIT_LOCAL_CHANGES
+
+ conf.CHECK_COMMAND(['uname', '-a'],
+ msg='Checking build system',
+ define='BUILD_SYSTEM',
+ on_target=False)
+ conf.CHECK_UNAME()
+
+ # see if we can compile and run a simple C program
+ conf.CHECK_CODE('printf("hello world")',
+ define='HAVE_SIMPLE_C_PROG',
+ mandatory=True,
+ execute=True,
+ headers='stdio.h',
+ msg='Checking simple C program')
+
+ # see if we can build shared libs
+ if not conf.CHECK_LIBRARY_SUPPORT():
+ conf.env.DISABLE_SHARED = True
+
+ # check for rpath
+ if not conf.env.DISABLE_SHARED and conf.CHECK_LIBRARY_SUPPORT(rpath=True):
+ support_rpath = True
+ conf.env.RPATH_ON_BUILD = not Options.options.disable_rpath_build
+ conf.env.RPATH_ON_INSTALL = (conf.env.RPATH_ON_BUILD and
+ not Options.options.disable_rpath_install)
+ if not conf.env.PRIVATELIBDIR:
+ conf.env.PRIVATELIBDIR = '%s/%s' % (conf.env.LIBDIR, Utils.g_module.APPNAME)
+ conf.env.RPATH_ON_INSTALL_PRIVATE = (
+ not Options.options.disable_rpath_private_install)
+ else:
+ support_rpath = False
+ conf.env.RPATH_ON_INSTALL = False
+ conf.env.RPATH_ON_BUILD = False
+ conf.env.RPATH_ON_INSTALL_PRIVATE = False
+ if not conf.env.PRIVATELIBDIR:
+ # rpath is not possible so there is no sense in having a
+ # private library directory by default.
+ # the user can of course always override it.
+ conf.env.PRIVATELIBDIR = conf.env.LIBDIR
+
+ if (not conf.env.DISABLE_SHARED and
+ not Options.options.disable_symbol_versions and
+ conf.CHECK_LIBRARY_SUPPORT(rpath=support_rpath,
+ version_script=True,
+ msg='-Wl,--version-script support')):
+ conf.env.HAVE_LD_VERSION_SCRIPT = True
+ else:
+ conf.env.HAVE_LD_VERSION_SCRIPT = False
+
+ if sys.platform == "aix5":
+ conf.DEFINE('_ALL_SOURCE', 1, add_to_cflags=True)
+ # Might not be needed if ALL_SOURCE is defined
+ # conf.DEFINE('_XOPEN_SOURCE', 600, add_to_cflags=True)
+
+ # we should use the PIC options in waf instead
+ # Some compilo didn't support -fPIC but just print a warning
+ if conf.env['COMPILER_CC'] == "suncc":
+ conf.ADD_CFLAGS('-KPIC', testflags=True)
+ # we really want define here as we need to have this
+ # define even during the tests otherwise detection of
+ # boolean is broken
+ conf.DEFINE('_STDC_C99', 1, add_to_cflags=True)
+ conf.DEFINE('_XPG6', 1, add_to_cflags=True)
+ else:
+ conf.ADD_CFLAGS('-fPIC', testflags=True)
+
+ # On Solaris 8 with suncc (at least) the flags for the linker to define the name of the
+ # library are not always working (if the command line is very very long and with a lot
+ # files)
+
+ if conf.env['COMPILER_CC'] == "suncc":
+ save = conf.env['SONAME_ST']
+ conf.env['SONAME_ST'] = '-Wl,-h,%s'
+ if not conf.CHECK_SHLIB_INTRASINC_NAME_FLAGS("Checking if flags %s are ok" % conf.env['SONAME_ST']):
+ conf.env['SONAME_ST'] = save
+
+ conf.CHECK_INLINE()
+
+ # check for pkgconfig
+ conf.check_cfg(atleast_pkgconfig_version='0.0.0')
+
+ conf.DEFINE('_GNU_SOURCE', 1, add_to_cflags=True)
+ conf.DEFINE('_XOPEN_SOURCE_EXTENDED', 1, add_to_cflags=True)
+
+ # get the base headers we'll use for the rest of the tests
+ conf.CHECK_HEADERS('stdio.h sys/types.h sys/stat.h stdlib.h stddef.h memory.h string.h',
+ add_headers=True)
+ conf.CHECK_HEADERS('strings.h inttypes.h stdint.h unistd.h minix/config.h', add_headers=True)
+ conf.CHECK_HEADERS('ctype.h standards.h stdbool.h stdint.h stdarg.h vararg.h', add_headers=True)
+ conf.CHECK_HEADERS('limits.h assert.h')
+
+ # see if we need special largefile flags
+ conf.CHECK_LARGEFILE()
+
+ if 'HAVE_STDDEF_H' in conf.env and 'HAVE_STDLIB_H' in conf.env:
+ conf.DEFINE('STDC_HEADERS', 1)
+
+ conf.CHECK_HEADERS('sys/time.h time.h', together=True)
+
+ if 'HAVE_SYS_TIME_H' in conf.env and 'HAVE_TIME_H' in conf.env:
+ conf.DEFINE('TIME_WITH_SYS_TIME', 1)
+
+ # cope with different extensions for libraries
+ (root, ext) = os.path.splitext(conf.env.shlib_PATTERN)
+ if ext[0] == '.':
+ conf.define('SHLIBEXT', ext[1:], quote=True)
+ else:
+ conf.define('SHLIBEXT', "so", quote=True)
+
+ conf.CHECK_CODE('long one = 1; return ((char *)(&one))[0]',
+ execute=True,
+ define='WORDS_BIGENDIAN')
+
+ # check if signal() takes a void function
+ if conf.CHECK_CODE('return *(signal (0, 0)) (0) == 1',
+ define='RETSIGTYPE_INT',
+ execute=False,
+ headers='signal.h',
+ msg='Checking if signal handlers return int'):
+ conf.DEFINE('RETSIGTYPE', 'int')
+ else:
+ conf.DEFINE('RETSIGTYPE', 'void')
+
+ conf.CHECK_VARIABLE('__FUNCTION__', define='HAVE_FUNCTION_MACRO')
+
+ conf.CHECK_CODE('va_list ap1,ap2; va_copy(ap1,ap2)',
+ define="HAVE_VA_COPY",
+ msg="Checking for va_copy")
+
+ conf.CHECK_CODE('''
+ #define eprintf(...) fprintf(stderr, __VA_ARGS__)
+ eprintf("bla", "bar")
+ ''', define='HAVE__VA_ARGS__MACRO')
+
+ conf.SAMBA_BUILD_ENV()
+
+
+def build(bld):
+ # give a more useful message if the source directory has moved
+ relpath = os_path_relpath(bld.curdir, bld.srcnode.abspath())
+ if relpath.find('../') != -1:
+ Logs.error('bld.curdir %s is not a child of %s' % (bld.curdir, bld.srcnode.abspath()))
+ raise Utils.WafError('''The top source directory has moved. Please run distclean and reconfigure''')
+
+ bld.CHECK_MAKEFLAGS()
+ bld.SETUP_BUILD_GROUPS()
+ bld.ENFORCE_GROUP_ORDERING()
+ bld.CHECK_PROJECT_RULES()