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-autoconf-h 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 # Note that the return code is not meaningful
34 proc cc-check-something
{name 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
} {
78 msg-checking
"Checking for sizeof $type..."
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 };"]} {
88 set define
[feature-define-name
$type SIZEOF_
]
91 # Return the last result
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
} {
104 if {![check-feature
$each $script]} {
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 cctest
-includes $each
120 # @cc-check-types type ...
122 # Checks that the types exist.
123 proc cc-check-types
{args
} {
124 cc-check-some-feature
$args {
129 # @cc-check-defines define ...
131 # Checks that the given preprocessor symbol is defined
132 proc cc-check-defines
{args
} {
133 cc-check-some-feature
$args {
138 # @cc-check-decls name ...
140 # Checks that each given name is either a preprocessor symbol or rvalue
141 # such as an enum. Note that the define used for a decl is HAVE_DECL_xxx
142 # rather than HAVE_xxx
143 proc cc-check-decls
{args
} {
146 msg-checking
"Checking for $name..."
147 set r
[cctest_decl
$name]
148 define-feature
"decl $name" $r
152 msg-result
"not found"
159 # @cc-check-functions function ...
161 # Checks that the given functions exist (can be linked)
162 proc cc-check-functions
{args
} {
163 cc-check-some-feature
$args {
164 cctest_function
$each
168 # @cc-check-members type.member ...
170 # Checks that the given type/structure members exist.
171 # A structure member is of the form "struct stat.st_mtime"
172 proc cc-check-members
{args
} {
173 cc-check-some-feature
$args {
178 # @cc-check-function-in-lib function libs ?otherlibs?
180 # Checks that the given given function can be found in one of the libs.
182 # First checks for no library required, then checks each of the libraries
185 # If the function is found, the feature is defined and lib_$function is defined
186 # to -l$lib where the function was found, or "" if no library required.
187 # In addition, -l$lib is added to the LIBS define.
189 # If additional libraries may be needed for linking, they should be specified
190 # as $extralibs as "-lotherlib1 -lotherlib2".
191 # These libraries are not automatically added to LIBS.
193 # Returns 1 if found or 0 if not.
195 proc cc-check-function-in-lib
{function libs
{otherlibs
{}}} {
196 msg-checking
"Checking libs for $function..."
198 cc-with
[list -libs $otherlibs] {
199 if {[cctest_function
$function]} {
200 msg-result
"none needed"
201 define lib_
$function ""
205 cc-with
[list -libs -l$lib] {
206 if {[cctest_function
$function]} {
208 define lib_
$function -l$lib
209 define-append LIBS
-l$lib
218 define
[feature-define-name
$function]
225 # @cc-check-tools tool ...
227 # Checks for existence of the given compiler tools, taking
228 # into account any cross compilation prefix.
230 # For example, when checking for "ar", first AR is checked on the command
231 # line and then in the environment. If not found, "${host}-ar" or
232 # simply "ar" is assumed depending upon whether cross compiling.
233 # The path is searched for this executable, and if found AR is defined
234 # to the executable name.
236 # It is an error if the executable is not found.
238 proc cc-check-tools
{args
} {
240 set TOOL
[string toupper
$tool]
241 set exe
[get-env
$TOOL [get-define cross
]$tool]
242 if {![find-executable
$exe]} {
243 user-error
"Failed to find $exe"
249 # @cc-check-progs prog ...
251 # Checks for existence of the given executables on the path.
253 # For example, when checking for "grep", the path is searched for
254 # the executable, 'grep', and if found GREP is defined as "grep".
256 # It the executable is not found, the variable is defined as false.
257 # Returns 1 if all programs were found, or 0 otherwise.
259 proc cc-check-progs
{args
} {
262 set PROG
[string toupper
$prog]
263 msg-checking
"Checking for $prog..."
264 if {![find-executable
$prog]} {
276 # Adds the given settings to $::autosetup(ccsettings) and
277 # returns the old settings.
279 proc cc-add-settings
{settings
} {
280 if {[llength $settings] % 2} {
281 autosetup-error
"settings list is missing a value: $settings"
284 set prev
[cc-get-settings
]
285 # workaround a bug in some versions of jimsh by forcing
286 # conversion of $prev to a list
291 foreach {name value
} $settings {
292 switch -exact -- $name {
293 -cflags - -includes {
294 # These are given as lists
295 lappend new
($name) {*}$value
298 lappend new
($name) $value
301 # Note that new libraries are added before previous libraries
302 set new
($name) [list {*}$value {*}$new($name)]
305 set new
($name) $value
307 -source - -sourcefile - -code {
308 # XXX: These probably are only valid directly from cctest
309 set new
($name) $value
312 autosetup-error
"unknown cctest setting: $name"
317 cc-store-settings
[array get new
]
322 proc cc-store-settings
{new
} {
323 set ::autosetup(ccsettings
) $new
326 proc cc-get-settings
{} {
327 return $::autosetup(ccsettings
)
330 # Similar to cc-add-settings, but each given setting
331 # simply replaces the existing value.
333 # Returns the previous settings
334 proc cc-update-settings
{args
} {
335 set prev
[cc-get-settings
]
336 cc-store-settings
[dict merge
$prev $args]
340 # @cc-with settings ?{ script }?
342 # Sets the given 'cctest' settings and then runs the tests in 'script'.
343 # Note that settings such as -lang replace the current setting, while
344 # those such as -includes are appended to the existing setting.
346 # If no script is given, the settings become the default for the remainder
347 # of the auto.def file.
349 ## cc-with {-lang c++} {
350 ## # This will check with the C++ compiler
351 ## cc-check-types bool
352 ## cc-with {-includes signal.h} {
353 ## # This will check with the C++ compiler, signal.h and any existing includes.
356 ## # back to just the C++ compiler
359 # The -libs setting is special in that newer values are added *before* earlier ones.
361 ## cc-with {-libs {-lc -lm}} {
362 ## cc-with {-libs -ldl} {
363 ## cctest -libs -lsocket ...
364 ## # libs will be in this order: -lsocket -ldl -lc -lm
367 proc cc-with
{settings args
} {
368 if {[llength $args] == 0} {
369 cc-add-settings
$settings
370 } elseif
{[llength $args] > 1} {
371 autosetup-error
"usage: cc-with settings ?script?"
373 set save
[cc-add-settings
$settings]
374 set rc
[catch {uplevel 1 [lindex $args 0]} result
info]
375 cc-store-settings
$save
377 return $result -code [dict get
$info -code]
385 # Low level C compiler checker. Compiles and or links a small C program
386 # according to the arguments and returns 1 if OK, or 0 if not.
388 # Supported settings are:
390 ## -cflags cflags A list of flags to pass to the compiler
391 ## -includes list A list of includes, e.g. {stdlib.h stdio.h}
392 ## -declare code Code to declare before main()
393 ## -link 1 Don't just compile, link too
394 ## -lang c|c++ Use the C (default) or C++ compiler
395 ## -libs liblist List of libraries to link, e.g. {-ldl -lm}
396 ## -code code Code to compile in the body of main()
397 ## -source code Compile a complete program. Ignore -includes, -declare and -code
398 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
400 # Unless -source or -sourcefile is specified, the C program looks like:
402 ## #include <firstinclude> /* same for remaining includes in the list */
404 ## declare-code /* any code in -declare, verbatim */
407 ## code /* any code in -code, verbatim */
411 # Any failures are recorded in 'config.log'
417 # Easiest way to merge in the settings
419 array set opts
[cc-get-settings
]
422 if {[info exists opts
(-sourcefile)]} {
423 set opts
(-source) [readfile
[get-define srcdir
]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
425 if {[info exists opts
(-source)]} {
426 set lines
$opts(-source)
428 foreach i
$opts(-includes) {
429 if {$opts(-code) ne
"" && ![feature-checked
$i]} {
430 # Compiling real code with an unchecked header file
431 # Quickly (and silently) check for it now
433 # Remove all -includes from settings before checking
434 set saveopts
[cc-update-settings
-includes {}]
435 msg-quiet cc-check-includes
$i
436 cc-store-settings
$saveopts
438 if {$opts(-code) eq
"" ||
[have-feature
$i]} {
439 lappend source "#include <$i>"
442 lappend source {*}$opts(-declare)
443 lappend source "int main(void) {"
444 lappend source $opts(-code)
445 lappend source "return 0;"
448 set lines
[join $source \n]
451 # Build the command line
453 lappend cmdline
{*}[get-define CCACHE
]
454 switch -exact -- $opts(-lang) {
456 lappend cmdline
{*}[get-define CXX
] {*}[get-define CXXFLAGS
]
459 lappend cmdline
{*}[get-define CC
] {*}[get-define CFLAGS
]
462 autosetup-error
"cctest called with unknown language: $opts(-lang)"
470 lappend cmdline
{*}$opts(-cflags)
472 switch -glob -- [get-define host
] {
474 # Don't generate .dSYM directories
475 lappend cmdline
-gstabs
478 lappend cmdline
$src -o $tmp {*}$opts(-libs)
480 # At this point we have the complete command line and the
481 # complete source to be compiled. Get the result from cache if
483 if {[info exists
::cc_cache($cmdline,$lines)]} {
484 msg-checking
"(cached) "
485 set ok
$::cc_cache($cmdline,$lines)
486 if {$::autosetup(debug
)} {
487 configlog
"From cache (ok=$ok): [join $cmdline]"
488 configlog
"============"
490 configlog
"============"
495 writefile
$src $lines\n
498 if {[catch {exec-with-stderr
{*}$cmdline} result errinfo
]} {
499 configlog
"Failed: [join $cmdline]"
501 configlog
"============"
502 configlog
"The failed code was:"
504 configlog
"============"
506 } elseif
{$::autosetup(debug
)} {
507 configlog
"Compiled OK: [join $cmdline]"
508 configlog
"============"
510 configlog
"============"
516 set ::cc_cache($cmdline,$lines) $ok
521 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
523 # Deprecated - see make-config-header
524 proc make-autoconf-h
{file {autopatterns
{HAVE_
*}} {barepatterns
{SIZEOF_
* HAVE_DECL_
*}}} {
525 user-notice
"*** make-autoconf-h is deprecated -- use make-config-header instead"
526 make-config-header
$file -auto $autopatterns -bare $barepatterns
529 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
531 # Examines all defined variables which match the given patterns
532 # and writes an include file, $file, which defines each of these.
533 # Variables which match '-auto' are output as follows:
534 # - defines which have the value "0" are ignored.
535 # - defines which have integer values are defined as the integer value.
536 # - any other value is defined as a string, e.g. "value"
537 # Variables which match '-bare' are defined as-is.
538 # Variables which match '-str' are defined as a string, e.g. "value"
539 # Variables which match '-none' are omitted.
541 # Note that order is important. The first pattern which matches is selected
542 # Default behaviour is:
544 # -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
546 # If the file would be unchanged, it is not written.
547 proc make-config-header
{file args
} {
548 set guard _
[string toupper
[regsub -all {[^a-zA-Z0-9
]} [file tail
$file] _
]]
549 file mkdir
[file dirname
$file]
551 lappend lines
"#ifndef $guard"
552 lappend lines
"#define $guard"
555 lappend args
-bare {SIZEOF_
* HAVE_DECL_
*} -auto HAVE_
*
557 foreach n
[lsort [dict keys
[all-defines
]]] {
558 set value
[get-define
$n]
559 set type
[calc-define-output-type
$n $args]
560 switch -exact -- $type {
562 # Just output the value unchanged
571 # Automatically determine the type
573 lappend lines
"/* #undef $n */"
576 if {![string is integer
-strict $value]} {
584 autosetup-error
"Unknown type in make-config-header: $type"
587 lappend lines
"#define $n $value"
589 lappend lines
"#endif"
590 set buf
[join $lines \n]
591 write-if-changed
$file $buf {
592 msg-result
"Created $file"
596 proc calc-define-output-type
{name spec
} {
597 foreach {type patterns
} $spec {
598 foreach pattern
$patterns {
599 if {[string match
$pattern $name]} {
607 # Initialise some values from the environment or commandline or default settings
608 foreach i
{LDFLAGS LIBS CPPFLAGS LINKFLAGS
{CFLAGS
"-g -O2"}} {
609 lassign
$i var
default
610 define
$var [get-env
$var $default]
613 if {[env-is-set CC
]} {
614 # Set by the user, so don't try anything else
615 set try
[list [get-env CC
""]]
617 # Try some reasonable options
618 set try
[list [get-define cross
]cc
[get-define cross
]gcc
]
620 define CC
[find-an-executable
{*}$try]
621 if {[get-define CC
] eq
""} {
622 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
625 define CPP
[get-env CPP
"[get-define CC] -E"]
627 # XXX: Could avoid looking for a C++ compiler until requested
628 # Note that if CXX isn't found, we just set it to "false". It might not be needed.
629 if {[env-is-set CXX
]} {
630 define CXX
[find-an-executable
-required [get-env CXX
""]]
632 define CXX
[find-an-executable
[get-define cross
]c
++ [get-define cross
]g
++ false
]
635 # CXXFLAGS default to CFLAGS if not specified
636 define CXXFLAGS
[get-env CXXFLAGS
[get-define CFLAGS
]]
640 # May need a CC_FOR_BUILD, so look for one
641 define CC_FOR_BUILD
[find-an-executable
[get-env CC_FOR_BUILD
""] cc gcc false
]
643 if {[get-define CC
] eq
""} {
644 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
647 define CCACHE
[find-an-executable
[get-env CCACHE ccache
]]
649 # Initial cctest settings
650 cc-store-settings
{-cflags {} -includes {} -declare {} -link 0 -lang c
-libs {} -code {}}
652 msg-result
"C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
653 if {[get-define CXX
] ne
"false"} {
654 msg-result
"C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
656 msg-result
"Build C compiler...[get-define CC_FOR_BUILD]"
658 if {![cc-check-includes stdlib.h
]} {
659 user-error
"Compiler does not work. See config.log"