build: Allow overriding CFLAGS for python packages.
[ira/wip.git] / source / build / smb_build / config_mk.pm
index 49b93a5d980693c54bda998c9ceda522aeb7e658..d07660ba1d826365c39a06f8bd3b7e9bdbc26a76 100644 (file)
-###########################################################
-### SMB Build System                                   ###
-### - config.mk parsing functions                      ###
-###                                                    ###
-###  Copyright (C) Stefan (metze) Metzmacher 2004      ###
-###  Released under the GNU GPL                                ###
-###########################################################
+# Samba Build System
+# - config.mk parsing functions
+#
+#  Copyright (C) Stefan (metze) Metzmacher 2004
+#  Copyright (C) Jelmer Vernooij 2005
+#  Released under the GNU GPL
+#
 
 package smb_build::config_mk;
 use smb_build::input;
+use File::Basename;
 
 use strict;
 
-my %attribute_types = (
-       "NOPROTO" => "bool",
-       "REQUIRED_SUBSYSTEMS" => "list",
-       "OUTPUT_TYPE" => "string",
-       "INIT_OBJ_FILES" => "list",
-       "ADD_OBJ_FILES" => "list",
-       "OBJ_FILES" => "list",
-       "SUBSYSTEM" => "string",
-       "CFLAGS" => "list",
-       "CPPFLAGS" => "list",
-       "LDFLAGS" => "list",
-       "INSTALLDIR" => "string",
-       "LIBS" => "list",
-       "INIT_FUNCTION" => "string",
-       "MAJOR_VERSION" => "string",
-       "MINOR_VERSION" => "string",
-       "RELEASE_VERSION" => "string",
-       "ENABLE" => "bool",
-       "CMD" => "string",
-       "MANPAGE" => "string"
-);
+my $section_types = {
+       "EXT_LIB" => {
+               "LIBS"                  => "list",
+               "CFLAGS"                => "list",
+               "CPPFLAGS"              => "list",
+               "LDFLAGS"               => "list",
+               "PC_NAME" => "string",
+               },
+       "PYTHON" => {
+               SWIG_FILE => "string",
+               "PRIVATE_DEPENDENCIES"  => "list",
+               "PUBLIC_DEPENDENCIES"   => "list",
+               "OBJ_FILES" => "list",
+               "ENABLE"                => "bool",
+               "LDFLAGS"               => "list",
+               "CFLAGS"                => "list",
+       },
+       "SUBSYSTEM" => {
+               "OBJ_FILES"             => "list",
+
+               "PRIVATE_DEPENDENCIES"  => "list",
+               "PUBLIC_DEPENDENCIES"   => "list",
+
+               "ENABLE"                => "bool",
+
+               "MANPAGE"               => "string",
+
+               "PUBLIC_PROTO_HEADER"   => "string",
+               "PRIVATE_PROTO_HEADER"  => "string",
+
+               "PUBLIC_HEADERS"        => "list",
+
+               "CFLAGS"                => "list",
+               "LDFLAGS"               => "list",
+               "STANDARD_VISIBILITY"   => "string",
+               "INIT_FUNCTION_SENTINEL" => "string"
+               },
+       "MODULE" => {
+               "SUBSYSTEM"             => "string",
+
+               "INIT_FUNCTION"         => "string",
+               "OBJ_FILES"             => "list",
+
+               "PRIVATE_DEPENDENCIES"  => "list",
+
+               "ALIASES" => "list",
+
+               "ENABLE"                => "bool",
+
+               "OUTPUT_TYPE"           => "list",
+
+               "MANPAGE"               => "string",
+               "PRIVATE_PROTO_HEADER"  => "string",
+
+               "CFLAGS"                => "list"
+               },
+       "BINARY" => {
+               "OBJ_FILES"             => "list",
+
+               "PRIVATE_DEPENDENCIES"  => "list",
+
+               "ENABLE"                => "bool",
+
+               "MANPAGE"               => "string",
+               "INSTALLDIR"            => "string",
+               "PRIVATE_PROTO_HEADER"  => "string",
+
+               "CFLAGS"                => "list",
+               "LDFLAGS"               => "list",
+               "STANDARD_VISIBILITY"   => "string",
+
+               "USE_HOSTCC"            => "bool"
+               },
+       "LIBRARY" => {
+               "VERSION"               => "string",
+               "SO_VERSION"            => "string",
+               "LIBRARY_REALNAME" => "string",
+
+               "PC_NAME" => "string",
+               
+               "INIT_FUNCTION_TYPE"    => "string",
+               "INIT_FUNCTION_SENTINEL" => "string",
+               "OUTPUT_TYPE"           => "list",
+
+               "OBJ_FILES"             => "list",
+
+               "DESCRIPTION"           => "string",
+
+               "PRIVATE_DEPENDENCIES"  => "list",
+               "PUBLIC_DEPENDENCIES"   => "list",
+
+               "ENABLE"                => "bool",
+
+               "MANPAGE"               => "string",
+
+               "PUBLIC_HEADERS"        => "list",
+
+               "PUBLIC_PROTO_HEADER"   => "string",
+               "PRIVATE_PROTO_HEADER"  => "string",
+
+               "CFLAGS"                => "list",
+               "LDFLAGS"               => "list",
+               "STANDARD_VISIBILITY"   => "string"
+               }
+};
 
 use vars qw(@parsed_files);
 
 @parsed_files = ();
 
