1 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
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:
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.
33 # Checks for the existence of the given function by linking
35 proc cctest_function
{function
} {
36 cctest
-link 1 -declare "extern void $function\(void);" -code "$function\();"
39 # Checks for the existence of the given type by compiling
40 proc cctest_type
{type
} {
41 cctest
-code "$type _x;"
44 # Checks for the existence of the given type/structure member.
45 # e.g. "struct stat.st_mtime"
46 proc cctest_member
{struct_member
} {
47 # split at the first dot
48 regexp {^
([^.
]+)[.
](.
*)$} $struct_member -> struct member
49 cctest
-code "static $struct _s; return sizeof(_s.$member);"
52 # Checks for the existence of the given define by compiling
54 proc cctest_define
{name
} {
55 cctest
-code "#ifndef $name\n#error not defined\n#endif"
58 # Checks for the existence of the given name either as
59 # a macro (#define) or an rvalue (such as an enum)
61 proc cctest_decl
{name
} {
62 cctest
-code "#ifndef $name\n(void)$name;\n#endif"
65 # @cc-check-sizeof type ...
67 # Checks the size of the given types (between 1 and 32, inclusive).
68 # Defines a variable with the size determined, or 'unknown' otherwise.
69 # e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
70 # Returns the size of the last type.
72 proc cc-check-sizeof
{args
} {
74 msg-checking
"Checking for sizeof $type..."
76 # Try the most common sizes first
77 foreach i
{4 8 1 2 16 32} {
78 if {[cctest
-code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
84 set define
[feature-define-name
$type SIZEOF_
]
87 # Return the last result
91 # Checks for each feature in $list by using the given script.
93 # When the script is evaluated, $each is set to the feature
94 # being checked, and $extra is set to any additional cctest args.
96 # Returns 1 if all features were found, or 0 otherwise.
97 proc cc-check-some-feature
{list script
} {
100 if {![check-feature
$each $script]} {
107 # @cc-check-includes includes ...
109 # Checks that the given include files can be used.
110 proc cc-check-includes
{args
} {
111 cc-check-some-feature
$args {
113 if {[dict exists
$::autosetup(cc-include-deps
) $each]} {
114 set deps
[dict keys
[dict get
$::autosetup(cc-include-deps
) $each]]
115 msg-quiet cc-check-includes
{*}$deps
117 if {[have-feature
$i]} {
122 if {[llength $with]} {
123 cc-with
[list -includes $with] {
124 cctest
-includes $each
127 cctest
-includes $each
132 # @cc-include-needs include required ...
134 # Ensures that when checking for '$include', a check is first
135 # made for each '$required' file, and if found, it is included with '#include'.
136 proc cc-include-needs
{file args
} {
137 foreach depfile
$args {
138 dict
set ::autosetup(cc-include-deps
) $file $depfile 1
142 # @cc-check-types type ...
144 # Checks that the types exist.
145 proc cc-check-types
{args
} {
146 cc-check-some-feature
$args {
151 # @cc-check-defines define ...
153 # Checks that the given preprocessor symbols are defined.
154 proc cc-check-defines
{args
} {
155 cc-check-some-feature
$args {
160 # @cc-check-decls name ...
162 # Checks that each given name is either a preprocessor symbol or rvalue
163 # such as an enum. Note that the define used is 'HAVE_DECL_xxx'
164 # rather than 'HAVE_xxx'.
165 proc cc-check-decls
{args
} {
168 msg-checking
"Checking for $name..."
169 set r
[cctest_decl
$name]
170 define-feature
"decl $name" $r
174 msg-result
"not found"
181 # @cc-check-functions function ...
183 # Checks that the given functions exist (can be linked).
184 proc cc-check-functions
{args
} {
185 cc-check-some-feature
$args {
186 cctest_function
$each
190 # @cc-check-members type.member ...
192 # Checks that the given type/structure members exist.
193 # A structure member is of the form 'struct stat.st_mtime'.
194 proc cc-check-members
{args
} {
195 cc-check-some-feature
$args {
200 # @cc-check-function-in-lib function libs ?otherlibs?
202 # Checks that the given function can be found in one of the libs.
204 # First checks for no library required, then checks each of the libraries
207 # If the function is found, the feature is defined and 'lib_$function' is defined
208 # to '-l$lib' where the function was found, or "" if no library required.
209 # In addition, '-l$lib' is prepended to the 'LIBS' define.
211 # If additional libraries may be needed for linking, they should be specified
212 # with '$extralibs' as '-lotherlib1 -lotherlib2'.
213 # These libraries are not automatically added to 'LIBS'.
215 # Returns 1 if found or 0 if not.
217 proc cc-check-function-in-lib
{function libs
{otherlibs
{}}} {
218 msg-checking
"Checking libs for $function..."
220 cc-with
[list -libs $otherlibs] {
221 if {[cctest_function
$function]} {
222 msg-result
"none needed"
223 define lib_
$function ""
227 cc-with
[list -libs -l$lib] {
228 if {[cctest_function
$function]} {
230 define lib_
$function -l$lib
232 define LIBS
"-l$lib [get-define LIBS]"
240 define-feature
$function $found
247 # @cc-check-tools tool ...
249 # Checks for existence of the given compiler tools, taking
250 # into account any cross compilation prefix.
252 # For example, when checking for 'ar', first 'AR' is checked on the command
253 # line and then in the environment. If not found, '${host}-ar' or
254 # simply 'ar' is assumed depending upon whether cross compiling.
255 # The path is searched for this executable, and if found 'AR' is defined
256 # to the executable name.
257 # Note that even when cross compiling, the simple 'ar' is used as a fallback,
258 # but a warning is generated. This is necessary for some toolchains.
260 # It is an error if the executable is not found.
262 proc cc-check-tools
{args
} {
264 set TOOL
[string toupper
$tool]
265 set exe
[get-env
$TOOL [get-define cross
]$tool]
266 if {[find-executable
{*}$exe]} {
270 if {[find-executable
{*}$tool]} {
271 msg-result
"Warning: Failed to find $exe, falling back to $tool which may be incorrect"
275 user-error
"Failed to find $exe"
279 # @cc-check-progs prog ...
281 # Checks for existence of the given executables on the path.
283 # For example, when checking for 'grep', the path is searched for
284 # the executable, 'grep', and if found 'GREP' is defined as 'grep'.
286 # If the executable is not found, the variable is defined as 'false'.
287 # Returns 1 if all programs were found, or 0 otherwise.
289 proc cc-check-progs
{args
} {
292 set PROG
[string toupper
$prog]
293 msg-checking
"Checking for $prog..."
294 if {![find-executable
$prog]} {
306 # @cc-path-progs prog ...
308 # Like cc-check-progs, but sets the define to the full path rather
309 # than just the program name.
311 proc cc-path-progs
{args
} {
314 set PROG
[string toupper
$prog]
315 msg-checking
"Checking for $prog..."
316 set path
[find-executable-path
$prog]
329 # Adds the given settings to $::autosetup(ccsettings) and
330 # returns the old settings.
332 proc cc-add-settings
{settings
} {
333 if {[llength $settings] % 2} {
334 autosetup-error
"settings list is missing a value: $settings"
337 set prev
[cc-get-settings
]
338 # workaround a bug in some versions of jimsh by forcing
339 # conversion of $prev to a list
344 foreach {name value
} $settings {
345 switch -exact -- $name {
346 -cflags - -includes {
347 # These are given as lists
348 lappend new
($name) {*}[list-non-empty
$value]
351 lappend new
($name) $value
354 # Note that new libraries are added before previous libraries
355 set new
($name) [list {*}[list-non-empty
$value] {*}$new($name)]
357 -link - -lang - -nooutput {
358 set new
($name) $value
360 -source - -sourcefile - -code {
361 # XXX: These probably are only valid directly from cctest
362 set new
($name) $value
365 autosetup-error
"unknown cctest setting: $name"
370 cc-store-settings
[array get new
]
375 proc cc-store-settings
{new
} {
376 set ::autosetup(ccsettings
) $new
379 proc cc-get-settings
{} {
380 return $::autosetup(ccsettings
)
383 # Similar to cc-add-settings, but each given setting
384 # simply replaces the existing value.
386 # Returns the previous settings
387 proc cc-update-settings
{args
} {
388 set prev
[cc-get-settings
]
389 cc-store-settings
[dict merge
$prev $args]
393 # @cc-with settings ?{ script }?
395 # Sets the given 'cctest' settings and then runs the tests in '$script'.
396 # Note that settings such as '-lang' replace the current setting, while
397 # those such as '-includes' are appended to the existing setting.
399 # If no script is given, the settings become the default for the remainder
400 # of the 'auto.def' file.
402 ## cc-with {-lang c++} {
403 ## # This will check with the C++ compiler
404 ## cc-check-types bool
405 ## cc-with {-includes signal.h} {
406 ## # This will check with the C++ compiler, signal.h and any existing includes.
409 ## # back to just the C++ compiler
412 # The '-libs' setting is special in that newer values are added *before* earlier ones.
414 ## cc-with {-libs {-lc -lm}} {
415 ## cc-with {-libs -ldl} {
416 ## cctest -libs -lsocket ...
417 ## # libs will be in this order: -lsocket -ldl -lc -lm
420 proc cc-with
{settings args
} {
421 if {[llength $args] == 0} {
422 cc-add-settings
$settings
423 } elseif
{[llength $args] > 1} {
424 autosetup-error
"usage: cc-with settings ?script?"
426 set save
[cc-add-settings
$settings]
427 set rc
[catch {uplevel 1 [lindex $args 0]} result
info]
428 cc-store-settings
$save
430 return -code [dict get
$info -code] $result
438 # Low level C/C++ compiler checker. Compiles and or links a small C program
439 # according to the arguments and returns 1 if OK, or 0 if not.
441 # Supported settings are:
443 ## -cflags cflags A list of flags to pass to the compiler
444 ## -includes list A list of includes, e.g. {stdlib.h stdio.h}
445 ## -declare code Code to declare before main()
446 ## -link 1 Don't just compile, link too
447 ## -lang c|c++ Use the C (default) or C++ compiler
448 ## -libs liblist List of libraries to link, e.g. {-ldl -lm}
449 ## -code code Code to compile in the body of main()
450 ## -source code Compile a complete program. Ignore -includes, -declare and -code
451 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
452 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
454 # Unless '-source' or '-sourcefile' is specified, the C program looks like:
456 ## #include <firstinclude> /* same for remaining includes in the list */
458 ## declare-code /* any code in -declare, verbatim */
461 ## code /* any code in -code, verbatim */
465 # Any failures are recorded in 'config.log'
471 # Easiest way to merge in the settings
473 array set opts
[cc-get-settings
]
476 if {[info exists opts
(-sourcefile)]} {
477 set opts
(-source) [readfile
[get-define srcdir
]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
479 if {[info exists opts
(-source)]} {
480 set lines
$opts(-source)
482 foreach i
$opts(-includes) {
483 if {$opts(-code) ne
"" && ![feature-checked
$i]} {
484 # Compiling real code with an unchecked header file
485 # Quickly (and silently) check for it now
487 # Remove all -includes from settings before checking
488 set saveopts
[cc-update-settings
-includes {}]
489 msg-quiet cc-check-includes
$i
490 cc-store-settings
$saveopts
492 if {$opts(-code) eq
"" ||
[have-feature
$i]} {
493 lappend source "#include <$i>"
496 lappend source {*}$opts(-declare)
497 lappend source "int main(void) {"
498 lappend source $opts(-code)
499 lappend source "return 0;"
502 set lines
[join $source \n]
505 # Build the command line
507 lappend cmdline
{*}[get-define CCACHE
]
508 switch -exact -- $opts(-lang) {
510 lappend cmdline
{*}[get-define CXX
] {*}[get-define CXXFLAGS
]
513 lappend cmdline
{*}[get-define CC
] {*}[get-define CFLAGS
]
516 autosetup-error
"cctest called with unknown language: $opts(-lang)"
521 lappend cmdline
{*}[get-define LDFLAGS
]
526 lappend cmdline
{*}$opts(-cflags) {*}[get-define cc-default-debug
""]
527 lappend cmdline
$src -o $tmp {*}$opts(-libs)
529 lappend cmdline
{*}[get-define LIBS
]
532 # At this point we have the complete command line and the
533 # complete source to be compiled. Get the result from cache if
535 if {[info exists
::cc_cache($cmdline,$lines)]} {
536 msg-checking
"(cached) "
537 set ok
$::cc_cache($cmdline,$lines)
538 if {$::autosetup(debug
)} {
539 configlog
"From cache (ok=$ok): [join $cmdline]"
540 configlog
"============"
542 configlog
"============"
547 writefile
$src $lines\n
550 set err
[catch {exec-with-stderr
{*}$cmdline} result errinfo
]
551 if {$err ||
($opts(-nooutput) && [string length
$result])} {
552 configlog
"Failed: [join $cmdline]"
554 configlog
"============"
555 configlog
"The failed code was:"
557 configlog
"============"
559 } elseif
{$::autosetup(debug
)} {
560 configlog
"Compiled OK: [join $cmdline]"
561 configlog
"============"
563 configlog
"============"
569 set ::cc_cache($cmdline,$lines) $ok
574 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
576 # Deprecated - see 'make-config-header'
577 proc make-autoconf-h
{file {autopatterns
{HAVE_
*}} {barepatterns
{SIZEOF_
* HAVE_DECL_
*}}} {
578 user-notice
"*** make-autoconf-h is deprecated -- use make-config-header instead"
579 make-config-header
$file -auto $autopatterns -bare $barepatterns
582 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
584 # Examines all defined variables which match the given patterns
585 # and writes an include file, '$file', which defines each of these.
586 # Variables which match '-auto' are output as follows:
587 # - defines which have the value '0' are ignored.
588 # - defines which have integer values are defined as the integer value.
589 # - any other value is defined as a string, e.g. '"value"'
590 # Variables which match '-bare' are defined as-is.
591 # Variables which match '-str' are defined as a string, e.g. '"value"'
592 # Variables which match '-none' are omitted.
594 # Note that order is important. The first pattern that matches is selected.
595 # Default behaviour is:
597 ## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
599 # If the file would be unchanged, it is not written.
600 proc make-config-header
{file args
} {
601 set guard _
[string toupper
[regsub -all {[^a-zA-Z0-9
]} [file tail
$file] _
]]
602 file mkdir
[file dirname
$file]
604 lappend lines
"#ifndef $guard"
605 lappend lines
"#define $guard"
608 lappend args
-bare {SIZEOF_
* HAVE_DECL_
*} -auto HAVE_
*
610 foreach n
[lsort [dict keys
[all-defines
]]] {
611 set value
[get-define
$n]
612 set type
[calc-define-output-type
$n $args]
613 switch -exact -- $type {
615 # Just output the value unchanged
621 set value
\"[string map
[list \\ \\\\ \" \\\"] $value]\"
624 # Automatically determine the type
626 lappend lines
"/* #undef $n */"
629 if {![string is integer
-strict $value]} {
630 set value
\"[string map
[list \\ \\\\ \" \\\"] $value]\"
637 autosetup-error
"Unknown type in make-config-header: $type"
640 lappend lines
"#define $n $value"
642 lappend lines
"#endif"
643 set buf
[join $lines \n]
644 write-if-changed
$file $buf {
645 msg-result
"Created $file"
649 proc calc-define-output-type
{name spec
} {
650 foreach {type patterns
} $spec {
651 foreach pattern
$patterns {
652 if {[string match
$pattern $name]} {
660 # Initialise some values from the environment or commandline or default settings
661 foreach i
{LDFLAGS LIBS CPPFLAGS LINKFLAGS
{CFLAGS
"-g -O2"}} {
662 lassign
$i var
default
663 define
$var [get-env
$var $default]
666 if {[env-is-set CC
]} {
667 # Set by the user, so don't try anything else
668 set try
[list [get-env CC
""]]
670 # Try some reasonable options
671 set try
[list [get-define cross
]cc
[get-define cross
]gcc
]
673 define CC
[find-an-executable
{*}$try]
674 if {[get-define CC
] eq
""} {
675 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
678 define CPP
[get-env CPP
"[get-define CC] -E"]
680 # XXX: Could avoid looking for a C++ compiler until requested
681 # Note that if CXX isn't found, we just set it to "false". It might not be needed.
682 if {[env-is-set CXX
]} {
683 define CXX
[find-an-executable
-required [get-env CXX
""]]
685 define CXX
[find-an-executable
[get-define cross
]c
++ [get-define cross
]g
++ false
]
688 # CXXFLAGS default to CFLAGS if not specified
689 define CXXFLAGS
[get-env CXXFLAGS
[get-define CFLAGS
]]
691 # May need a CC_FOR_BUILD, so look for one
692 define CC_FOR_BUILD
[find-an-executable
[get-env CC_FOR_BUILD
""] cc gcc false
]
694 if {[get-define CC
] eq
""} {
695 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
698 define CCACHE
[find-an-executable
[get-env CCACHE ccache
]]
700 # Initial cctest settings
701 cc-store-settings
{-cflags {} -includes {} -declare {} -link 0 -lang c
-libs {} -code {} -nooutput 0}
702 set autosetup
(cc-include-deps
) {}
704 msg-result
"C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
705 if {[get-define CXX
] ne
"false"} {
706 msg-result
"C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
708 msg-result
"Build C compiler...[get-define CC_FOR_BUILD]"
710 # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
711 # but some compilers may not support it, so test here.
712 switch -glob -- [get-define host
] {
714 if {[cctest
-cflags {-g0}]} {
715 define cc-default-debug
-g0
720 if {![cc-check-includes stdlib.h
]} {
721 user-error
"Compiler does not work. See config.log"