• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/usb-modeswitch-2.2.3/jim/autosetup/
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, make-autoconf-h and make-template.
9#
10# The following environment variables are used if set:
11#
12## CC       - C compiler
13## CXX      - C++ compiler
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
20#
21# The following variables are defined from the corresponding
22# environment variables if set.
23#
24## CPPFLAGS
25## LINKFLAGS
26## CC_FOR_BUILD
27## LD
28
29use system
30
31module-options {}
32
33# Note that the return code is not meaningful
34proc cc-check-something {name code} {
35	uplevel 1 $code
36}
37
38# Checks for the existence of the given function by linking
39#
40proc cctest_function {function} {
41	cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
42}
43
44# Checks for the existence of the given type by compiling
45proc cctest_type {type} {
46	cctest -code "$type _x;"
47}
48
49# Checks for the existence of the given type/structure member.
50# e.g. "struct stat.st_mtime"
51proc cctest_member {struct_member} {
52	lassign [split $struct_member .] struct member
53	cctest -code "static $struct _s; return sizeof(_s.$member);"
54}
55
56# Checks for the existence of the given define by compiling
57#
58proc cctest_define {name} {
59	cctest -code "#ifndef $name\n#error not defined\n#endif"
60}
61
62# Checks for the existence of the given name either as
63# a macro (#define) or an rvalue (such as an enum)
64#
65proc cctest_decl {name} {
66	cctest -code "#ifndef $name\n(void)$name;\n#endif"
67}
68
69# @cc-check-sizeof type ...
70#
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.
75#
76proc cc-check-sizeof {args} {
77	foreach type $args {
78		msg-checking "Checking for sizeof $type..."
79		set size unknown
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 };"]} {
83				set size $i
84				break
85			}
86		}
87		msg-result $size
88		set define [feature-define-name $type SIZEOF_]
89		define $define $size
90	}
91	# Return the last result
92	get-define $define
93}
94
95# Checks for each feature in $list by using the given script.
96#
97# When the script is evaluated, $each is set to the feature
98# being checked, and $extra is set to any additional cctest args.
99#
100# Returns 1 if all features were found, or 0 otherwise.
101proc cc-check-some-feature {list script} {
102	set ret 1
103	foreach each $list {
104		if {![check-feature $each $script]} {
105			set ret 0
106		}
107	}
108	return $ret
109}
110
111# @cc-check-includes includes ...
112#
113# Checks that the given include files can be used
114proc cc-check-includes {args} {
115	cc-check-some-feature $args {
116		cctest -includes $each
117	}
118}
119
120# @cc-check-types type ...
121#
122# Checks that the types exist.
123proc cc-check-types {args} {
124	cc-check-some-feature $args {
125		cctest_type $each
126	}
127}
128
129# @cc-check-defines define ...
130#
131# Checks that the given preprocessor symbol is defined
132proc cc-check-defines {args} {
133	cc-check-some-feature $args {
134		cctest_define $each
135	}
136}
137
138# @cc-check-decls name ...
139#
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
143proc cc-check-decls {args} {
144	set ret 1
145	foreach name $args {
146		msg-checking "Checking for $name..."
147		set r [cctest_decl $name]
148		define-feature "decl $name" $r
149		if {$r} {
150			msg-result "ok"
151		} else {
152			msg-result "not found"
153			set ret 0
154		}
155	}
156	return $ret
157}
158
159# @cc-check-functions function ...
160#
161# Checks that the given functions exist (can be linked)
162proc cc-check-functions {args} {
163	cc-check-some-feature $args {
164		cctest_function $each
165	}
166}
167
168# @cc-check-members type.member ...
169#
170# Checks that the given type/structure members exist.
171# A structure member is of the form "struct stat.st_mtime"
172proc cc-check-members {args} {
173	cc-check-some-feature $args {
174		cctest_member $each
175	}
176}
177
178# @cc-check-function-in-lib function libs ?otherlibs?
179#
180# Checks that the given given function can be found in one of the libs.
181#
182# First checks for no library required, then checks each of the libraries
183# in turn.
184#
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.
188#
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.
192#
193# Returns 1 if found or 0 if not.
194#
195proc cc-check-function-in-lib {function libs {otherlibs {}}} {
196	msg-checking "Checking libs for $function..."
197	set found 0
198	cc-with [list -libs $otherlibs] {
199		if {[cctest_function $function]} {
200			msg-result "none needed"
201			define lib_$function ""
202			incr found
203		} else {
204			foreach lib $libs {
205				cc-with [list -libs -l$lib] {
206					if {[cctest_function $function]} {
207						msg-result -l$lib
208						define lib_$function -l$lib
209						define-append LIBS -l$lib
210						incr found
211						break
212					}
213				}
214			}
215		}
216	}
217	if {$found} {
218		define [feature-define-name $function]
219	} else {
220		msg-result "no"
221	}
222	return $found
223}
224
225# @cc-check-tools tool ...
226#
227# Checks for existence of the given compiler tools, taking
228# into account any cross compilation prefix.
229#
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.
235#
236# It is an error if the executable is not found.
237#
238proc cc-check-tools {args} {
239	foreach tool $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"
244		}
245		define $TOOL $exe
246	}
247}
248
249# @cc-check-progs prog ...
250#
251# Checks for existence of the given executables on the path.
252#
253# For example, when checking for "grep", the path is searched for
254# the executable, 'grep', and if found GREP is defined as "grep".
255#
256# It the executable is not found, the variable is defined as false.
257# Returns 1 if all programs were found, or 0 otherwise.
258#
259proc cc-check-progs {args} {
260	set failed 0
261	foreach prog $args {
262		set PROG [string toupper $prog]
263		msg-checking "Checking for $prog..."
264		if {![find-executable $prog]} {
265			msg-result no
266			define $PROG false
267			incr failed
268		} else {
269			msg-result ok
270			define $PROG $prog
271		}
272	}
273	expr {!$failed}
274}
275
276# Adds the given settings to $::autosetup(ccsettings) and
277# returns the old settings.
278#
279proc cc-add-settings {settings} {
280	if {[llength $settings] % 2} {
281		autosetup-error "settings list is missing a value: $settings"
282	}
283
284	set prev [cc-get-settings]
285	# workaround a bug in some versions of jimsh by forcing
286	# conversion of $prev to a list
287	llength $prev
288
289	array set new $prev
290
291	foreach {name value} $settings {
292		switch -exact -- $name {
293			-cflags - -includes {
294				# These are given as lists
295				lappend new($name) {*}$value
296			}
297			-declare {
298				lappend new($name) $value
299			}
300			-libs {
301				# Note that new libraries are added before previous libraries
302				set new($name) [list {*}$value {*}$new($name)]
303			}
304			-link - -lang {
305				set new($name) $value
306			}
307			-source - -sourcefile - -code {
308				# XXX: These probably are only valid directly from cctest
309				set new($name) $value
310			}
311			default {
312				autosetup-error "unknown cctest setting: $name"
313			}
314		}
315	}
316
317	cc-store-settings [array get new]
318
319	return $prev
320}
321
322proc cc-store-settings {new} {
323	set ::autosetup(ccsettings) $new
324}
325
326proc cc-get-settings {} {
327	return $::autosetup(ccsettings)
328}
329
330# Similar to cc-add-settings, but each given setting
331# simply replaces the existing value.
332#
333# Returns the previous settings
334proc cc-update-settings {args} {
335	set prev [cc-get-settings]
336	cc-store-settings [dict merge $prev $args]
337	return $prev
338}
339
340# @cc-with settings ?{ script }?
341#
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.
345#
346# If no script is given, the settings become the default for the remainder
347# of the auto.def file.
348#
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.
354##     ...
355##   }
356##   # back to just the C++ compiler
357## }
358#
359# The -libs setting is special in that newer values are added *before* earlier ones.
360#
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
365##   }
366## }
367proc 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?"
372	} else {
373		set save [cc-add-settings $settings]
374		set rc [catch {uplevel 1 [lindex $args 0]} result info]
375		cc-store-settings $save
376		if {$rc != 0} {
377			return $result -code [dict get $info -code]
378		}
379		return $result
380	}
381}
382
383# @cctest ?settings?
384#
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.
387#
388# Supported settings are:
389#
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]
399#
400# Unless -source or -sourcefile is specified, the C program looks like:
401#
402## #include <firstinclude>   /* same for remaining includes in the list */
403##
404## declare-code              /* any code in -declare, verbatim */
405##
406## int main(void) {
407##   code                    /* any code in -code, verbatim */
408##   return 0;
409## }
410#
411# Any failures are recorded in 'config.log'
412#
413proc cctest {args} {
414	set src conftest__.c
415	set tmp conftest__
416
417	# Easiest way to merge in the settings
418	cc-with $args {
419		array set opts [cc-get-settings]
420	}
421
422	if {[info exists opts(-sourcefile)]} {
423		set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
424	}
425	if {[info exists opts(-source)]} {
426		set lines $opts(-source)
427	} else {
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
432
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
437			}
438			if {$opts(-code) eq "" || [have-feature $i]} {
439				lappend source "#include <$i>"
440			}
441		}
442		lappend source {*}$opts(-declare)
443		lappend source "int main(void) {"
444		lappend source $opts(-code)
445		lappend source "return 0;"
446		lappend source "}"
447
448		set lines [join $source \n]
449	}
450
451	# Build the command line
452	set cmdline {}
453	lappend cmdline {*}[get-define CCACHE]
454	switch -exact -- $opts(-lang) {
455		c++ {
456			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
457		}
458		c {
459			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
460		}
461		default {
462			autosetup-error "cctest called with unknown language: $opts(-lang)"
463		}
464	}
465
466	if {!$opts(-link)} {
467		set tmp conftest__.o
468		lappend cmdline -c
469	}
470	lappend cmdline {*}$opts(-cflags)
471
472	switch -glob -- [get-define host] {
473		*-*-darwin* {
474			# Don't generate .dSYM directories
475			lappend cmdline -gstabs
476		}
477	}
478	lappend cmdline $src -o $tmp {*}$opts(-libs)
479
480	# At this point we have the complete command line and the
481	# complete source to be compiled. Get the result from cache if
482	# we can
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 "============"
489			configlog $lines
490			configlog "============"
491		}
492		return $ok
493	}
494
495	writefile $src $lines\n
496
497	set ok 1
498	if {[catch {exec-with-stderr {*}$cmdline} result errinfo]} {
499		configlog "Failed: [join $cmdline]"
500		configlog $result
501		configlog "============"
502		configlog "The failed code was:"
503		configlog $lines
504		configlog "============"
505		set ok 0
506	} elseif {$::autosetup(debug)} {
507		configlog "Compiled OK: [join $cmdline]"
508		configlog "============"
509		configlog $lines
510		configlog "============"
511	}
512	file delete $src
513	file delete $tmp
514
515	# cache it
516	set ::cc_cache($cmdline,$lines) $ok
517
518	return $ok
519}
520
521# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
522#
523# Deprecated - see make-config-header
524proc 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
527}
528
529# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
530#
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.
540#
541# Note that order is important. The first pattern which matches is selected
542# Default behaviour is:
543#
544#  -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
545#
546# If the file would be unchanged, it is not written.
547proc 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]
550	set lines {}
551	lappend lines "#ifndef $guard"
552	lappend lines "#define $guard"
553
554	# Add some defaults
555	lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
556
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 {
561			-bare {
562				# Just output the value unchanged
563			}
564			-none {
565				continue
566			}
567			-str {
568				set value \"$value\"
569			}
570			-auto {
571				# Automatically determine the type
572				if {$value eq "0"} {
573					lappend lines "/* #undef $n */"
574					continue
575				}
576				if {![string is integer -strict $value]} {
577					set value \"$value\"
578				}
579			}
580			"" {
581				continue
582			}
583			default {
584				autosetup-error "Unknown type in make-config-header: $type"
585			}
586		}
587		lappend lines "#define $n $value"
588	}
589	lappend lines "#endif"
590	set buf [join $lines \n]
591	write-if-changed $file $buf {
592		msg-result "Created $file"
593	}
594}
595
596proc calc-define-output-type {name spec} {
597	foreach {type patterns} $spec {
598		foreach pattern $patterns {
599			if {[string match $pattern $name]} {
600				return $type
601			}
602		}
603	}
604	return ""
605}
606
607# Initialise some values from the environment or commandline or default settings
608foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
609	lassign $i var default
610	define $var [get-env $var $default]
611}
612
613if {[env-is-set CC]} {
614	# Set by the user, so don't try anything else
615	set try [list [get-env CC ""]]
616} else {
617	# Try some reasonable options
618	set try [list [get-define cross]cc [get-define cross]gcc]
619}
620define CC [find-an-executable {*}$try]
621if {[get-define CC] eq ""} {
622	user-error "Could not find a C compiler. Tried: [join $try ", "]"
623}
624
625define CPP [get-env CPP "[get-define CC] -E"]
626
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.
629if {[env-is-set CXX]} {
630	define CXX [find-an-executable -required [get-env CXX ""]]
631} else {
632	define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
633}
634
635# CXXFLAGS default to CFLAGS if not specified
636define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
637
638cc-check-tools ld
639
640# May need a CC_FOR_BUILD, so look for one
641define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
642
643if {[get-define CC] eq ""} {
644	user-error "Could not find a C compiler. Tried: [join $try ", "]"
645}
646
647define CCACHE [find-an-executable [get-env CCACHE ccache]]
648
649# Initial cctest settings
650cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
651
652msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
653if {[get-define CXX] ne "false"} {
654	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
655}
656msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
657
658if {![cc-check-includes stdlib.h]} {
659	user-error "Compiler does not work. See config.log"
660}
661