1 | # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/ |
---|
2 | # All rights reserved |
---|
3 | |
---|
4 | # @synopsis: |
---|
5 | # |
---|
6 | # This module supports common system interrogation and options |
---|
7 | # such as '--host', '--build', '--prefix', and setting 'srcdir', 'builddir', and 'EXEEXT'. |
---|
8 | # |
---|
9 | # It also support the "feature" naming convention, where searching |
---|
10 | # for a feature such as 'sys/type.h' defines 'HAVE_SYS_TYPES_H'. |
---|
11 | # |
---|
12 | # It defines the following variables, based on '--prefix' unless overridden by the user: |
---|
13 | # |
---|
14 | ## datadir |
---|
15 | ## sysconfdir |
---|
16 | ## sharedstatedir |
---|
17 | ## localstatedir |
---|
18 | ## infodir |
---|
19 | ## mandir |
---|
20 | ## includedir |
---|
21 | # |
---|
22 | # If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before* |
---|
23 | # including the 'system' module. |
---|
24 | |
---|
25 | if {[is-defined defaultprefix]} { |
---|
26 | user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options" |
---|
27 | options-defaults [list prefix [get-define defaultprefix]] |
---|
28 | } |
---|
29 | |
---|
30 | module-options [subst -noc -nob { |
---|
31 | host:host-alias => {a complete or partial cpu-vendor-opsys for the system where |
---|
32 | the application will run (defaults to the same value as --build)} |
---|
33 | build:build-alias => {a complete or partial cpu-vendor-opsys for the system |
---|
34 | where the application will be built (defaults to the |
---|
35 | result of running config.guess)} |
---|
36 | prefix:dir=/usr/local => {the target directory for the build (default: '@default@')} |
---|
37 | |
---|
38 | # These (hidden) options are supported for autoconf/automake compatibility |
---|
39 | exec-prefix: |
---|
40 | bindir: |
---|
41 | sbindir: |
---|
42 | includedir: |
---|
43 | mandir: |
---|
44 | infodir: |
---|
45 | libexecdir: |
---|
46 | datadir: |
---|
47 | libdir: |
---|
48 | sysconfdir: |
---|
49 | sharedstatedir: |
---|
50 | localstatedir: |
---|
51 | runstatedir: |
---|
52 | maintainer-mode=0 |
---|
53 | dependency-tracking=0 |
---|
54 | silent-rules=0 |
---|
55 | }] |
---|
56 | |
---|
57 | # @check-feature name { script } |
---|
58 | # |
---|
59 | # defines feature '$name' to the return value of '$script', |
---|
60 | # which should be 1 if found or 0 if not found. |
---|
61 | # |
---|
62 | # e.g. the following will define 'HAVE_CONST' to 0 or 1. |
---|
63 | # |
---|
64 | ## check-feature const { |
---|
65 | ## cctest -code {const int _x = 0;} |
---|
66 | ## } |
---|
67 | proc check-feature {name code} { |
---|
68 | msg-checking "Checking for $name..." |
---|
69 | set r [uplevel 1 $code] |
---|
70 | define-feature $name $r |
---|
71 | if {$r} { |
---|
72 | msg-result "ok" |
---|
73 | } else { |
---|
74 | msg-result "not found" |
---|
75 | } |
---|
76 | return $r |
---|
77 | } |
---|
78 | |
---|
79 | # @have-feature name ?default=0? |
---|
80 | # |
---|
81 | # Returns the value of feature '$name' if defined, or '$default' if not. |
---|
82 | # |
---|
83 | # See 'feature-define-name' for how the "feature" name |
---|
84 | # is translated into the "define" name. |
---|
85 | # |
---|
86 | proc have-feature {name {default 0}} { |
---|
87 | get-define [feature-define-name $name] $default |
---|
88 | } |
---|
89 | |
---|
90 | # @define-feature name ?value=1? |
---|
91 | # |
---|
92 | # Sets the feature 'define' to '$value'. |
---|
93 | # |
---|
94 | # See 'feature-define-name' for how the "feature" name |
---|
95 | # is translated into the "define" name. |
---|
96 | # |
---|
97 | proc define-feature {name {value 1}} { |
---|
98 | define [feature-define-name $name] $value |
---|
99 | } |
---|
100 | |
---|
101 | # @feature-checked name |
---|
102 | # |
---|
103 | # Returns 1 if feature '$name' has been checked, whether true or not. |
---|
104 | # |
---|
105 | proc feature-checked {name} { |
---|
106 | is-defined [feature-define-name $name] |
---|
107 | } |
---|
108 | |
---|
109 | # @feature-define-name name ?prefix=HAVE_? |
---|
110 | # |
---|
111 | # Converts a "feature" name to the corresponding "define", |
---|
112 | # e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'. |
---|
113 | # |
---|
114 | # Converts '*' to 'P' and all non-alphanumeric to underscore. |
---|
115 | # |
---|
116 | proc feature-define-name {name {prefix HAVE_}} { |
---|
117 | string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _] |
---|
118 | } |
---|
119 | |
---|
120 | # @write-if-changed filename contents ?script? |
---|
121 | # |
---|
122 | # If '$filename' doesn't exist, or it's contents are different to '$contents', |
---|
123 | # the file is written and '$script' is evaluated. |
---|
124 | # |
---|
125 | # Otherwise a "file is unchanged" message is displayed. |
---|
126 | proc write-if-changed {file buf {script {}}} { |
---|
127 | set old [readfile $file ""] |
---|
128 | if {$old eq $buf && [file exists $file]} { |
---|
129 | msg-result "$file is unchanged" |
---|
130 | } else { |
---|
131 | writefile $file $buf\n |
---|
132 | uplevel 1 $script |
---|
133 | } |
---|
134 | } |
---|
135 | |
---|
136 | # @make-template template ?outfile? |
---|
137 | # |
---|
138 | # Reads the input file '<srcdir>/$template' and writes the output file '$outfile' |
---|
139 | # (unless unchanged). |
---|
140 | # If '$outfile' is blank/omitted, '$template' should end with '.in' which |
---|
141 | # is removed to create the output file name. |
---|
142 | # |
---|
143 | # Each pattern of the form '@define@' is replaced with the corresponding |
---|
144 | # "define", if it exists, or left unchanged if not. |
---|
145 | # |
---|
146 | # The special value '@srcdir@' is substituted with the relative |
---|
147 | # path to the source directory from the directory where the output |
---|
148 | # file is created, while the special value '@top_srcdir@' is substituted |
---|
149 | # with the relative path to the top level source directory. |
---|
150 | # |
---|
151 | # Conditional sections may be specified as follows: |
---|
152 | ## @if NAME eq "value" |
---|
153 | ## lines |
---|
154 | ## @else |
---|
155 | ## lines |
---|
156 | ## @endif |
---|
157 | # |
---|
158 | # Where 'NAME' is a defined variable name and '@else' is optional. |
---|
159 | # Note that variables names *must* start with an uppercase letter. |
---|
160 | # If the expression does not match, all lines through '@endif' are ignored. |
---|
161 | # |
---|
162 | # The alternative forms may also be used: |
---|
163 | ## @if NAME (true if the variable is defined, but not empty and not "0") |
---|
164 | ## @if !NAME (opposite of the form above) |
---|
165 | ## @if <general-tcl-expression> |
---|
166 | # |
---|
167 | # In the general Tcl expression, any words beginning with an uppercase letter |
---|
168 | # are translated into [get-define NAME] |
---|
169 | # |
---|
170 | # Expressions may be nested |
---|
171 | # |
---|
172 | proc make-template {template {out {}}} { |
---|
173 | set infile [file join $::autosetup(srcdir) $template] |
---|
174 | |
---|
175 | if {![file exists $infile]} { |
---|
176 | user-error "Template $template is missing" |
---|
177 | } |
---|
178 | |
---|
179 | # Define this as late as possible |
---|
180 | define AUTODEPS $::autosetup(deps) |
---|
181 | |
---|
182 | if {$out eq ""} { |
---|
183 | if {[file ext $template] ne ".in"} { |
---|
184 | autosetup-error "make_template $template has no target file and can't guess" |
---|
185 | } |
---|
186 | set out [file rootname $template] |
---|
187 | } |
---|
188 | |
---|
189 | set outdir [file dirname $out] |
---|
190 | |
---|
191 | # Make sure the directory exists |
---|
192 | file mkdir $outdir |
---|
193 | |
---|
194 | # Set up srcdir and top_srcdir to be relative to the target dir |
---|
195 | define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] |
---|
196 | define top_srcdir [relative-path $::autosetup(srcdir) $outdir] |
---|
197 | |
---|
198 | set mapping {} |
---|
199 | foreach {n v} [array get ::define] { |
---|
200 | lappend mapping @$n@ $v |
---|
201 | } |
---|
202 | |
---|
203 | # A stack of true/false conditions, one for each nested conditional |
---|
204 | # starting with "true" |
---|
205 | set condstack {1} |
---|
206 | set result {} |
---|
207 | set linenum 0 |
---|
208 | foreach line [split [readfile $infile] \n] { |
---|
209 | incr linenum |
---|
210 | if {[regexp {^@(if|else|endif)\s*(.*)} $line -> condtype condargs]} { |
---|
211 | if {$condtype eq "if"} { |
---|
212 | if {[llength $condargs] == 1} { |
---|
213 | # ABC => [get-define ABC] ni {0 ""} |
---|
214 | # !ABC => [get-define ABC] in {0 ""} |
---|
215 | lassign $condargs condvar |
---|
216 | if {[regexp {^!(.*)} $condvar -> condvar]} { |
---|
217 | set op in |
---|
218 | } else { |
---|
219 | set op ni |
---|
220 | } |
---|
221 | set condexpr "\[[list get-define $condvar]\] $op {0 {}}" |
---|
222 | } else { |
---|
223 | # Translate alphanumeric ABC into [get-define ABC] and leave the |
---|
224 | # rest of the expression untouched |
---|
225 | regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr |
---|
226 | } |
---|
227 | if {[catch [list expr $condexpr] condval]} { |
---|
228 | dputs $condval |
---|
229 | autosetup-error "$infile:$linenum: Invalid expression: $line" |
---|
230 | } |
---|
231 | dputs "@$condtype: $condexpr => $condval" |
---|
232 | } |
---|
233 | if {$condtype ne "if" && [llength $condstack] <= 1} { |
---|
234 | autosetup-error "$infile:$linenum: Error: @$condtype missing @if" |
---|
235 | } |
---|
236 | switch -exact $condtype { |
---|
237 | if { |
---|
238 | # push condval |
---|
239 | lappend condstack $condval |
---|
240 | } |
---|
241 | else { |
---|
242 | # Toggle the last entry |
---|
243 | set condval [lpop condstack] |
---|
244 | set condval [expr {!$condval}] |
---|
245 | lappend condstack $condval |
---|
246 | } |
---|
247 | endif { |
---|
248 | if {[llength $condstack] == 0} { |
---|
249 | user-notice "$infile:$linenum: Error: @endif missing @if" |
---|
250 | } |
---|
251 | lpop condstack |
---|
252 | } |
---|
253 | } |
---|
254 | continue |
---|
255 | } |
---|
256 | # Only output this line if the stack contains all "true" |
---|
257 | if {"0" in $condstack} { |
---|
258 | continue |
---|
259 | } |
---|
260 | lappend result $line |
---|
261 | } |
---|
262 | write-if-changed $out [string map $mapping [join $result \n]] { |
---|
263 | msg-result "Created [relative-path $out] from [relative-path $template]" |
---|
264 | } |
---|
265 | } |
---|
266 | |
---|
267 | # build/host tuples and cross-compilation prefix |
---|
268 | opt-str build build "" |
---|
269 | define build_alias $build |
---|
270 | if {$build eq ""} { |
---|
271 | define build [config_guess] |
---|
272 | } else { |
---|
273 | define build [config_sub $build] |
---|
274 | } |
---|
275 | |
---|
276 | opt-str host host "" |
---|
277 | define host_alias $host |
---|
278 | if {$host eq ""} { |
---|
279 | define host [get-define build] |
---|
280 | set cross "" |
---|
281 | } else { |
---|
282 | define host [config_sub $host] |
---|
283 | set cross $host- |
---|
284 | } |
---|
285 | define cross [get-env CROSS $cross] |
---|
286 | |
---|
287 | # build/host _cpu, _vendor and _os |
---|
288 | foreach type {build host} { |
---|
289 | set v [get-define $type] |
---|
290 | if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} { |
---|
291 | user-error "Invalid canonical $type: $v" |
---|
292 | } |
---|
293 | define ${type}_cpu $cpu |
---|
294 | define ${type}_vendor $vendor |
---|
295 | define ${type}_os $os |
---|
296 | } |
---|
297 | |
---|
298 | opt-str prefix prefix /usr/local |
---|
299 | |
---|
300 | # These are for compatibility with autoconf |
---|
301 | define target [get-define host] |
---|
302 | define prefix $prefix |
---|
303 | define builddir $autosetup(builddir) |
---|
304 | define srcdir $autosetup(srcdir) |
---|
305 | define top_srcdir $autosetup(srcdir) |
---|
306 | define abs_top_srcdir [file-normalize $autosetup(srcdir)] |
---|
307 | define abs_top_builddir [file-normalize $autosetup(builddir)] |
---|
308 | |
---|
309 | # autoconf supports all of these |
---|
310 | define exec_prefix [opt-str exec-prefix exec_prefix $prefix] |
---|
311 | foreach {name defpath} { |
---|
312 | bindir /bin |
---|
313 | sbindir /sbin |
---|
314 | libexecdir /libexec |
---|
315 | libdir /lib |
---|
316 | } { |
---|
317 | define $name [opt-str $name o $exec_prefix$defpath] |
---|
318 | } |
---|
319 | foreach {name defpath} { |
---|
320 | datadir /share |
---|
321 | sharedstatedir /com |
---|
322 | infodir /share/info |
---|
323 | mandir /share/man |
---|
324 | includedir /include |
---|
325 | } { |
---|
326 | define $name [opt-str $name o $prefix$defpath] |
---|
327 | } |
---|
328 | if {$prefix ne {/usr}} { |
---|
329 | opt-str sysconfdir sysconfdir $prefix/etc |
---|
330 | } else { |
---|
331 | opt-str sysconfdir sysconfdir /etc |
---|
332 | } |
---|
333 | define sysconfdir $sysconfdir |
---|
334 | |
---|
335 | define localstatedir [opt-str localstatedir o /var] |
---|
336 | define runstatedir [opt-str runstatedir o /run] |
---|
337 | |
---|
338 | define SHELL [get-env SHELL [find-an-executable sh bash ksh]] |
---|
339 | |
---|
340 | # These could be used to generate Makefiles following some automake conventions |
---|
341 | define AM_SILENT_RULES [opt-bool silent-rules] |
---|
342 | define AM_MAINTAINER_MODE [opt-bool maintainer-mode] |
---|
343 | define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking] |
---|
344 | |
---|
345 | # Windows vs. non-Windows |
---|
346 | switch -glob -- [get-define host] { |
---|
347 | *-*-ming* - *-*-cygwin - *-*-msys { |
---|
348 | define-feature windows |
---|
349 | define EXEEXT .exe |
---|
350 | } |
---|
351 | default { |
---|
352 | define EXEEXT "" |
---|
353 | } |
---|
354 | } |
---|
355 | |
---|
356 | # Display |
---|
357 | msg-result "Host System...[get-define host]" |
---|
358 | msg-result "Build System...[get-define build]" |
---|