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