1"""SCons.Conftest 2 3Autoconf-like configuration support; low level implementation of tests. 4""" 5 6# 7# Copyright (c) 2003 Stichting NLnet Labs 8# Copyright (c) 2001, 2002, 2003 Steven Knight 9# 10# Permission is hereby granted, free of charge, to any person obtaining 11# a copy of this software and associated documentation files (the 12# "Software"), to deal in the Software without restriction, including 13# without limitation the rights to use, copy, modify, merge, publish, 14# distribute, sublicense, and/or sell copies of the Software, and to 15# permit persons to whom the Software is furnished to do so, subject to 16# the following conditions: 17# 18# The above copyright notice and this permission notice shall be included 19# in all copies or substantial portions of the Software. 20# 21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 22# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 23# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 25# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28# 29 30# 31# The purpose of this module is to define how a check is to be performed. 32# Use one of the Check...() functions below. 33# 34 35# 36# A context class is used that defines functions for carrying out the tests, 37# logging and messages. The following methods and members must be present: 38# 39# context.Display(msg) Function called to print messages that are normally 40# displayed for the user. Newlines are explicitly used. 41# The text should also be written to the logfile! 42# 43# context.Log(msg) Function called to write to a log file. 44# 45# context.BuildProg(text, ext) 46# Function called to build a program, using "ext" for the 47# file extention. Must return an empty string for 48# success, an error message for failure. 49# For reliable test results building should be done just 50# like an actual program would be build, using the same 51# command and arguments (including configure results so 52# far). 53# 54# context.CompileProg(text, ext) 55# Function called to compile a program, using "ext" for 56# the file extention. Must return an empty string for 57# success, an error message for failure. 58# For reliable test results compiling should be done just 59# like an actual source file would be compiled, using the 60# same command and arguments (including configure results 61# so far). 62# 63# context.AppendLIBS(lib_name_list) 64# Append "lib_name_list" to the value of LIBS. 65# "lib_namelist" is a list of strings. 66# Return the value of LIBS before changing it (any type 67# can be used, it is passed to SetLIBS() later.) 68# 69# context.PrependLIBS(lib_name_list) 70# Prepend "lib_name_list" to the value of LIBS. 71# "lib_namelist" is a list of strings. 72# Return the value of LIBS before changing it (any type 73# can be used, it is passed to SetLIBS() later.) 74# 75# context.SetLIBS(value) 76# Set LIBS to "value". The type of "value" is what 77# AppendLIBS() returned. 78# Return the value of LIBS before changing it (any type 79# can be used, it is passed to SetLIBS() later.) 80# 81# context.headerfilename 82# Name of file to append configure results to, usually 83# "confdefs.h". 84# The file must not exist or be empty when starting. 85# Empty or None to skip this (some tests will not work!). 86# 87# context.config_h (may be missing). If present, must be a string, which 88# will be filled with the contents of a config_h file. 89# 90# context.vardict Dictionary holding variables used for the tests and 91# stores results from the tests, used for the build 92# commands. 93# Normally contains "CC", "LIBS", "CPPFLAGS", etc. 94# 95# context.havedict Dictionary holding results from the tests that are to 96# be used inside a program. 97# Names often start with "HAVE_". These are zero 98# (feature not present) or one (feature present). Other 99# variables may have any value, e.g., "PERLVERSION" can100# be a number and "SYSTEMNAME" a string.101#102103importre104fromtypesimportIntType105106#107# PUBLIC VARIABLES108#109110LogInputFiles=1# Set that to log the input files in case of a failed test111LogErrorMessages=1# Set that to log Conftest-generated error messages112113#114# PUBLIC FUNCTIONS115#116117# Generic remarks:118# - When a language is specified which is not supported the test fails. The119# message is a bit different, because not all the arguments for the normal120# message are available yet (chicken-egg problem).121122

124"""125 Configure check to see if the compiler works.126 Note that this uses the current value of compiler and linker flags, make127 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.128 "language" should be "C" or "C++" and is used to select the compiler.129 Default is "C".130 "text" may be used to specify the code to be build.131 Returns an empty string for success, an error message for failure.132 """133lang,suffix,msg=_lang2suffix(language)134ifmsg:135context.Display("%s\n"%msg)136returnmsg137138ifnottext:139text="""140int main() {141 return 0;142}143"""144145context.Display("Checking if building a %s file works... "%lang)146ret=context.BuildProg(text,suffix)147_YesNoResult(context,ret,None,text)148returnret

151"""152 Configure check for a working C compiler.153154 This checks whether the C compiler, as defined in the $CC construction155 variable, can compile a C source file. It uses the current $CCCOM value156 too, so that it can test against non working flags.157158 """159context.Display("Checking whether the C compiler works")160text="""161int main()162{163 return 0;164}165"""166ret=_check_empty_program(context,'CC',text,'C')167_YesNoResult(context,ret,None,text)168returnret

171"""172 Configure check for a working shared C compiler.173174 This checks whether the C compiler, as defined in the $SHCC construction175 variable, can compile a C source file. It uses the current $SHCCCOM value176 too, so that it can test against non working flags.177178 """179context.Display("Checking whether the (shared) C compiler works")180text="""181int foo()182{183 return 0;184}185"""186ret=_check_empty_program(context,'SHCC',text,'C',use_shared=True)187_YesNoResult(context,ret,None,text)188returnret

191"""192 Configure check for a working CXX compiler.193194 This checks whether the CXX compiler, as defined in the $CXX construction195 variable, can compile a CXX source file. It uses the current $CXXCOM value196 too, so that it can test against non working flags.197198 """199context.Display("Checking whether the C++ compiler works")200text="""201int main()202{203 return 0;204}205"""206ret=_check_empty_program(context,'CXX',text,'C++')207_YesNoResult(context,ret,None,text)208returnret

211"""212 Configure check for a working shared CXX compiler.213214 This checks whether the CXX compiler, as defined in the $SHCXX construction215 variable, can compile a CXX source file. It uses the current $SHCXXCOM value216 too, so that it can test against non working flags.217218 """219context.Display("Checking whether the (shared) C++ compiler works")220text="""221int main()222{223 return 0;224}225"""226ret=_check_empty_program(context,'SHCXX',text,'C++',use_shared=True)227_YesNoResult(context,ret,None,text)228returnret

231"""Return 0 on success, 1 otherwise."""232ifcompnotincontext.envornotcontext.env[comp]:233# The compiler construction variable is not set or empty234return1235236lang,suffix,msg=_lang2suffix(language)237ifmsg:238return1239240ifuse_shared:241returncontext.CompileSharedObject(text,suffix)242else:243returncontext.CompileProg(text,suffix)

247"""248 Configure check for a function "function_name".249 "language" should be "C" or "C++" and is used to select the compiler.250 Default is "C".251 Optional "header" can be defined to define a function prototype, include a252 header file or anything else that comes before main().253 Sets HAVE_function_name in context.havedict according to the result.254 Note that this uses the current value of compiler and linker flags, make255 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.256 Returns an empty string for success, an error message for failure.257 """258259# Remarks from autoconf:260# - Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>261# which includes <sys/select.h> which contains a prototype for select.262# Similarly for bzero.263# - assert.h is included to define __stub macros and hopefully few264# prototypes, which can conflict with char $1(); below.265# - Override any gcc2 internal prototype to avoid an error.266# - We use char for the function declaration because int might match the267# return type of a gcc2 builtin and then its argument prototype would268# still apply.269# - The GNU C library defines this for functions which it implements to270# always fail with ENOSYS. Some functions are actually named something271# starting with __ and the normal name is an alias.272273ifcontext.headerfilename:274includetext='#include "%s"'%context.headerfilename275else:276includetext=''277ifnotheader:278header="""279#ifdef __cplusplus280extern "C"281#endif282char %s();"""%function_name283284lang,suffix,msg=_lang2suffix(language)285ifmsg:286context.Display("Cannot check for %s(): %s\n"%(function_name,msg))287returnmsg288289text="""290%(include)s291#include <assert.h>292%(hdr)s293294int main() {295#if defined (__stub_%(name)s) || defined (__stub___%(name)s)296 fail fail fail297#else298 %(name)s();299#endif300301 return 0;302}303"""%{'name':function_name,304'include':includetext,305'hdr':header}306307context.Display("Checking for %s function %s()... "%(lang,function_name))308ret=context.BuildProg(text,suffix)309_YesNoResult(context,ret,"HAVE_"+function_name,text,310"Define to 1 if the system has the function `%s'."%\ 311function_name)312returnret

