Fossil SCM

fossil-scm / autosetup / system.tcl
Blame History Raw 413 lines
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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button