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
98
99
100
101
102
103 import re
104
105
106
107
108
109 LogInputFiles = 1
110 LogErrorMessages = 1
111
112
113
114
115
116
117
118
119
120
121
123 """
124 Configure check to see if the compiler works.
125 Note that this uses the current value of compiler and linker flags, make
126 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
127 "language" should be "C" or "C++" and is used to select the compiler.
128 Default is "C".
129 "text" may be used to specify the code to be build.
130 Returns an empty string for success, an error message for failure.
131 """
132 lang, suffix, msg = _lang2suffix(language)
133 if msg:
134 context.Display("%s\n" % msg)
135 return msg
136
137 if not text:
138 text = """
139 int main(void) {
140 return 0;
141 }
142 """
143
144 context.Display("Checking if building a %s file works... " % lang)
145 ret = context.BuildProg(text, suffix)
146 _YesNoResult(context, ret, None, text)
147 return ret
148
150 """
151 Configure check for a working C compiler.
152
153 This checks whether the C compiler, as defined in the $CC construction
154 variable, can compile a C source file. It uses the current $CCCOM value
155 too, so that it can test against non working flags.
156
157 """
158 context.Display("Checking whether the C compiler works... ")
159 text = """
160 int main(void)
161 {
162 return 0;
163 }
164 """
165 ret = _check_empty_program(context, 'CC', text, 'C')
166 _YesNoResult(context, ret, None, text)
167 return ret
168
170 """
171 Configure check for a working shared C compiler.
172
173 This checks whether the C compiler, as defined in the $SHCC construction
174 variable, can compile a C source file. It uses the current $SHCCCOM value
175 too, so that it can test against non working flags.
176
177 """
178 context.Display("Checking whether the (shared) C compiler works... ")
179 text = """
180 int foo(void)
181 {
182 return 0;
183 }
184 """
185 ret = _check_empty_program(context, 'SHCC', text, 'C', use_shared = True)
186 _YesNoResult(context, ret, None, text)
187 return ret
188
190 """
191 Configure check for a working CXX compiler.
192
193 This checks whether the CXX compiler, as defined in the $CXX construction
194 variable, can compile a CXX source file. It uses the current $CXXCOM value
195 too, so that it can test against non working flags.
196
197 """
198 context.Display("Checking whether the C++ compiler works... ")
199 text = """
200 int main(void)
201 {
202 return 0;
203 }
204 """
205 ret = _check_empty_program(context, 'CXX', text, 'C++')
206 _YesNoResult(context, ret, None, text)
207 return ret
208
210 """
211 Configure check for a working shared CXX compiler.
212
213 This checks whether the CXX compiler, as defined in the $SHCXX construction
214 variable, can compile a CXX source file. It uses the current $SHCXXCOM value
215 too, so that it can test against non working flags.
216
217 """
218 context.Display("Checking whether the (shared) C++ compiler works... ")
219 text = """
220 int main(void)
221 {
222 return 0;
223 }
224 """
225 ret = _check_empty_program(context, 'SHCXX', text, 'C++', use_shared = True)
226 _YesNoResult(context, ret, None, text)
227 return ret
228
230 """Return 0 on success, 1 otherwise."""
231 if comp not in context.env or not context.env[comp]:
232
233 return 1
234
235 lang, suffix, msg = _lang2suffix(language)
236 if msg:
237 return 1
238
239 if use_shared:
240 return context.CompileSharedObject(text, suffix)
241 else:
242 return context.CompileProg(text, suffix)
243
244
245 -def CheckFunc(context, function_name, header = None, language = None):
246 """
247 Configure check for a function "function_name".
248 "language" should be "C" or "C++" and is used to select the compiler.
249 Default is "C".
250 Optional "header" can be defined to define a function prototype, include a
251 header file or anything else that comes before main().
252 Sets HAVE_function_name in context.havedict according to the result.
253 Note that this uses the current value of compiler and linker flags, make
254 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
255 Returns an empty string for success, an error message for failure.
256 """
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272 if context.headerfilename:
273 includetext = '#include "%s"' % context.headerfilename
274 else:
275 includetext = ''
276 if not header:
277 header = """
278 #ifdef __cplusplus
279 extern "C"
280 #endif
281 char %s();""" % function_name
282
283 lang, suffix, msg = _lang2suffix(language)
284 if msg:
285 context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
286 return msg
287
288 text = """
289 %(include)s
290 #include <assert.h>
291 %(hdr)s
292
293 int main(void) {
294 #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
295 fail fail fail
296 #else
297 %(name)s();
298 #endif
299
300 return 0;
301 }
302 """ % { 'name': function_name,
303 'include': includetext,
304 'hdr': header }
305
306 context.Display("Checking for %s function %s()... " % (lang, function_name))
307 ret = context.BuildProg(text, suffix)
308 _YesNoResult(context, ret, "HAVE_" + function_name, text,
309 "Define to 1 if the system has the function `%s'." %\
310 function_name)
311 return ret
312
313
316 """
317 Configure check for a C or C++ header file "header_name".
318 Optional "header" can be defined to do something before including the
319 header file (unusual, supported for consistency).
320 "language" should be "C" or "C++" and is used to select the compiler.
321 Default is "C".
322 Sets HAVE_header_name in context.havedict according to the result.
323 Note that this uses the current value of compiler and linker flags, make
324 sure $CFLAGS and $CPPFLAGS are set correctly.
325 Returns an empty string for success, an error message for failure.
326 """
327
328
329
330
331
332
333
334
335
336 if context.headerfilename:
337 includetext = '#include "%s"\n' % context.headerfilename
338 else:
339 includetext = ''
340 if not header:
341 header = ""
342
343 lang, suffix, msg = _lang2suffix(language)
344 if msg:
345 context.Display("Cannot check for header file %s: %s\n"
346 % (header_name, msg))
347 return msg
348
349 if not include_quotes:
350 include_quotes = "<>"
351
352 text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
353 include_quotes[0], header_name, include_quotes[1])
354
355 context.Display("Checking for %s header file %s... " % (lang, header_name))
356 ret = context.CompileProg(text, suffix)
357 _YesNoResult(context, ret, "HAVE_" + header_name, text,
358 "Define to 1 if you have the <%s> header file." % header_name)
359 return ret
360
361
362 -def CheckType(context, type_name, fallback = None,
363 header = None, language = None):
364 """
365 Configure check for a C or C++ type "type_name".
366 Optional "header" can be defined to include a header file.
367 "language" should be "C" or "C++" and is used to select the compiler.
368 Default is "C".
369 Sets HAVE_type_name in context.havedict according to the result.
370 Note that this uses the current value of compiler and linker flags, make
371 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
372 Returns an empty string for success, an error message for failure.
373 """
374
375
376 if context.headerfilename:
377 includetext = '#include "%s"' % context.headerfilename
378 else:
379 includetext = ''
380 if not header:
381 header = ""
382
383 lang, suffix, msg = _lang2suffix(language)
384 if msg:
385 context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
386 return msg
387
388
389
390
391
392
393
394
395
396
397
398
399 text = """
400 %(include)s
401 %(header)s
402
403 int main(void) {
404 if ((%(name)s *) 0)
405 return 0;
406 if (sizeof (%(name)s))
407 return 0;
408 }
409 """ % { 'include': includetext,
410 'header': header,
411 'name': type_name }
412
413 context.Display("Checking for %s type %s... " % (lang, type_name))
414 ret = context.BuildProg(text, suffix)
415 _YesNoResult(context, ret, "HAVE_" + type_name, text,
416 "Define to 1 if the system has the type `%s'." % type_name)
417 if ret and fallback and context.headerfilename:
418 f = open(context.headerfilename, "a")
419 f.write("typedef %s %s;\n" % (fallback, type_name))
420 f.close()
421
422 return ret
423
424 -def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
425 """This check can be used to get the size of a given type, or to check whether
426 the type is of expected size.
427
428 Arguments:
429 - type : str
430 the type to check
431 - includes : sequence
432 list of headers to include in the test code before testing the type
433 - language : str
434 'C' or 'C++'
435 - expect : int
436 if given, will test wether the type has the given number of bytes.
437 If not given, will automatically find the size.
438
439 Returns:
440 status : int
441 0 if the check failed, or the found size of the type if the check succeeded."""
442
443
444 if context.headerfilename:
445 includetext = '#include "%s"' % context.headerfilename
446 else:
447 includetext = ''
448
449 if not header:
450 header = ""
451
452 lang, suffix, msg = _lang2suffix(language)
453 if msg:
454 context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
455 return msg
456
457 src = includetext + header
458 if not expect is None:
459
460 context.Display('Checking %s is %d bytes... ' % (type_name, expect))
461
462
463
464
465 src = src + r"""
466 typedef %s scons_check_type;
467
468 int main(void)
469 {
470 static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
471 test_array[0] = 0;
472
473 return 0;
474 }
475 """
476
477 st = context.CompileProg(src % (type_name, expect), suffix)
478 if not st:
479 context.Display("yes\n")
480 _Have(context, "SIZEOF_%s" % type_name, expect,
481 "The size of `%s', as computed by sizeof." % type_name)
482 return expect
483 else:
484 context.Display("no\n")
485 _LogFailed(context, src, st)
486 return 0
487 else:
488
489 context.Message('Checking size of %s ... ' % type_name)
490
491
492
493
494
495
496
497
498 src = src + """
499 #include <stdlib.h>
500 #include <stdio.h>
501 int main(void) {
502 printf("%d", (int)sizeof(""" + type_name + """));
503 return 0;
504 }
505 """
506 st, out = context.RunProg(src, suffix)
507 try:
508 size = int(out)
509 except ValueError:
510
511
512 st = 1
513 size = 0
514
515 if not st:
516 context.Display("yes\n")
517 _Have(context, "SIZEOF_%s" % type_name, size,
518 "The size of `%s', as computed by sizeof." % type_name)
519 return size
520 else:
521 context.Display("no\n")
522 _LogFailed(context, src, st)
523 return 0
524
525 return 0
526
528 """Checks whether symbol is declared.
529
530 Use the same test as autoconf, that is test whether the symbol is defined
531 as a macro or can be used as an r-value.
532
533 Arguments:
534 symbol : str
535 the symbol to check
536 includes : str
537 Optional "header" can be defined to include a header file.
538 language : str
539 only C and C++ supported.
540
541 Returns:
542 status : bool
543 True if the check failed, False if succeeded."""
544
545
546 if context.headerfilename:
547 includetext = '#include "%s"' % context.headerfilename
548 else:
549 includetext = ''
550
551 if not includes:
552 includes = ""
553
554 lang, suffix, msg = _lang2suffix(language)
555 if msg:
556 context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
557 return msg
558
559 src = includetext + includes
560 context.Display('Checking whether %s is declared... ' % symbol)
561
562 src = src + r"""
563 int main(void)
564 {
565 #ifndef %s
566 (void) %s;
567 #endif
568 ;
569 return 0;
570 }
571 """ % (symbol, symbol)
572
573 st = context.CompileProg(src, suffix)
574 _YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
575 "Set to 1 if %s is defined." % symbol)
576 return st
577
578 -def CheckLib(context, libs, func_name = None, header = None,
579 extra_libs = None, call = None, language = None, autoadd = 1,
580 append = True):
581 """
582 Configure check for a C or C++ libraries "libs". Searches through
583 the list of libraries, until one is found where the test succeeds.
584 Tests if "func_name" or "call" exists in the library. Note: if it exists
585 in another library the test succeeds anyway!
586 Optional "header" can be defined to include a header file. If not given a
587 default prototype for "func_name" is added.
588 Optional "extra_libs" is a list of library names to be added after
589 "lib_name" in the build command. To be used for libraries that "lib_name"
590 depends on.
591 Optional "call" replaces the call to "func_name" in the test code. It must
592 consist of complete C statements, including a trailing ";".
593 Both "func_name" and "call" arguments are optional, and in that case, just
594 linking against the libs is tested.
595 "language" should be "C" or "C++" and is used to select the compiler.
596 Default is "C".
597 Note that this uses the current value of compiler and linker flags, make
598 sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
599 Returns an empty string for success, an error message for failure.
600 """
601
602 if context.headerfilename:
603 includetext = '#include "%s"' % context.headerfilename
604 else:
605 includetext = ''
606 if not header:
607 header = ""
608
609 text = """
610 %s
611 %s""" % (includetext, header)
612
613
614 if func_name and func_name != "main":
615 if not header:
616 text = text + """
617 #ifdef __cplusplus
618 extern "C"
619 #endif
620 char %s();
621 """ % func_name
622
623
624 if not call:
625 call = "%s();" % func_name
626
627
628 text = text + """
629 int
630 main() {
631 %s
632 return 0;
633 }
634 """ % (call or "")
635
636 if call:
637 i = call.find("\n")
638 if i > 0:
639 calltext = call[:i] + ".."
640 elif call[-1] == ';':
641 calltext = call[:-1]
642 else:
643 calltext = call
644
645 for lib_name in libs:
646
647 lang, suffix, msg = _lang2suffix(language)
648 if msg:
649 context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
650 return msg
651
652
653 if call:
654 context.Display("Checking for %s in %s library %s... "
655 % (calltext, lang, lib_name))
656
657 else:
658 context.Display("Checking for %s library %s... "
659 % (lang, lib_name))
660
661 if lib_name:
662 l = [ lib_name ]
663 if extra_libs:
664 l.extend(extra_libs)
665 if append:
666 oldLIBS = context.AppendLIBS(l)
667 else:
668 oldLIBS = context.PrependLIBS(l)
669 sym = "HAVE_LIB" + lib_name
670 else:
671 oldLIBS = -1
672 sym = None
673
674 ret = context.BuildProg(text, suffix)
675
676 _YesNoResult(context, ret, sym, text,
677 "Define to 1 if you have the `%s' library." % lib_name)
678 if oldLIBS != -1 and (ret or not autoadd):
679 context.SetLIBS(oldLIBS)
680
681 if not ret:
682 return ret
683
684 return ret
685
687 """
688 Configure check for a specific program.
689
690 Check whether program prog_name exists in path. If it is found,
691 returns the path for it, otherwise returns None.
692 """
693 context.Display("Checking whether %s program exists..." % prog_name)
694 path = context.env.WhereIs(prog_name)
695 if path:
696 context.Display(path + "\n")
697 else:
698 context.Display("no\n")
699 return path
700
701
702
703
704
705
707 """
708 Handle the result of a test with a "yes" or "no" result.
709
710 :Parameters:
711 - `ret` is the return value: empty if OK, error message when not.
712 - `key` is the name of the symbol to be defined (HAVE_foo).
713 - `text` is the source code of the program used for testing.
714 - `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
715 """
716 if key:
717 _Have(context, key, not ret, comment)
718 if ret:
719 context.Display("no\n")
720 _LogFailed(context, text, ret)
721 else:
722 context.Display("yes\n")
723
724
725 -def _Have(context, key, have, comment = None):
726 """
727 Store result of a test in context.havedict and context.headerfilename.
728
729 :Parameters:
730 - `key` - is a "HAVE_abc" name. It is turned into all CAPITALS and non-alphanumerics are replaced by an underscore.
731 - `have` - value as it should appear in the header file, include quotes when desired and escape special characters!
732 - `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
733
734
735 The value of "have" can be:
736 - 1 - Feature is defined, add "#define key".
737 - 0 - Feature is not defined, add "/\* #undef key \*/". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done.
738 - number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then.
739 - string - Feature is defined to this string "#define key have".
740
741
742 """
743 key_up = key.upper()
744 key_up = re.sub('[^A-Z0-9_]', '_', key_up)
745 context.havedict[key_up] = have
746 if have == 1:
747 line = "#define %s 1\n" % key_up
748 elif have == 0:
749 line = "/* #undef %s */\n" % key_up
750 elif isinstance(have, int):
751 line = "#define %s %d\n" % (key_up, have)
752 else:
753 line = "#define %s %s\n" % (key_up, str(have))
754
755 if comment is not None:
756 lines = "\n/* %s */\n" % comment + line
757 else:
758 lines = "\n" + line
759
760 if context.headerfilename:
761 f = open(context.headerfilename, "a")
762 f.write(lines)
763 f.close()
764 elif hasattr(context,'config_h'):
765 context.config_h = context.config_h + lines
766
767
769 """
770 Write to the log about a failed program.
771 Add line numbers, so that error messages can be understood.
772 """
773 if LogInputFiles:
774 context.Log("Failed program was:\n")
775 lines = text.split('\n')
776 if len(lines) and lines[-1] == '':
777 lines = lines[:-1]
778 n = 1
779 for line in lines:
780 context.Log("%d: %s\n" % (n, line))
781 n = n + 1
782 if LogErrorMessages:
783 context.Log("Error message: %s\n" % msg)
784
785
787 """
788 Convert a language name to a suffix.
789 When "lang" is empty or None C is assumed.
790 Returns a tuple (lang, suffix, None) when it works.
791 For an unrecognized language returns (None, None, msg).
792
793 Where:
794 - lang = the unified language name
795 - suffix = the suffix, including the leading dot
796 - msg = an error message
797 """
798 if not lang or lang in ["C", "c"]:
799 return ("C", ".c", None)
800 if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
801 return ("C++", ".cpp", None)
802
803 return None, None, "Unsupported language: %s" % lang
804
805
806
807
808
809
810
811
812
813