|
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 'options-defaults { prefix ... }' is used *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
|
options { |
|
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
|
program-prefix: |
|
56
|
program-suffix: |
|
57
|
program-transform-name: |
|
58
|
} |
|
59
|
|
|
60
|
# @check-feature name { script } |
|
61
|
# |
|
62
|
# defines feature '$name' to the return value of '$script', |
|
63
|
# which should be 1 if found or 0 if not found. |
|
64
|
# |
|
65
|
# e.g. the following will define 'HAVE_CONST' to 0 or 1. |
|
66
|
# |
|
67
|
## check-feature const { |
|
68
|
## cctest -code {const int _x = 0;} |
|
69
|
## } |
|
70
|
proc check-feature {name code} { |
|
71
|
msg-checking "Checking for $name..." |
|
72
|
set r [uplevel 1 $code] |
|
73
|
define-feature $name $r |
|
74
|
if {$r} { |
|
75
|
msg-result "ok" |
|
76
|
} else { |
|
77
|
msg-result "not found" |
|
78
|
} |
|
79
|
return $r |
|
80
|
} |
|
81
|
|
|
82
|
# @have-feature name ?default=0? |
|
83
|
# |
|
84
|
# Returns the value of feature '$name' if defined, or '$default' if not. |
|
85
|
# |
|
86
|
# See 'feature-define-name' for how the "feature" name |
|
87
|
# is translated into the "define" name. |
|
88
|
# |
|
89
|
proc have-feature {name {default 0}} { |
|
90
|
get-define [feature-define-name $name] $default |
|
91
|
} |
|
92
|
|
|
93
|
# @define-feature name ?value=1? |
|
94
|
# |
|
95
|
# Sets the feature 'define' to '$value'. |
|
96
|
# |
|
97
|
# See 'feature-define-name' for how the "feature" name |
|
98
|
# is translated into the "define" name. |
|
99
|
# |
|
100
|
proc define-feature {name {value 1}} { |
|
101
|
define [feature-define-name $name] $value |
|
102
|
} |
|
103
|
|
|
104
|
# @feature-checked name |
|
105
|
# |
|
106
|
# Returns 1 if feature '$name' has been checked, whether true or not. |
|
107
|
# |
|
108
|
proc feature-checked {name} { |
|
109
|
is-defined [feature-define-name $name] |
|
110
|
} |
|
111
|
|
|
112
|
# @feature-define-name name ?prefix=HAVE_? |
|
113
|
# |
|
114
|
# Converts a "feature" name to the corresponding "define", |
|
115
|
# e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'. |
|
116
|
# |
|
117
|
# Converts '*' to 'P' and all non-alphanumeric to underscore. |
|
118
|
# |
|
119
|
proc feature-define-name {name {prefix HAVE_}} { |
|
120
|
string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _] |
|
121
|
} |
|
122
|
|
|
123
|
# @write-if-changed filename contents ?script? |
|
124
|
# |
|
125
|
# If '$filename' doesn't exist, or it's contents are different to '$contents', |
|
126
|
# the file is written and '$script' is evaluated. |
|
127
|
# |
|
128
|
# Otherwise a "file is unchanged" message is displayed. |
|
129
|
proc write-if-changed {file buf {script {}}} { |
|
130
|
set old [readfile $file ""] |
|
131
|
if {$old eq $buf && [file exists $file]} { |
|
132
|
msg-result "$file is unchanged" |
|
133
|
} else { |
|
134
|
writefile $file $buf\n |
|
135
|
uplevel 1 $script |
|
136
|
} |
|
137
|
} |
|
138
|
|
|
139
|
|
|
140
|
# @include-file infile mapping |
|
141
|
# |
|
142
|
# The core of make-template, called recursively for each @include |
|
143
|
# directive found within that template so that this proc's result |
|
144
|
# is the fully-expanded template. |
|
145
|
# |
|
146
|
# The mapping parameter is how we expand @varname@ within the template. |
|
147
|
# We do that inline within this step only for @include directives which |
|
148
|
# can have variables in the filename arg. A separate substitution pass |
|
149
|
# happens when this recursive function returns, expanding the rest of |
|
150
|
# the variables. |
|
151
|
# |
|
152
|
proc include-file {infile mapping} { |
|
153
|
# A stack of true/false conditions, one for each nested conditional |
|
154
|
# starting with "true" |
|
155
|
set condstack {1} |
|
156
|
set result {} |
|
157
|
set linenum 0 |
|
158
|
foreach line [split [readfile $infile] \n] { |
|
159
|
incr linenum |
|
160
|
if {[regexp {^@(if|else|endif)(\s*)(.*)} $line -> condtype condspace condargs]} { |
|
161
|
if {$condtype eq "if"} { |
|
162
|
if {[string length $condspace] == 0} { |
|
163
|
autosetup-error "$infile:$linenum: Invalid expression: $line" |
|
164
|
} |
|
165
|
if {[llength $condargs] == 1} { |
|
166
|
# ABC => [get-define ABC] ni {0 ""} |
|
167
|
# !ABC => [get-define ABC] in {0 ""} |
|
168
|
lassign $condargs condvar |
|
169
|
if {[regexp {^!(.*)} $condvar -> condvar]} { |
|
170
|
set op in |
|
171
|
} else { |
|
172
|
set op ni |
|
173
|
} |
|
174
|
set condexpr "\[[list get-define $condvar]\] $op {0 {}}" |
|
175
|
} else { |
|
176
|
# Translate alphanumeric ABC into [get-define ABC] and leave the |
|
177
|
# rest of the expression untouched |
|
178
|
regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr |
|
179
|
} |
|
180
|
if {[catch [list expr $condexpr] condval]} { |
|
181
|
dputs $condval |
|
182
|
autosetup-error "$infile:$linenum: Invalid expression: $line" |
|
183
|
} |
|
184
|
dputs "@$condtype: $condexpr => $condval" |
|
185
|
} |
|
186
|
if {$condtype ne "if"} { |
|
187
|
if {[llength $condstack] <= 1} { |
|
188
|
autosetup-error "$infile:$linenum: Error: @$condtype missing @if" |
|
189
|
} elseif {[string length $condargs] && [string index $condargs 0] ne "#"} { |
|
190
|
autosetup-error "$infile:$linenum: Error: Extra arguments after @$condtype" |
|
191
|
} |
|
192
|
} |
|
193
|
switch -exact $condtype { |
|
194
|
if { |
|
195
|
# push condval |
|
196
|
lappend condstack $condval |
|
197
|
} |
|
198
|
else { |
|
199
|
# Toggle the last entry |
|
200
|
set condval [lpop condstack] |
|
201
|
set condval [expr {!$condval}] |
|
202
|
lappend condstack $condval |
|
203
|
} |
|
204
|
endif { |
|
205
|
if {[llength $condstack] == 0} { |
|
206
|
user-notice "$infile:$linenum: Error: @endif missing @if" |
|
207
|
} |
|
208
|
lpop condstack |
|
209
|
} |
|
210
|
} |
|
211
|
continue |
|
212
|
} |
|
213
|
# Only continue if the stack contains all "true" |
|
214
|
if {"0" in $condstack} { |
|
215
|
continue |
|
216
|
} |
|
217
|
if {[regexp {^@include\s+(.*)} $line -> filearg]} { |
|
218
|
set incfile [string map $mapping $filearg] |
|
219
|
if {[file exists $incfile]} { |
|
220
|
lappend ::autosetup(deps) [file-normalize $incfile] |
|
221
|
lappend result {*}[include-file $incfile $mapping] |
|
222
|
} else { |
|
223
|
user-error "$infile:$linenum: Include file $incfile is missing" |
|
224
|
} |
|
225
|
continue |
|
226
|
} |
|
227
|
if {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} { |
|
228
|
define $var $val |
|
229
|
continue |
|
230
|
} |
|
231
|
lappend result $line |
|
232
|
} |
|
233
|
return $result |
|
234
|
} |
|
235
|
|
|
236
|
|
|
237
|
# @make-template template ?outfile? |
|
238
|
# |
|
239
|
# Reads the input file '<srcdir>/$template' and writes the output file '$outfile' |
|
240
|
# (unless unchanged). |
|
241
|
# If '$outfile' is blank/omitted, '$template' should end with '.in' which |
|
242
|
# is removed to create the output file name. |
|
243
|
# |
|
244
|
# Each pattern of the form '@define@' is replaced with the corresponding |
|
245
|
# "define", if it exists, or left unchanged if not. |
|
246
|
# |
|
247
|
# The special value '@srcdir@' is substituted with the relative |
|
248
|
# path to the source directory from the directory where the output |
|
249
|
# file is created, while the special value '@top_srcdir@' is substituted |
|
250
|
# with the relative path to the top level source directory. |
|
251
|
# |
|
252
|
# Conditional sections may be specified as follows: |
|
253
|
## @if NAME eq "value" |
|
254
|
## lines |
|
255
|
## @else |
|
256
|
## lines |
|
257
|
## @endif |
|
258
|
# |
|
259
|
# Where 'NAME' is a defined variable name and '@else' is optional. |
|
260
|
# Note that variables names *must* start with an uppercase letter. |
|
261
|
# If the expression does not match, all lines through '@endif' are ignored. |
|
262
|
# |
|
263
|
# The alternative forms may also be used: |
|
264
|
## @if NAME (true if the variable is defined, but not empty and not "0") |
|
265
|
## @if !NAME (opposite of the form above) |
|
266
|
## @if <general-tcl-expression> |
|
267
|
# |
|
268
|
# In the general Tcl expression, any words beginning with an uppercase letter |
|
269
|
# are translated into [get-define NAME] |
|
270
|
# |
|
271
|
# Expressions may be nested |
|
272
|
# |
|
273
|
proc make-template {template {out {}}} { |
|
274
|
set infile [file join $::autosetup(srcdir) $template] |
|
275
|
|
|
276
|
if {![file exists $infile]} { |
|
277
|
user-error "Template $template is missing" |
|
278
|
} |
|
279
|
|
|
280
|
# Define this as late as possible |
|
281
|
define AUTODEPS $::autosetup(deps) |
|
282
|
|
|
283
|
if {$out eq ""} { |
|
284
|
if {[file ext $template] ne ".in"} { |
|
285
|
autosetup-error "make_template $template has no target file and can't guess" |
|
286
|
} |
|
287
|
set out [file rootname $template] |
|
288
|
} |
|
289
|
|
|
290
|
set outdir [file dirname $out] |
|
291
|
|
|
292
|
# Make sure the directory exists |
|
293
|
file mkdir $outdir |
|
294
|
|
|
295
|
# Set up srcdir and top_srcdir to be relative to the target dir |
|
296
|
define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir] |
|
297
|
define top_srcdir [relative-path $::autosetup(srcdir) $outdir] |
|
298
|
|
|
299
|
# Build map from global defines to their values so they can be |
|
300
|
# substituted into @include file names. |
|
301
|
proc build-define-mapping {} { |
|
302
|
set mapping {} |
|
303
|
foreach {n v} [array get ::define] { |
|
304
|
lappend mapping @$n@ $v |
|
305
|
} |
|
306
|
return $mapping |
|
307
|
} |
|
308
|
set mapping [build-define-mapping] |
|
309
|
|
|
310
|
set result [include-file $infile $mapping] |
|
311
|
|
|
312
|
# Rebuild the define mapping in case we ran across @define |
|
313
|
# directives in the template or a file it @included, then |
|
314
|
# apply that mapping to the expanded template. |
|
315
|
set mapping [build-define-mapping] |
|
316
|
write-if-changed $out [string map $mapping [join $result \n]] { |
|
317
|
msg-result "Created [relative-path $out] from [relative-path $template]" |
|
318
|
} |
|
319
|
} |
|
320
|
|
|
321
|
# build/host tuples and cross-compilation prefix |
|
322
|
opt-str build build "" |
|
323
|
define build_alias $build |
|
324
|
if {$build eq ""} { |
|
325
|
define build [config_guess] |
|
326
|
} else { |
|
327
|
define build [config_sub $build] |
|
328
|
} |
|
329
|
|
|
330
|
opt-str host host "" |
|
331
|
define host_alias $host |
|
332
|
if {$host eq ""} { |
|
333
|
define host [get-define build] |
|
334
|
set cross "" |
|
335
|
} else { |
|
336
|
define host [config_sub $host] |
|
337
|
set cross $host- |
|
338
|
} |
|
339
|
define cross [get-env CROSS $cross] |
|
340
|
|
|
341
|
# build/host _cpu, _vendor and _os |
|
342
|
foreach type {build host} { |
|
343
|
set v [get-define $type] |
|
344
|
if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} { |
|
345
|
user-error "Invalid canonical $type: $v" |
|
346
|
} |
|
347
|
define ${type}_cpu $cpu |
|
348
|
define ${type}_vendor $vendor |
|
349
|
define ${type}_os $os |
|
350
|
} |
|
351
|
|
|
352
|
opt-str prefix prefix /usr/local |
|
353
|
|
|
354
|
# These are for compatibility with autoconf |
|
355
|
define target [get-define host] |
|
356
|
define prefix $prefix |
|
357
|
define builddir $autosetup(builddir) |
|
358
|
define srcdir $autosetup(srcdir) |
|
359
|
define top_srcdir $autosetup(srcdir) |
|
360
|
define abs_top_srcdir [file-normalize $autosetup(srcdir)] |
|
361
|
define abs_top_builddir [file-normalize $autosetup(builddir)] |
|
362
|
|
|
363
|
# autoconf supports all of these |
|
364
|
define exec_prefix [opt-str exec-prefix exec_prefix $prefix] |
|
365
|
foreach {name defpath} { |
|
366
|
bindir /bin |
|
367
|
sbindir /sbin |
|
368
|
libexecdir /libexec |
|
369
|
libdir /lib |
|
370
|
} { |
|
371
|
define $name [opt-str $name o $exec_prefix$defpath] |
|
372
|
} |
|
373
|
foreach {name defpath} { |
|
374
|
datadir /share |
|
375
|
sharedstatedir /com |
|
376
|
infodir /share/info |
|
377
|
mandir /share/man |
|
378
|
includedir /include |
|
379
|
} { |
|
380
|
define $name [opt-str $name o $prefix$defpath] |
|
381
|
} |
|
382
|
if {$prefix ne {/usr}} { |
|
383
|
opt-str sysconfdir sysconfdir $prefix/etc |
|
384
|
} else { |
|
385
|
opt-str sysconfdir sysconfdir /etc |
|
386
|
} |
|
387
|
define sysconfdir $sysconfdir |
|
388
|
|
|
389
|
define localstatedir [opt-str localstatedir o /var] |
|
390
|
define runstatedir [opt-str runstatedir o /run] |
|
391
|
|
|
392
|
define SHELL [get-env SHELL [find-an-executable sh bash ksh]] |
|
393
|
|
|
394
|
# These could be used to generate Makefiles following some automake conventions |
|
395
|
define AM_SILENT_RULES [opt-bool silent-rules] |
|
396
|
define AM_MAINTAINER_MODE [opt-bool maintainer-mode] |
|
397
|
define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking] |
|
398
|
|
|
399
|
# Windows vs. non-Windows |
|
400
|
switch -glob -- [get-define host] { |
|
401
|
*-*-ming* - *-*-cygwin - *-*-msys { |
|
402
|
define-feature windows |
|
403
|
define EXEEXT .exe |
|
404
|
} |
|
405
|
default { |
|
406
|
define EXEEXT "" |
|
407
|
} |
|
408
|
} |
|
409
|
|
|
410
|
# Display |
|
411
|
msg-result "Host System...[get-define host]" |
|
412
|
msg-result "Build System...[get-define build]" |
|
413
|
|