[build] fix link of test_configfile.c
[lighttpd.git] / SConstruct
blobdfb2e4964dc0720bec0accce3c0a5de2c9780ed6
1 import os
2 import re
3 import string
4 import sys
5 from copy import copy
6 from stat import *
8 package = 'lighttpd'
9 version = '1.4.48'
11 underscorify_reg = re.compile('[^A-Z0-9]')
12 def underscorify(id):
13 return underscorify_reg.sub('_', id.upper())
15 def fail(*args, **kwargs):
16 print(*args, file=sys.stderr, **kwargs)
17 env.Exit(-1)
19 class Autoconf:
20 class RestoreEnvLibs:
21 def __init__(self, env):
22 self.env = env
23 self.active = False
25 def __enter__(self):
26 if self.active:
27 raise Exception('entered twice')
28 self.active = True
29 if 'LIBS' in self.env:
30 #print("Backup LIBS: " + repr(self.env['LIBS']))
31 self.empty = False
32 self.backup_libs = copy(self.env['LIBS'])
33 else:
34 #print("No LIBS to backup")
35 self.empty = True
37 def __exit__(self, type, value, traceback):
38 if not self.active:
39 raise Exception('exited twice')
40 self.active = False
41 if self.empty:
42 if 'LIBS' in self.env:
43 del self.env['LIBS']
44 else:
45 #print("Restoring LIBS, now: " + repr(self.env['LIBS']))
46 self.env['LIBS'] = self.backup_libs
47 #print("Restoring LIBS, to: " + repr(self.env['LIBS']))
49 def __init__(self, env):
50 self.conf = Configure(env, custom_tests = {
51 'CheckGmtOffInStructTm': Autoconf.__checkGmtOffInStructTm,
52 'CheckIPv6': Autoconf.__checkIPv6,
53 'CheckWeakSymbols': Autoconf.__checkWeakSymbols,
56 def append(self, *args, **kw):
57 return self.conf.env.Append(*args, **kw)
59 def Finish(self):
60 return self.conf.Finish()
62 @property
63 def env(self):
64 return self.conf.env
66 def restoreEnvLibs(self):
67 return Autoconf.RestoreEnvLibs(self.conf.env)
69 def CheckType(self, *args, **kw):
70 return self.conf.CheckType(*args, **kw)
72 def CheckLib(self, *args, **kw):
73 return self.conf.CheckLib(*args, autoadd = 0, **kw)
75 def CheckLibWithHeader(self, *args, **kw):
76 return self.conf.CheckLibWithHeader(*args, autoadd = 0, **kw)
78 def CheckGmtOffInStructTm(self):
79 return self.conf.CheckGmtOffInStructTm()
81 def CheckIPv6(self):
82 return self.conf.CheckIPv6()
84 def CheckWeakSymbols(self):
85 return self.conf.CheckWeakSymbols()
87 def CheckCHeader(self, hdr):
88 return self.conf.CheckCHeader(hdr)
90 def haveCHeader(self, hdr):
91 if self.CheckCHeader(hdr):
92 # if we have a list of headers define HAVE_ only for last one
93 target = hdr
94 if not isinstance(target, basestring):
95 target = target[-1]
96 self.conf.env.Append(CPPFLAGS = [ '-DHAVE_' + underscorify(target) ])
97 return True
98 return False
100 def haveCHeaders(self, hdrs):
101 for hdr in hdrs:
102 self.haveCHeader(hdr)
104 def CheckFunc(self, func, header = None, libs = []):
105 with self.restoreEnvLibs():
106 self.env.Append(LIBS = libs)
107 return self.conf.CheckFunc(func, header = header)
109 def CheckFuncInLib(self, func, lib):
110 return self.CheckFunc(func, libs = [lib])
112 def haveFuncInLib(self, func, lib):
113 if self.CheckFuncInLib(func, lib):
114 self.conf.env.Append(CPPFLAGS = [ '-DHAVE_' + underscorify(func) ])
115 return True
116 return False
118 def haveFunc(self, func, header = None, libs = []):
119 if self.CheckFunc(func, header = header, libs = libs):
120 self.conf.env.Append(CPPFLAGS = [ '-DHAVE_' + underscorify(func) ])
121 return True
122 return False
124 def haveFuncs(self, funcs):
125 for func in funcs:
126 self.haveFunc(func)
128 def haveTypes(self, types):
129 for type in types:
130 if self.conf.CheckType(type, '#include <sys/types.h>'):
131 self.conf.env.Append(CPPFLAGS = [ '-DHAVE_' + underscorify(type) ])
133 def CheckParseConfig(self, *args, **kw):
134 try:
135 self.conf.env.ParseConfig(*args, **kw)
136 return True
137 except Exception as e:
138 print(e.message, file=sys.stderr)
139 return False
141 def CheckParseConfigForLib(self, lib, *args, **kw):
142 with self.restoreEnvLibs():
143 self.env['LIBS'] = []
144 if not self.CheckParseConfig(*args, **kw):
145 return False
146 self.env.Append(**{lib: self.env['LIBS']})
147 return True
149 @staticmethod
150 def __checkGmtOffInStructTm(context):
151 source = """
152 #include <time.h>
153 int main() {
154 struct tm a;
155 a.tm_gmtoff = 0;
156 return 0;
159 context.Message('Checking for tm_gmtoff in struct tm...')
160 result = context.TryLink(source, '.c')
161 context.Result(result)
163 return result
165 @staticmethod
166 def __checkIPv6(context):
167 source = """
168 #include <sys/types.h>
169 #include <sys/socket.h>
170 #include <netinet/in.h>
172 int main() {
173 struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0;
174 return 0;
177 context.Message('Checking for IPv6 support...')
178 result = context.TryLink(source, '.c')
179 context.Result(result)
181 return result
183 @staticmethod
184 def __checkWeakSymbols(context):
185 source = """
186 __attribute__((weak)) void __dummy(void *x) { }
187 int main() {
188 void *x;
189 __dummy(x);
192 context.Message('Checking for weak symbol support...')
193 result = context.TryLink(source, '.c')
194 context.Result(result)
196 return result
198 def checkProgram(self, withname, progname):
199 withname = 'with_' + withname
200 binpath = None
202 if self.env[withname] != 1:
203 binpath = self.env[withname]
204 else:
205 prog = self.env.Detect(progname)
206 if prog:
207 binpath = self.env.WhereIs(prog)
209 if binpath:
210 mode = os.stat(binpath)[ST_MODE]
211 if S_ISDIR(mode):
212 fail("* error: path `%s' is a directory" % (binpath))
213 if not S_ISREG(mode):
214 fail("* error: path `%s' is not a file or not exists" % (binpath))
216 if not binpath:
217 fail("* error: can't find program `%s'" % (progname))
219 return binpath
221 VariantDir('sconsbuild/build', 'src', duplicate = 0)
222 VariantDir('sconsbuild/tests', 'tests', duplicate = 0)
224 vars = Variables()
225 vars.AddVariables(
226 ('prefix', 'prefix', '/usr/local'),
227 ('bindir', 'binary directory', '${prefix}/bin'),
228 ('sbindir', 'binary directory', '${prefix}/sbin'),
229 ('libdir', 'library directory', '${prefix}/lib'),
230 PathVariable('CC', 'path to the c-compiler', None),
231 BoolVariable('build_dynamic', 'enable dynamic build', 'yes'),
232 BoolVariable('build_static', 'enable static build', 'no'),
233 BoolVariable('build_fullstatic', 'enable fullstatic build', 'no'),
235 BoolVariable('with_bzip2', 'enable bzip2 compression', 'no'),
236 PackageVariable('with_dbi', 'enable dbi support', 'no'),
237 BoolVariable('with_fam', 'enable FAM/gamin support', 'no'),
238 BoolVariable('with_gdbm', 'enable gdbm support', 'no'),
239 BoolVariable('with_geoip', 'enable GeoIP support', 'no'),
240 BoolVariable('with_krb5', 'enable krb5 auth support', 'no'),
241 BoolVariable('with_ldap', 'enable ldap auth support', 'no'),
242 # with_libev not supported
243 # with_libunwind not supported
244 BoolVariable('with_lua', 'enable lua support for mod_cml', 'no'),
245 BoolVariable('with_memcached', 'enable memcached support', 'no'),
246 PackageVariable('with_mysql', 'enable mysql support', 'no'),
247 BoolVariable('with_openssl', 'enable openssl support', 'no'),
248 PackageVariable('with_pcre', 'enable pcre support', 'yes'),
249 PackageVariable('with_pgsql', 'enable pgsql support', 'no'),
250 BoolVariable('with_sqlite3', 'enable sqlite3 support (required for webdav props)', 'no'),
251 BoolVariable('with_uuid', 'enable uuid support (required for webdav locks)', 'no'),
252 # with_valgrind not supported
253 # with_xattr not supported
254 PackageVariable('with_xml', 'enable xml support (required for webdav props)', 'no'),
255 BoolVariable('with_zlib', 'enable deflate/gzip compression', 'no'),
257 BoolVariable('with_all', 'enable all with_* features', 'no'),
260 env = Environment(
261 ENV = os.environ,
262 variables = vars,
263 CPPPATH = Split('#sconsbuild/build')
266 env.Help(vars.GenerateHelpText(env))
268 if env.subst('${CC}') is not '':
269 env['CC'] = env.subst('${CC}')
271 env['package'] = package
272 env['version'] = version
273 if env['CC'] == 'gcc':
274 ## we need x-open 6 and bsd 4.3 features
275 env.Append(CCFLAGS = Split('-Wall -O2 -g -W -pedantic -Wunused -Wshadow -std=gnu99'))
277 env.Append(CPPFLAGS = [
278 '-D_FILE_OFFSET_BITS=64',
279 '-D_LARGEFILE_SOURCE',
280 '-D_LARGE_FILES',
281 '-D_GNU_SOURCE',
284 if env['with_all']:
285 for feature in vars.keys():
286 # only enable 'with_*' flags
287 if not feature.startswith('with_'): continue
288 # don't overwrite manual arguments
289 if feature in vars.args: continue
290 # now activate
291 env[feature] = True
293 # cache configure checks
294 if 1:
295 autoconf = Autoconf(env)
297 if 'CFLAGS' in os.environ:
298 autoconf.env.Append(CCFLAGS = os.environ['CFLAGS'])
299 print(">> Appending custom build flags : " + os.environ['CFLAGS'])
301 if 'LDFLAGS' in os.environ:
302 autoconf.env.Append(LINKFLAGS = os.environ['LDFLAGS'])
303 print(">> Appending custom link flags : " + os.environ['LDFLAGS'])
305 if 'LIBS' in os.environ:
306 autoconf.env.Append(APPEND_LIBS = os.environ['LIBS'])
307 print(">> Appending custom libraries : " + os.environ['LIBS'])
308 else:
309 autoconf.env.Append(APPEND_LIBS = '')
311 autoconf.env.Append(
312 LIBBZ2 = '',
313 LIBCRYPT = '',
314 LIBCRYPTO = '',
315 LIBDBI = '',
316 LIBDL = '',
317 LIBFCGI = '',
318 LIBGDBM = '',
319 LIBGSSAPI_KRB5 = '',
320 LIBKRB5 = '',
321 LIBLBER = '',
322 LIBLDAP = '',
323 LIBLUA = '',
324 LIBMEMCACHED = '',
325 LIBMYSQL = '',
326 LIBPCRE = '',
327 LIBPGSQL = '',
328 LIBSQLITE3 = '',
329 LIBSSL = '',
330 LIBUUID = '',
331 LIBXML2 = '',
332 LIBZ = '',
335 autoconf.haveCHeaders([
336 'arpa/inet.h',
337 'crypt.h',
338 'fcntl.h',
339 'getopt.h',
340 'inttypes.h',
341 'linux/random.h',
342 'netinet/in.h',
343 'poll.h',
344 'pwd.h',
345 'stdint.h',
346 'stdlib.h',
347 'string.h',
348 'strings.h',
349 'sys/devpoll.h',
350 'sys/epoll.h',
351 'sys/event.h',
352 'sys/filio.h',
353 'sys/mman.h',
354 'sys/poll.h',
355 'sys/port.h',
356 'sys/prctl.h',
357 'sys/resource.h',
358 'sys/select.h',
359 'sys/sendfile.h',
360 'sys/socket.h',
361 'sys/time.h',
362 'sys/uio.h',
363 'sys/un.h',
364 'sys/wait.h',
365 'syslog.h',
366 'unistd.h',
367 'winsock2.h',
369 # "have" the last header if we include others before?
370 ['sys/time.h', 'sys/types.h', 'sys/resource.h'],
371 ['sys/types.h', 'netinet/in.h'],
372 ['sys/types.h', 'sys/event.h'],
373 ['sys/types.h', 'sys/mman.h'],
374 ['sys/types.h', 'sys/select.h'],
375 ['sys/types.h', 'sys/socket.h'],
376 ['sys/types.h', 'sys/uio.h'],
377 ['sys/types.h', 'sys/un.h'],
380 autoconf.haveFuncs([
381 'arc4random_buf',
382 'chroot',
383 'clock_gettime',
384 'dup2',
385 'epoll_ctl',
386 'explicit_bzero',
387 'fork',
388 'getcwd',
389 'gethostbyname',
390 'getloadavg',
391 'getopt',
392 'getrlimit',
393 'getuid',
394 'inet_ntoa',
395 'inet_ntop',
396 'inet_pton',
397 'issetugid',
398 'jrand48',
399 'kqueue',
400 'localtime_r',
401 'lstat',
402 'madvise',
403 'memset_s',
404 'memset',
405 'mmap',
406 'munmap',
407 'pathconf',
408 'pipe2',
409 'poll',
410 'port_create',
411 'posix_fadvise',
412 'prctl',
413 'select',
414 'send_file',
415 'sendfile',
416 'sendfile64',
417 'sigaction',
418 'signal',
419 'socket',
420 'srandom',
421 'stat',
422 'strchr',
423 'strdup',
424 'strerror',
425 'strftime',
426 'strstr',
427 'strtol',
428 'writev',
430 autoconf.haveFunc('getentropy', 'sys/random.h')
431 autoconf.haveFunc('getrandom', 'linux/random.h')
433 autoconf.haveTypes(Split('pid_t size_t off_t'))
435 # have crypt_r/crypt, and is -lcrypt needed?
436 if autoconf.CheckLib('crypt'):
437 autoconf.env.Append(
438 CPPFLAGS = [ '-DHAVE_LIBCRYPT' ],
439 LIBCRYPT = 'crypt',
441 with autoconf.restoreEnvLibs():
442 autoconf.env['LIBS'] = ['crypt']
443 autoconf.haveFuncs(['crypt', 'crypt_r'])
444 else:
445 autoconf.haveFuncs(['crypt', 'crypt_r'])
447 if autoconf.CheckType('socklen_t', '#include <unistd.h>\n#include <sys/socket.h>\n#include <sys/types.h>'):
448 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_SOCKLEN_T' ])
450 if autoconf.CheckType('struct sockaddr_storage', '#include <sys/socket.h>\n'):
451 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_SOCKADDR_STORAGE' ])
453 if autoconf.CheckLibWithHeader('rt', 'time.h', 'c', 'clock_gettime(CLOCK_MONOTONIC, (struct timespec*)0);'):
454 autoconf.env.Append(
455 CPPFLAGS = [ '-DHAVE_CLOCK_GETTIME' ],
456 LIBS = [ 'rt' ],
459 if autoconf.CheckIPv6():
460 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_IPV6' ])
462 if autoconf.CheckWeakSymbols():
463 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_WEAK_SYMBOLS' ])
465 if autoconf.CheckGmtOffInStructTm():
466 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_TM_GMTOFF' ])
468 if autoconf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
469 autoconf.env.Append(LIBDL = 'dl')
471 # used in tests if present
472 if autoconf.CheckLibWithHeader('fcgi', 'fastcgi.h', 'C'):
473 autoconf.env.Append(LIBFCGI = 'fcgi')
475 if env['with_bzip2']:
476 if not autoconf.CheckLibWithHeader('bz2', 'bzlib.h', 'C'):
477 fail("Couldn't find bz2")
478 autoconf.env.Append(
479 CPPFLAGS = [ '-DHAVE_BZLIB_H', '-DHAVE_LIBBZ2' ],
480 LIBBZ2 = 'bz2',
483 if env['with_dbi']:
484 if not autoconf.CheckLibWithHeader('dbi', 'dbi/dbi.h', 'C'):
485 fail("Couldn't find dbi")
486 autoconf.env.Append(
487 CPPFLAGS = [ '-DHAVE_DBI_H', '-DHAVE_LIBDBI' ],
488 LIBDBI = 'dbi',
491 if env['with_fam']:
492 if not autoconf.CheckLibWithHeader('fam', 'fam.h', 'C'):
493 fail("Couldn't find fam")
494 autoconf.env.Append(
495 CPPFLAGS = [ '-DHAVE_FAM_H', '-DHAVE_LIBFAM' ],
496 LIBS = [ 'fam' ],
498 autoconf.haveFunc('FAMNoExists')
500 if env['with_gdbm']:
501 if not autoconf.CheckLibWithHeader('gdbm', 'gdbm.h', 'C'):
502 fail("Couldn't find gdbm")
503 autoconf.env.Append(
504 CPPFLAGS = [ '-DHAVE_GDBM_H', '-DHAVE_GDBM' ],
505 LIBGDBM = 'gdbm',
508 if env['with_geoip']:
509 if not autoconf.CheckLibWithHeader('GeoIP', 'GeoIP.h', 'C'):
510 fail("Couldn't find geoip")
511 autoconf.env.Append(
512 CPPFLAGS = [ '-DHAVE_GEOIP' ],
513 LIBGEOIP = 'GeoIP',
516 if env['with_krb5']:
517 if not autoconf.CheckLibWithHeader('krb5', 'krb5.h', 'C'):
518 fail("Couldn't find krb5")
519 if not autoconf.CheckLibWithHeader('gssapi_krb5', 'gssapi/gssapi_krb5.h', 'C'):
520 fail("Couldn't find gssapi_krb5")
521 autoconf.env.Append(
522 CPPFLAGS = [ '-DHAVE_KRB5' ],
523 LIBKRB5 = 'krb5',
524 LIBGSSAPI_KRB5 = 'gssapi_krb5',
527 if env['with_ldap']:
528 if not autoconf.CheckLibWithHeader('ldap', 'ldap.h', 'C'):
529 fail("Couldn't find ldap")
530 if not autoconf.CheckLibWithHeader('lber', 'lber.h', 'C'):
531 fail("Couldn't find lber")
532 autoconf.env.Append(
533 CPPFLAGS = [
534 '-DLDAP_DEPRECATED=1',
535 '-DHAVE_LDAP_H', '-DHAVE_LIBLDAP',
536 '-DHAVE_LBER_H', '-DHAVE_LIBLBER',
538 LIBLDAP = 'ldap',
539 LIBLBER = 'lber',
542 if env['with_lua']:
543 found_lua = False
544 for lua_name in ['lua5.3', 'lua-5.3', 'lua5.2', 'lua-5.2', 'lua5.1', 'lua-5.1', 'lua']:
545 print("Searching for lua: " + lua_name + " >= 5.0")
546 if autoconf.CheckParseConfigForLib('LIBLUA', "pkg-config '" + lua_name + " >= 5.0' --cflags --libs"):
547 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LUA_H' ])
548 found_lua = True
549 break
550 if not found_lua:
551 fail("Couldn't find any lua implementation")
553 if env['with_memcached']:
554 if not autoconf.CheckLibWithHeader('memcached', 'libmemcached/memcached.h', 'C'):
555 fail("Couldn't find memcached")
556 autoconf.env.Append(
557 CPPFLAGS = [ '-DUSE_MEMCACHED' ],
558 LIBMEMCACHED = 'memcached',
561 if env['with_mysql']:
562 mysql_config = autoconf.checkProgram('mysql', 'mysql_config')
563 if not autoconf.CheckParseConfigForLib('LIBMYSQL', mysql_config + ' --cflags --libs'):
564 fail("Couldn't find mysql")
565 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_MYSQL_H', '-DHAVE_LIBMYSQL' ])
567 if env['with_openssl']:
568 if not autoconf.CheckLibWithHeader('ssl', 'openssl/ssl.h', 'C'):
569 fail("Couldn't find openssl")
570 autoconf.env.Append(
571 CPPFLAGS = [ '-DHAVE_OPENSSL_SSL_H', '-DHAVE_LIBSSL'],
572 LIBSSL = 'ssl',
573 LIBCRYPTO = 'crypto',
576 if env['with_pcre']:
577 pcre_config = autoconf.checkProgram('pcre', 'pcre-config')
578 if not autoconf.CheckParseConfigForLib('LIBPCRE', pcre_config + ' --cflags --libs'):
579 fail("Couldn't find pcre")
580 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_PCRE_H', '-DHAVE_LIBPCRE' ])
582 if env['with_pgsql']:
583 if not autoconf.CheckParseConfigForLib('LIBPGSQL', 'pkg-config libpq --cflags --libs'):
584 fail("Couldn't find libpq")
585 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_PGSQL_H', '-DHAVE_LIBPGSQL' ])
587 if env['with_sqlite3']:
588 if not autoconf.CheckLibWithHeader('sqlite3', 'sqlite3.h', 'C'):
589 fail("Couldn't find sqlite3")
590 autoconf.env.Append(
591 CPPFLAGS = [ '-DHAVE_SQLITE3_H', '-DHAVE_LIBSQLITE3' ],
592 LIBSQLITE3 = 'sqlite3',
595 if env['with_uuid']:
596 if not autoconf.CheckLibWithHeader('uuid', 'uuid/uuid.h', 'C'):
597 fail("Couldn't find uuid")
598 autoconf.env.Append(
599 CPPFLAGS = [ '-DHAVE_UUID_UUID_H', '-DHAVE_LIBUUID' ],
600 LIBUUID = 'uuid',
603 if env['with_xml']:
604 xml2_config = autoconf.checkProgram('xml', 'xml2-config')
605 if not autoconf.CheckParseConfigForLib('LIBXML2', xml2_config + ' --cflags --libs'):
606 fail("Couldn't find xml2")
607 autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LIBXML_H', '-DHAVE_LIBXML2' ])
609 if env['with_zlib']:
610 if not autoconf.CheckLibWithHeader('z', 'zlib.h', 'C'):
611 fail("Couldn't find zlib")
612 autoconf.env.Append(
613 CPPFLAGS = [ '-DHAVE_ZLIB_H', '-DHAVE_LIBZ' ],
614 LIBZ = 'z',
617 env = autoconf.Finish()
619 if re.compile("cygwin|mingw|midipix").search(env['PLATFORM']):
620 env.Append(COMMON_LIB = 'bin')
621 elif re.compile("darwin|aix").search(env['PLATFORM']):
622 env.Append(COMMON_LIB = 'lib')
623 else:
624 env.Append(COMMON_LIB = False)
626 versions = string.split(version, '.')
627 version_id = int(versions[0]) << 16 | int(versions[1]) << 8 | int(versions[2])
628 env.Append(CPPFLAGS = [
629 '-DLIGHTTPD_VERSION_ID=' + hex(version_id),
630 '-DPACKAGE_NAME=\\"' + package + '\\"',
631 '-DPACKAGE_VERSION=\\"' + version + '\\"',
632 '-DLIBRARY_DIR="\\"${libdir}\\""',
635 SConscript('src/SConscript', exports = 'env', variant_dir = 'sconsbuild/build', duplicate = 0)
636 SConscript('tests/SConscript', exports = 'env', variant_dir = 'sconsbuild/tests')