Home | History | Annotate | Line # | Download | only in autosetup
cc.tcl revision 1.1
      1  1.1  christos # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
      2  1.1  christos # All rights reserved
      3  1.1  christos 
      4  1.1  christos # @synopsis:
      5  1.1  christos #
      6  1.1  christos # The 'cc' module supports checking various 'features' of the C or C++
      7  1.1  christos # compiler/linker environment. Common commands are 'cc-check-includes',
      8  1.1  christos # 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
      9  1.1  christos #
     10  1.1  christos # The following environment variables are used if set:
     11  1.1  christos #
     12  1.1  christos ## CC       - C compiler
     13  1.1  christos ## CXX      - C++ compiler
     14  1.1  christos ## CPP      - C preprocessor
     15  1.1  christos ## CCACHE   - Set to "none" to disable automatic use of ccache
     16  1.1  christos ## CPPFLAGS  - Additional C preprocessor compiler flags (C and C++), before CFLAGS, CXXFLAGS
     17  1.1  christos ## CFLAGS   - Additional C compiler flags
     18  1.1  christos ## CXXFLAGS - Additional C++ compiler flags
     19  1.1  christos ## LDFLAGS  - Additional compiler flags during linking
     20  1.1  christos ## LINKFLAGS - ?How is this different from LDFLAGS?
     21  1.1  christos ## LIBS     - Additional libraries to use (for all tests)
     22  1.1  christos ## CROSS    - Tool prefix for cross compilation
     23  1.1  christos #
     24  1.1  christos # The following variables are defined from the corresponding
     25  1.1  christos # environment variables if set.
     26  1.1  christos #
     27  1.1  christos ## CC_FOR_BUILD
     28  1.1  christos ## LD
     29  1.1  christos 
     30  1.1  christos use system
     31  1.1  christos 
     32  1.1  christos options {}
     33  1.1  christos 
     34  1.1  christos # Checks for the existence of the given function by linking
     35  1.1  christos #
     36  1.1  christos proc cctest_function {function} {
     37  1.1  christos 	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
     38  1.1  christos }
     39  1.1  christos 
     40  1.1  christos # Checks for the existence of the given type by compiling
     41  1.1  christos proc cctest_type {type} {
     42  1.1  christos 	cctest -code "$type _x;"
     43  1.1  christos }
     44  1.1  christos 
     45  1.1  christos # Checks for the existence of the given type/structure member.
     46  1.1  christos # e.g. "struct stat.st_mtime"
     47  1.1  christos proc cctest_member {struct_member} {
     48  1.1  christos 	# split at the first dot
     49  1.1  christos 	regexp {^([^.]+)[.](.*)$} $struct_member -> struct member
     50  1.1  christos 	cctest -code "static $struct _s; return sizeof(_s.$member);"
     51  1.1  christos }
     52  1.1  christos 
     53  1.1  christos # Checks for the existence of the given define by compiling
     54  1.1  christos #
     55  1.1  christos proc cctest_define {name} {
     56  1.1  christos 	cctest -code "#ifndef $name\n#error not defined\n#endif"
     57  1.1  christos }
     58  1.1  christos 
     59  1.1  christos # Checks for the existence of the given name either as
     60  1.1  christos # a macro (#define) or an rvalue (such as an enum)
     61  1.1  christos #
     62  1.1  christos proc cctest_decl {name} {
     63  1.1  christos 	cctest -code "#ifndef $name\n(void)$name;\n#endif"
     64  1.1  christos }
     65  1.1  christos 
     66  1.1  christos # @cc-check-sizeof type ...
     67  1.1  christos #
     68  1.1  christos # Checks the size of the given types (between 1 and 32, inclusive).
     69  1.1  christos # Defines a variable with the size determined, or 'unknown' otherwise.
     70  1.1  christos # e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
     71  1.1  christos # Returns the size of the last type.
     72  1.1  christos #
     73  1.1  christos proc cc-check-sizeof {args} {
     74  1.1  christos 	foreach type $args {
     75  1.1  christos 		msg-checking "Checking for sizeof $type..."
     76  1.1  christos 		set size unknown
     77  1.1  christos 		# Try the most common sizes first
     78  1.1  christos 		foreach i {4 8 1 2 16 32} {
     79  1.1  christos 			if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
     80  1.1  christos 				set size $i
     81  1.1  christos 				break
     82  1.1  christos 			}
     83  1.1  christos 		}
     84  1.1  christos 		msg-result $size
     85  1.1  christos 		set define [feature-define-name $type SIZEOF_]
     86  1.1  christos 		define $define $size
     87  1.1  christos 	}
     88  1.1  christos 	# Return the last result
     89  1.1  christos 	get-define $define
     90  1.1  christos }
     91  1.1  christos 
     92  1.1  christos # Checks for each feature in $list by using the given script.
     93  1.1  christos #
     94  1.1  christos # When the script is evaluated, $each is set to the feature
     95  1.1  christos # being checked, and $extra is set to any additional cctest args.
     96  1.1  christos #
     97  1.1  christos # Returns 1 if all features were found, or 0 otherwise.
     98  1.1  christos proc cc-check-some-feature {list script} {
     99  1.1  christos 	set ret 1
    100  1.1  christos 	foreach each $list {
    101  1.1  christos 		if {![check-feature $each $script]} {
    102  1.1  christos 			set ret 0
    103  1.1  christos 		}
    104  1.1  christos 	}
    105  1.1  christos 	return $ret
    106  1.1  christos }
    107  1.1  christos 
    108  1.1  christos # @cc-check-includes includes ...
    109  1.1  christos #
    110  1.1  christos # Checks that the given include files can be used.
    111  1.1  christos proc cc-check-includes {args} {
    112  1.1  christos 	cc-check-some-feature $args {
    113  1.1  christos 		set with {}
    114  1.1  christos 		if {[dict exists $::autosetup(cc-include-deps) $each]} {
    115  1.1  christos 			set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
    116  1.1  christos 			msg-quiet cc-check-includes {*}$deps
    117  1.1  christos 			foreach i $deps {
    118  1.1  christos 				if {[have-feature $i]} {
    119  1.1  christos 					lappend with $i
    120  1.1  christos 				}
    121  1.1  christos 			}
    122  1.1  christos 		}
    123  1.1  christos 		if {[llength $with]} {
    124  1.1  christos 			cc-with [list -includes $with] {
    125  1.1  christos 				cctest -includes $each
    126  1.1  christos 			}
    127  1.1  christos 		} else {
    128  1.1  christos 			cctest -includes $each
    129  1.1  christos 		}
    130  1.1  christos 	}
    131  1.1  christos }
    132  1.1  christos 
    133  1.1  christos # @cc-include-needs include required ...
    134  1.1  christos #
    135  1.1  christos # Ensures that when checking for '$include', a check is first
    136  1.1  christos # made for each '$required' file, and if found, it is included with '#include'.
    137  1.1  christos proc cc-include-needs {file args} {
    138  1.1  christos 	foreach depfile $args {
    139  1.1  christos 		dict set ::autosetup(cc-include-deps) $file $depfile 1
    140  1.1  christos 	}
    141  1.1  christos }
    142  1.1  christos 
    143  1.1  christos # @cc-check-types type ...
    144  1.1  christos #
    145  1.1  christos # Checks that the types exist.
    146  1.1  christos proc cc-check-types {args} {
    147  1.1  christos 	cc-check-some-feature $args {
    148  1.1  christos 		cctest_type $each
    149  1.1  christos 	}
    150  1.1  christos }
    151  1.1  christos 
    152  1.1  christos # @cc-check-defines define ...
    153  1.1  christos #
    154  1.1  christos # Checks that the given preprocessor symbols are defined.
    155  1.1  christos proc cc-check-defines {args} {
    156  1.1  christos 	cc-check-some-feature $args {
    157  1.1  christos 		cctest_define $each
    158  1.1  christos 	}
    159  1.1  christos }
    160  1.1  christos 
    161  1.1  christos # @cc-check-decls name ...
    162  1.1  christos #
    163  1.1  christos # Checks that each given name is either a preprocessor symbol or rvalue
    164  1.1  christos # such as an enum. Note that the define used is 'HAVE_DECL_xxx'
    165  1.1  christos # rather than 'HAVE_xxx'.
    166  1.1  christos proc cc-check-decls {args} {
    167  1.1  christos 	set ret 1
    168  1.1  christos 	foreach name $args {
    169  1.1  christos 		msg-checking "Checking for $name..."
    170  1.1  christos 		set r [cctest_decl $name]
    171  1.1  christos 		define-feature "decl $name" $r
    172  1.1  christos 		if {$r} {
    173  1.1  christos 			msg-result "ok"
    174  1.1  christos 		} else {
    175  1.1  christos 			msg-result "not found"
    176  1.1  christos 			set ret 0
    177  1.1  christos 		}
    178  1.1  christos 	}
    179  1.1  christos 	return $ret
    180  1.1  christos }
    181  1.1  christos 
    182  1.1  christos # @cc-check-functions function ...
    183  1.1  christos #
    184  1.1  christos # Checks that the given functions exist (can be linked).
    185  1.1  christos proc cc-check-functions {args} {
    186  1.1  christos 	cc-check-some-feature $args {
    187  1.1  christos 		cctest_function $each
    188  1.1  christos 	}
    189  1.1  christos }
    190  1.1  christos 
    191  1.1  christos # @cc-check-members type.member ...
    192  1.1  christos #
    193  1.1  christos # Checks that the given type/structure members exist.
    194  1.1  christos # A structure member is of the form 'struct stat.st_mtime'.
    195  1.1  christos proc cc-check-members {args} {
    196  1.1  christos 	cc-check-some-feature $args {
    197  1.1  christos 		cctest_member $each
    198  1.1  christos 	}
    199  1.1  christos }
    200  1.1  christos 
    201  1.1  christos # @cc-check-function-in-lib function libs ?otherlibs?
    202  1.1  christos #
    203  1.1  christos # Checks that the given function can be found in one of the libs.
    204  1.1  christos #
    205  1.1  christos # First checks for no library required, then checks each of the libraries
    206  1.1  christos # in turn.
    207  1.1  christos #
    208  1.1  christos # If the function is found, the feature is defined and 'lib_$function' is defined
    209  1.1  christos # to '-l$lib' where the function was found, or "" if no library required.
    210  1.1  christos # In addition, '-l$lib' is prepended to the 'LIBS' define.
    211  1.1  christos #
    212  1.1  christos # If additional libraries may be needed for linking, they should be specified
    213  1.1  christos # with '$extralibs' as '-lotherlib1 -lotherlib2'.
    214  1.1  christos # These libraries are not automatically added to 'LIBS'.
    215  1.1  christos #
    216  1.1  christos # Returns 1 if found or 0 if not.
    217  1.1  christos #
    218  1.1  christos proc cc-check-function-in-lib {function libs {otherlibs {}}} {
    219  1.1  christos 	msg-checking "Checking libs for $function..."
    220  1.1  christos 	set found 0
    221  1.1  christos 	cc-with [list -libs $otherlibs] {
    222  1.1  christos 		if {[cctest_function $function]} {
    223  1.1  christos 			msg-result "none needed"
    224  1.1  christos 			define lib_$function ""
    225  1.1  christos 			incr found
    226  1.1  christos 		} else {
    227  1.1  christos 			foreach lib $libs {
    228  1.1  christos 				cc-with [list -libs -l$lib] {
    229  1.1  christos 					if {[cctest_function $function]} {
    230  1.1  christos 						msg-result -l$lib
    231  1.1  christos 						define lib_$function -l$lib
    232  1.1  christos 						# prepend to LIBS
    233  1.1  christos 						define LIBS "-l$lib [get-define LIBS]"
    234  1.1  christos 						incr found
    235  1.1  christos 						break
    236  1.1  christos 					}
    237  1.1  christos 				}
    238  1.1  christos 			}
    239  1.1  christos 		}
    240  1.1  christos 	}
    241  1.1  christos 	define-feature $function $found
    242  1.1  christos 	if {!$found} {
    243  1.1  christos 		msg-result "no"
    244  1.1  christos 	}
    245  1.1  christos 	return $found
    246  1.1  christos }
    247  1.1  christos 
    248  1.1  christos # @cc-check-tools tool ...
    249  1.1  christos #
    250  1.1  christos # Checks for existence of the given compiler tools, taking
    251  1.1  christos # into account any cross compilation prefix.
    252  1.1  christos #
    253  1.1  christos # For example, when checking for 'ar', first 'AR' is checked on the command
    254  1.1  christos # line and then in the environment. If not found, '${host}-ar' or
    255  1.1  christos # simply 'ar' is assumed depending upon whether cross compiling.
    256  1.1  christos # The path is searched for this executable, and if found 'AR' is defined
    257  1.1  christos # to the executable name.
    258  1.1  christos # Note that even when cross compiling, the simple 'ar' is used as a fallback,
    259  1.1  christos # but a warning is generated. This is necessary for some toolchains.
    260  1.1  christos #
    261  1.1  christos # It is an error if the executable is not found.
    262  1.1  christos #
    263  1.1  christos proc cc-check-tools {args} {
    264  1.1  christos 	foreach tool $args {
    265  1.1  christos 		set TOOL [string toupper $tool]
    266  1.1  christos 		set exe [get-env $TOOL [get-define cross]$tool]
    267  1.1  christos 		if {[find-executable $exe]} {
    268  1.1  christos 			define $TOOL $exe
    269  1.1  christos 			continue
    270  1.1  christos 		}
    271  1.1  christos 		if {[find-executable $tool]} {
    272  1.1  christos 			msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
    273  1.1  christos 			define $TOOL $tool
    274  1.1  christos 			continue
    275  1.1  christos 		}
    276  1.1  christos 		user-error "Failed to find $exe"
    277  1.1  christos 	}
    278  1.1  christos }
    279  1.1  christos 
    280  1.1  christos # @cc-check-progs prog ...
    281  1.1  christos #
    282  1.1  christos # Checks for existence of the given executables on the path.
    283  1.1  christos #
    284  1.1  christos # For example, when checking for 'grep', the path is searched for
    285  1.1  christos # the executable, 'grep', and if found 'GREP' is defined as 'grep'.
    286  1.1  christos #
    287  1.1  christos # If the executable is not found, the variable is defined as 'false'.
    288  1.1  christos # Returns 1 if all programs were found, or 0 otherwise.
    289  1.1  christos #
    290  1.1  christos proc cc-check-progs {args} {
    291  1.1  christos 	set failed 0
    292  1.1  christos 	foreach prog $args {
    293  1.1  christos 		set PROG [string toupper $prog]
    294  1.1  christos 		msg-checking "Checking for $prog..."
    295  1.1  christos 		if {![find-executable $prog]} {
    296  1.1  christos 			msg-result no
    297  1.1  christos 			define $PROG false
    298  1.1  christos 			incr failed
    299  1.1  christos 		} else {
    300  1.1  christos 			msg-result ok
    301  1.1  christos 			define $PROG $prog
    302  1.1  christos 		}
    303  1.1  christos 	}
    304  1.1  christos 	expr {!$failed}
    305  1.1  christos }
    306  1.1  christos 
    307  1.1  christos # @cc-path-progs prog ...
    308  1.1  christos #
    309  1.1  christos # Like cc-check-progs, but sets the define to the full path rather
    310  1.1  christos # than just the program name.
    311  1.1  christos #
    312  1.1  christos proc cc-path-progs {args} {
    313  1.1  christos 	set failed 0
    314  1.1  christos 	foreach prog $args {
    315  1.1  christos 		set PROG [string toupper $prog]
    316  1.1  christos 		msg-checking "Checking for $prog..."
    317  1.1  christos 		set path [find-executable-path $prog]
    318  1.1  christos 		if {$path eq ""} {
    319  1.1  christos 			msg-result no
    320  1.1  christos 			define $PROG false
    321  1.1  christos 			incr failed
    322  1.1  christos 		} else {
    323  1.1  christos 			msg-result $path
    324  1.1  christos 			define $PROG $path
    325  1.1  christos 		}
    326  1.1  christos 	}
    327  1.1  christos 	expr {!$failed}
    328  1.1  christos }
    329  1.1  christos 
    330  1.1  christos # Adds the given settings to $::autosetup(ccsettings) and
    331  1.1  christos # returns the old settings.
    332  1.1  christos #
    333  1.1  christos proc cc-add-settings {settings} {
    334  1.1  christos 	if {[llength $settings] % 2} {
    335  1.1  christos 		autosetup-error "settings list is missing a value: $settings"
    336  1.1  christos 	}
    337  1.1  christos 
    338  1.1  christos 	set prev [cc-get-settings]
    339  1.1  christos 	# workaround a bug in some versions of jimsh by forcing
    340  1.1  christos 	# conversion of $prev to a list
    341  1.1  christos 	llength $prev
    342  1.1  christos 
    343  1.1  christos 	array set new $prev
    344  1.1  christos 
    345  1.1  christos 	foreach {name value} $settings {
    346  1.1  christos 		switch -exact -- $name {
    347  1.1  christos 			-cflags - -includes {
    348  1.1  christos 				# These are given as lists
    349  1.1  christos 				lappend new($name) {*}[list-non-empty $value]
    350  1.1  christos 			}
    351  1.1  christos 			-declare {
    352  1.1  christos 				lappend new($name) $value
    353  1.1  christos 			}
    354  1.1  christos 			-libs {
    355  1.1  christos 				# Note that new libraries are added before previous libraries
    356  1.1  christos 				set new($name) [list {*}[list-non-empty $value] {*}$new($name)]
    357  1.1  christos 			}
    358  1.1  christos 			-link - -lang - -nooutput {
    359  1.1  christos 				set new($name) $value
    360  1.1  christos 			}
    361  1.1  christos 			-source - -sourcefile - -code {
    362  1.1  christos 				# XXX: These probably are only valid directly from cctest
    363  1.1  christos 				set new($name) $value
    364  1.1  christos 			}
    365  1.1  christos 			default {
    366  1.1  christos 				autosetup-error "unknown cctest setting: $name"
    367  1.1  christos 			}
    368  1.1  christos 		}
    369  1.1  christos 	}
    370  1.1  christos 
    371  1.1  christos 	cc-store-settings [array get new]
    372  1.1  christos 
    373  1.1  christos 	return $prev
    374  1.1  christos }
    375  1.1  christos 
    376  1.1  christos proc cc-store-settings {new} {
    377  1.1  christos 	set ::autosetup(ccsettings) $new
    378  1.1  christos }
    379  1.1  christos 
    380  1.1  christos proc cc-get-settings {} {
    381  1.1  christos 	return $::autosetup(ccsettings)
    382  1.1  christos }
    383  1.1  christos 
    384  1.1  christos # Similar to cc-add-settings, but each given setting
    385  1.1  christos # simply replaces the existing value.
    386  1.1  christos #
    387  1.1  christos # Returns the previous settings
    388  1.1  christos proc cc-update-settings {args} {
    389  1.1  christos 	set prev [cc-get-settings]
    390  1.1  christos 	cc-store-settings [dict merge $prev $args]
    391  1.1  christos 	return $prev
    392  1.1  christos }
    393  1.1  christos 
    394  1.1  christos # @cc-with settings ?{ script }?
    395  1.1  christos #
    396  1.1  christos # Sets the given 'cctest' settings and then runs the tests in '$script'.
    397  1.1  christos # Note that settings such as '-lang' replace the current setting, while
    398  1.1  christos # those such as '-includes' are appended to the existing setting.
    399  1.1  christos #
    400  1.1  christos # If no script is given, the settings become the default for the remainder
    401  1.1  christos # of the 'auto.def' file.
    402  1.1  christos #
    403  1.1  christos ## cc-with {-lang c++} {
    404  1.1  christos ##   # This will check with the C++ compiler
    405  1.1  christos ##   cc-check-types bool
    406  1.1  christos ##   cc-with {-includes signal.h} {
    407  1.1  christos ##     # This will check with the C++ compiler, signal.h and any existing includes.
    408  1.1  christos ##     ...
    409  1.1  christos ##   }
    410  1.1  christos ##   # back to just the C++ compiler
    411  1.1  christos ## }
    412  1.1  christos #
    413  1.1  christos # The '-libs' setting is special in that newer values are added *before* earlier ones.
    414  1.1  christos #
    415  1.1  christos ## cc-with {-libs {-lc -lm}} {
    416  1.1  christos ##   cc-with {-libs -ldl} {
    417  1.1  christos ##     cctest -libs -lsocket ...
    418  1.1  christos ##     # libs will be in this order: -lsocket -ldl -lc -lm
    419  1.1  christos ##   }
    420  1.1  christos ## }
    421  1.1  christos #
    422  1.1  christos # If you wish to invoke something like cc-check-flags but not have -cflags updated,
    423  1.1  christos # use the following idiom:
    424  1.1  christos #
    425  1.1  christos ## cc-with {} {
    426  1.1  christos ##   cc-check-flags ...
    427  1.1  christos ## }
    428  1.1  christos proc cc-with {settings args} {
    429  1.1  christos 	if {[llength $args] == 0} {
    430  1.1  christos 		cc-add-settings $settings
    431  1.1  christos 	} elseif {[llength $args] > 1} {
    432  1.1  christos 		autosetup-error "usage: cc-with settings ?script?"
    433  1.1  christos 	} else {
    434  1.1  christos 		set save [cc-add-settings $settings]
    435  1.1  christos 		set rc [catch {uplevel 1 [lindex $args 0]} result info]
    436  1.1  christos 		cc-store-settings $save
    437  1.1  christos 		if {$rc != 0} {
    438  1.1  christos 			return -code [dict get $info -code] $result
    439  1.1  christos 		}
    440  1.1  christos 		return $result
    441  1.1  christos 	}
    442  1.1  christos }
    443  1.1  christos 
    444  1.1  christos # @cctest ?settings?
    445  1.1  christos #
    446  1.1  christos # Low level C/C++ compiler checker. Compiles and or links a small C program
    447  1.1  christos # according to the arguments and returns 1 if OK, or 0 if not.
    448  1.1  christos #
    449  1.1  christos # Supported settings are:
    450  1.1  christos #
    451  1.1  christos ## -cflags cflags      A list of flags to pass to the compiler
    452  1.1  christos ## -includes list      A list of includes, e.g. {stdlib.h stdio.h}
    453  1.1  christos ## -declare code       Code to declare before main()
    454  1.1  christos ## -link 1             Don't just compile, link too
    455  1.1  christos ## -lang c|c++         Use the C (default) or C++ compiler
    456  1.1  christos ## -libs liblist       List of libraries to link, e.g. {-ldl -lm}
    457  1.1  christos ## -code code          Code to compile in the body of main()
    458  1.1  christos ## -source code        Compile a complete program. Ignore -includes, -declare and -code
    459  1.1  christos ## -sourcefile file    Shorthand for -source [readfile [get-define srcdir]/$file]
    460  1.1  christos ## -nooutput 1         Treat any compiler output (e.g. a warning) as an error
    461  1.1  christos #
    462  1.1  christos # Unless '-source' or '-sourcefile' is specified, the C program looks like:
    463  1.1  christos #
    464  1.1  christos ## #include <firstinclude>   /* same for remaining includes in the list */
    465  1.1  christos ## declare-code              /* any code in -declare, verbatim */
    466  1.1  christos ## int main(void) {
    467  1.1  christos ##   code                    /* any code in -code, verbatim */
    468  1.1  christos ##   return 0;
    469  1.1  christos ## }
    470  1.1  christos #
    471  1.1  christos # And the command line looks like:
    472  1.1  christos #
    473  1.1  christos ## CC -cflags CFLAGS CPPFLAGS conftest.c -o conftest.o
    474  1.1  christos ## CXX -cflags CXXFLAGS CPPFLAGS conftest.cpp -o conftest.o
    475  1.1  christos #
    476  1.1  christos # And if linking:
    477  1.1  christos #
    478  1.1  christos ## CC LDFLAGS -cflags CFLAGS conftest.c -o conftest -libs LIBS
    479  1.1  christos ## CXX LDFLAGS -cflags CXXFLAGS conftest.c -o conftest -libs LIBS
    480  1.1  christos #
    481  1.1  christos # Any failures are recorded in 'config.log'
    482  1.1  christos #
    483  1.1  christos proc cctest {args} {
    484  1.1  christos 	set tmp conftest__
    485  1.1  christos 
    486  1.1  christos 	# Easiest way to merge in the settings
    487  1.1  christos 	cc-with $args {
    488  1.1  christos 		array set opts [cc-get-settings]
    489  1.1  christos 	}
    490  1.1  christos 
    491  1.1  christos 	if {[info exists opts(-sourcefile)]} {
    492  1.1  christos 		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
    493  1.1  christos 	}
    494  1.1  christos 	if {[info exists opts(-source)]} {
    495  1.1  christos 		set lines $opts(-source)
    496  1.1  christos 	} else {
    497  1.1  christos 		foreach i $opts(-includes) {
    498  1.1  christos 			if {$opts(-code) ne "" && ![feature-checked $i]} {
    499  1.1  christos 				# Compiling real code with an unchecked header file
    500  1.1  christos 				# Quickly (and silently) check for it now
    501  1.1  christos 
    502  1.1  christos 				# Remove all -includes from settings before checking
    503  1.1  christos 				set saveopts [cc-update-settings -includes {}]
    504  1.1  christos 				msg-quiet cc-check-includes $i
    505  1.1  christos 				cc-store-settings $saveopts
    506  1.1  christos 			}
    507  1.1  christos 			if {$opts(-code) eq "" || [have-feature $i]} {
    508  1.1  christos 				lappend source "#include <$i>"
    509  1.1  christos 			}
    510  1.1  christos 		}
    511  1.1  christos 		lappend source {*}$opts(-declare)
    512  1.1  christos 		lappend source "int main(void) {"
    513  1.1  christos 		lappend source $opts(-code)
    514  1.1  christos 		lappend source "return 0;"
    515  1.1  christos 		lappend source "}"
    516  1.1  christos 
    517  1.1  christos 		set lines [join $source \n]
    518  1.1  christos 	}
    519  1.1  christos 
    520  1.1  christos 	# Build the command line
    521  1.1  christos 	set cmdline {}
    522  1.1  christos 	lappend cmdline {*}[get-define CCACHE]
    523  1.1  christos 	switch -exact -- $opts(-lang) {
    524  1.1  christos 		c++ {
    525  1.1  christos 			set src conftest__.cpp
    526  1.1  christos 			lappend cmdline {*}[get-define CXX]
    527  1.1  christos 			set cflags [get-define CXXFLAGS]
    528  1.1  christos 		}
    529  1.1  christos 		c {
    530  1.1  christos 			set src conftest__.c
    531  1.1  christos 			lappend cmdline {*}[get-define CC]
    532  1.1  christos 			set cflags [get-define CFLAGS]
    533  1.1  christos 		}
    534  1.1  christos 		default {
    535  1.1  christos 			autosetup-error "cctest called with unknown language: $opts(-lang)"
    536  1.1  christos 		}
    537  1.1  christos 	}
    538  1.1  christos 
    539  1.1  christos 	if {$opts(-link)} {
    540  1.1  christos 		lappend cmdline {*}[get-define LDFLAGS]
    541  1.1  christos 	} else {
    542  1.1  christos 		lappend cflags {*}[get-define CPPFLAGS]
    543  1.1  christos 		set tmp conftest__.o
    544  1.1  christos 		lappend cmdline -c
    545  1.1  christos 	}
    546  1.1  christos 	lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""] {*}$cflags
    547  1.1  christos 	lappend cmdline $src -o $tmp
    548  1.1  christos 	if {$opts(-link)} {
    549  1.1  christos 		lappend cmdline {*}$opts(-libs) {*}[get-define LIBS]
    550  1.1  christos 	}
    551  1.1  christos 
    552  1.1  christos 	# At this point we have the complete command line and the
    553  1.1  christos 	# complete source to be compiled. Get the result from cache if
    554  1.1  christos 	# we can
    555  1.1  christos 	if {[info exists ::cc_cache($cmdline,$lines)]} {
    556  1.1  christos 		msg-checking "(cached) "
    557  1.1  christos 		set ok $::cc_cache($cmdline,$lines)
    558  1.1  christos 		if {$::autosetup(debug)} {
    559  1.1  christos 			configlog "From cache (ok=$ok): [join $cmdline]"
    560  1.1  christos 			configlog "============"
    561  1.1  christos 			configlog $lines
    562  1.1  christos 			configlog "============"
    563  1.1  christos 		}
    564  1.1  christos 		return $ok
    565  1.1  christos 	}
    566  1.1  christos 
    567  1.1  christos 	writefile $src $lines\n
    568  1.1  christos 
    569  1.1  christos 	set ok 1
    570  1.1  christos 	set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
    571  1.1  christos 	if {$err || ($opts(-nooutput) && [string length $result])} {
    572  1.1  christos 		configlog "Failed: [join $cmdline]"
    573  1.1  christos 		configlog $result
    574  1.1  christos 		configlog "============"
    575  1.1  christos 		configlog "The failed code was:"
    576  1.1  christos 		configlog $lines
    577  1.1  christos 		configlog "============"
    578  1.1  christos 		set ok 0
    579  1.1  christos 	} elseif {$::autosetup(debug)} {
    580  1.1  christos 		configlog "Compiled OK: [join $cmdline]"
    581  1.1  christos 		configlog "============"
    582  1.1  christos 		configlog $lines
    583  1.1  christos 		configlog "============"
    584  1.1  christos 	}
    585  1.1  christos 	file delete $src
    586  1.1  christos 	file delete $tmp
    587  1.1  christos 
    588  1.1  christos 	# cache it
    589  1.1  christos 	set ::cc_cache($cmdline,$lines) $ok
    590  1.1  christos 
    591  1.1  christos 	return $ok
    592  1.1  christos }
    593  1.1  christos 
    594  1.1  christos # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
    595  1.1  christos #
    596  1.1  christos # Deprecated - see 'make-config-header'
    597  1.1  christos proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
    598  1.1  christos 	user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
    599  1.1  christos 	make-config-header $file -auto $autopatterns -bare $barepatterns
    600  1.1  christos }
    601  1.1  christos 
    602  1.1  christos # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
    603  1.1  christos #
    604  1.1  christos # Examines all defined variables which match the given patterns
    605  1.1  christos # and writes an include file, '$file', which defines each of these.
    606  1.1  christos # Variables which match '-auto' are output as follows:
    607  1.1  christos # - defines which have the value '0' are ignored.
    608  1.1  christos # - defines which have integer values are defined as the integer value.
    609  1.1  christos # - any other value is defined as a string, e.g. '"value"'
    610  1.1  christos # Variables which match '-bare' are defined as-is.
    611  1.1  christos # Variables which match '-str' are defined as a string, e.g. '"value"'
    612  1.1  christos # Variables which match '-none' are omitted.
    613  1.1  christos #
    614  1.1  christos # Note that order is important. The first pattern that matches is selected.
    615  1.1  christos # Default behaviour is:
    616  1.1  christos #
    617  1.1  christos ##  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
    618  1.1  christos #
    619  1.1  christos # If the file would be unchanged, it is not written.
    620  1.1  christos proc make-config-header {file args} {
    621  1.1  christos 	set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
    622  1.1  christos 	file mkdir [file dirname $file]
    623  1.1  christos 	set lines {}
    624  1.1  christos 	lappend lines "#ifndef $guard"
    625  1.1  christos 	lappend lines "#define $guard"
    626  1.1  christos 
    627  1.1  christos 	# Add some defaults
    628  1.1  christos 	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
    629  1.1  christos 
    630  1.1  christos 	foreach n [lsort [dict keys [all-defines]]] {
    631  1.1  christos 		set value [get-define $n]
    632  1.1  christos 		set type [calc-define-output-type $n $args]
    633  1.1  christos 		switch -exact -- $type {
    634  1.1  christos 			-bare {
    635  1.1  christos 				# Just output the value unchanged
    636  1.1  christos 			}
    637  1.1  christos 			-none {
    638  1.1  christos 				continue
    639  1.1  christos 			}
    640  1.1  christos 			-str {
    641  1.1  christos 				set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
    642  1.1  christos 			}
    643  1.1  christos 			-auto {
    644  1.1  christos 				# Automatically determine the type
    645  1.1  christos 				if {$value eq "0"} {
    646  1.1  christos 					lappend lines "/* #undef $n */"
    647  1.1  christos 					continue
    648  1.1  christos 				}
    649  1.1  christos 				if {![string is integer -strict $value]} {
    650  1.1  christos 					set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
    651  1.1  christos 				}
    652  1.1  christos 			}
    653  1.1  christos 			"" {
    654  1.1  christos 				continue
    655  1.1  christos 			}
    656  1.1  christos 			default {
    657  1.1  christos 				autosetup-error "Unknown type in make-config-header: $type"
    658  1.1  christos 			}
    659  1.1  christos 		}
    660  1.1  christos 		lappend lines "#define $n $value"
    661  1.1  christos 	}
    662  1.1  christos 	lappend lines "#endif"
    663  1.1  christos 	set buf [join $lines \n]
    664  1.1  christos 	write-if-changed $file $buf {
    665  1.1  christos 		msg-result "Created $file"
    666  1.1  christos 	}
    667  1.1  christos }
    668  1.1  christos 
    669  1.1  christos proc calc-define-output-type {name spec} {
    670  1.1  christos 	foreach {type patterns} $spec {
    671  1.1  christos 		foreach pattern $patterns {
    672  1.1  christos 			if {[string match $pattern $name]} {
    673  1.1  christos 				return $type
    674  1.1  christos 			}
    675  1.1  christos 		}
    676  1.1  christos 	}
    677  1.1  christos 	return ""
    678  1.1  christos }
    679  1.1  christos 
    680  1.1  christos proc cc-init {} {
    681  1.1  christos 	global autosetup
    682  1.1  christos 
    683  1.1  christos 	# Initialise some values from the environment or commandline or default settings
    684  1.1  christos 	foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
    685  1.1  christos 		lassign $i var default
    686  1.1  christos 		define $var [get-env $var $default]
    687  1.1  christos 	}
    688  1.1  christos 
    689  1.1  christos 	if {[env-is-set CC]} {
    690  1.1  christos 		# Set by the user, so don't try anything else
    691  1.1  christos 		set try [list [get-env CC ""]]
    692  1.1  christos 	} else {
    693  1.1  christos 		# Try some reasonable options
    694  1.1  christos 		set try [list [get-define cross]cc [get-define cross]gcc]
    695  1.1  christos 	}
    696  1.1  christos 	define CC [find-an-executable {*}$try]
    697  1.1  christos 	if {[get-define CC] eq ""} {
    698  1.1  christos 		user-error "Could not find a C compiler. Tried: [join $try ", "]"
    699  1.1  christos 	}
    700  1.1  christos 
    701  1.1  christos 	define CPP [get-env CPP "[get-define CC] -E"]
    702  1.1  christos 
    703  1.1  christos 	# XXX: Could avoid looking for a C++ compiler until requested
    704  1.1  christos 	# If CXX isn't found, it is set to the empty string.
    705  1.1  christos 	if {[env-is-set CXX]} {
    706  1.1  christos 		define CXX [find-an-executable -required [get-env CXX ""]]
    707  1.1  christos 	} else {
    708  1.1  christos 		define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++]
    709  1.1  christos 	}
    710  1.1  christos 
    711  1.1  christos 	# CXXFLAGS default to CFLAGS if not specified
    712  1.1  christos 	define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
    713  1.1  christos 
    714  1.1  christos 	# May need a CC_FOR_BUILD, so look for one
    715  1.1  christos 	define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
    716  1.1  christos 
    717  1.1  christos 	# These start empty and never come from the user or environment
    718  1.1  christos 	define AS_CFLAGS ""
    719  1.1  christos 	define AS_CPPFLAGS ""
    720  1.1  christos 	define AS_CXXFLAGS ""
    721  1.1  christos 
    722  1.1  christos 	define CCACHE [find-an-executable [get-env CCACHE ccache]]
    723  1.1  christos 
    724  1.1  christos 	# If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
    725  1.1  christos 	foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
    726  1.1  christos 		if {[env-is-set $i]} {
    727  1.1  christos 			# Note: If the variable is set on the command line, get-env will return that value
    728  1.1  christos 			# so the command line will continue to override the environment
    729  1.1  christos 			define-append-argv AUTOREMAKE $i=[get-env $i ""]
    730  1.1  christos 		}
    731  1.1  christos 	}
    732  1.1  christos 
    733  1.1  christos 	# Initial cctest settings
    734  1.1  christos 	cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
    735  1.1  christos 	set autosetup(cc-include-deps) {}
    736  1.1  christos 
    737  1.1  christos 	msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
    738  1.1  christos 	if {[get-define CXX] ne "false"} {
    739  1.1  christos 		msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
    740  1.1  christos 	}
    741  1.1  christos 	msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
    742  1.1  christos 
    743  1.1  christos 	# On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
    744  1.1  christos 	# but some compilers may not support it, so test here.
    745  1.1  christos 	switch -glob -- [get-define host] {
    746  1.1  christos 		*-*-darwin* {
    747  1.1  christos 			if {[cctest -cflags {-g0}]} {
    748  1.1  christos 				define cc-default-debug -g0
    749  1.1  christos 			}
    750  1.1  christos 		}
    751  1.1  christos 	}
    752  1.1  christos 
    753  1.1  christos 	if {![cc-check-includes stdlib.h]} {
    754  1.1  christos 		user-error "Compiler does not work. See config.log"
    755  1.1  christos 	}
    756  1.1  christos }
    757  1.1  christos 
    758  1.1  christos cc-init
    759