+sub _read_config_file
+{
+       use File::Basename;
+       use Cwd;
+
+       my $srcdir = shift;
+       my $builddir = shift;
+       my $filename = shift;
+       my @dirlist;
+
+       # We need to change our working directory because config.mk files can
+       # give shell commands as the argument to "include". These shell
+       # commands can take arguments that are relative paths and we don't have
+       # a way of sensibly rewriting these.
+       my $cwd = getcwd;
+       chomp $cwd;
+
+       if ($srcdir ne $builddir) {
+               # Push the builddir path on the front, so we prefer builddir
+               # to srcdir when the file exists in both.
+               @dirlist = ($builddir, $srcdir);
+       } else {
+               @dirlist = ($srcdir);
+       }
+
+       foreach my $d (@dirlist) {
+               my @lines;
+               my $basedir;
+
+               chdir $cwd;
+               chdir $d;
+
+               # We need to catch the exception from open in the case where
+               # the filename is actually a shell pipeline. Why is this
+               # different to opening a regular file? Because this is perl!
+               eval {
+                       open(CONFIG_MK, "./$filename");
+                       @lines = <CONFIG_MK>;
+                       close(CONFIG_MK);
+               };
+
+               chdir $cwd;
+               next unless (@lines);
+
+               # I blame abartlett for this crazy hack -- jpeach
+               if ($filename =~ /\|$/) {
+                       $basedir = $builddir;
+               } else {
+                       $basedir = dirname($filename);
+                       push(@parsed_files, $filename);
+               }
+               $basedir =~ s!^($builddir|$srcdir)[/]!!;
+               return ($filename, $basedir, @lines);
+       }
+
+       chdir $cwd;
+       return;
+}
+
 ###########################################################
 # The parsing function which parses the file
 #
-# $result = _parse_config_mk($filename)
+# $result = _parse_config_mk($input, $srcdir, $builddir, $filename)
 #
 # $filename -  the path of the config.mk file
 #              which should be parsed
-sub run_config_mk($$)
+sub run_config_mk($$$$)
 {
-       my ($input, $filename) = @_;
+       sub run_config_mk($$$$);
+       my ($input, $srcdir, $builddir, $filename) = @_;
        my $result;
        my $linenum = -1;
        my $infragment = 0;
        my $section = "GLOBAL";
        my $makefile = "";
 
-       push (@parsed_files, $filename);
-       
-       open(CONFIG_MK, $filename) or die("Can't open `$filename'\n");
-       my @lines = <CONFIG_MK>;
-       close(CONFIG_MK);
+       my $basedir;
+
+       my $parsing_file;
+       my @lines;
+
+       $ENV{builddir} = $builddir;
+       $ENV{srcdir} = $srcdir;
+
+       ($parsing_file, $basedir, @lines) =
+           _read_config_file($srcdir, $builddir, $filename);
+
+       die ("$0: can't open '$filename'")
+               unless ($parsing_file and $basedir and @lines);
 
        my $line = "";
        my $prev = "";
 
+       # Emit a line that lets us match up final makefile output with the
+       # corresponding input files. The curlies are so you can match the
+       # BEGIN/END pairs in a text editor.
+       $makefile .= "# BEGIN{ $parsing_file\n";
+
        foreach (@lines) {
                $linenum++;
 
@@ -76,7 +234,7 @@ sub run_config_mk($$)
                        $prev = "";
                }
 
-               if ($line =~ /^\[([a-zA-Z0-9_:]+)\][\t ]*$/) 
+               if ($line =~ /^\[([-a-zA-Z0-9_:]+)\][\t ]*$/) 
                {
                        $section = $1;
                        $infragment = 0;
@@ -85,7 +243,12 @@ sub run_config_mk($$)
 
                # include
                if ($line =~ /^include (.*)$/) {
-                       $makefile .= run_config_mk($input, $1);
+                       my $subfile= $1;
+                       my $subdir = dirname($filename);
+                       $subdir =~ s/^\.$//g;
+                       $subdir =~ s/^\.\///g;
+                       $subdir .= "/" if ($subdir ne "");
+                       $makefile .= run_config_mk($input, $srcdir, $builddir, $subdir.$subfile);
                        next;
                }
 
@@ -98,6 +261,7 @@ sub run_config_mk($$)
 
                # global stuff is considered part of the makefile
                if ($section eq "GLOBAL") {
+                       if (!$infragment) { $makefile.="\n"; }
                        $makefile .= $line;
                        $infragment = 1;
                        next;
@@ -112,20 +276,29 @@ sub run_config_mk($$)
                        next;
                }
 
-               die("$filename:$linenum: Bad line while parsing $filename");
+               die("$parsing_file:$linenum: Bad line while parsing $parsing_file");
        }
 
+       $makefile .= "# }END $parsing_file\n";
+
        foreach my $section (keys %{$result}) {
                my ($type, $name) = split(/::/, $section, 2);
-               
+
+               my $sectype = $section_types->{$type};
+               if (not defined($sectype)) {
+                       die($parsing_file.":[".$section."] unknown section type \"".$type."\"!");
+               }
+
                $input->{$name}{NAME} = $name;
                $input->{$name}{TYPE} = $type;
+               $input->{$name}{MK_FILE} = $parsing_file;
+               $input->{$name}{BASEDIR} = $basedir;
 
                foreach my $key (values %{$result->{$section}}) {
                        $key->{VAL} = smb_build::input::strtrim($key->{VAL});
-                       my $vartype = $attribute_types{$key->{KEY}};
+                       my $vartype = $sectype->{$key->{KEY}};
                        if (not defined($vartype)) {
-                               die("$filename:Unknown attribute $key->{KEY} with value $key->{VAL} in section $section");
+                               die($parsing_file.":[".$section."]: unknown attribute type \"$key->{KEY}\"!");
                        }
                        if ($vartype eq "string") {
                                $input->{$name}{$key->{KEY}} = $key->{VAL};