317"""318 Configure check for a C or C++ header file "header_name".319 Optional "header" can be defined to do something before including the320 header file (unusual, supported for consistency).321 "language" should be "C" or "C++" and is used to select the compiler.322 Default is "C".323 Sets HAVE_header_name in context.havedict according to the result.324 Note that this uses the current value of compiler and linker flags, make325 sure $CFLAGS and $CPPFLAGS are set correctly.326 Returns an empty string for success, an error message for failure.327 """328# Why compile the program instead of just running the preprocessor?329# It is possible that the header file exists, but actually using it may330# fail (e.g., because it depends on other header files). Thus this test is331# more strict. It may require using the "header" argument.332#333# Use <> by default, because the check is normally used for system header334# files. SCons passes '""' to overrule this.335336# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.337ifcontext.headerfilename:338includetext='#include "%s"\n'%context.headerfilename339else:340includetext=''341ifnotheader:342header=""343344lang,suffix,msg=_lang2suffix(language)345ifmsg:346context.Display("Cannot check for header file %s: %s\n"347%(header_name,msg))348returnmsg349350ifnotinclude_quotes:351include_quotes="<>"352353text="%s%s\n#include %s%s%s\n\n"%(includetext,header,354include_quotes[0],header_name,include_quotes[1])355356context.Display("Checking for %s header file %s... "%(lang,header_name))357ret=context.CompileProg(text,suffix)358_YesNoResult(context,ret,"HAVE_"+header_name,text,359"Define to 1 if you have the <%s> header file."%header_name)360returnret

365"""366 Configure check for a C or C++ type "type_name".367 Optional "header" can be defined to include a header file.368 "language" should be "C" or "C++" and is used to select the compiler.369 Default is "C".370 Sets HAVE_type_name in context.havedict according to the result.371 Note that this uses the current value of compiler and linker flags, make372 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.373 Returns an empty string for success, an error message for failure.374 """375376# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.377ifcontext.headerfilename:378includetext='#include "%s"'%context.headerfilename379else:380includetext=''381ifnotheader:382header=""383384lang,suffix,msg=_lang2suffix(language)385ifmsg:386context.Display("Cannot check for %s type: %s\n"%(type_name,msg))387returnmsg388389# Remarks from autoconf about this test:390# - Grepping for the type in include files is not reliable (grep isn't391# portable anyway).392# - Using "TYPE my_var;" doesn't work for const qualified types in C++.393# Adding an initializer is not valid for some C++ classes.394# - Using the type as parameter to a function either fails for K&$ C or for395# C++.396# - Using "TYPE *my_var;" is valid in C for some types that are not397# declared (struct something).398# - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.399# - Using the previous two together works reliably.400text="""401%(include)s402%(header)s403404int main() {405 if ((%(name)s *) 0)406 return 0;407 if (sizeof (%(name)s))408 return 0;409}410"""%{'include':includetext,411'header':header,412'name':type_name}413414context.Display("Checking for %s type %s... "%(lang,type_name))415ret=context.BuildProg(text,suffix)416_YesNoResult(context,ret,"HAVE_"+type_name,text,417"Define to 1 if the system has the type `%s'."%type_name)418ifretandfallbackandcontext.headerfilename:419f=open(context.headerfilename,"a")420f.write("typedef %s %s;\n"%(fallback,type_name))421f.close()422423returnret

