1 """SCons.Conftest
2
3 Autoconf-like configuration support; low level implementation of tests.
4 """
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 import re
98 import string
99 from types import IntType
100
101
102
103
104
105 LogInputFiles = 1
106 LogErrorMessages = 1
107
108
109
110
111
112
113
114
115
116
117
119 """
120 Configure check to see if the compiler works.
121 Note that this uses the current value of compiler and linker flags, make
122 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
123 "language" should be "C" or "C++" and is used to select the compiler.
124 Default is "C".
125 "text" may be used to specify the code to be build.
126 Returns an empty string for success, an error message for failure.
127 """
128 lang, suffix, msg = _lang2suffix(language)
129 if msg:
130 context.Display("%s\n" % msg)
131 return msg
132
133 if not text:
134 text = """
135 int main() {
136 return 0;
137 }
138 """
139
140 context.Display("Checking if building a %s file works... " % lang)
141 ret = context.BuildProg(text, suffix)
142 _YesNoResult(context, ret, None, text)
143 return ret
144
145
146 -def CheckFunc(context, function_name, header = None, language = None):
147 """
148 Configure check for a function "function_name".
149 "language" should be "C" or "C++" and is used to select the compiler.
150 Default is "C".
151 Optional "header" can be defined to define a function prototype, include a
152 header file or anything else that comes before main().
153 Sets HAVE_function_name in context.havedict according to the result.
154 Note that this uses the current value of compiler and linker flags, make
155 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
156 Returns an empty string for success, an error message for failure.
157 """
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 if context.headerfilename:
174 includetext = '#include "%s"' % context.headerfilename
175 else:
176 includetext = ''
177 if not header:
178 header = """
179 #ifdef __cplusplus
180 extern "C"
181 #endif
182 char %s();""" % function_name
183
184 lang, suffix, msg = _lang2suffix(language)
185 if msg:
186 context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
187 return msg
188
189 text = """
190 %(include)s
191 #include <assert.h>
192 %(hdr)s
193
194 int main() {
195 #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
196 fail fail fail
197 #else
198 %(name)s();
199 #endif
200
201 return 0;
202 }
203 """ % { 'name': function_name,
204 'include': includetext,
205 'hdr': header }
206
207 context.Display("Checking for %s function %s()... " % (lang, function_name))
208 ret = context.BuildProg(text, suffix)
209 _YesNoResult(context, ret, "HAVE_" + function_name, text,
210 "Define to 1 if the system has the function `%s'." %\
211 function_name)
212 return ret
213
214
217 """
218 Configure check for a C or C++ header file "header_name".
219 Optional "header" can be defined to do something before including the
220 header file (unusual, supported for consistency).
221 "language" should be "C" or "C++" and is used to select the compiler.
222 Default is "C".
223 Sets HAVE_header_name in context.havedict according to the result.
224 Note that this uses the current value of compiler and linker flags, make
225 sure $CFLAGS and $CPPFLAGS are set correctly.
226 Returns an empty string for success, an error message for failure.
227 """
228
229
230
231
232
233
234
235
236
237 if context.headerfilename:
238 includetext = '#include "%s"\n' % context.headerfilename
239 else:
240 includetext = ''
241 if not header:
242 header = ""
243
244 lang, suffix, msg = _lang2suffix(language)
245 if msg:
246 context.Display("Cannot check for header file %s: %s\n"
247 % (header_name, msg))
248 return msg
249
250 if not include_quotes:
251 include_quotes = "<>"
252
253 text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
254 include_quotes[0], header_name, include_quotes[1])
255
256 context.Display("Checking for %s header file %s... " % (lang, header_name))
257 ret = context.CompileProg(text, suffix)
258 _YesNoResult(context, ret, "HAVE_" + header_name, text,
259 "Define to 1 if you have the <%s> header file." % header_name)
260 return ret
261
262
263 -def CheckType(context, type_name, fallback = None,
264 header = None, language = None):
265 """
266 Configure check for a C or C++ type "type_name".
267 Optional "header" can be defined to include a header file.
268 "language" should be "C" or "C++" and is used to select the compiler.
269 Default is "C".
270 Sets HAVE_type_name in context.havedict according to the result.
271 Note that this uses the current value of compiler and linker flags, make
272 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
273 Returns an empty string for success, an error message for failure.
274 """
275
276
277 if context.headerfilename:
278 includetext = '#include "%s"' % context.headerfilename
279 else:
280 includetext = ''
281 if not header:
282 header = ""
283
284 lang, suffix, msg = _lang2suffix(language)
285 if msg:
286 context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
287 return msg
288
289
290
291
292
293
294
295
296
297
298
299
300 text = """
301 %(include)s
302 %(header)s
303
304 int main() {
305 if ((%(name)s *) 0)
306 return 0;
307 if (sizeof (%(name)s))
308 return 0;
309 }
310 """ % { 'include': includetext,
311 'header': header,
312 'name': type_name }
313
314 context.Display("Checking for %s type %s... " % (lang, type_name))
315 ret = context.BuildProg(text, suffix)
316 _YesNoResult(context, ret, "HAVE_" + type_name, text,
317 "Define to 1 if the system has the type `%s'." % type_name)
318 if ret and fallback and context.headerfilename:
319 f = open(context.headerfilename, "a")
320 f.write("typedef %s %s;\n" % (fallback, type_name))
321 f.close()
322
323 return ret
324
325 -def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
326 """This check can be used to get the size of a given type, or to check whether
327 the type is of expected size.
328
329 Arguments:
330 - type : str
331 the type to check
332 - includes : sequence
333 list of headers to include in the test code before testing the type
334 - language : str
335 'C' or 'C++'
336 - expect : int
337 if given, will test wether the type has the given number of bytes.
338 If not given, will automatically find the size.
339
340 Returns:
341 status : int
342 0 if the check failed, or the found size of the type if the check succeeded."""
343
344
345 if context.headerfilename:
346 includetext = '#include "%s"' % context.headerfilename
347 else:
348 includetext = ''
349
350 if not header:
351 header = ""
352
353 lang, suffix, msg = _lang2suffix(language)
354 if msg:
355 context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
356 return msg
357
358 src = includetext + header
359 if not expect is None:
360
361 context.Display('Checking %s is %d bytes... ' % (type_name, expect))
362
363
364
365
366 src = src + r"""
367 typedef %s scons_check_type;
368
369 int main()
370 {
371 static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
372 test_array[0] = 0;
373
374 return 0;
375 }
376 """
377
378 st = context.CompileProg(src % (type_name, expect), suffix)
379 if not st:
380 context.Display("yes\n")
381 _Have(context, "SIZEOF_%s" % type_name, expect,
382 "The size of `%s', as computed by sizeof." % type_name)
383 return expect
384 else:
385 context.Display("no\n")
386 _LogFailed(context, src, st)
387 return 0
388 else:
389
390 context.Message('Checking size of %s ... ' % type_name)
391
392
393
394
395
396
397
398
399 src = src + """
400 #include <stdlib.h>
401 #include <stdio.h>
402 int main() {
403 printf("%d", (int)sizeof(""" + type_name + """));
404 return 0;
405 }
406 """
407 st, out = context.RunProg(src, suffix)
408 try:
409 size = int(out)
410 except ValueError:
411
412
413 st = 1
414 size = 0
415
416 if not st:
417 context.Display("yes\n")
418 _Have(context, "SIZEOF_%s" % type_name, size,
419 "The size of `%s', as computed by sizeof." % type_name)
420 return size
421 else:
422 context.Display("no\n")
423 _LogFailed(context, src, st)
424 return 0
425
426 return 0
427
429 """Checks whether symbol is declared.
430
431 Use the same test as autoconf, that is test whether the symbol is defined
432 as a macro or can be used as an r-value.
433
434 Arguments:
435 symbol : str
436 the symbol to check
437 includes : str
438 Optional "header" can be defined to include a header file.
439 language : str
440 only C and C++ supported.
441
442 Returns:
443 status : bool
444 True if the check failed, False if succeeded."""
445
446
447 if context.headerfilename:
448 includetext = '#include "%s"' % context.headerfilename
449 else:
450 includetext = ''
451
452 if not includes:
453 includes = ""
454
455 lang, suffix, msg = _lang2suffix(language)
456 if msg:
457 context.Display("Cannot check for declaration %s: %s\n" % (type_name, msg))
458 return msg
459
460 src = includetext + includes
461 context.Display('Checking whether %s is declared... ' % symbol)
462
463 src = src + r"""
464 int main()
465 {
466 #ifndef %s
467 (void) %s;
468 #endif
469 ;
470 return 0;
471 }
472 """ % (symbol, symbol)
473
474 st = context.CompileProg(src, suffix)
475 _YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
476 "Set to 1 if %s is defined." % symbol)
477 return st
478
479 -def CheckLib(context, libs, func_name = None, header = None,
480 extra_libs = None, call = None, language = None, autoadd = 1):
481 """
482 Configure check for a C or C++ libraries "libs". Searches through
483 the list of libraries, until one is found where the test succeeds.
484 Tests if "func_name" or "call" exists in the library. Note: if it exists
485 in another library the test succeeds anyway!
486 Optional "header" can be defined to include a header file. If not given a
487 default prototype for "func_name" is added.
488 Optional "extra_libs" is a list of library names to be added after
489 "lib_name" in the build command. To be used for libraries that "lib_name"
490 depends on.
491 Optional "call" replaces the call to "func_name" in the test code. It must
492 consist of complete C statements, including a trailing ";".
493 Both "func_name" and "call" arguments are optional, and in that case, just
494 linking against the libs is tested.
495 "language" should be "C" or "C++" and is used to select the compiler.
496 Default is "C".
497 Note that this uses the current value of compiler and linker flags, make
498 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
499 Returns an empty string for success, an error message for failure.
500 """
501
502 if context.headerfilename:
503 includetext = '#include "%s"' % context.headerfilename
504 else:
505 includetext = ''
506 if not header:
507 header = ""
508
509 text = """
510 %s
511 %s""" % (includetext, header)
512
513
514 if func_name and func_name != "main":
515 if not header:
516 text = text + """
517 #ifdef __cplusplus
518 extern "C"
519 #endif
520 char %s();
521 """ % func_name
522
523
524 if not call:
525 call = "%s();" % func_name
526
527
528 text = text + """
529 int
530 main() {
531 %s
532 return 0;
533 }
534 """ % (call or "")
535
536 if call:
537 i = string.find(call, "\n")
538 if i > 0:
539 calltext = call[:i] + ".."
540 elif call[-1] == ';':
541 calltext = call[:-1]
542 else:
543 calltext = call
544
545 for lib_name in libs:
546
547 lang, suffix, msg = _lang2suffix(language)
548 if msg:
549 context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
550 return msg
551
552
553 if call:
554 context.Display("Checking for %s in %s library %s... "
555 % (calltext, lang, lib_name))
556
557 else:
558 context.Display("Checking for %s library %s... "
559 % (lang, lib_name))
560
561 if lib_name:
562 l = [ lib_name ]
563 if extra_libs:
564 l.extend(extra_libs)
565 oldLIBS = context.AppendLIBS(l)
566 sym = "HAVE_LIB" + lib_name
567 else:
568 oldLIBS = -1
569 sym = None
570
571 ret = context.BuildProg(text, suffix)
572
573 _YesNoResult(context, ret, sym, text,
574 "Define to 1 if you have the `%s' library." % lib_name)
575 if oldLIBS != -1 and (ret or not autoadd):
576 context.SetLIBS(oldLIBS)
577
578 if not ret:
579 return ret
580
581 return ret
582
583
584
585
586
588 """
589 Handle the result of a test with a "yes" or "no" result.
590 "ret" is the return value: empty if OK, error message when not.
591 "key" is the name of the symbol to be defined (HAVE_foo).
592 "text" is the source code of the program used for testing.
593 "comment" is the C comment to add above the line defining the symbol (the
594 comment is automatically put inside a /* */). If None, no comment is added.
595 """
596 if key:
597 _Have(context, key, not ret, comment)
598 if ret:
599 context.Display("no\n")
600 _LogFailed(context, text, ret)
601 else:
602 context.Display("yes\n")
603
604
605 -def _Have(context, key, have, comment = None):
606 """
607 Store result of a test in context.havedict and context.headerfilename.
608 "key" is a "HAVE_abc" name. It is turned into all CAPITALS and non-
609 alphanumerics are replaced by an underscore.
610 The value of "have" can be:
611 1 - Feature is defined, add "#define key".
612 0 - Feature is not defined, add "/* #undef key */".
613 Adding "undef" is what autoconf does. Not useful for the
614 compiler, but it shows that the test was done.
615 number - Feature is defined to this number "#define key have".
616 Doesn't work for 0 or 1, use a string then.
617 string - Feature is defined to this string "#define key have".
618 Give "have" as is should appear in the header file, include quotes
619 when desired and escape special characters!
620 """
621 key_up = string.upper(key)
622 key_up = re.sub('[^A-Z0-9_]', '_', key_up)
623 context.havedict[key_up] = have
624 if have == 1:
625 line = "#define %s 1\n" % key_up
626 elif have == 0:
627 line = "/* #undef %s */\n" % key_up
628 elif type(have) == IntType:
629 line = "#define %s %d\n" % (key_up, have)
630 else:
631 line = "#define %s %s\n" % (key_up, str(have))
632
633 if comment is not None:
634 lines = "\n/* %s */\n" % comment + line
635 else:
636 lines = "\n" + line
637
638 if context.headerfilename:
639 f = open(context.headerfilename, "a")
640 f.write(lines)
641 f.close()
642 elif hasattr(context,'config_h'):
643 context.config_h = context.config_h + lines
644
645
647 """
648 Write to the log about a failed program.
649 Add line numbers, so that error messages can be understood.
650 """
651 if LogInputFiles:
652 context.Log("Failed program was:\n")
653 lines = string.split(text, '\n')
654 if len(lines) and lines[-1] == '':
655 lines = lines[:-1]
656 n = 1
657 for line in lines:
658 context.Log("%d: %s\n" % (n, line))
659 n = n + 1
660 if LogErrorMessages:
661 context.Log("Error message: %s\n" % msg)
662
663
665 """
666 Convert a language name to a suffix.
667 When "lang" is empty or None C is assumed.
668 Returns a tuple (lang, suffix, None) when it works.
669 For an unrecognized language returns (None, None, msg).
670 Where:
671 lang = the unified language name
672 suffix = the suffix, including the leading dot
673 msg = an error message
674 """
675 if not lang or lang in ["C", "c"]:
676 return ("C", ".c", None)
677 if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
678 return ("C++", ".cpp", None)
679
680 return None, None, "Unsupported language: %s" % lang
681
682
683
684