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