Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-local
[kai/samba-autobuild/.git] / source4 / build / smb_build / config_mk.pm
1 # Samba Build System
2 # - config.mk parsing functions
3 #
4 #  Copyright (C) Stefan (metze) Metzmacher 2004
5 #  Copyright (C) Jelmer Vernooij 2005
6 #  Released under the GNU GPL
7 #
8
9 package smb_build::config_mk;
10 use smb_build::input;
11 use File::Basename;
12
13 use strict;
14
15 my $section_types = {
16         "EXT_LIB" => {
17                 "LIBS"                  => "list",
18                 "CFLAGS"                => "list",
19                 "CPPFLAGS"              => "list",
20                 "LDFLAGS"               => "list",
21                 },
22         "PYTHON" => {
23                 "LIBRARY_REALNAME" => "string",
24                 "PRIVATE_DEPENDENCIES"  => "list",
25                 "PUBLIC_DEPENDENCIES"   => "list",
26                 "ENABLE"                => "bool",
27                 "LDFLAGS"               => "list",
28         },
29         "SUBSYSTEM" => {
30                 "PRIVATE_DEPENDENCIES"  => "list",
31                 "PUBLIC_DEPENDENCIES"   => "list",
32
33                 "ENABLE"                => "bool",
34
35                 "CFLAGS"                => "list",
36                 "LDFLAGS"               => "list",
37                 "STANDARD_VISIBILITY"   => "string",
38                 "INIT_FUNCTION_SENTINEL" => "string"
39                 },
40         "MODULE" => {
41                 "SUBSYSTEM"             => "string",
42
43                 "INIT_FUNCTION"         => "string",
44
45                 "PRIVATE_DEPENDENCIES"  => "list",
46
47                 "ALIASES" => "list",
48
49                 "ENABLE"                => "bool",
50
51                 "OUTPUT_TYPE"           => "list",
52
53                 "CFLAGS"                => "list"
54                 },
55         "BINARY" => {
56
57                 "PRIVATE_DEPENDENCIES"  => "list",
58
59                 "ENABLE"                => "bool",
60
61                 "INSTALLDIR"            => "string",
62                 "LDFLAGS"               => "list",
63                 "STANDARD_VISIBILITY"   => "string",
64
65                 "USE_HOSTCC"            => "bool"
66                 },
67         "LIBRARY" => {
68                 "LIBRARY_REALNAME" => "string",
69
70                 "INIT_FUNCTION_TYPE"    => "string",
71                 "INIT_FUNCTION_SENTINEL" => "string",
72                 "OUTPUT_TYPE"           => "list",
73
74                 "PRIVATE_DEPENDENCIES"  => "list",
75                 "PUBLIC_DEPENDENCIES"   => "list",
76
77                 "ENABLE"                => "bool",
78
79                 "CFLAGS"                => "list",
80                 "LDFLAGS"               => "list",
81                 "STANDARD_VISIBILITY"   => "string"
82                 }
83 };
84
85 use vars qw(@parsed_files);
86
87 @parsed_files = ();
88
89 sub _read_config_file($$$)
90 {
91         use Cwd;
92
93         my ($srcdir, $builddir, $filename) = @_;
94         my @dirlist;
95
96         # We need to change our working directory because config.mk files can
97         # give shell commands as the argument to "include". These shell
98         # commands can take arguments that are relative paths and we don't have
99         # a way of sensibly rewriting these.
100         my $cwd = getcwd;
101         chomp $cwd;
102
103         if ($srcdir ne $builddir) {
104                 # Push the builddir path on the front, so we prefer builddir
105                 # to srcdir when the file exists in both.
106                 @dirlist = ($builddir, $srcdir);
107         } else {
108                 @dirlist = ($srcdir);
109         }
110
111         foreach my $d (@dirlist) {
112                 my @lines;
113                 my $basedir;
114
115                 chdir $cwd;
116                 chdir $d;
117
118                 # We need to catch the exception from open in the case where
119                 # the filename is actually a shell pipeline. Why is this
120                 # different to opening a regular file? Because this is perl!
121                 eval {
122                         open(CONFIG_MK, "./$filename");
123                         @lines = <CONFIG_MK>;
124                         close(CONFIG_MK);
125                 };
126
127                 chdir $cwd;
128                 next unless (@lines);
129
130                 # I blame abartlett for this crazy hack -- jpeach
131                 if ($filename =~ /\|$/) {
132                         $basedir = $builddir;
133                 } else {
134                         $basedir = dirname($filename);
135                         push(@parsed_files, $filename);
136                 }
137                 $basedir =~ s!^($builddir|$srcdir)[/]!!;
138                 return ($filename, $basedir, @lines);
139         }
140
141         chdir $cwd;
142         return;
143 }
144
145 ###########################################################
146 # The parsing function which parses the file
147 #
148 # $result = _parse_config_mk($input, $srcdir, $builddir, $filename)
149 #
150 # $filename -   the path of the config.mk file
151 #               which should be parsed
152 sub run_config_mk($$$$)
153 {
154         sub run_config_mk($$$$);
155         my ($input, $srcdir, $builddir, $filename) = @_;
156         my $result;
157         my $linenum = -1;
158         my $infragment = 0;
159         my $section = "GLOBAL";
160         my $makefile = "";
161
162         my $basedir;
163
164         my $parsing_file;
165         my @lines;
166
167         $ENV{builddir} = $builddir;
168         $ENV{srcdir} = $srcdir;
169
170         ($parsing_file, $basedir, @lines) =
171             _read_config_file($srcdir, $builddir, $filename);
172
173         die ("$0: can't open '$filename'")
174                 unless ($parsing_file and $basedir and @lines);
175
176         my $line = "";
177         my $prev = "";
178
179         # Emit a line that lets us match up final makefile output with the
180         # corresponding input files. The curlies are so you can match the
181         # BEGIN/END pairs in a text editor.
182         $makefile .= "# BEGIN{ $parsing_file\n";
183
184         foreach (@lines) {
185                 $linenum++;
186
187                 # lines beginning with '#' are ignored
188                 next if (/^\#.*$/);
189                 
190                 if (/^(.*)\\$/) {
191                         $prev .= $1;
192                         next;
193                 } else {
194                         $line = "$prev$_";
195                         $prev = "";
196                 }
197
198                 if ($line =~ /^\[([-a-zA-Z0-9_.:]+)\][\t ]*$/) 
199                 {
200                         $section = $1;
201                         $infragment = 0;
202
203                         $result->{$section}{EXISTS}{KEY} = "EXISTS";
204                         $result->{$section}{EXISTS}{VAL} = 1;
205                         next;
206                 }
207
208                 # include
209                 if ($line =~ /^mkinclude (.*)$/) {
210                         my $subfile= $1;
211                         my $subdir = dirname($filename);
212                         $subdir =~ s/^\.$//g;
213                         $subdir =~ s/^\.\///g;
214                         $subdir .= "/" if ($subdir ne "");
215                         $makefile .= "basedir := $subdir\n";
216                         $makefile .= run_config_mk($input, $srcdir, $builddir, $subdir.$subfile);
217                         next;
218                 }
219
220                 # empty line
221                 if ($line =~ /^[ \t]*$/) {
222                         $section = "GLOBAL";
223                         if ($infragment) { $makefile.="\n"; }
224                         next;
225                 }
226
227                 # global stuff is considered part of the makefile
228                 if ($section eq "GLOBAL") {
229                         if (!$infragment) { $makefile.="\n"; }
230                         $makefile .= $line;
231                         $infragment = 1;
232                         next;
233                 }
234                 
235                 # Assignment
236                 if ($line =~ /^([a-zA-Z0-9_]+)[\t ]*=(.*)$/) {
237                         $result->{$section}{$1}{VAL} = $2;
238                         $result->{$section}{$1}{KEY} = $1;
239                 
240                         next;
241                 }
242
243                 die("$parsing_file:$linenum: Bad line");
244         }
245
246         $makefile .= "# }END $parsing_file\n";
247
248         foreach my $section (keys %{$result}) {
249                 my ($type, $name) = split(/::/, $section, 2);
250
251                 my $sectype = $section_types->{$type};
252                 if (not defined($sectype)) {
253                         die($parsing_file.":[".$section."] unknown section type \"".$type."\"!");
254                 }
255
256                 $input->{$name}{NAME} = $name;
257                 $input->{$name}{TYPE} = $type;
258                 $input->{$name}{MK_FILE} = $parsing_file;
259                 $input->{$name}{BASEDIR} = $basedir;
260
261                 foreach my $key (values %{$result->{$section}}) {
262                         next if ($key->{KEY} eq "EXISTS");
263                         $key->{VAL} = smb_build::input::strtrim($key->{VAL});
264                         my $vartype = $sectype->{$key->{KEY}};
265                         if (not defined($vartype)) {
266                                 die($parsing_file.":[".$section."]: unknown attribute type \"$key->{KEY}\"!");
267                         }
268                         if ($vartype eq "string") {
269                                 $input->{$name}{$key->{KEY}} = $key->{VAL};
270                         } elsif ($vartype eq "list") {
271                                 $input->{$name}{$key->{KEY}} = [smb_build::input::str2array($key->{VAL})];
272                         } elsif ($vartype eq "bool") {
273                                 if (($key->{VAL} ne "YES") and ($key->{VAL} ne "NO")) {
274                                         die("Invalid value for bool attribute $key->{KEY}: $key->{VAL} in section $section");
275                                 }
276                                 $input->{$name}{$key->{KEY}} = $key->{VAL};
277                         }
278                 }
279         }
280
281         return $makefile;
282 }
283
284 1;