3 Autoconf-like configuration support; low level implementation of tests.
7 # Copyright (c) 2003 Stichting NLnet Labs
8 # Copyright (c) 2001, 2002, 2003 Steven Knight
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:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
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.
31 # The purpose of this module is to define how a check is to be performed.
32 # Use one of the Check...() functions below.
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:
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!
43 # context.Log(msg) Function called to write to a log file.
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
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
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.
69 # context.SetLIBS(value)
70 # Set LIBS to "value". The type of "value" is what
71 # AppendLIBS() returned.
72 # Return the value of LIBS before changing it (any type
73 # can be used, it is passed to SetLIBS() later.
75 # context.headerfilename
76 # Name of file to append configure results to, usually
78 # The file must not exist or be empty when starting.
79 # Empty or None to skip this (some tests will not work!).
81 # context.vardict Dictionary holding variables used for the tests and
82 # stores results from the tests, used for the build
84 # Normally contains "CC", "LIBS", "CPPFLAGS", etc.
86 # context.havedict Dictionary holding results from the tests that are to
87 # be used inside a program.
88 # Names often start with "HAVE_". These are zero
89 # (feature not present) or one (feature present). Other
90 # variables may have any value, e.g., "PERLVERSION" can
91 # be a number and "SYSTEMNAME" a string.
95 from types import IntType
102 # - When a language is specified which is not supported the test fails. The
103 # message is a bit different, because not all the arguments for the normal
104 # message are available yet (chicken-egg problem).
107 def CheckBuilder(context, text = None, language = None):
109 Configure check to see if the compiler works.
110 Note that this uses the current value of compiler and linker flags, make
111 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
112 "language" should be "C" or "C++" and is used to select the compiler.
114 "text" may be used to specify the code to be build.
115 Returns an empty string for success, an error message for failure.
117 lang, suffix, msg = _lang2suffix(language)
119 context.Display("%s\n" % msg)
128 context.Display("Checking if building a %s file works... " % lang)
129 ret = context.BuildProg(text, suffix)
130 _YesNoResult(context, ret, None, text)
134 def CheckFunc(context, function_name, header = None, language = None):
136 Configure check for a function "function_name".
137 "language" should be "C" or "C++" and is used to select the compiler.
139 Optional "header" can be defined to define a function prototype, include a
140 header file or anything else that comes before main().
141 Sets HAVE_function_name in context.havedict according to the result.
142 Note that this uses the current value of compiler and linker flags, make
143 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
144 Returns an empty string for success, an error message for failure.
147 # Remarks from autoconf:
148 # - Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
149 # which includes <sys/select.h> which contains a prototype for select.
150 # Similarly for bzero.
151 # - assert.h is included to define __stub macros and hopefully few
152 # prototypes, which can conflict with char $1(); below.
153 # - Override any gcc2 internal prototype to avoid an error.
154 # - We use char for the function declaration because int might match the
155 # return type of a gcc2 builtin and then its argument prototype would
157 # - The GNU C library defines this for functions which it implements to
158 # always fail with ENOSYS. Some functions are actually named something
159 # starting with __ and the normal name is an alias.
161 if context.headerfilename:
162 includetext = '#include "%s"' % context.headerfilename
170 char %s();""" % function_name
172 lang, suffix, msg = _lang2suffix(language)
174 context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
183 #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
190 }\n\n""" % { 'name': function_name,
191 'include': includetext,
194 context.Display("Checking for %s function %s()... " % (lang, function_name))
195 ret = context.BuildProg(text, suffix)
196 _YesNoResult(context, ret, "HAVE_" + function_name, text)
200 def CheckHeader(context, header_name, header = None, language = None,
201 include_quotes = None):
203 Configure check for a C or C++ header file "header_name".
204 Optional "header" can be defined to do something before including the
205 header file (unusual, supported for consistency).
206 "language" should be "C" or "C++" and is used to select the compiler.
208 Sets HAVE_header_name in context.havedict according to the result.
209 Note that this uses the current value of compiler and linker flags, make
210 sure $CFLAGS and $CPPFLAGS are set correctly.
211 Returns an empty string for success, an error message for failure.
213 # Why compile the program instead of just running the preprocessor?
214 # It is possible that the header file exists, but actually using it may
215 # fail (e.g., because it depends on other header files). Thus this test is
216 # more strict. It may require using the "header" argument.
218 # Use <> by default, because the check is normally used for system header
219 # files. SCons passes '""' to overrule this.
221 # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
222 if context.headerfilename:
223 includetext = '#include "%s"\n' % context.headerfilename
229 lang, suffix, msg = _lang2suffix(language)
231 context.Display("Cannot check for header file %s: %s\n"
232 % (header_name, msg))
235 if not include_quotes:
236 include_quotes = "<>"
238 text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
239 include_quotes[0], header_name, include_quotes[1])
241 context.Display("Checking for %s header file %s... " % (lang, header_name))
242 ret = context.CompileProg(text, suffix)
243 _YesNoResult(context, ret, "HAVE_" + header_name, text)
247 def CheckType(context, type_name, fallback = None,
248 header = None, language = None):
250 Configure check for a C or C++ type "type_name".
251 Optional "header" can be defined to include a header file.
252 "language" should be "C" or "C++" and is used to select the compiler.
254 Sets HAVE_type_name in context.havedict according to the result.
255 Note that this uses the current value of compiler and linker flags, make
256 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
257 Returns an empty string for success, an error message for failure.
260 # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
261 if context.headerfilename:
262 includetext = '#include "%s"' % context.headerfilename
268 lang, suffix, msg = _lang2suffix(language)
270 context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
273 # Remarks from autoconf about this test:
274 # - Grepping for the type in include files is not reliable (grep isn't
276 # - Using "TYPE my_var;" doesn't work for const qualified types in C++.
277 # Adding an initializer is not valid for some C++ classes.
278 # - Using the type as parameter to a function either fails for K&$ C or for
280 # - Using "TYPE *my_var;" is valid in C for some types that are not
281 # declared (struct something).
282 # - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
283 # - Using the previous two together works reliably.
291 if (sizeof (%(name)s))
293 }\n\n""" % { 'include': includetext,
297 context.Display("Checking for %s type %s... " % (lang, type_name))
298 ret = context.BuildProg(text, suffix)
299 _YesNoResult(context, ret, "HAVE_" + type_name, text)
300 if ret and fallback and context.headerfilename:
301 f = open(context.headerfilename, "a")
302 f.write("typedef %s %s;\n" % (fallback, type_name))
308 def CheckLib(context, libs, func_name, header = None,
309 extra_libs = None, call = None, language = None, autoadd = 1):
311 Configure check for a C or C++ libraries "libs". Searches through
312 the list of libraries, until one is found where the test succeeds.
313 Tests if "func_name" or "call" exists in the library. Note: if it exists
314 in another library the test succeeds anyway!
315 Optional "header" can be defined to include a header file. If not given a
316 default prototype for "func_name" is added.
317 Optional "extra_libs" is a list of library names to be added after
318 "lib_name" in the build command. To be used for libraries that "lib_name"
320 Optional "call" replaces the call to "func_name" in the test code. It must
321 consist of complete C statements, including a trailing ";".
322 There must either be a "func_name" or a "call" argument (or both).
323 "language" should be "C" or "C++" and is used to select the compiler.
325 Note that this uses the current value of compiler and linker flags, make
326 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
327 Returns an empty string for success, an error message for failure.
329 # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
330 if context.headerfilename:
331 includetext = '#include "%s"' % context.headerfilename
339 %s """ % (includetext, header)
341 # Add a function declaration if needed.
342 if func_name and func_name != "main" and not header:
347 char %s();""" % func_name
349 # The actual test code.
351 call = "%s();" % func_name
360 i = string.find(call, "\n")
362 calltext = call[:i] + ".."
363 elif call[-1] == ';':
368 for lib_name in libs:
370 lang, suffix, msg = _lang2suffix(language)
372 context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
375 context.Display("Checking for %s in %s library %s... "
376 % (calltext, lang, lib_name))
381 oldLIBS = context.AppendLIBS(l)
382 sym = "HAVE_LIB" + lib_name
387 ret = context.BuildProg(text, suffix)
389 _YesNoResult(context, ret, sym, text)
390 if oldLIBS != -1 and (ret or not autoadd):
391 context.SetLIBS(oldLIBS)
399 # END OF PUBLIC FUNCTIONS
402 def _YesNoResult(context, ret, key, text):
404 Handle the result of a test with a "yes" or "no" result.
405 "ret" is the return value: empty if OK, error message when not.
406 "key" is the name of the symbol to be defined (HAVE_foo).
407 "text" is the source code of the program used for testing.
410 _Have(context, key, not ret)
412 context.Display("no\n")
413 _LogFailed(context, text, ret)
415 context.Display("yes\n")
418 def _Have(context, key, have):
420 Store result of a test in context.havedict and context.headerfilename.
421 "key" is a "HAVE_abc" name. It is turned into all CAPITALS and ":./" are
422 replaced by an underscore.
423 The value of "have" can be:
424 1 - Feature is defined, add "#define key".
425 0 - Feature is not defined, add "/* #undef key */".
426 Adding "undef" is what autoconf does. Not useful for the
427 compiler, but it shows that the test was done.
428 number - Feature is defined to this number "#define key have".
429 Doesn't work for 0 or 1, use a string then.
430 string - Feature is defined to this string "#define key have".
431 Give "have" as is should appear in the header file, include quotes
432 when desired and escape special characters!
434 key_up = string.upper(key)
435 key_up = string.replace(key_up, ':', '_')
436 key_up = string.replace(key_up, '.', '_')
437 key_up = string.replace(key_up, '/', '_')
438 key_up = string.replace(key_up, ' ', '_')
439 context.havedict[key_up] = have
440 if context.headerfilename:
441 f = open(context.headerfilename, "a")
443 f.write("#define %s\n" % key_up)
445 f.write("/* #undef %s */\n" % key_up)
446 elif type(have) == IntType:
447 f.write("#define %s %d\n" % (key_up, have))
449 f.write("#define %s %s\n" % (key_up, str(have)))
453 def _LogFailed(context, text, msg):
455 Write to the log about a failed program.
456 Add line numbers, so that error messages can be understood.
458 context.Log("Failed program was:\n")
459 lines = string.split(text, '\n')
460 if len(lines) and lines[-1] == '':
461 lines = lines[:-1] # remove trailing empty line
464 context.Log("%d: %s\n" % (n, line))
466 context.Log("Error message: %s\n" % msg)
469 def _lang2suffix(lang):
471 Convert a language name to a suffix.
472 When "lang" is empty or None C is assumed.
473 Returns a tuple (lang, suffix, None) when it works.
474 For an unrecognized language returns (None, None, msg).
476 lang = the unified language name
477 suffix = the suffix, including the leading dot
478 msg = an error message
480 if not lang or lang in ["C", "c"]:
481 return ("C", ".c", None)
482 if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
483 return ("C++", ".cpp", None)
485 return None, None, "Unsupported language: %s" % lang
488 # vim: set sw=4 et sts=4 tw=79 fo+=l: