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