exec: Fix check for | and |&
[jimtcl.git] / autosetup / cc.tcl
blob5f066b5030c38e61c7e60090ab5760eeea43aa9d
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-config-header' 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 # split at the first dot
53 regexp {^([^.]+)[.](.*)$} $struct_member -> struct member
54 cctest -code "static $struct _s; return sizeof(_s.$member);"
57 # Checks for the existence of the given define by compiling
59 proc cctest_define {name} {
60 cctest -code "#ifndef $name\n#error not defined\n#endif"
63 # Checks for the existence of the given name either as
64 # a macro (#define) or an rvalue (such as an enum)
66 proc cctest_decl {name} {
67 cctest -code "#ifndef $name\n(void)$name;\n#endif"
70 # @cc-check-sizeof type ...
72 # Checks the size of the given types (between 1 and 32, inclusive).
73 # Defines a variable with the size determined, or 'unknown' otherwise.
74 # e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
75 # Returns the size of the last type.
77 proc cc-check-sizeof {args} {
78 foreach type $args {
79 msg-checking "Checking for sizeof $type..."
80 set size unknown
81 # Try the most common sizes first
82 foreach i {4 8 1 2 16 32} {
83 if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
84 set size $i
85 break
88 msg-result $size
89 set define [feature-define-name $type SIZEOF_]
90 define $define $size
92 # Return the last result
93 get-define $define
96 # Checks for each feature in $list by using the given script.
98 # When the script is evaluated, $each is set to the feature
99 # being checked, and $extra is set to any additional cctest args.
101 # Returns 1 if all features were found, or 0 otherwise.
102 proc cc-check-some-feature {list script} {
103 set ret 1
104 foreach each $list {
105 if {![check-feature $each $script]} {
106 set ret 0
109 return $ret
112 # @cc-check-includes includes ...
114 # Checks that the given include files can be used.
115 proc cc-check-includes {args} {
116 cc-check-some-feature $args {
117 set with {}
118 if {[dict exists $::autosetup(cc-include-deps) $each]} {
119 set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
120 msg-quiet cc-check-includes {*}$deps
121 foreach i $deps {
122 if {[have-feature $i]} {
123 lappend with $i
127 if {[llength $with]} {
128 cc-with [list -includes $with] {
129 cctest -includes $each
131 } else {
132 cctest -includes $each
137 # @cc-include-needs include required ...
139 # Ensures that when checking for '$include', a check is first
140 # made for each '$required' file, and if found, it is included with '#include'.
141 proc cc-include-needs {file args} {
142 foreach depfile $args {
143 dict set ::autosetup(cc-include-deps) $file $depfile 1
147 # @cc-check-types type ...
149 # Checks that the types exist.
150 proc cc-check-types {args} {
151 cc-check-some-feature $args {
152 cctest_type $each
156 # @cc-check-defines define ...
158 # Checks that the given preprocessor symbol is defined.
159 proc cc-check-defines {args} {
160 cc-check-some-feature $args {
161 cctest_define $each
165 # @cc-check-decls name ...
167 # Checks that each given name is either a preprocessor symbol or rvalue
168 # such as an enum. Note that the define used is 'HAVE_DECL_xxx'
169 # rather than 'HAVE_xxx'.
170 proc cc-check-decls {args} {
171 set ret 1
172 foreach name $args {
173 msg-checking "Checking for $name..."
174 set r [cctest_decl $name]
175 define-feature "decl $name" $r
176 if {$r} {
177 msg-result "ok"
178 } else {
179 msg-result "not found"
180 set ret 0
183 return $ret
186 # @cc-check-functions function ...
188 # Checks that the given functions exist (can be linked).
189 proc cc-check-functions {args} {
190 cc-check-some-feature $args {
191 cctest_function $each
195 # @cc-check-members type.member ...
197 # Checks that the given type/structure members exist.
198 # A structure member is of the form 'struct stat.st_mtime'.
199 proc cc-check-members {args} {
200 cc-check-some-feature $args {
201 cctest_member $each
205 # @cc-check-function-in-lib function libs ?otherlibs?
207 # Checks that the given function can be found in one of the libs.
209 # First checks for no library required, then checks each of the libraries
210 # in turn.
212 # If the function is found, the feature is defined and 'lib_$function' is defined
213 # to '-l$lib' where the function was found, or "" if no library required.
214 # In addition, '-l$lib' is prepended to the 'LIBS' define.
216 # If additional libraries may be needed for linking, they should be specified
217 # with '$extralibs' as '-lotherlib1 -lotherlib2'.
218 # These libraries are not automatically added to 'LIBS'.
220 # Returns 1 if found or 0 if not.
222 proc cc-check-function-in-lib {function libs {otherlibs {}}} {
223 msg-checking "Checking libs for $function..."
224 set found 0
225 cc-with [list -libs $otherlibs] {
226 if {[cctest_function $function]} {
227 msg-result "none needed"
228 define lib_$function ""
229 incr found
230 } else {
231 foreach lib $libs {
232 cc-with [list -libs -l$lib] {
233 if {[cctest_function $function]} {
234 msg-result -l$lib
235 define lib_$function -l$lib
236 # prepend to LIBS
237 define LIBS "-l$lib [get-define LIBS]"
238 incr found
239 break
245 if {$found} {
246 define [feature-define-name $function]
247 } else {
248 msg-result "no"
250 return $found
253 # @cc-check-tools tool ...
255 # Checks for existence of the given compiler tools, taking
256 # into account any cross compilation prefix.
258 # For example, when checking for 'ar', first 'AR' is checked on the command
259 # line and then in the environment. If not found, '${host}-ar' or
260 # simply 'ar' is assumed depending upon whether cross compiling.
261 # The path is searched for this executable, and if found 'AR' is defined
262 # to the executable name.
263 # Note that even when cross compiling, the simple 'ar' is used as a fallback,
264 # but a warning is generated. This is necessary for some toolchains.
266 # It is an error if the executable is not found.
268 proc cc-check-tools {args} {
269 foreach tool $args {
270 set TOOL [string toupper $tool]
271 set exe [get-env $TOOL [get-define cross]$tool]
272 if {[find-executable {*}$exe]} {
273 define $TOOL $exe
274 continue
276 if {[find-executable {*}$tool]} {
277 msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
278 define $TOOL $tool
279 continue
281 user-error "Failed to find $exe"
285 # @cc-check-progs prog ...
287 # Checks for existence of the given executables on the path.
289 # For example, when checking for 'grep', the path is searched for
290 # the executable, 'grep', and if found 'GREP' is defined as 'grep'.
292 # If the executable is not found, the variable is defined as 'false'.
293 # Returns 1 if all programs were found, or 0 otherwise.
295 proc cc-check-progs {args} {
296 set failed 0
297 foreach prog $args {
298 set PROG [string toupper $prog]
299 msg-checking "Checking for $prog..."
300 if {![find-executable $prog]} {
301 msg-result no
302 define $PROG false
303 incr failed
304 } else {
305 msg-result ok
306 define $PROG $prog
309 expr {!$failed}
312 # Adds the given settings to $::autosetup(ccsettings) and
313 # returns the old settings.
315 proc cc-add-settings {settings} {
316 if {[llength $settings] % 2} {
317 autosetup-error "settings list is missing a value: $settings"
320 set prev [cc-get-settings]
321 # workaround a bug in some versions of jimsh by forcing
322 # conversion of $prev to a list
323 llength $prev
325 array set new $prev
327 foreach {name value} $settings {
328 switch -exact -- $name {
329 -cflags - -includes {
330 # These are given as lists
331 lappend new($name) {*}$value
333 -declare {
334 lappend new($name) $value
336 -libs {
337 # Note that new libraries are added before previous libraries
338 set new($name) [list {*}$value {*}$new($name)]
340 -link - -lang - -nooutput {
341 set new($name) $value
343 -source - -sourcefile - -code {
344 # XXX: These probably are only valid directly from cctest
345 set new($name) $value
347 default {
348 autosetup-error "unknown cctest setting: $name"
353 cc-store-settings [array get new]
355 return $prev
358 proc cc-store-settings {new} {
359 set ::autosetup(ccsettings) $new
362 proc cc-get-settings {} {
363 return $::autosetup(ccsettings)
366 # Similar to cc-add-settings, but each given setting
367 # simply replaces the existing value.
369 # Returns the previous settings
370 proc cc-update-settings {args} {
371 set prev [cc-get-settings]
372 cc-store-settings [dict merge $prev $args]
373 return $prev
376 # @cc-with settings ?{ script }?
378 # Sets the given 'cctest' settings and then runs the tests in '$script'.
379 # Note that settings such as '-lang' replace the current setting, while
380 # those such as '-includes' are appended to the existing setting.
382 # If no script is given, the settings become the default for the remainder
383 # of the 'auto.def' file.
385 ## cc-with {-lang c++} {
386 ## # This will check with the C++ compiler
387 ## cc-check-types bool
388 ## cc-with {-includes signal.h} {
389 ## # This will check with the C++ compiler, signal.h and any existing includes.
390 ## ...
391 ## }
392 ## # back to just the C++ compiler
393 ## }
395 # The '-libs' setting is special in that newer values are added *before* earlier ones.
397 ## cc-with {-libs {-lc -lm}} {
398 ## cc-with {-libs -ldl} {
399 ## cctest -libs -lsocket ...
400 ## # libs will be in this order: -lsocket -ldl -lc -lm
401 ## }
402 ## }
403 proc cc-with {settings args} {
404 if {[llength $args] == 0} {
405 cc-add-settings $settings
406 } elseif {[llength $args] > 1} {
407 autosetup-error "usage: cc-with settings ?script?"
408 } else {
409 set save [cc-add-settings $settings]
410 set rc [catch {uplevel 1 [lindex $args 0]} result info]
411 cc-store-settings $save
412 if {$rc != 0} {
413 return -code [dict get $info -code] $result
415 return $result
419 # @cctest ?settings?
421 # Low level C/C++ compiler checker. Compiles and or links a small C program
422 # according to the arguments and returns 1 if OK, or 0 if not.
424 # Supported settings are:
426 ## -cflags cflags A list of flags to pass to the compiler
427 ## -includes list A list of includes, e.g. {stdlib.h stdio.h}
428 ## -declare code Code to declare before main()
429 ## -link 1 Don't just compile, link too
430 ## -lang c|c++ Use the C (default) or C++ compiler
431 ## -libs liblist List of libraries to link, e.g. {-ldl -lm}
432 ## -code code Code to compile in the body of main()
433 ## -source code Compile a complete program. Ignore -includes, -declare and -code
434 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
435 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
437 # Unless '-source' or '-sourcefile' is specified, the C program looks like:
439 ## #include <firstinclude> /* same for remaining includes in the list */
441 ## declare-code /* any code in -declare, verbatim */
443 ## int main(void) {
444 ## code /* any code in -code, verbatim */
445 ## return 0;
446 ## }
448 # Any failures are recorded in 'config.log'
450 proc cctest {args} {
451 set src conftest__.c
452 set tmp conftest__
454 # Easiest way to merge in the settings
455 cc-with $args {
456 array set opts [cc-get-settings]
459 if {[info exists opts(-sourcefile)]} {
460 set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
462 if {[info exists opts(-source)]} {
463 set lines $opts(-source)
464 } else {
465 foreach i $opts(-includes) {
466 if {$opts(-code) ne "" && ![feature-checked $i]} {
467 # Compiling real code with an unchecked header file
468 # Quickly (and silently) check for it now
470 # Remove all -includes from settings before checking
471 set saveopts [cc-update-settings -includes {}]
472 msg-quiet cc-check-includes $i
473 cc-store-settings $saveopts
475 if {$opts(-code) eq "" || [have-feature $i]} {
476 lappend source "#include <$i>"
479 lappend source {*}$opts(-declare)
480 lappend source "int main(void) {"
481 lappend source $opts(-code)
482 lappend source "return 0;"
483 lappend source "}"
485 set lines [join $source \n]
488 # Build the command line
489 set cmdline {}
490 lappend cmdline {*}[get-define CCACHE]
491 switch -exact -- $opts(-lang) {
492 c++ {
493 lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
496 lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
498 default {
499 autosetup-error "cctest called with unknown language: $opts(-lang)"
503 if {$opts(-link)} {
504 lappend cmdline {*}[get-define LDFLAGS]
505 } else {
506 set tmp conftest__.o
507 lappend cmdline -c
509 lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]
510 lappend cmdline $src -o $tmp {*}$opts(-libs)
511 if {$opts(-link)} {
512 lappend cmdline {*}[get-define LIBS]
515 # At this point we have the complete command line and the
516 # complete source to be compiled. Get the result from cache if
517 # we can
518 if {[info exists ::cc_cache($cmdline,$lines)]} {
519 msg-checking "(cached) "
520 set ok $::cc_cache($cmdline,$lines)
521 if {$::autosetup(debug)} {
522 configlog "From cache (ok=$ok): [join $cmdline]"
523 configlog "============"
524 configlog $lines
525 configlog "============"
527 return $ok
530 writefile $src $lines\n
532 set ok 1
533 set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
534 if {$err || ($opts(-nooutput) && [string length $result])} {
535 configlog "Failed: [join $cmdline]"
536 configlog $result
537 configlog "============"
538 configlog "The failed code was:"
539 configlog $lines
540 configlog "============"
541 set ok 0
542 } elseif {$::autosetup(debug)} {
543 configlog "Compiled OK: [join $cmdline]"
544 configlog "============"
545 configlog $lines
546 configlog "============"
548 file delete $src
549 file delete $tmp
551 # cache it
552 set ::cc_cache($cmdline,$lines) $ok
554 return $ok
557 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
559 # Deprecated - see 'make-config-header'
560 proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
561 user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
562 make-config-header $file -auto $autopatterns -bare $barepatterns
565 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
567 # Examines all defined variables which match the given patterns
568 # and writes an include file, '$file', which defines each of these.
569 # Variables which match '-auto' are output as follows:
570 # - defines which have the value '0' are ignored.
571 # - defines which have integer values are defined as the integer value.
572 # - any other value is defined as a string, e.g. '"value"'
573 # Variables which match '-bare' are defined as-is.
574 # Variables which match '-str' are defined as a string, e.g. '"value"'
575 # Variables which match '-none' are omitted.
577 # Note that order is important. The first pattern that matches is selected.
578 # Default behaviour is:
580 ## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
582 # If the file would be unchanged, it is not written.
583 proc make-config-header {file args} {
584 set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
585 file mkdir [file dirname $file]
586 set lines {}
587 lappend lines "#ifndef $guard"
588 lappend lines "#define $guard"
590 # Add some defaults
591 lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
593 foreach n [lsort [dict keys [all-defines]]] {
594 set value [get-define $n]
595 set type [calc-define-output-type $n $args]
596 switch -exact -- $type {
597 -bare {
598 # Just output the value unchanged
600 -none {
601 continue
603 -str {
604 set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
606 -auto {
607 # Automatically determine the type
608 if {$value eq "0"} {
609 lappend lines "/* #undef $n */"
610 continue
612 if {![string is integer -strict $value]} {
613 set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
616 "" {
617 continue
619 default {
620 autosetup-error "Unknown type in make-config-header: $type"
623 lappend lines "#define $n $value"
625 lappend lines "#endif"
626 set buf [join $lines \n]
627 write-if-changed $file $buf {
628 msg-result "Created $file"
632 proc calc-define-output-type {name spec} {
633 foreach {type patterns} $spec {
634 foreach pattern $patterns {
635 if {[string match $pattern $name]} {
636 return $type
640 return ""
643 # Initialise some values from the environment or commandline or default settings
644 foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
645 lassign $i var default
646 define $var [get-env $var $default]
649 if {[env-is-set CC]} {
650 # Set by the user, so don't try anything else
651 set try [list [get-env CC ""]]
652 } else {
653 # Try some reasonable options
654 set try [list [get-define cross]cc [get-define cross]gcc]
656 define CC [find-an-executable {*}$try]
657 if {[get-define CC] eq ""} {
658 user-error "Could not find a C compiler. Tried: [join $try ", "]"
661 define CPP [get-env CPP "[get-define CC] -E"]
663 # XXX: Could avoid looking for a C++ compiler until requested
664 # Note that if CXX isn't found, we just set it to "false". It might not be needed.
665 if {[env-is-set CXX]} {
666 define CXX [find-an-executable -required [get-env CXX ""]]
667 } else {
668 define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
671 # CXXFLAGS default to CFLAGS if not specified
672 define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
674 # May need a CC_FOR_BUILD, so look for one
675 define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
677 if {[get-define CC] eq ""} {
678 user-error "Could not find a C compiler. Tried: [join $try ", "]"
681 define CCACHE [find-an-executable [get-env CCACHE ccache]]
683 # Initial cctest settings
684 cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
685 set autosetup(cc-include-deps) {}
687 msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
688 if {[get-define CXX] ne "false"} {
689 msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
691 msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
693 # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
694 # but some compilers may not support it, so test here.
695 switch -glob -- [get-define host] {
696 *-*-darwin* {
697 if {[cctest -cflags {-g0}]} {
698 define cc-default-debug -g0
703 if {![cc-check-includes stdlib.h]} {
704 user-error "Compiler does not work. See config.log"