426"""This check can be used to get the size of a given type, or to check whether427 the type is of expected size.428429 Arguments:430 - type : str431 the type to check432 - includes : sequence433 list of headers to include in the test code before testing the type434 - language : str435 'C' or 'C++'436 - expect : int437 if given, will test wether the type has the given number of bytes.438 If not given, will automatically find the size.439440 Returns:441 status : int442 0 if the check failed, or the found size of the type if the check succeeded."""443444# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.445ifcontext.headerfilename:446includetext='#include "%s"'%context.headerfilename447else:448includetext=''449450ifnotheader:451header=""452453lang,suffix,msg=_lang2suffix(language)454ifmsg:455context.Display("Cannot check for %s type: %s\n"%(type_name,msg))456returnmsg457458src=includetext+header459ifnotexpectisNone:460# Only check if the given size is the right one461context.Display('Checking %s is %d bytes... '%(type_name,expect))462463# test code taken from autoconf: this is a pretty clever hack to find that464# a type is of a given size using only compilation. This speeds things up465# quite a bit compared to straightforward code using TryRun466src=src+r"""467typedef %s scons_check_type;468469int main()470{471 static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];472 test_array[0] = 0;473474 return 0;475}476"""477478st=context.CompileProg(src%(type_name,expect),suffix)479ifnotst:480context.Display("yes\n")481_Have(context,"SIZEOF_%s"%type_name,expect,482"The size of `%s', as computed by sizeof."%type_name)483returnexpect484else:485context.Display("no\n")486_LogFailed(context,src,st)487return0488else:489# Only check if the given size is the right one490context.Message('Checking size of %s ... '%type_name)491492# We have to be careful with the program we wish to test here since493# compilation will be attempted using the current environment's flags.494# So make sure that the program will compile without any warning. For495# example using: 'int main(int argc, char** argv)' will fail with the496# '-Wall -Werror' flags since the variables argc and argv would not be497# used in the program...498#499src=src+"""500#include <stdlib.h>501#include <stdio.h>502int main() {503 printf("%d", (int)sizeof("""+type_name+"""));504 return 0;505}506 """507st,out=context.RunProg(src,suffix)508try:509size=int(out)510exceptValueError:511# If cannot convert output of test prog to an integer (the size),512# something went wront, so just fail513st=1514size=0515516ifnotst:517context.Display("yes\n")518_Have(context,"SIZEOF_%s"%type_name,size,519"The size of `%s', as computed by sizeof."%type_name)520returnsize521else:522context.Display("no\n")523_LogFailed(context,src,st)524return0525526return0

529"""Checks whether symbol is declared.530531 Use the same test as autoconf, that is test whether the symbol is defined532 as a macro or can be used as an r-value.533534 Arguments:535 symbol : str536 the symbol to check537 includes : str538 Optional "header" can be defined to include a header file.539 language : str540 only C and C++ supported.541542 Returns:543 status : bool544 True if the check failed, False if succeeded."""545546# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.547ifcontext.headerfilename:548includetext='#include "%s"'%context.headerfilename549else:550includetext=''551552ifnotincludes:553includes=""554555lang,suffix,msg=_lang2suffix(language)556ifmsg:557context.Display("Cannot check for declaration %s: %s\n"%(symbol,msg))558returnmsg559560src=includetext+includes561context.Display('Checking whether %s is declared... '%symbol)562563src=src+r"""564int main()565{566#ifndef %s567 (void) %s;568#endif569 ;570 return 0;571}572"""%(symbol,symbol)573574st=context.CompileProg(src,suffix)575_YesNoResult(context,st,"HAVE_DECL_"+symbol,src,576"Set to 1 if %s is defined."%symbol)577returnst

