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 ## CPP - C preprocessor
15 ## CCACHE - Set to "none" to disable automatic use of ccache
16 ## CFLAGS - Additional C compiler flags
17 ## CXXFLAGS - Additional C++ compiler flags
18 ## LDFLAGS - Additional compiler flags during linking
19 ## LIBS - Additional libraries to use (for all tests)
20 ## CROSS - Tool prefix for cross compilation
22 # The following variables are defined from the corresponding
23 # environment variables if set.
34 # Checks for the existence of the given function by linking
36 proc cctest_function
{function
} {
37 cctest
-link 1 -declare "extern void $function\(void);" -code "$function\();"
40 # Checks for the existence of the given type by compiling
41 proc cctest_type
{type
} {
42 cctest
-code "$type _x;"
45 # Checks for the existence of the given type/structure member.
46 # e.g. "struct stat.st_mtime"
47 proc cctest_member
{struct_member
} {
48 # split at the first dot
49 regexp {^
([^.
]+)[.
](.
*)$} $struct_member -> struct member
50 cctest
-code "static $struct _s; return sizeof(_s.$member);"
53 # Checks for the existence of the given define by compiling
55 proc cctest_define
{name
} {
56 cctest
-code "#ifndef $name\n#error not defined\n#endif"
59 # Checks for the existence of the given name either as
60 # a macro (#define) or an rvalue (such as an enum)
62 proc cctest_decl
{name
} {
63 cctest
-code "#ifndef $name\n(void)$name;\n#endif"
66 # @cc-check-sizeof type ...
68 # Checks the size of the given types (between 1 and 32, inclusive).
69 # Defines a variable with the size determined, or 'unknown' otherwise.
70 # e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
71 # Returns the size of the last type.
73 proc cc-check-sizeof
{args
} {
75 msg-checking
"Checking for sizeof $type..."
77 # Try the most common sizes first
78 foreach i
{4 8 1 2 16 32} {
79 if {[cctest
-code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
85 set define
[feature-define-name
$type SIZEOF_
]
88 # Return the last result
92 # Checks for each feature in $list by using the given script.
94 # When the script is evaluated, $each is set to the feature
95 # being checked, and $extra is set to any additional cctest args.
97 # Returns 1 if all features were found, or 0 otherwise.
98 proc cc-check-some-feature
{list script
} {
101 if {![check-feature
$each $script]} {
108 # @cc-check-includes includes ...
110 # Checks that the given include files can be used.
111 proc cc-check-includes
{args
} {
112 cc-check-some-feature
$args {
114 if {[dict exists
$::autosetup(cc-include-deps
) $each]} {
115 set deps
[dict keys
[dict get
$::autosetup(cc-include-deps
) $each]]
116 msg-quiet cc-check-includes
{*}$deps
118 if {[have-feature
$i]} {
123 if {[llength $with]} {
124 cc-with
[list -includes $with] {
125 cctest
-includes $each
128 cctest
-includes $each
133 # @cc-include-needs include required ...
135 # Ensures that when checking for '$include', a check is first
136 # made for each '$required' file, and if found, it is included with '#include'.
137 proc cc-include-needs
{file args
} {
138 foreach depfile
$args {
139 dict
set ::autosetup(cc-include-deps
) $file $depfile 1
143 # @cc-check-types type ...
145 # Checks that the types exist.
146 proc cc-check-types
{args
} {
147 cc-check-some-feature
$args {
152 # @cc-check-defines define ...
154 # Checks that the given preprocessor symbols are defined.
155 proc cc-check-defines
{args
} {
156 cc-check-some-feature
$args {
161 # @cc-check-decls name ...
163 # Checks that each given name is either a preprocessor symbol or rvalue
164 # such as an enum. Note that the define used is 'HAVE_DECL_xxx'
165 # rather than 'HAVE_xxx'.
166 proc cc-check-decls
{args
} {
169 msg-checking
"Checking for $name..."
170 set r
[cctest_decl
$name]
171 define-feature
"decl $name" $r
175 msg-result
"not found"
182 # @cc-check-functions function ...
184 # Checks that the given functions exist (can be linked).
185 proc cc-check-functions
{args
} {
186 cc-check-some-feature
$args {
187 cctest_function
$each
191 # @cc-check-members type.member ...
193 # Checks that the given type/structure members exist.
194 # A structure member is of the form 'struct stat.st_mtime'.
195 proc cc-check-members
{args
} {
196 cc-check-some-feature
$args {
201 # @cc-check-function-in-lib function libs ?otherlibs?
203 # Checks that the given function can be found in one of the libs.
205 # First checks for no library required, then checks each of the libraries
208 # If the function is found, the feature is defined and 'lib_$function' is defined
209 # to '-l$lib' where the function was found, or "" if no library required.
210 # In addition, '-l$lib' is prepended to the 'LIBS' define.
212 # If additional libraries may be needed for linking, they should be specified
213 # with '$extralibs' as '-lotherlib1 -lotherlib2'.
214 # These libraries are not automatically added to 'LIBS'.
216 # Returns 1 if found or 0 if not.
218 proc cc-check-function-in-lib
{function libs
{otherlibs
{}}} {
219 msg-checking
"Checking libs for $function..."
221 cc-with
[list -libs $otherlibs] {
222 if {[cctest_function
$function]} {
223 msg-result
"none needed"
224 define lib_
$function ""
228 cc-with
[list -libs -l$lib] {
229 if {[cctest_function
$function]} {
231 define lib_
$function -l$lib
233 define LIBS
"-l$lib [get-define LIBS]"
241 define-feature
$function $found
248 # @cc-check-tools tool ...
250 # Checks for existence of the given compiler tools, taking
251 # into account any cross compilation prefix.
253 # For example, when checking for 'ar', first 'AR' is checked on the command
254 # line and then in the environment. If not found, '${host}-ar' or
255 # simply 'ar' is assumed depending upon whether cross compiling.
256 # The path is searched for this executable, and if found 'AR' is defined
257 # to the executable name.
258 # Note that even when cross compiling, the simple 'ar' is used as a fallback,
259 # but a warning is generated. This is necessary for some toolchains.
261 # It is an error if the executable is not found.
263 proc cc-check-tools
{args
} {
265 set TOOL
[string toupper
$tool]
266 set exe
[get-env
$TOOL [get-define cross
]$tool]
267 if {[find-executable
{*}$exe]} {
271 if {[find-executable
{*}$tool]} {
272 msg-result
"Warning: Failed to find $exe, falling back to $tool which may be incorrect"
276 user-error
"Failed to find $exe"
280 # @cc-check-progs prog ...
282 # Checks for existence of the given executables on the path.
284 # For example, when checking for 'grep', the path is searched for
285 # the executable, 'grep', and if found 'GREP' is defined as 'grep'.
287 # If the executable is not found, the variable is defined as 'false'.
288 # Returns 1 if all programs were found, or 0 otherwise.
290 proc cc-check-progs
{args
} {
293 set PROG
[string toupper
$prog]
294 msg-checking
"Checking for $prog..."
295 if {![find-executable
$prog]} {
307 # @cc-path-progs prog ...
309 # Like cc-check-progs, but sets the define to the full path rather
310 # than just the program name.
312 proc cc-path-progs
{args
} {
315 set PROG
[string toupper
$prog]
316 msg-checking
"Checking for $prog..."
317 set path
[find-executable-path
$prog]
330 # Adds the given settings to $::autosetup(ccsettings) and
331 # returns the old settings.
333 proc cc-add-settings
{settings
} {
334 if {[llength $settings] % 2} {
335 autosetup-error
"settings list is missing a value: $settings"
338 set prev
[cc-get-settings
]
339 # workaround a bug in some versions of jimsh by forcing
340 # conversion of $prev to a list
345 foreach {name value
} $settings {
346 switch -exact -- $name {
347 -cflags - -includes {
348 # These are given as lists
349 lappend new
($name) {*}[list-non-empty
$value]
352 lappend new
($name) $value
355 # Note that new libraries are added before previous libraries
356 set new
($name) [list {*}[list-non-empty
$value] {*}$new($name)]
358 -link - -lang - -nooutput {
359 set new
($name) $value
361 -source - -sourcefile - -code {
362 # XXX: These probably are only valid directly from cctest
363 set new
($name) $value
366 autosetup-error
"unknown cctest setting: $name"
371 cc-store-settings
[array get new
]
376 proc cc-store-settings
{new
} {
377 set ::autosetup(ccsettings
) $new
380 proc cc-get-settings
{} {
381 return $::autosetup(ccsettings
)
384 # Similar to cc-add-settings, but each given setting
385 # simply replaces the existing value.
387 # Returns the previous settings
388 proc cc-update-settings
{args
} {
389 set prev
[cc-get-settings
]
390 cc-store-settings
[dict merge
$prev $args]
394 # @cc-with settings ?{ script }?
396 # Sets the given 'cctest' settings and then runs the tests in '$script'.
397 # Note that settings such as '-lang' replace the current setting, while
398 # those such as '-includes' are appended to the existing setting.
400 # If no script is given, the settings become the default for the remainder
401 # of the 'auto.def' file.
403 ## cc-with {-lang c++} {
404 ## # This will check with the C++ compiler
405 ## cc-check-types bool
406 ## cc-with {-includes signal.h} {
407 ## # This will check with the C++ compiler, signal.h and any existing includes.
410 ## # back to just the C++ compiler
413 # The '-libs' setting is special in that newer values are added *before* earlier ones.
415 ## cc-with {-libs {-lc -lm}} {
416 ## cc-with {-libs -ldl} {
417 ## cctest -libs -lsocket ...
418 ## # libs will be in this order: -lsocket -ldl -lc -lm
421 proc cc-with
{settings args
} {
422 if {[llength $args] == 0} {
423 cc-add-settings
$settings
424 } elseif
{[llength $args] > 1} {
425 autosetup-error
"usage: cc-with settings ?script?"
427 set save
[cc-add-settings
$settings]
428 set rc
[catch {uplevel 1 [lindex $args 0]} result
info]
429 cc-store-settings
$save
431 return -code [dict get
$info -code] $result
439 # Low level C/C++ compiler checker. Compiles and or links a small C program
440 # according to the arguments and returns 1 if OK, or 0 if not.
442 # Supported settings are:
444 ## -cflags cflags A list of flags to pass to the compiler
445 ## -includes list A list of includes, e.g. {stdlib.h stdio.h}
446 ## -declare code Code to declare before main()
447 ## -link 1 Don't just compile, link too
448 ## -lang c|c++ Use the C (default) or C++ compiler
449 ## -libs liblist List of libraries to link, e.g. {-ldl -lm}
450 ## -code code Code to compile in the body of main()
451 ## -source code Compile a complete program. Ignore -includes, -declare and -code
452 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
453 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
455 # Unless '-source' or '-sourcefile' is specified, the C program looks like:
457 ## #include <firstinclude> /* same for remaining includes in the list */
459 ## declare-code /* any code in -declare, verbatim */
462 ## code /* any code in -code, verbatim */
466 # 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 set src conftest__.cpp
511 lappend cmdline
{*}[get-define CXX
] {*}[get-define CXXFLAGS
]
515 lappend cmdline
{*}[get-define CC
] {*}[get-define CFLAGS
]
518 autosetup-error
"cctest called with unknown language: $opts(-lang)"
523 lappend cmdline
{*}[get-define LDFLAGS
]
528 lappend cmdline
{*}$opts(-cflags) {*}[get-define cc-default-debug
""]
529 lappend cmdline
$src -o $tmp {*}$opts(-libs)
531 lappend cmdline
{*}[get-define LIBS
]
534 # At this point we have the complete command line and the
535 # complete source to be compiled. Get the result from cache if
537 if {[info exists
::cc_cache($cmdline,$lines)]} {
538 msg-checking
"(cached) "
539 set ok
$::cc_cache($cmdline,$lines)
540 if {$::autosetup(debug
)} {
541 configlog
"From cache (ok=$ok): [join $cmdline]"
542 configlog
"============"
544 configlog
"============"
549 writefile
$src $lines\n
552 set err
[catch {exec-with-stderr
{*}$cmdline} result errinfo
]
553 if {$err ||
($opts(-nooutput) && [string length
$result])} {
554 configlog
"Failed: [join $cmdline]"
556 configlog
"============"
557 configlog
"The failed code was:"
559 configlog
"============"
561 } elseif
{$::autosetup(debug
)} {
562 configlog
"Compiled OK: [join $cmdline]"
563 configlog
"============"
565 configlog
"============"
571 set ::cc_cache($cmdline,$lines) $ok
576 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
578 # Deprecated - see 'make-config-header'
579 proc make-autoconf-h
{file {autopatterns
{HAVE_
*}} {barepatterns
{SIZEOF_
* HAVE_DECL_
*}}} {
580 user-notice
"*** make-autoconf-h is deprecated -- use make-config-header instead"
581 make-config-header
$file -auto $autopatterns -bare $barepatterns
584 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
586 # Examines all defined variables which match the given patterns
587 # and writes an include file, '$file', which defines each of these.
588 # Variables which match '-auto' are output as follows:
589 # - defines which have the value '0' are ignored.
590 # - defines which have integer values are defined as the integer value.
591 # - any other value is defined as a string, e.g. '"value"'
592 # Variables which match '-bare' are defined as-is.
593 # Variables which match '-str' are defined as a string, e.g. '"value"'
594 # Variables which match '-none' are omitted.
596 # Note that order is important. The first pattern that matches is selected.
597 # Default behaviour is:
599 ## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
601 # If the file would be unchanged, it is not written.
602 proc make-config-header
{file args
} {
603 set guard _
[string toupper
[regsub -all {[^a-zA-Z0-9
]} [file tail
$file] _
]]
604 file mkdir
[file dirname
$file]
606 lappend lines
"#ifndef $guard"
607 lappend lines
"#define $guard"
610 lappend args
-bare {SIZEOF_
* HAVE_DECL_
*} -auto HAVE_
*
612 foreach n
[lsort [dict keys
[all-defines
]]] {
613 set value
[get-define
$n]
614 set type
[calc-define-output-type
$n $args]
615 switch -exact -- $type {
617 # Just output the value unchanged
623 set value
\"[string map
[list \\ \\\\ \" \\\"] $value]\"
626 # Automatically determine the type
628 lappend lines
"/* #undef $n */"
631 if {![string is integer
-strict $value]} {
632 set value
\"[string map
[list \\ \\\\ \" \\\"] $value]\"
639 autosetup-error
"Unknown type in make-config-header: $type"
642 lappend lines
"#define $n $value"
644 lappend lines
"#endif"
645 set buf
[join $lines \n]
646 write-if-changed
$file $buf {
647 msg-result
"Created $file"
651 proc calc-define-output-type
{name spec
} {
652 foreach {type patterns
} $spec {
653 foreach pattern
$patterns {
654 if {[string match
$pattern $name]} {
662 # Initialise some values from the environment or commandline or default settings
663 foreach i
{LDFLAGS LIBS CPPFLAGS LINKFLAGS
{CFLAGS
"-g -O2"}} {
664 lassign
$i var
default
665 define
$var [get-env
$var $default]
668 if {[env-is-set CC
]} {
669 # Set by the user, so don't try anything else
670 set try
[list [get-env CC
""]]
672 # Try some reasonable options
673 set try
[list [get-define cross
]cc
[get-define cross
]gcc
]
675 define CC
[find-an-executable
{*}$try]
676 if {[get-define CC
] eq
""} {
677 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
680 define CPP
[get-env CPP
"[get-define CC] -E"]
682 # XXX: Could avoid looking for a C++ compiler until requested
683 # Note that if CXX isn't found, we just set it to "false". It might not be needed.
684 if {[env-is-set CXX
]} {
685 define CXX
[find-an-executable
-required [get-env CXX
""]]
687 define CXX
[find-an-executable
[get-define cross
]c
++ [get-define cross
]g
++ false
]
690 # CXXFLAGS default to CFLAGS if not specified
691 define CXXFLAGS
[get-env CXXFLAGS
[get-define CFLAGS
]]
693 # May need a CC_FOR_BUILD, so look for one
694 define CC_FOR_BUILD
[find-an-executable
[get-env CC_FOR_BUILD
""] cc gcc false
]
696 if {[get-define CC
] eq
""} {
697 user-error
"Could not find a C compiler. Tried: [join $try ", "]"
700 define CCACHE
[find-an-executable
[get-env CCACHE ccache
]]
702 # If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
703 foreach i
{CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD
} {
704 if {[env-is-set
$i]} {
705 # Note: If the variable is set on the command line, get-env will return that value
706 # so the command line will continue to override the environment
707 define-append AUTOREMAKE
[quote-if-needed
$i=[get-env
$i ""]]
711 # Initial cctest settings
712 cc-store-settings
{-cflags {} -includes {} -declare {} -link 0 -lang c
-libs {} -code {} -nooutput 0}
713 set autosetup
(cc-include-deps
) {}
715 msg-result
"C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
716 if {[get-define CXX
] ne
"false"} {
717 msg-result
"C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
719 msg-result
"Build C compiler...[get-define CC_FOR_BUILD]"
721 # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
722 # but some compilers may not support it, so test here.
723 switch -glob -- [get-define host
] {
725 if {[cctest
-cflags {-g0}]} {
726 define cc-default-debug
-g0
731 if {![cc-check-includes stdlib.h
]} {
732 user-error
"Compiler does not work. See config.log"