Allow CheckLib to search a list of libraries. (sam th)
[scons.git] / src / engine / SCons / Conftest.py
1 """SCons.Conftest
2
3 Autoconf-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.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.
74 #
75 # context.headerfilename
76 #                       Name of file to append configure results to, usually
77 #                       "confdefs.h".
78 #                       The file must not exist or be empty when starting.
79 #                       Empty or None to skip this (some tests will not work!).
80 #
81 # context.vardict       Dictionary holding variables used for the tests and
82 #                       stores results from the tests, used for the build
83 #                       commands.
84 #                       Normally contains "CC", "LIBS", "CPPFLAGS", etc.
85 #
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.
92 #
93
94 import string
95 from types import IntType
96
97 #
98 # PUBLIC FUNCTIONS
99 #
100
101 # Generic remarks:
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).
105
106
107 def CheckBuilder(context, text = None, language = None):
108     """
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.
113     Default is "C".
114     "text" may be used to specify the code to be build.
115     Returns an empty string for success, an error message for failure.
116     """
117     lang, suffix, msg = _lang2suffix(language)
118     if msg:
119         context.Display("%s\n" % msg)
120         return msg
121
122     if not text:
123         text = """
124                 int main() {
125                         return 0;
126                     }\n\n"""
127
128     context.Display("Checking if building a %s file works... " % lang)
129     ret = context.BuildProg(text, suffix)
130     _YesNoResult(context, ret, None, text)
131     return ret
132
133
134 def CheckFunc(context, function_name, header = None, language = None):
135     """
136     Configure check for a function "function_name".
137     "language" should be "C" or "C++" and is used to select the compiler.
138     Default is "C".
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.
145     """
146
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
156     #   still apply.
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.
160
161     if context.headerfilename:
162         includetext = '#include "%s"' % context.headerfilename
163     else:
164         includetext = ''
165     if not header:
166         header = """
167                 #ifdef __cplusplus
168                 extern "C"
169                 #endif
170                 char %s();""" % function_name
171
172     lang, suffix, msg = _lang2suffix(language)
173     if msg:
174         context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
175         return msg
176
177     text = """
178             %(include)s
179             #include <assert.h>
180             %(hdr)s
181
182             int main() {
183                     #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
184                     fail fail fail
185                     #else
186                     %(name)s();
187                     #endif
188
189                     return 0;
190                 }\n\n""" % { 'name': function_name,
191                              'include': includetext,
192                              'hdr': header }
193
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)
197     return ret
198
199
200 def CheckHeader(context, header_name, header = None, language = None,
201                                                         include_quotes = None):
202     """
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.
207     Default is "C".
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.
212     """
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.
217     #
218     # Use <> by default, because the check is normally used for system header
219     # files.  SCons passes '""' to overrule this.
220
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
224     else:
225         includetext = ''
226     if not header:
227         header = ""
228
229     lang, suffix, msg = _lang2suffix(language)
230     if msg:
231         context.Display("Cannot check for header file %s: %s\n"
232                                                           % (header_name, msg))
233         return msg
234
235     if not include_quotes:
236         include_quotes = "<>"
237
238     text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
239                              include_quotes[0], header_name, include_quotes[1])
240
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)
244     return ret
245
246
247 def CheckType(context, type_name, fallback = None,
248                                                header = None, language = None):
249     """
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.
253     Default is "C".
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.
258     """
259
260     # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
261     if context.headerfilename:
262         includetext = '#include "%s"' % context.headerfilename
263     else:
264         includetext = ''
265     if not header:
266         header = ""
267
268     lang, suffix, msg = _lang2suffix(language)
269     if msg:
270         context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
271         return msg
272
273     # Remarks from autoconf about this test:
274     # - Grepping for the type in include files is not reliable (grep isn't
275     #   portable anyway).
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
279     #   C++.
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.
284     text = """
285             %(include)s
286             %(header)s
287
288             int main() {
289                     if ((%(name)s *) 0)
290                             return 0;
291                     if (sizeof (%(name)s))
292                             return 0;
293             }\n\n""" % { 'include': includetext,
294                          'header': header,
295                          'name': type_name }
296
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))
303         f.close()
304
305     return ret
306
307
308 def CheckLib(context, libs, func_name, header = None,
309                  extra_libs = None, call = None, language = None, autoadd = 1):
310     """
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"
319     depends on.
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.
324     Default is "C".
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.
328     """
329     # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
330     if context.headerfilename:
331         includetext = '#include "%s"' % context.headerfilename
332     else:
333         includetext = ''
334     if not header:
335         header = ""
336
337     text = """
338             %s
339             %s """ % (includetext, header)
340
341     # Add a function declaration if needed.
342     if func_name and func_name != "main" and not header:
343         text = text + """
344                 #ifdef __cplusplus
345                 extern "C"
346                 #endif
347                 char %s();""" % func_name
348
349     # The actual test code.
350     if not call:
351         call = "%s();" % func_name
352     text = text + """
353             int
354             main() {
355             %s
356             return 0;
357             }
358             \n\n""" % call
359
360     i = string.find(call, "\n")
361     if i > 0:
362         calltext = call[:i] + ".."
363     elif call[-1] == ';':
364         calltext = call[:-1]
365     else:
366         calltext = call
367
368     for lib_name in libs:
369
370         lang, suffix, msg = _lang2suffix(language)
371         if msg:
372             context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
373             return msg
374
375         context.Display("Checking for %s in %s library %s... "
376                         % (calltext, lang, lib_name))
377         if lib_name:
378             l = [ lib_name ]
379             if extra_libs:
380                 l.extend(extra_libs)
381             oldLIBS = context.AppendLIBS(l)
382             sym = "HAVE_LIB" + lib_name
383         else:
384             oldLIBS = -1
385             sym = None
386
387         ret = context.BuildProg(text, suffix)
388
389         _YesNoResult(context, ret, sym, text)
390         if oldLIBS != -1 and (ret or not autoadd):
391             context.SetLIBS(oldLIBS)
392             
393         if ret == "":
394             return ret
395
396     return ret
397
398 #
399 # END OF PUBLIC FUNCTIONS
400 #
401
402 def _YesNoResult(context, ret, key, text):
403     """
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.
408     """
409     if key:
410         _Have(context, key, not ret)
411     if ret:
412         context.Display("no\n")
413         _LogFailed(context, text, ret)
414     else:
415         context.Display("yes\n")
416
417
418 def _Have(context, key, have):
419     """
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!
433     """
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")
442         if have == 1:
443             f.write("#define %s\n" % key_up)
444         elif have == 0:
445             f.write("/* #undef %s */\n" % key_up)
446         elif type(have) == IntType:
447             f.write("#define %s %d\n" % (key_up, have))
448         else:
449             f.write("#define %s %s\n" % (key_up, str(have)))
450         f.close()
451
452
453 def _LogFailed(context, text, msg):
454     """
455     Write to the log about a failed program.
456     Add line numbers, so that error messages can be understood.
457     """
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
462     n = 1
463     for line in lines:
464         context.Log("%d: %s\n" % (n, line))
465         n = n + 1
466     context.Log("Error message: %s\n" % msg)
467
468
469 def _lang2suffix(lang):
470     """
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).
475     Where:
476         lang   = the unified language name
477         suffix = the suffix, including the leading dot
478         msg    = an error message
479     """
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)
484
485     return None, None, "Unsupported language: %s" % lang
486
487
488 # vim: set sw=4 et sts=4 tw=79 fo+=l: