tcltest: do a better job of cleanup up after tests
[jimtcl.git] / autosetup / cc.tcl
blobebd9789c3254787f51acdd15719941ed48e2dc96
1 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2 # All rights reserved
4 # @synopsis:
6 # The 'cc' module supports checking various 'features' of the C or C++
7 # compiler/linker environment. Common commands are cc-check-includes,
8 # cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
10 # The following environment variables are used if set:
12 ## CC - C compiler
13 ## CXX - C++ compiler
14 ## CCACHE - Set to "none" to disable automatic use of ccache
15 ## CFLAGS - Additional C compiler flags
16 ## CXXFLAGS - Additional C++ compiler flags
17 ## LDFLAGS - Additional compiler flags during linking
18 ## LIBS - Additional libraries to use (for all tests)
19 ## CROSS - Tool prefix for cross compilation
21 # The following variables are defined from the corresponding
22 # environment variables if set.
24 ## CPPFLAGS
25 ## LINKFLAGS
26 ## CC_FOR_BUILD
27 ## LD
29 use system
31 module-options {}
33 # Note that the return code is not meaningful
34 proc cc-check-something {name code} {
35 uplevel 1 $code
38 # Checks for the existence of the given function by linking
40 proc cctest_function {function} {
41 cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
44 # Checks for the existence of the given type by compiling
45 proc cctest_type {type} {
46 cctest -code "$type _x;"
49 # Checks for the existence of the given type/structure member.
50 # e.g. "struct stat.st_mtime"
51 proc cctest_member {struct_member} {
52 lassign [split $struct_member .] struct member
53 cctest -code "static $struct _s; return sizeof(_s.$member);"
56 # Checks for the existence of the given define by compiling
58 proc cctest_define {name} {
59 cctest -code "#ifndef $name\n#error not defined\n#endif"
62 # Checks for the existence of the given name either as
63 # a macro (#define) or an rvalue (such as an enum)
65 proc cctest_decl {name} {
66 cctest -code "#ifndef $name\n(void)$name;\n#endif"
69 # @cc-check-sizeof type ...
71 # Checks the size of the given types (between 1 and 32, inclusive).
72 # Defines a variable with the size determined, or "unknown" otherwise.
73 # e.g. for type 'long long', defines SIZEOF_LONG_LONG.
74 # Returns the size of the last type.
76 proc cc-check-sizeof {args} {
77 foreach type $args {
78 msg-checking "Checking for sizeof $type..."
79 set size unknown
80 # Try the most common sizes first
81 foreach i {4 8 1 2 16 32} {
82 if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
83 set size $i
84 break
87 msg-result $size
88 set define [feature-define-name $type SIZEOF_]
89 define $define $size
91 # Return the last result
92 get-define $define
95 # Checks for each feature in $list by using the given script.
97 # When the script is evaluated, $each is set to the feature
98 # being checked, and $extra is set to any additional cctest args.
100 # Returns 1 if all features were found, or 0 otherwise.
101 proc cc-check-some-feature {list script} {
102 set ret 1
103 foreach each $list {
104 if {![check-feature $each $script]} {
105 set ret 0
108 return $ret
111 # @cc-check-includes includes ...
113 # Checks that the given include files can be used
114 proc cc-check-includes {args} {
115 cc-check-some-feature $args {
116 set with {}
117 if {[dict exists $::autosetup(cc-include-deps) $each]} {
118 set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
119 msg-quiet cc-check-includes {*}$deps
120 foreach i $deps {
121 if {[have-feature $i]} {
122 lappend with $i
126 if {[llength $with]} {
127 cc-with [list -includes $with] {
128 cctest -includes $each
130 } else {
131 cctest -includes $each
136 # @cc-include-needs include required ...
138 # Ensures that when checking for 'include', a check is first
139 # made for each 'required' file, and if found, it is #included
140 proc cc-include-needs {file args} {
141 foreach depfile $args {
142 dict set ::autosetup(cc-include-deps) $file $depfile 1
146 # @cc-check-types type ...
148 # Checks that the types exist.
149 proc cc-check-types {args} {
150 cc-check-some-feature $args {
151 cctest_type $each
155 # @cc-check-defines define ...
157 # Checks that the given preprocessor symbol is defined
158 proc cc-check-defines {args} {
159 cc-check-some-feature $args {
160 cctest_define $each
164 # @cc-check-decls name ...
166 # Checks that each given name is either a preprocessor symbol or rvalue
167 # such as an enum. Note that the define used is HAVE_DECL_xxx
168 # rather than HAVE_xxx
169 proc cc-check-decls {args} {
170 set ret 1
171 foreach name $args {
172 msg-checking "Checking for $name..."
173 set r [cctest_decl $name]
174 define-feature "decl $name" $r
175 if {$r} {
176 msg-result "ok"
177 } else {
178 msg-result "not found"
179 set ret 0
182 return $ret
185 # @cc-check-functions function ...
187 # Checks that the given functions exist (can be linked)
188 proc cc-check-functions {args} {
189 cc-check-some-feature $args {
190 cctest_function $each
194 # @cc-check-members type.member ...
196 # Checks that the given type/structure members exist.
197 # A structure member is of the form "struct stat.st_mtime"
198 proc cc-check-members {args} {
199 cc-check-some-feature $args {
200 cctest_member $each
204 # @cc-check-function-in-lib function libs ?otherlibs?
206 # Checks that the given function can be found in one of the libs.
208 # First checks for no library required, then checks each of the libraries
209 # in turn.
211 # If the function is found, the feature is defined and lib_$function is defined
212 # to -l$lib where the function was found, or "" if no library required.
213 # In addition, -l$lib is added to the LIBS define.
215 # If additional libraries may be needed for linking, they should be specified
216 # as $extralibs as "-lotherlib1 -lotherlib2".
217 # These libraries are not automatically added to LIBS.
219 # Returns 1 if found or 0 if not.
221 proc cc-check-function-in-lib {function libs {otherlibs {}}} {
222 msg-checking "Checking libs for $function..."
223 set found 0
224 cc-with [list -libs $otherlibs] {
225 if {[cctest_function $function]} {
226 msg-result "none needed"
227 define lib_$function ""
228 incr found
229 } else {
230 foreach lib $libs {
231 cc-with [list -libs -l$lib] {
232 if {[cctest_function $function]} {
233 msg-result -l$lib
234 define lib_$function -l$lib
235 define-append LIBS -l$lib
236 incr found
237 break
243 if {$found} {
244 define [feature-define-name $function]
245 } else {
246 msg-result "no"
248 return $found
251 # @cc-check-tools tool ...
253 # Checks for existence of the given compiler tools, taking
254 # into account any cross compilation prefix.
256 # For example, when checking for "ar", first AR is checked on the command
257 # line and then in the environment. If not found, "${host}-ar" or
258 # simply "ar" is assumed depending upon whether cross compiling.
259 # The path is searched for this executable, and if found AR is defined
260 # to the executable name.
261 # Note that even when cross compiling, the simple "ar" is used as a fallback,
262 # but a warning is generated. This is necessary for some toolchains.
264 # It is an error if the executable is not found.
266 proc cc-check-tools {args} {
267 foreach tool $args {
268 set TOOL [string toupper $tool]
269 set exe [get-env $TOOL [get-define cross]$tool]
270 if {[find-executable {*}$exe]} {
271 define $TOOL $exe
272 continue
274 if {[find-executable {*}$tool]} {
275 msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
276 define $TOOL $tool
277 continue
279 user-error "Failed to find $exe"
283 # @cc-check-progs prog ...
285 # Checks for existence of the given executables on the path.
287 # For example, when checking for "grep", the path is searched for
288 # the executable, 'grep', and if found GREP is defined as "grep".
290 # If the executable is not found, the variable is defined as false.
291 # Returns 1 if all programs were found, or 0 otherwise.
293 proc cc-check-progs {args} {
294 set failed 0
295 foreach prog $args {
296 set PROG [string toupper $prog]
297 msg-checking "Checking for $prog..."
298 if {![find-executable $prog]} {
299 msg-result no
300 define $PROG false
301 incr failed
302 } else {
303 msg-result ok
304 define $PROG $prog
307 expr {!$failed}
310 # Adds the given settings to $::autosetup(ccsettings) and
311 # returns the old settings.
313 proc cc-add-settings {settings} {
314 if {[llength $settings] % 2} {
315 autosetup-error "settings list is missing a value: $settings"
318 set prev [cc-get-settings]
319 # workaround a bug in some versions of jimsh by forcing
320 # conversion of $prev to a list
321 llength $prev
323 array set new $prev
325 foreach {name value} $settings {
326 switch -exact -- $name {
327 -cflags - -includes {
328 # These are given as lists
329 lappend new($name) {*}$value
331 -declare {
332 lappend new($name) $value
334 -libs {
335 # Note that new libraries are added before previous libraries
336 set new($name) [list {*}$value {*}$new($name)]
338 -link - -lang - -nooutput {
339 set new($name) $value
341 -source - -sourcefile - -code {
342 # XXX: These probably are only valid directly from cctest
343 set new($name) $value
345 default {
346 autosetup-error "unknown cctest setting: $name"
351 cc-store-settings [array get new]
353 return $prev
356 proc cc-store-settings {new} {
357 set ::autosetup(ccsettings) $new
360 proc cc-get-settings {} {
361 return $::autosetup(ccsettings)
364 # Similar to cc-add-settings, but each given setting
365 # simply replaces the existing value.
367 # Returns the previous settings
368 proc cc-update-settings {args} {
369 set prev [cc-get-settings]
370 cc-store-settings [dict merge $prev $args]
371 return $prev
374 # @cc-with settings ?{ script }?
376 # Sets the given 'cctest' settings and then runs the tests in 'script'.
377 # Note that settings such as -lang replace the current setting, while
378 # those such as -includes are appended to the existing setting.
380 # If no script is given, the settings become the default for the remainder
381 # of the auto.def file.
383 ## cc-with {-lang c++} {
384 ## # This will check with the C++ compiler
385 ## cc-check-types bool
386 ## cc-with {-includes signal.h} {
387 ## # This will check with the C++ compiler, signal.h and any existing includes.
388 ## ...
389 ## }
390 ## # back to just the C++ compiler
391 ## }
393 # The -libs setting is special in that newer values are added *before* earlier ones.
395 ## cc-with {-libs {-lc -lm}} {
396 ## cc-with {-libs -ldl} {
397 ## cctest -libs -lsocket ...
398 ## # libs will be in this order: -lsocket -ldl -lc -lm
399 ## }
400 ## }
401 proc cc-with {settings args} {
402 if {[llength $args] == 0} {
403 cc-add-settings $settings
404 } elseif {[llength $args] > 1} {
405 autosetup-error "usage: cc-with settings ?script?"
406 } else {
407 set save [cc-add-settings $settings]
408 set rc [catch {uplevel 1 [lindex $args 0]} result info]
409 cc-store-settings $save
410 if {$rc != 0} {
411 return -code [dict get $info -code] $result
413 return $result
417 # @cctest ?settings?
419 # Low level C compiler checker. Compiles and or links a small C program
420 # according to the arguments and returns 1 if OK, or 0 if not.
422 # Supported settings are:
424 ## -cflags cflags A list of flags to pass to the compiler
425 ## -includes list A list of includes, e.g. {stdlib.h stdio.h}
426 ## -declare code Code to declare before main()
427 ## -link 1 Don't just compile, link too
428 ## -lang c|c++ Use the C (default) or C++ compiler
429 ## -libs liblist List of libraries to link, e.g. {-ldl -lm}
430 ## -code code Code to compile in the body of main()
431 ## -source code Compile a complete program. Ignore -includes, -declare and -code
432 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
433 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
435 # Unless -source or -sourcefile is specified, the C program looks like:
437 ## #include <firstinclude> /* same for remaining includes in the list */
439 ## declare-code /* any code in -declare, verbatim */
441 ## int main(void) {
442 ## code /* any code in -code, verbatim */
443 ## return 0;
444 ## }
446 # Any failures are recorded in 'config.log'
448 proc cctest {args} {
449 set src conftest__.c
450 set tmp conftest__
452 # Easiest way to merge in the settings
453 cc-with $args {
454 array set opts [cc-get-settings]
457 if {[info exists opts(-sourcefile)]} {
458 set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
460 if {[info exists opts(-source)]} {
461 set lines $opts(-source)
462 } else {
463 foreach i $opts(-includes) {
464 if {$opts(-code) ne "" && ![feature-checked $i]} {
465 # Compiling real code with an unchecked header file
466 # Quickly (and silently) check for it now
468 # Remove all -includes from settings before checking
469 set saveopts [cc-update-settings -includes {}]
470 msg-quiet cc-check-includes $i
471 cc-store-settings $saveopts
473 if {$opts(-code) eq "" || [have-feature $i]} {
474 lappend source "#include <$i>"
477 lappend source {*}$opts(-declare)
478 lappend source "int main(void) {"
479 lappend source $opts(-code)
480 lappend source "return 0;"
481 lappend source "}"
483 set lines [join $source \n]
486 # Build the command line
487 set cmdline {}
488 lappend cmdline {*}[get-define CCACHE]
489 switch -exact -- $opts(-lang) {
490 c++ {
491 lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
494 lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
496 default {
497 autosetup-error "cctest called with unknown language: $opts(-lang)"
501 if {!$opts(-link)} {
502 set tmp conftest__.o
503 lappend cmdline -c
505 lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]
507 lappend cmdline $src -o $tmp {*}$opts(-libs)
509 # At this point we have the complete command line and the
510 # complete source to be compiled. Get the result from cache if
511 # we can
512 if {[info exists ::cc_cache($cmdline,$lines)]} {
513 msg-checking "(cached) "
514 set ok $::cc_cache($cmdline,$lines)
515 if {$::autosetup(debug)} {
516 configlog "From cache (ok=$ok): [join $cmdline]"
517 configlog "============"
518 configlog $lines
519 configlog "============"
521 return $ok
524 writefile $src $lines\n
526 set ok 1
527 set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
528 if {$err || ($opts(-nooutput) && [string length $result])} {
529 configlog "Failed: [join $cmdline]"
530 configlog $result
531 configlog "============"
532 configlog "The failed code was:"
533 configlog $lines
534 configlog "============"
535 set ok 0
536 } elseif {$::autosetup(debug)} {
537 configlog "Compiled OK: [join $cmdline]"
538 configlog "============"
539 configlog $lines
540 configlog "============"
542 file delete $src
543 file delete $tmp
545 # cache it
546 set ::cc_cache($cmdline,$lines) $ok
548 return $ok
551 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
553 # Deprecated - see make-config-header
554 proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
555 user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
556 make-config-header $file -auto $autopatterns -bare $barepatterns
559 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
561 # Examines all defined variables which match the given patterns
562 # and writes an include file, $file, which defines each of these.
563 # Variables which match '-auto' are output as follows:
564 # - defines which have the value "0" are ignored.
565 # - defines which have integer values are defined as the integer value.
566 # - any other value is defined as a string, e.g. "value"
567 # Variables which match '-bare' are defined as-is.
568 # Variables which match '-str' are defined as a string, e.g. "value"
569 # Variables which match '-none' are omitted.
571 # Note that order is important. The first pattern which matches is selected
572 # Default behaviour is:
574 # -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
576 # If the file would be unchanged, it is not written.
577 proc make-config-header {file args} {
578 set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
579 file mkdir [file dirname $file]
580 set lines {}
581 lappend lines "#ifndef $guard"
582 lappend lines "#define $guard"
584 # Add some defaults
585 lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
587 foreach n [lsort [dict keys [all-defines]]] {
588 set value [get-define $n]
589 set type [calc-define-output-type $n $args]
590 switch -exact -- $type {
591 -bare {
592 # Just output the value unchanged
594 -none {
595 continue
597 -str {
598 set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
600 -auto {
601 # Automatically determine the type
602 if {$value eq "0"} {
603 lappend lines "/* #undef $n */"
604 continue
606 if {![string is integer -strict $value]} {
607 set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
610 "" {
611 continue
613 default {
614 autosetup-error "Unknown type in make-config-header: $type"
617 lappend lines "#define $n $value"
619 lappend lines "#endif"
620 set buf [join $lines \n]
621 write-if-changed $file $buf {
622 msg-result "Created $file"
626 proc calc-define-output-type {name spec} {
627 foreach {type patterns} $spec {
628 foreach pattern $patterns {
629 if {[string match $pattern $name]} {
630 return $type
634 return ""
637 # Initialise some values from the environment or commandline or default settings
638 foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
639 lassign $i var default
640 define $var [get-env $var $default]
643 if {[env-is-set CC]} {
644 # Set by the user, so don't try anything else
645 set try [list [get-env CC ""]]
646 } else {
647 # Try some reasonable options
648 set try [list [get-define cross]cc [get-define cross]gcc]
650 define CC [find-an-executable {*}$try]
651 if {[get-define CC] eq ""} {
652 user-error "Could not find a C compiler. Tried: [join $try ", "]"
655 define CPP [get-env CPP "[get-define CC] -E"]
657 # XXX: Could avoid looking for a C++ compiler until requested
658 # Note that if CXX isn't found, we just set it to "false". It might not be needed.
659 if {[env-is-set CXX]} {
660 define CXX [find-an-executable -required [get-env CXX ""]]
661 } else {
662 define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
665 # CXXFLAGS default to CFLAGS if not specified
666 define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
668 # May need a CC_FOR_BUILD, so look for one
669 define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
671 if {[get-define CC] eq ""} {
672 user-error "Could not find a C compiler. Tried: [join $try ", "]"
675 define CCACHE [find-an-executable [get-env CCACHE ccache]]
677 # Initial cctest settings
678 cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
679 set autosetup(cc-include-deps) {}
681 msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
682 if {[get-define CXX] ne "false"} {
683 msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
685 msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
687 # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
688 # but some compilers may not support it, so test here.
689 switch -glob -- [get-define host] {
690 *-*-darwin* {
691 if {[cctest -cflags {-g0}]} {
692 define cc-default-debug -g0
697 if {![cc-check-includes stdlib.h]} {
698 user-error "Compiler does not work. See config.log"