582"""583 Configure check for a C or C++ libraries "libs". Searches through584 the list of libraries, until one is found where the test succeeds.585 Tests if "func_name" or "call" exists in the library. Note: if it exists586 in another library the test succeeds anyway!587 Optional "header" can be defined to include a header file. If not given a588 default prototype for "func_name" is added.589 Optional "extra_libs" is a list of library names to be added after590 "lib_name" in the build command. To be used for libraries that "lib_name"591 depends on.592 Optional "call" replaces the call to "func_name" in the test code. It must593 consist of complete C statements, including a trailing ";".594 Both "func_name" and "call" arguments are optional, and in that case, just595 linking against the libs is tested.596 "language" should be "C" or "C++" and is used to select the compiler.597 Default is "C".598 Note that this uses the current value of compiler and linker flags, make599 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.600 Returns an empty string for success, an error message for failure.601 """602# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.603ifcontext.headerfilename:604includetext='#include "%s"'%context.headerfilename605else:606includetext=''607ifnotheader:608header=""609610text="""611%s612%s"""%(includetext,header)613614# Add a function declaration if needed.615iffunc_nameandfunc_name!="main":616ifnotheader:617text=text+"""618#ifdef __cplusplus619extern "C"620#endif621char %s();622"""%func_name623624# The actual test code.625ifnotcall:626call="%s();"%func_name627628# if no function to test, leave main() blank629text=text+"""630int631main() {632 %s633return 0;634}635"""%(callor"")636637ifcall:638i=call.find("\n")639ifi>0:640calltext=call[:i]+".."641elifcall[-1]==';':642calltext=call[:-1]643else:644calltext=call645646forlib_nameinlibs:647648lang,suffix,msg=_lang2suffix(language)649ifmsg:650context.Display("Cannot check for library %s: %s\n"%(lib_name,msg))651returnmsg652653# if a function was specified to run in main(), say it654ifcall:655context.Display("Checking for %s in %s library %s... "656%(calltext,lang,lib_name))657# otherwise, just say the name of library and language658else:659context.Display("Checking for %s library %s... "660%(lang,lib_name))661662iflib_name:663l=[lib_name]664ifextra_libs:665l.extend(extra_libs)666ifappend:667oldLIBS=context.AppendLIBS(l)668else:669oldLIBS=context.PrependLIBS(l)670sym="HAVE_LIB"+lib_name671else:672oldLIBS=-1673sym=None674675ret=context.BuildProg(text,suffix)676677_YesNoResult(context,ret,sym,text,678"Define to 1 if you have the `%s' library."%lib_name)679ifoldLIBS!=-1and(retornotautoadd):680context.SetLIBS(oldLIBS)681682ifnotret:683returnret684685returnret

692"""693 Handle the result of a test with a "yes" or "no" result.694 "ret" is the return value: empty if OK, error message when not.695 "key" is the name of the symbol to be defined (HAVE_foo).696 "text" is the source code of the program used for testing.697 "comment" is the C comment to add above the line defining the symbol (the698 comment is automatically put inside a /* */). If None, no comment is added.699 """700ifkey:701_Have(context,key,notret,comment)702ifret:703context.Display("no\n")704_LogFailed(context,text,ret)705else:706context.Display("yes\n")

710"""711 Store result of a test in context.havedict and context.headerfilename.712 "key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-713 alphanumerics are replaced by an underscore.714 The value of "have" can be:715 1 - Feature is defined, add "#define key".716 0 - Feature is not defined, add "/* #undef key */".717 Adding "undef" is what autoconf does. Not useful for the718 compiler, but it shows that the test was done.719 number - Feature is defined to this number "#define key have".720 Doesn't work for 0 or 1, use a string then.721 string - Feature is defined to this string "#define key have".722 Give "have" as is should appear in the header file, include quotes723 when desired and escape special characters!724 """725key_up=key.upper()726key_up=re.sub('[^A-Z0-9_]','_',key_up)727context.havedict[key_up]=have728ifhave==1:729line="#define %s 1\n"%key_up730elifhave==0:731line="/* #undef %s */\n"%key_up732elifisinstance(have,IntType):733line="#define %s %d\n"%(key_up,have)734else:735line="#define %s %s\n"%(key_up,str(have))736737ifcommentisnotNone:738lines="\n/* %s */\n"%comment+line739else:740lines="\n"+line741742ifcontext.headerfilename:743f=open(context.headerfilename,"a")744f.write(lines)745f.close()746elifhasattr(context,'config_h'):747context.config_h=context.config_h+lines

751"""752 Write to the log about a failed program.753 Add line numbers, so that error messages can be understood.754 """755ifLogInputFiles:756context.Log("Failed program was:\n")757lines=text.split('\n')758iflen(lines)andlines[-1]=='':759lines=lines[:-1]# remove trailing empty line760n=1761forlineinlines:762context.Log("%d: %s\n"%(n,line))763n=n+1764ifLogErrorMessages:765context.Log("Error message: %s\n"%msg)

769"""770 Convert a language name to a suffix.771 When "lang" is empty or None C is assumed.772 Returns a tuple (lang, suffix, None) when it works.773 For an unrecognized language returns (None, None, msg).774 Where:775 lang = the unified language name776 suffix = the suffix, including the leading dot777 msg = an error message778 """779ifnotlangorlangin["C","c"]:780return("C",".c",None)781iflangin["c++","C++","cpp","CXX","cxx"]:782return("C++",".cpp",None)783784returnNone,None,"Unsupported language: %s"%lang