blob: ac1d9226abf221335cbbde6610328be802479320 [file] [log] [blame]
#!/usr/bin/env python
import os
import re
import shutil
import sys
import stat
FILES_HDR = [
('.', 'serf'),
('.', 'serf_bucket_types'),
('.', 'serf_bucket_util'),
('.', 'serf_declare'),
]
LIB_FILES = [
('.', 'context'),
('.', 'incoming'),
('.', 'outgoing'),
('buckets', 'aggregate_buckets'),
('buckets', 'request_buckets'),
('buckets', 'buckets'),
('buckets', 'simple_buckets'),
('buckets', 'file_buckets'),
('buckets', 'mmap_buckets'),
('buckets', 'socket_buckets'),
('buckets', 'response_buckets'),
('buckets', 'headers_buckets'),
('buckets', 'allocator'),
('buckets', 'dechunk_buckets'),
('buckets', 'deflate_buckets'),
('buckets', 'limit_buckets'),
('buckets', 'ssl_buckets'),
('buckets', 'barrier_buckets'),
('buckets', 'chunk_buckets'),
('auth', 'auth'),
('auth', 'auth_basic'),
('auth', 'auth_digest'),
('auth', 'auth_kerb'),
('auth', 'auth_kerb_gss'),
]
TEST_DEPS = [
('test', 'CuTest'),
('test', 'test_util'),
('test', 'test_context'),
('test', 'test_buckets'),
('test', 'test_ssl'),
]
TEST_HDR_FILES = [
('test', 'CuTest'),
('test', 'test_serf'),
]
TEST_FILES = [
('test', 'serf_get'),
('test', 'serf_response'),
('test', 'serf_request'),
('test', 'serf_spider'),
('test', 'test_all'),
]
TESTCASES = [
('test/testcases', 'simple.response'),
('test/testcases', 'chunked-empty.response'),
('test/testcases', 'chunked.response'),
('test/testcases', 'chunked-trailers.response'),
('test/testcases', 'deflate.response'),
]
def main(argv):
params = {}
commands = []
for arg in argv[1:]:
idx = arg.find('=')
if idx > 0:
start = arg.rfind('-', 0, idx)
if start > 0:
params[arg[start+1:idx]] = arg[idx+1:].strip()
else:
func = globals().get('cmd_' + arg)
if func:
commands.append(func)
else:
print('ERROR: unknown argument: ' + arg)
usage()
if not commands:
usage()
for func in commands:
try:
func(params)
except:
print('ERROR: exception:')
print(sys.exc_info()[1])
print("")
usage()
def usage():
### print something
print('serfmake [cmd] [options]')
print('Commands:')
print('\tbuild\tBuilds (default)')
print('\tcheck\tRuns test cases')
print('\tinstall\tInstalls serf into PREFIX')
print('\tclean\tCleans')
print('Options:')
print('\t--with-apr=PATH\tprefix for installed APR and APR-util')
print('\t\t\t(needs apr-1-config and apu-1-config; will look in PATH)')
print('\t--prefix=PATH\tinstall serf into PATH (default: /usr/local)')
print('Quick guide:')
print('\tserfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install')
sys.exit(1)
def cmd_build(param):
builder = Builder(param)
builder.build_target(File('.', 'libserf-0', 'la'), False)
def cmd_install(param):
builder = Builder(param)
builder.install_target(File('.', 'libserf-0', 'la'), False)
def cmd_check(param):
builder = Builder(param)
for dirpath, fname in TEST_FILES:
builder.build_target(File(dirpath, fname, None), False)
for dirpath, fname in TESTCASES:
case = os.path.join(dirpath, fname)
print('== Testing %s ==' % case)
result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
if result:
raise TestError("", result)
# run the test suite based on the CuTest framework
result = os.system(os.path.join('test', 'test_all'))
if result:
raise TestError(case, result)
def cmd_clean(param):
targets = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
targets += [File('.', 'libserf-0', 'la')]
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_DEPS]
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
clean = [file for file in targets if file.mtime]
if clean:
sys.stdout.write('Cleaning %d files... ' % len(clean))
for i in clean:
if i.mtime:
os.remove(i.fname)
print('done.')
else:
print('Clean.')
class Builder:
def __init__(self, params):
if 'apr' in params:
self.apr = APRConfig(params['apr'])
self.apu = APUConfig(params['apr'])
else:
self.apr = APRConfig(None)
self.apu = APUConfig(None)
try:
self.libdir = os.path.join(params['prefix'], 'lib')
self.includedir = os.path.join(params['prefix'], 'include', 'serf-0')
except:
self.libdir = '/usr/local/lib'
self.includedir = '/usr/local/include/serf-0'
self.load_vars()
self.load_deps()
def load_vars(self):
self.CC = self.apr.get_value('CC', '--cc')
self.CFLAGS = self.apr.get_value('CFLAGS', '--cflags')
self.CPPFLAGS = self.apr.get_value('CPPFLAGS', '--cppflags')
self.LIBTOOL = self.apr.get_value('LIBTOOL', '--apr-libtool')
self.LDFLAGS = self.apr.get_value('LDFLAGS', '--ldflags') \
+ ' ' + self.apu.get_value('LDFLAGS', '--ldflags')
self.INCLUDES = '-I%s -I%s -I%s' % (
'.',
self.apr.get_value(None, '--includedir'),
self.apu.get_value(None, '--includedir'),
)
if os.getenv('EXTRA_INCLUDES'):
self.INCLUDES += ' -I' + os.getenv('EXTRA_INCLUDES')
self.LIBS = self.apu.get_value(None, '--link-libtool') \
+ ' ' + self.apu.get_value(None, '--libs') \
+ ' ' + self.apr.get_value(None, '--link-libtool') \
+ ' ' + self.apr.get_value(None, '--libs') \
+ ' -lz -lssl -lcrypto'
self.MODE = 644
def load_deps(self):
self.deps = { }
hdrs = [File(dirpath, fname, 'h') for dirpath, fname in FILES_HDR]
libfiles = [File(dirpath, fname, 'c') for dirpath, fname in LIB_FILES]
libobjs = [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
for src, obj in zip(libfiles, libobjs):
self._add_compile(src, obj, hdrs)
self.hdrs = hdrs
lib = File('.', 'libserf-0', 'la')
cmd = '%s --silent --mode=link %s %s -rpath %s -o %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS, self.libdir,
lib.fname, ' '.join([l.fname for l in libobjs]), self.LIBS)
self._add_dep(lib, libobjs, cmd)
# load the test program dependencies now
testhdrs = hdrs
testhdrs += [File(dirpath, fname, 'h') for dirpath, fname in TEST_HDR_FILES]
testdeps = [File(dirpath, fname, 'c') for dirpath, fname in TEST_DEPS]
testobjs = [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
for testsrc, testobj in zip(testdeps, testobjs):
self._add_compile(testsrc, testobj, testhdrs)
for dirpath, fname in TEST_FILES:
src = File(dirpath, fname, 'c')
obj = File(dirpath, fname, 'lo')
prog = File(dirpath, fname, None)
self._add_compile(src, obj, hdrs)
# test_all requires extra dependencies
if fname == "test_all":
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS,
prog.fname, lib.fname, ' '.join([l.fname for l in [obj] + testobjs]),
self.LIBS)
self._add_dep(prog, [lib, obj] + testobjs, cmd)
else:
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
self.LIBTOOL, self.CC, self.LDFLAGS,
prog.fname, lib.fname, obj.fname, self.LIBS)
self._add_dep(prog, [lib, obj], cmd)
def _add_compile(self, src, obj, hdrs):
cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
self.LIBTOOL, self.CC, self.CFLAGS, self.CPPFLAGS, self.INCLUDES,
obj.fname, src.fname)
self._add_dep(obj, [src] + hdrs, cmd)
def _add_dep(self, target, deps, cmd):
if target.mtime:
for dep in deps:
if dep in self.deps or (dep.mtime and dep.mtime > target.mtime):
# a dep is newer. this needs to be rebuilt.
break
else:
# this is up to date. don't add it to the deps[] structure.
return
# else non-existent, so it must be rebuilt.
# register the dependency so this will get built
self.deps[target] = deps, cmd
def build_target(self, target, dry_run):
dep = self.deps.get(target)
if not dep:
# it's already up to date. all done.
return
for f in dep[0]:
subdep = self.deps.get(f)
if subdep:
self.build_target(f, dry_run)
# build the target now
print(dep[1])
if not dry_run:
result = os.system(dep[1])
if result:
raise BuildError(dep[1], result)
# FALLTHROUGH
# it's a dry run. pretend we built the target.
del self.deps[target]
return 0
def install_target(self, target, dry_run):
self.build_target(target, dry_run)
# install the target now
if not dry_run:
try:
os.makedirs(self.includedir)
os.makedirs(self.libdir)
except:
pass
for f in self.hdrs:
shutil.copy(f.fname, self.includedir)
cmd = '%s --silent --mode=install %s -c -m %d %s %s' % (
self.LIBTOOL, '/usr/bin/install', self.MODE, target.fname,
self.libdir)
result = os.system(cmd)
if result:
raise BuildError(cmd, result)
# FALLTHROUGH
return 0
class ConfigScript(object):
script_name = None
locations = [
'/usr/bin',
'/usr/local/bin',
'/usr/local/apache2/bin',
]
def __init__(self, search_dir):
if search_dir:
locations = [search_dir, os.path.join(search_dir, 'bin')]
else:
locations = self.locations
for dirname in locations:
bin = os.path.join(dirname, self.script_name)
if os.access(bin, os.X_OK):
self.bin = bin
break
else:
raise ConfigScriptNotFound(self.script_name)
def get_value(self, env_name, switch):
if env_name and os.getenv(env_name):
return os.getenv(env_name)
return os.popen('%s %s' % (self.bin, switch), 'r').read().strip()
class APRConfig(ConfigScript):
script_name = 'apr-1-config'
class APUConfig(ConfigScript):
script_name = 'apu-1-config'
class File:
def __init__(self, dirpath, fname, ext):
if ext:
self.fname = os.path.join(dirpath, fname + '.' + ext)
else:
self.fname = os.path.join(dirpath, fname)
try:
s = os.stat(self.fname)
except OSError:
self.mtime = None
else:
self.mtime = s[stat.ST_MTIME]
def __eq__(self, other):
return self.fname == other.fname
def __hash__(self):
return hash(self.fname)
class BuildError(Exception):
"An error occurred while building a target."
class TestError(Exception):
"An error occurred while running a unit test."
class ConfigScriptNotFound(Exception):
def __init__(self, value):
self.value = "ERROR: A configuration script was not found: " + value
def __str__(self):
return self.value
if __name__ == '__main__':
main(sys.argv)
###
### TODO:
### * obey DESTDIR
### * arfrever says LDFLAGS is passed twice
### * be able to specify libdir and includedir
###