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