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