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