OSDN Git Service

* Added serf library.
[modchxj/mod_chxj.git] / src / serf / serfmake
1 #!/usr/bin/python
2
3 import os
4 import re
5 import shutil
6 import sys
7 import stat
8
9 FILES_HDR = [
10   ('.', 'serf'),
11   ('.', 'serf_bucket_types'),
12   ('.', 'serf_bucket_util'),
13   ('.', 'serf_declare'),
14   ]
15
16 LIB_FILES = [
17   ('.', 'context'),
18
19   ('buckets', 'aggregate_buckets'),
20   ('buckets', 'request_buckets'),
21   ('buckets', 'buckets'),
22   ('buckets', 'simple_buckets'),
23   ('buckets', 'file_buckets'),
24   ('buckets', 'mmap_buckets'),
25   ('buckets', 'socket_buckets'),
26   ('buckets', 'response_buckets'),
27   ('buckets', 'headers_buckets'),
28   ('buckets', 'allocator'),
29   ('buckets', 'dechunk_buckets'),
30   ('buckets', 'deflate_buckets'),
31   ('buckets', 'limit_buckets'),
32   ('buckets', 'ssl_buckets'),
33   ('buckets', 'barrier_buckets'),
34   ('buckets', 'chunk_buckets'),
35   ]
36
37 TEST_FILES = [
38   ('test', 'serf_get'),
39   ('test', 'serf_response'),
40   ('test', 'serf_request'),
41   ('test', 'serf_spider'),
42   ]
43
44 TESTCASES = [
45   ('test/testcases', 'simple.response'),
46   ('test/testcases', 'chunked-empty.response'),
47   ('test/testcases', 'chunked.response'),
48   ('test/testcases', 'chunked-trailers.response'),
49   ('test/testcases', 'deflate.response'),
50   ]
51
52
53 def main(argv):
54   params = {}
55
56   cmd = None
57
58   for i in argv[1:]:
59     idx = i.find('=')
60     if idx > 0:
61       start = i.rfind('-', 0, idx)
62       if start > 0:
63         params[i[start+1:idx]] = i[idx+1:].strip()
64     elif not cmd:
65       cmd = i
66
67   if not cmd:
68     cmd = 'build'
69  
70   func = globals().get('cmd_' + cmd)
71   if not func:
72     print 'ERROR: no such command:', cmd
73     usage()
74
75   try:
76     func(params)
77   except Exception, e:
78     print e
79     usage()
80
81
82 def usage():
83   ### print something
84   print 'serfmake [cmd] [options]'
85   print 'Commands:'
86   print '\tbuild\tBuilds (default)'
87   print '\tcheck\tRuns test cases'
88   print '\tinstall\tInstalls serf into PREFIX'
89   print '\tclean\tCleans'
90   print 'Options:'
91   print '\t--with-apr=PATH\tprefix for installed APR and APR-util'
92   print '\t\t\t(needs apr-1-config and apu-1-config; will look in PATH)'
93   print '\t--prefix=PATH\tinstall serf into PATH (default: /usr/local)'
94   print 'Quick guide:'
95   print '\tserfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install'
96   sys.exit(1)
97
98
99 def cmd_build(param):
100   builder = Builder(param)
101   builder.build_target(File('.', 'libserf-0', 'la'), False)
102
103
104 def cmd_install(param):
105   builder = Builder(param)
106   builder.install_target(File('.', 'libserf-0', 'la'), False)
107
108
109 def cmd_check(param):
110   builder = Builder(param)
111   builder.build_target(File('test', 'serf_response', None), False)
112
113   for dirpath, fname in TESTCASES:
114     case = os.path.join(dirpath, fname)
115     print '== Testing %s ==' % case
116     result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
117     if result:
118       raise TestError(case, result)
119
120
121 def cmd_clean(param):
122   clean = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
123   clean += [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
124   clean += [File('.', 'libserf-0', 'la')]
125   clean += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
126   clean += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
127   clean += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
128   for i in clean:
129     if i.mtime:
130       os.remove(i.fname)
131
132 class Builder:
133   def __init__(self, params):
134     try:
135       self.apr = APRConfig(params['apr'])
136       self.apu = APUConfig(params['apr'])
137     except:
138       self.apr = APRConfig(None)
139       self.apu = APUConfig(None)
140
141     try:
142       self.libdir = os.path.join(params['prefix'], 'lib')
143       self.includedir = os.path.join(params['prefix'], 'include', 'serf-0')
144     except:
145       self.libdir = '/usr/local/lib'
146       self.includedir = '/usr/local/include/serf-0'
147
148     self.load_vars()
149     self.load_deps()
150
151   def load_vars(self):
152     self.CC = self.apr.get_value('CC', '--cc')
153     self.CFLAGS = self.apr.get_value('CFLAGS', '--cflags')
154     self.CPPFLAGS = self.apr.get_value('CPPFLAGS', '--cppflags')
155     self.LIBTOOL = self.apr.get_value('LIBTOOL', '--apr-libtool')
156     self.LDFLAGS = self.apr.get_value('LDFLAGS', '--ldflags') \
157                    + ' ' + self.apu.get_value('LDFLAGS', '--ldflags')
158
159     self.INCLUDES = '-I%s -I%s -I%s' % (
160       '.',
161       self.apr.get_value(None, '--includedir'),
162       self.apu.get_value(None, '--includedir'),
163       )
164     if os.getenv('EXTRA_INCLUDES'):
165       self.INCLUDES += ' -I' + os.getenv('EXTRA_INCLUDES')
166
167     self.LIBS = self.apu.get_value(None, '--link-libtool') \
168                 + ' ' + self.apu.get_value(None, '--libs') \
169                 + ' ' + self.apr.get_value(None, '--link-libtool') \
170                 + ' ' + self.apr.get_value(None, '--libs') \
171                 + ' -lz -lssl -lcrypto'
172
173     self.MODE = 644
174
175   def load_deps(self):
176     self.deps = { }
177
178     hdrs = [File(dirpath, fname, 'h') for dirpath, fname in FILES_HDR]
179     libfiles = [File(dirpath, fname, 'c') for dirpath, fname in LIB_FILES]
180     libobjs = [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
181     for src, obj in zip(libfiles, libobjs):
182       self._add_compile(src, obj, hdrs)
183
184     self.hdrs = hdrs
185
186     lib = File('.', 'libserf-0', 'la')
187     cmd = '%s --silent --mode=link %s %s -rpath %s -o %s %s %s' % (
188       self.LIBTOOL, self.CC, self.LDFLAGS, self.libdir,
189       lib.fname, ' '.join([l.fname for l in libobjs]), self.LIBS)
190     self._add_dep(lib, libobjs, cmd)
191
192     # load the test program dependencies now
193     for dirpath, fname in TEST_FILES:
194       src = File(dirpath, fname, 'c')
195       obj = File(dirpath, fname, 'lo')
196       prog = File(dirpath, fname, None)
197
198       self._add_compile(src, obj, hdrs)
199
200       cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
201         self.LIBTOOL, self.CC, self.LDFLAGS,
202         prog.fname, lib.fname, obj.fname, self.LIBS)
203       self._add_dep(prog, [lib, obj], cmd)
204
205   def _add_compile(self, src, obj, hdrs):
206     cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
207       self.LIBTOOL, self.CC, self.CFLAGS, self.CPPFLAGS, self.INCLUDES,
208       obj.fname, src.fname)
209     self._add_dep(obj, [src] + hdrs, cmd)
210
211   def _add_dep(self, target, deps, cmd):
212     if target.mtime:
213       for dep in deps:
214         if self.deps.has_key(dep) \
215                or (dep.mtime and dep.mtime > target.mtime):
216           # a dep is newer. this needs to be rebuilt.
217           break
218       else:
219         # this is up to date. don't add it to the deps[] structure.
220         return
221     # else non-existent, so it must be rebuilt.
222
223     # register the dependency so this will get built
224     self.deps[target] = deps, cmd
225
226   def build_target(self, target, dry_run):
227     dep = self.deps.get(target)
228     if not dep:
229       # it's already up to date. all done.
230       return
231
232     for f in dep[0]:
233       subdep = self.deps.get(f)
234       if subdep:
235         self.build_target(f, dry_run)
236
237     # build the target now
238     print dep[1]
239     if not dry_run:
240       result = os.system(dep[1])
241       if result:
242         raise BuildError(dep[1], result)
243       # FALLTHROUGH
244
245     # it's a dry run. pretend we built the target.
246     del self.deps[target]
247     return 0
248
249   def install_target(self, target, dry_run):
250     self.build_target(target, dry_run)
251
252     # install the target now
253     if not dry_run:
254
255       try:
256         os.makedirs(self.includedir)
257         os.makedirs(self.libdir)
258       except:
259         pass
260
261       for f in self.hdrs:
262         shutil.copy(f.fname, self.includedir)
263
264       cmd = '%s --silent --mode=install %s -c -m %d %s %s' % (
265             self.LIBTOOL, '/usr/bin/install', self.MODE, target.fname,
266             self.libdir)
267
268       result = os.system(cmd)
269       if result:
270         raise BuildError(cmd, result)
271       # FALLTHROUGH
272
273     return 0
274
275
276 class ConfigScript(object):
277   script_name = None
278   locations = [
279     '/usr/bin',
280     '/usr/local/bin',
281     '/usr/local/apache2/bin',
282     ]
283
284   def __init__(self, search_dir):
285     if search_dir:
286       self.locations.append(search_dir)
287       self.locations.append(os.path.join(search_dir, 'bin'))
288     for dirname in self.locations:
289       bin = os.path.join(dirname, self.script_name)
290       if os.access(bin, os.X_OK):
291         self.bin = bin
292         break
293     else:
294       raise ConfigScriptNotFound(self.script_name)
295
296   def get_value(self, env_name, switch):
297     if env_name and os.getenv(env_name):
298       return os.getenv(env_name)
299     return os.popen('%s %s' % (self.bin, switch), 'r').read().strip()
300
301
302 class APRConfig(ConfigScript):
303   script_name = 'apr-1-config'
304
305
306 class APUConfig(ConfigScript):
307   script_name = 'apu-1-config'
308
309
310 class File:
311   def __init__(self, dirpath, fname, ext):
312     if ext:
313       self.fname = os.path.join(dirpath, fname + '.' + ext)
314     else:
315       self.fname = os.path.join(dirpath, fname)
316
317     try:
318       s = os.stat(self.fname)
319     except OSError:
320       self.mtime = None
321     else:
322       self.mtime = s[stat.ST_MTIME]
323
324   def __cmp__(self, other):
325     return cmp(self.fname, other.fname)
326
327   def __hash__(self):
328     return hash(self.fname)
329
330
331 class BuildError(Exception):
332   "An error occurred while building a target."
333 class TestError(Exception):
334   "An error occurred while running a unit test."
335 class ConfigScriptNotFound(Exception):
336   def __init__(self, value):
337     self.value = "ERROR: A configuration script was not found: " + value
338   def __str__(self):
339     return self.value
340
341
342 if __name__ == '__main__':
343   main(sys.argv)