1import os
2import sys
3import re
4import string
5from stat import *
6
7package = 'lighttpd'
8version = '1.4.39'
9
10def checkCHeaders(autoconf, hdrs):
11	p = re.compile('[^A-Z0-9]')
12	for hdr in hdrs:
13		if not hdr:
14			continue
15		_hdr = Split(hdr)
16		if autoconf.CheckCHeader(_hdr):
17			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', _hdr[-1].upper()) ])
18
19def checkFuncs(autoconf, funcs):
20	p = re.compile('[^A-Z0-9]')
21	for func in funcs:
22		if autoconf.CheckFunc(func):
23			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', func.upper()) ])
24
25def checkTypes(autoconf, types):
26	p = re.compile('[^A-Z0-9]')
27	for type in types:
28		if autoconf.CheckType(type, '#include <sys/types.h>'):
29			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', type.upper()) ])
30
31def checkGmtOffInStructTm(context):
32	source = """
33#include <time.h>
34int main() {
35	struct tm a;
36	a.tm_gmtoff = 0;
37	return 0;
38}
39"""
40	context.Message('Checking for tm_gmtoff in struct tm...')
41	result = context.TryLink(source, '.c')
42	context.Result(result)
43
44	return result
45
46def checkIPv6(context):
47	source = """
48#include <sys/types.h>
49#include <sys/socket.h>
50#include <netinet/in.h>
51
52int main() {
53	struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0;
54	return 0;
55}
56"""
57	context.Message('Checking for IPv6 support...')
58	result = context.TryLink(source, '.c')
59	context.Result(result)
60
61	return result
62
63def checkWeakSymbols(context):
64	source = """
65__attribute__((weak)) void __dummy(void *x) { }
66int main() {
67	void *x;
68	__dummy(x);
69}
70"""
71	context.Message('Checking for weak symbol support...')
72	result = context.TryLink(source, '.c')
73	context.Result(result)
74
75	return result
76
77def checkProgram(env, withname, progname):
78	withname = 'with_' + withname
79	binpath = None
80
81	if env[withname] != 1:
82		binpath = env[withname]
83	else:
84		prog = env.Detect(progname)
85		if prog:
86			binpath = env.WhereIs(prog)
87
88	if binpath:
89		mode = os.stat(binpath)[ST_MODE]
90		if S_ISDIR(mode):
91			print >> sys.stderr, "* error: path `%s' is a directory" % (binpath)
92			env.Exit(-1)
93		if not S_ISREG(mode):
94			print >> sys.stderr, "* error: path `%s' is not a file or not exists" % (binpath)
95			env.Exit(-1)
96
97	if not binpath:
98		print >> sys.stderr, "* error: can't find program `%s'" % (progname)
99		env.Exit(-1)
100
101	return binpath
102
103VariantDir('sconsbuild/build', 'src', duplicate = 0)
104VariantDir('sconsbuild/tests', 'tests', duplicate = 0)
105
106vars = Variables() #('config.py')
107vars.AddVariables(
108	('prefix', 'prefix', '/usr/local'),
109	('bindir', 'binary directory', '${prefix}/bin'),
110	('sbindir', 'binary directory', '${prefix}/sbin'),
111	('libdir', 'library directory', '${prefix}/lib'),
112	PackageVariable('with_mysql', 'enable mysql support', 'no'),
113	PackageVariable('with_xml', 'enable xml support', 'no'),
114	PackageVariable('with_pcre', 'enable pcre support', 'yes'),
115	PathVariable('CC', 'path to the c-compiler', None),
116	BoolVariable('build_dynamic', 'enable dynamic build', 'yes'),
117	BoolVariable('build_static', 'enable static build', 'no'),
118	BoolVariable('build_fullstatic', 'enable fullstatic build', 'no'),
119	BoolVariable('with_sqlite3', 'enable sqlite3 support', 'no'),
120	BoolVariable('with_memcache', 'enable memcache support', 'no'),
121	BoolVariable('with_fam', 'enable FAM/gamin support', 'no'),
122	BoolVariable('with_openssl', 'enable memcache support', 'no'),
123	BoolVariable('with_gzip', 'enable gzip compression', 'no'),
124	BoolVariable('with_bzip2', 'enable bzip2 compression', 'no'),
125	BoolVariable('with_lua', 'enable lua support for mod_cml', 'no'),
126	BoolVariable('with_ldap', 'enable ldap auth support', 'no'))
127
128env = Environment(
129	ENV = os.environ,
130	variables = vars,
131	CPPPATH = Split('#sconsbuild/build')
132)
133
134env.Help(vars.GenerateHelpText(env))
135
136if env.subst('${CC}') is not '':
137	env['CC'] = env.subst('${CC}')
138
139env['package'] = package
140env['version'] = version
141if env['CC'] == 'gcc':
142	## we need x-open 6 and bsd 4.3 features
143	env.Append(CCFLAGS = Split('-Wall -O2 -g -W -pedantic -Wunused -Wshadow -std=gnu99'))
144
145# cache configure checks
146if 1:
147	autoconf = Configure(env, custom_tests = {
148		'CheckGmtOffInStructTm': checkGmtOffInStructTm,
149		'CheckIPv6': checkIPv6,
150		'CheckWeakSymbols': checkWeakSymbols,
151	})
152
153	if 'CFLAGS' in os.environ:
154		autoconf.env.Append(CCFLAGS = os.environ['CFLAGS'])
155		print(">> Appending custom build flags : " + os.environ['CFLAGS'])
156
157	if 'LDFLAGS' in os.environ:
158		autoconf.env.Append(LINKFLAGS = os.environ['LDFLAGS'])
159		print(">> Appending custom link flags : " + os.environ['LDFLAGS'])
160
161	if 'LIBS' in os.environ:
162		autoconf.env.Append(APPEND_LIBS = os.environ['LIBS'])
163		print(">> Appending custom libraries : " + os.environ['LIBS'])
164	else:
165		autoconf.env.Append(APPEND_LIBS = '')
166
167	autoconf.headerfile = "foo.h"
168	checkCHeaders(autoconf, string.split("""
169			arpa/inet.h
170			crypt.h
171			fcntl.h
172			getopt.h
173			inttypes.h
174			netinet/in.h
175			poll.h
176			pwd.h
177			stdint.h
178			stdlib.h
179			string.h
180			sys/devpoll.h
181			sys/epoll.h
182			sys/event.h
183			sys/filio.h
184			sys/mman.h
185			sys/poll.h
186			sys/port.h
187			sys/prctl.h
188			sys/resource.h
189			sys/select.h
190			sys/sendfile.h
191			sys/socket.h
192			sys/time.h
193			sys/time.h sys/types.h sys/resource.h
194			sys/types.h netinet/in.h
195			sys/types.h sys/event.h
196			sys/types.h sys/mman.h
197			sys/types.h sys/select.h
198			sys/types.h sys/socket.h
199			sys/types.h sys/uio.h
200			sys/types.h sys/un.h
201			sys/uio.h
202			sys/un.h
203			sys/wait.h
204			syslog.h
205			unistd.h
206			winsock2.h""", "\n"))
207
208	checkFuncs(autoconf, Split('fork stat lstat strftime dup2 getcwd inet_ntoa inet_ntop memset mmap munmap strchr \
209			strdup strerror strstr strtol sendfile getopt socket \
210			gethostbyname poll epoll_ctl getrlimit chroot \
211			getuid select signal pathconf madvise prctl\
212			writev sigaction sendfile64 send_file kqueue port_create localtime_r posix_fadvise issetugid inet_pton \
213			memset_s explicit_bzero'))
214
215	checkTypes(autoconf, Split('pid_t size_t off_t'))
216
217	autoconf.env.Append( LIBSQLITE3 = '', LIBXML2 = '', LIBMYSQL = '', LIBZ = '',
218		LIBBZ2 = '', LIBCRYPT = '', LIBMEMCACHE = '', LIBFCGI = '', LIBPCRE = '',
219		LIBLDAP = '', LIBLBER = '', LIBLUA = '', LIBDL = '', LIBUUID = '')
220
221	if env['with_fam']:
222		if autoconf.CheckLibWithHeader('fam', 'fam.h', 'C'):
223			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_FAM_H', '-DHAVE_LIBFAM' ], LIBS = 'fam')
224			checkFuncs(autoconf, ['FAMNoExists']);
225
226	if autoconf.CheckLib('crypt'):
227		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LIBCRYPT' ], LIBCRYPT = 'crypt')
228		oldlib = env['LIBS']
229		env['LIBS'] += ['crypt']
230		checkFuncs(autoconf, ['crypt', 'crypt_r']);
231		env['LIBS'] = oldlib
232	else:
233		checkFuncs(autoconf, ['crypt', 'crypt_r']);
234
235	if autoconf.CheckLibWithHeader('uuid', 'uuid/uuid.h', 'C'):
236		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_UUID_UUID_H', '-DHAVE_LIBUUID' ], LIBUUID = 'uuid')
237
238	if env['with_openssl']:
239		if autoconf.CheckLibWithHeader('ssl', 'openssl/ssl.h', 'C'):
240			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_OPENSSL_SSL_H', '-DHAVE_LIBSSL'] , LIBS = [ 'ssl', 'crypto' ])
241
242	if env['with_gzip']:
243		if autoconf.CheckLibWithHeader('z', 'zlib.h', 'C'):
244			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_ZLIB_H', '-DHAVE_LIBZ' ], LIBZ = 'z')
245
246	if env['with_ldap']:
247		if autoconf.CheckLibWithHeader('ldap', 'ldap.h', 'C'):
248			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LDAP_H', '-DHAVE_LIBLDAP' ], LIBLDAP = 'ldap')
249		if autoconf.CheckLibWithHeader('lber', 'lber.h', 'C'):
250			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LBER_H', '-DHAVE_LIBLBER' ], LIBLBER = 'lber')
251
252	if env['with_bzip2']:
253		if autoconf.CheckLibWithHeader('bz2', 'bzlib.h', 'C'):
254			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_BZLIB_H', '-DHAVE_LIBBZ2' ], LIBBZ2 = 'bz2')
255
256	if env['with_memcache']:
257		if autoconf.CheckLibWithHeader('memcache', 'memcache.h', 'C'):
258			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_MEMCACHE_H', '-DHAVE_LIBMEMCACHE' ], LIBMEMCACHE = 'memcache')
259
260	if env['with_sqlite3']:
261		if autoconf.CheckLibWithHeader('sqlite3', 'sqlite3.h', 'C'):
262			autoconf.env.Append(CPPFLAGS = [ '-DHAVE_SQLITE3_H', '-DHAVE_LIBSQLITE3' ], LIBSQLITE3 = 'sqlite3')
263
264	ol = env['LIBS']
265	if autoconf.CheckLibWithHeader('fcgi', 'fastcgi.h', 'C'):
266		autoconf.env.Append(LIBFCGI = 'fcgi')
267	env['LIBS'] = ol
268
269	ol = env['LIBS']
270	if autoconf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
271		autoconf.env.Append(LIBDL = 'dl')
272	env['LIBS'] = ol
273
274	if autoconf.CheckType('socklen_t', '#include <unistd.h>\n#include <sys/socket.h>\n#include <sys/types.h>'):
275		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_SOCKLEN_T' ])
276
277	if autoconf.CheckType('struct sockaddr_storage', '#include <sys/socket.h>\n'):
278		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_SOCKADDR_STORAGE' ])
279
280	if autoconf.CheckGmtOffInStructTm():
281		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_TM_GMTOFF' ])
282
283	if autoconf.CheckIPv6():
284		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_IPV6' ])
285
286	if autoconf.CheckWeakSymbols():
287		autoconf.env.Append(CPPFLAGS = [ '-DHAVE_WEAK_SYMBOLS' ])
288
289	env = autoconf.Finish()
290
291def TryLua(env, name):
292	result = False
293	oldlibs = env['LIBS']
294	try:
295		print("Searching for lua: " + name + " >= 5.0")
296		env.ParseConfig("pkg-config '" + name + " >= 5.0' --cflags --libs")
297		env.Append(LIBLUA = env['LIBS'][len(oldlibs):])
298		env.Append(CPPFLAGS = [ '-DHAVE_LUA_H' ])
299		result = True
300	except:
301		pass
302	env['LIBS'] = oldlibs
303	return result
304
305if env['with_lua']:
306	found_lua = False
307	for lua_name in ['lua5.1', 'lua5.0', 'lua']:
308		if TryLua(env, lua_name):
309			found_lua = True
310			break
311	if not found_lua:
312		raise RuntimeError("Couldn't find any lua implementation")
313
314if env['with_pcre']:
315	pcre_config = checkProgram(env, 'pcre', 'pcre-config')
316	env.ParseConfig(pcre_config + ' --cflags --libs')
317	env.Append(CPPFLAGS = [ '-DHAVE_PCRE_H', '-DHAVE_LIBPCRE' ], LIBPCRE = 'pcre')
318
319if env['with_xml']:
320	xml2_config = checkProgram(env, 'xml', 'xml2-config')
321	oldlib = env['LIBS']
322	env['LIBS'] = []
323	env.ParseConfig(xml2_config + ' --cflags --libs')
324	env.Append(CPPFLAGS = [ '-DHAVE_LIBXML_H', '-DHAVE_LIBXML2' ], LIBXML2 = env['LIBS'])
325	env['LIBS'] = oldlib
326
327if env['with_mysql']:
328	mysql_config = checkProgram(env, 'mysql', 'mysql_config')
329	oldlib = env['LIBS']
330	env['LIBS'] = []
331	env.ParseConfig(mysql_config + ' --cflags --libs')
332	env.Append(CPPFLAGS = [ '-DHAVE_MYSQL_H', '-DHAVE_LIBMYSQL' ], LIBMYSQL = 'mysqlclient')
333	env['LIBS'] = oldlib
334
335if re.compile("cygwin|mingw").search(env['PLATFORM']):
336	env.Append(COMMON_LIB = 'bin')
337elif re.compile("darwin|aix").search(env['PLATFORM']):
338	env.Append(COMMON_LIB = 'lib')
339else:
340	env.Append(COMMON_LIB = False)
341
342versions = string.split(version, '.')
343version_id = int(versions[0]) << 16 | int(versions[1]) << 8 | int(versions[2])
344env.Append(CPPFLAGS = [
345		'-DLIGHTTPD_VERSION_ID=' + hex(version_id),
346		'-DPACKAGE_NAME=\\"' + package + '\\"',
347		'-DPACKAGE_VERSION=\\"' + version + '\\"',
348		'-DLIBRARY_DIR="\\"${libdir}\\""',
349		'-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE_SOURCE', '-D_LARGE_FILES'
350		] )
351
352SConscript('src/SConscript', exports = 'env', variant_dir = 'sconsbuild/build', duplicate = 0)
353SConscript('tests/SConscript', exports = 'env', variant_dir = 'sconsbuild/tests')
354