10
### use get_version() ?
13
# Basic defines for our outputs.
14
LIBNAME = 'libserf-%d' % (MAJOR,)
15
INCLUDES = 'serf-%d' % (MAJOR,)
16
PCFILE = 'serf-%d' % (MAJOR,)
21
('.', 'serf_bucket_types'),
22
('.', 'serf_bucket_util'),
31
('buckets', 'aggregate_buckets'),
32
('buckets', 'request_buckets'),
33
('buckets', 'buckets'),
34
('buckets', 'simple_buckets'),
35
('buckets', 'file_buckets'),
36
('buckets', 'mmap_buckets'),
37
('buckets', 'socket_buckets'),
38
('buckets', 'response_buckets'),
39
('buckets', 'headers_buckets'),
40
('buckets', 'allocator'),
41
('buckets', 'dechunk_buckets'),
42
('buckets', 'deflate_buckets'),
43
('buckets', 'limit_buckets'),
44
('buckets', 'ssl_buckets'),
45
('buckets', 'barrier_buckets'),
46
('buckets', 'chunk_buckets'),
47
('buckets', 'iovec_buckets'),
49
('auth', 'auth_basic'),
50
('auth', 'auth_digest'),
51
('auth', 'auth_kerb'),
52
('auth', 'auth_kerb_gss'),
57
('test', 'test_util'),
58
('test', 'test_context'),
59
('test', 'test_buckets'),
61
('test/server', 'test_server'),
66
('test', 'test_serf'),
71
('test', 'serf_response'),
72
('test', 'serf_request'),
73
('test', 'serf_spider'),
78
('test/testcases', 'simple.response'),
79
('test/testcases', 'chunked-empty.response'),
80
('test/testcases', 'chunked.response'),
81
('test/testcases', 'chunked-trailers.response'),
82
('test/testcases', 'deflate.response'),
94
start = arg.rfind('-', 0, idx)
96
params[arg[start+1:idx]] = arg[idx+1:].strip()
98
func = globals().get('cmd_' + arg)
100
commands.append(func)
102
print('ERROR: unknown argument: ' + arg)
108
for func in commands:
112
print('ERROR: exception:')
113
print(sys.exc_info()[1])
120
print('serfmake [cmd] [options]')
122
print('\tbuild\tBuilds (default)')
123
print('\tcheck\tRuns test cases')
124
print('\tinstall\tInstalls serf into PREFIX')
125
print('\tclean\tCleans')
127
print('\t--with-apr=PATH\tprefix for installed APR and APR-util')
128
print('\t\t\t(needs apr-1-config and apu-1-config; will look in PATH)')
129
print('\t--prefix=PATH\tinstall serf into PATH (default: /usr/local)')
130
print('Quick guide:')
131
print('\tserfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install')
135
def cmd_build(param):
136
builder = Builder(param)
137
builder.build_target(File('.', LIBNAME, 'la'), False)
138
builder.build_target(File('.', PCFILE, 'pc'), False)
141
def cmd_install(param):
142
builder = Builder(param)
143
### should be called .install_all()
144
builder.install_target(File('.', LIBNAME, 'la'), False)
147
def cmd_check(param):
148
builder = Builder(param)
149
for dirpath, fname in TEST_FILES:
150
builder.build_target(File(dirpath, fname, None), False)
152
for dirpath, fname in TESTCASES:
153
case = os.path.join(dirpath, fname)
154
print('== Testing %s ==' % case)
155
result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
157
raise TestError("", result)
159
# run the test suite based on the CuTest framework
160
result = os.system(os.path.join('test', 'test_all'))
162
raise TestError(case, result)
164
def cmd_clean(param):
165
targets = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
166
targets += [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
167
targets += [File('.', LIBNAME, 'la'),
168
File('.', PCFILE, 'pc'),
170
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
171
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
172
targets += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
173
targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_DEPS]
174
targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
176
clean = [file for file in targets if file.mtime]
178
sys.stdout.write('Cleaning %d files... ' % len(clean))
187
class Builder(object):
188
def __init__(self, params):
190
self.apr = APRConfig(params['apr'])
191
self.apu = APUConfig(params['apr'])
193
self.apr = APRConfig(None)
194
self.apu = APUConfig(None)
197
self.prefix = params['prefix']
199
self.prefix = '/usr/local'
201
### no way to tweak these
202
self.libdir = os.path.join(self.prefix, 'lib')
203
self.pkgconfigdir = os.path.join(self.prefix, 'lib', 'pkgconfig')
204
self.includedir = os.path.join(self.prefix, 'include', INCLUDES)
210
self.CC = self.apr.get_value('CC', '--cc')
211
self.CFLAGS = self.apr.get_value('CFLAGS', '--cflags')
212
self.CPPFLAGS = self.apr.get_value('CPPFLAGS', '--cppflags')
213
self.LIBTOOL = self.apr.get_value('LIBTOOL', '--apr-libtool')
214
self.LDFLAGS = self.apr.get_value('LDFLAGS', '--ldflags') \
215
+ ' ' + self.apu.get_value('LDFLAGS', '--ldflags')
217
self.INCLUDES = '-I%s -I%s -I%s' % (
219
self.apr.get_value(None, '--includedir'),
220
self.apu.get_value(None, '--includedir'),
222
if os.getenv('EXTRA_INCLUDES'):
223
self.INCLUDES += ' -I' + os.getenv('EXTRA_INCLUDES')
225
self.LIBS = self.apu.get_value(None, '--link-libtool') \
226
+ ' ' + self.apu.get_value(None, '--libs') \
227
+ ' ' + self.apr.get_value(None, '--link-libtool') \
228
+ ' ' + self.apr.get_value(None, '--libs') \
230
self.SSL_LIBS = '-lssl -lcrypto'
237
hdrs = [File(dirpath, fname, 'h') for dirpath, fname in FILES_HDR]
238
libfiles = [File(dirpath, fname, 'c') for dirpath, fname in LIB_FILES]
239
libobjs = [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
240
for src, obj in zip(libfiles, libobjs):
241
self._add_compile(src, obj, hdrs)
245
all_libs = self.LIBS + ' ' + self.SSL_LIBS
247
lib = File('.', LIBNAME, 'la')
248
cmd = '%s --silent --mode=link %s %s -rpath %s -o %s %s %s' % (
249
self.LIBTOOL, self.CC, self.LDFLAGS, self.libdir,
250
lib.fname, ' '.join([l.fname for l in libobjs]), all_libs)
251
self._add_dep(lib, libobjs, cmd)
253
# load the test program dependencies now
254
testhdrs = copy.deepcopy(hdrs)
255
testhdrs += [File(dirpath, fname, 'h') for dirpath, fname in TEST_HDR_FILES]
256
testdeps = [File(dirpath, fname, 'c') for dirpath, fname in TEST_DEPS]
257
testobjs = [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
259
for testsrc, testobj in zip(testdeps, testobjs):
260
self._add_compile(testsrc, testobj, testhdrs)
262
for dirpath, fname in TEST_FILES:
263
src = File(dirpath, fname, 'c')
264
obj = File(dirpath, fname, 'lo')
265
prog = File(dirpath, fname, None)
267
self._add_compile(src, obj, hdrs)
269
# test_all requires extra dependencies
270
if fname == "test_all":
271
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
272
self.LIBTOOL, self.CC, self.LDFLAGS,
273
prog.fname, lib.fname, ' '.join([l.fname for l in [obj] + testobjs]),
275
self._add_dep(prog, [lib, obj] + testobjs, cmd)
277
cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
278
self.LIBTOOL, self.CC, self.LDFLAGS,
279
prog.fname, lib.fname, obj.fname, all_libs)
280
self._add_dep(prog, [lib, obj], cmd)
282
# create 'serf-1.pc' if it doesn't exist.
283
pcfile = File('.', PCFILE, 'pc')
284
self._add_dep(pcfile, [], self._write_pcfile)
286
def _add_compile(self, src, obj, hdrs):
287
cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
288
self.LIBTOOL, self.CC, self.CFLAGS, self.CPPFLAGS, self.INCLUDES,
289
obj.fname, src.fname)
290
self._add_dep(obj, [src] + hdrs, cmd)
292
def _add_dep(self, target, deps, cmd):
295
if dep in self.deps or (dep.mtime and dep.mtime > target.mtime):
296
# a dep is newer. this needs to be rebuilt.
299
# this is up to date. don't add it to the deps[] structure.
301
# else non-existent, so it must be rebuilt.
303
# Commands that are strings are cmdline invocations. Otherwise, it
304
# should be a callable.
305
if isinstance(cmd, str):
306
cmd = CommandLine(cmd)
308
# register the dependency so this will get built
309
self.deps[target] = deps, cmd
311
def _write_pcfile(self):
312
"""Generating serf-1.pc ..."""
314
open(PCFILE + '.pc', 'w').write(
315
"""SERF_MAJOR_VERSION=%d
317
exec_prefix=${prefix}
318
libdir=${exec_prefix}/lib
319
includedir=${prefix}/include/%s
322
Description: HTTP client library
324
Requires.private: libssl libcrypto
325
Libs: -L${libdir} -lserf-${SERF_MAJOR_VERSION}
327
Cflags: -I${includedir}
328
""" % (MAJOR, self.prefix, INCLUDES, get_version(), self.LIBS))
330
def build_target(self, target, dry_run):
331
deps, cmd = self.deps.get(target, (None, None))
333
# it's already up to date. all done.
337
subdep = self.deps.get(f)
339
self.build_target(f, dry_run)
341
# build the target now
346
raise BuildError(cmd.__doc__, result)
349
# it's a dry run. pretend we built the target.
350
del self.deps[target]
353
def install_target(self, target, dry_run):
354
self.build_target(target, dry_run)
356
# install the target now
359
for path in (self.libdir, self.pkgconfigdir, self.includedir):
360
if not os.path.exists(path):
364
raise BuildError('os.makedirs',
365
'can not create install directories')
368
print("Installing: %s" % (os.path.basename(f.fname),))
369
shutil.copy(f.fname, self.includedir)
371
print("Installing: %s.pc" % (PCFILE,))
372
shutil.copy(PCFILE + '.pc', self.pkgconfigdir)
374
cmd = '%s --silent --mode=install %s -c -m %d %s %s' % (
375
self.LIBTOOL, '/usr/bin/install', self.MODE, target.fname,
378
print("Installing: %s" % (os.path.basename(target.fname),))
379
result = os.system(cmd)
381
raise BuildError(cmd, result)
387
class ConfigScript(object):
392
'/usr/local/apache2/bin',
395
def __init__(self, search_dir):
397
locations = [search_dir, os.path.join(search_dir, 'bin')]
399
locations = self.locations
401
for dirname in locations:
402
bin = os.path.join(dirname, self.script_name)
403
if os.access(bin, os.X_OK):
407
raise ConfigScriptNotFound(self.script_name)
409
def get_value(self, env_name, switch):
410
if env_name and os.getenv(env_name):
411
return os.getenv(env_name)
412
return os.popen('%s %s' % (self.bin, switch), 'r').read().strip()
415
class APRConfig(ConfigScript):
416
script_name = 'apr-1-config'
419
class APUConfig(ConfigScript):
420
script_name = 'apu-1-config'
423
class CommandLine(object):
424
"""Simple helper to invoke a system command when called."""
426
def __init__(self, cmd):
428
self.__doc__ = cmd # when we print the execution of this command
431
return os.system(self.cmd)
435
def __init__(self, dirpath, fname, ext):
437
self.fname = os.path.join(dirpath, fname + '.' + ext)
439
self.fname = os.path.join(dirpath, fname)
442
s = os.stat(self.fname)
446
self.mtime = s[stat.ST_MTIME]
448
def __eq__(self, other):
449
return self.fname == other.fname
452
return hash(self.fname)
456
match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
457
'SERF_MINOR_VERSION ([0-9]+).*'
458
'SERF_PATCH_VERSION ([0-9]+)',
459
open('serf.h').read(),
461
major, minor, patch = match.groups()
462
return '%s.%s.%s' % (major, minor, patch)
465
class BuildError(Exception):
466
"An error occurred while building a target."
467
class TestError(Exception):
468
"An error occurred while running a unit test."
469
class ConfigScriptNotFound(Exception):
470
def __init__(self, value):
471
self.value = "ERROR: A configuration script was not found: " + value
476
if __name__ == '__main__':
483
### * arfrever says LDFLAGS is passed twice
484
### * be able to specify libdir and includedir