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