]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/serf/SConstruct
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / contrib / serf / SConstruct
1 # -*- python -*-
2 #
3 # Copyright 2011-2012 Justin Erenkrantz and Greg Stein
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import sys
19 import os
20 import re
21
22 HEADER_FILES = ['serf.h',
23                 'serf_bucket_types.h',
24                 'serf_bucket_util.h',
25                 ]
26
27 # where we save the configuration variables
28 SAVED_CONFIG = '.saved_config'
29
30 # Variable class that does no validation on the input
31 def _converter(val):
32     """
33     """
34     if val == 'none':
35       val = []
36     else:
37       val = val.split(',')
38     return val
39
40 def RawListVariable(key, help, default):
41     """
42     The input parameters describe a 'raw string list' option. This class
43     accepts a comma separated list and converts it to a space separated
44     list.
45     """
46     return (key, '%s' % (help), default, None, lambda val: _converter(val))
47
48 # default directories
49 if sys.platform == 'win32':
50   default_libdir='..'
51   default_prefix='Debug'
52 else:
53   default_libdir='/usr'
54   default_prefix='/usr/local'
55
56 opts = Variables(files=[SAVED_CONFIG])
57 opts.AddVariables(
58   PathVariable('PREFIX',
59                'Directory to install under',
60                default_prefix,
61                PathVariable.PathIsDir),
62   PathVariable('APR',
63                "Path to apr-1-config, or to APR's install area",
64                default_libdir,
65                PathVariable.PathAccept),
66   PathVariable('APU',
67                "Path to apu-1-config, or to APR's install area",
68                default_libdir,
69                PathVariable.PathAccept),
70   PathVariable('OPENSSL',
71                "Path to OpenSSL's install area",
72                default_libdir,
73                PathVariable.PathIsDir),
74   PathVariable('ZLIB',
75                "Path to zlib's install area",
76                default_libdir,
77                PathVariable.PathIsDir),
78   PathVariable('GSSAPI',
79                "Path to GSSAPI's install area",
80                None,
81                None),
82   BoolVariable('DEBUG',
83                "Enable debugging info and strict compile warnings",
84                False),
85   BoolVariable('APR_STATIC',
86                "Enable using a static compiled APR",
87                False),
88   RawListVariable('CC', "Command name or path of the C compiler", None),
89   RawListVariable('CFLAGS', "Extra flags for the C compiler (comma separated)",
90                   None),
91   RawListVariable('LIBS', "Extra libraries passed to the linker, "
92                   "e.g. -l<library> (comma separated)", None),
93   RawListVariable('LINKFLAGS', "Extra flags for the linker (comma separated)",
94                   None),
95   RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor "
96                   "(comma separated)", None), 
97   )
98
99 if sys.platform == 'win32':
100   opts.AddVariables(
101     # By default SCons builds for the host platform on Windows, when using
102     # a supported compiler (E.g. VS2010/VS2012). Allow overriding
103
104     # Note that Scons 1.3 only supports this on Windows and only when
105     # constructing Environment(). Later changes to TARGET_ARCH are ignored
106     EnumVariable('TARGET_ARCH',
107                  "Platform to build for (x86|x64|win32|x86_64)",
108                  'x86',
109                  allowed_values=('x86', 'x86_64', 'ia64'),
110                  map={'X86'  : 'x86',
111                       'win32': 'x86',
112                       'Win32': 'x86',
113                       'x64'  : 'x86_64',
114                       'X64'  : 'x86_64'
115                      }),
116
117     EnumVariable('MSVC_VERSION',
118                  "Visual C++ to use for building (E.g. 11.0, 9.0)",
119                  None,
120                  allowed_values=('12.0', '11.0', '10.0', '9.0', '8.0', '6.0')
121                 ),
122
123     # We always documented that we handle an install layout, but in fact we
124     # hardcoded source layouts. Allow disabling this behavior.
125     # ### Fix default?
126     BoolVariable('SOURCE_LAYOUT',
127                  "Assume a source layout instead of install layout",
128                  True),
129     )
130
131 env = Environment(variables=opts,
132                   tools=('default', 'textfile',),
133                   CPPPATH=['.', ],
134                   )
135
136 env.Append(BUILDERS = {
137     'GenDef' : 
138       Builder(action = sys.executable + ' build/gen_def.py $SOURCES > $TARGET',
139               suffix='.def', src_suffix='.h')
140   })
141
142 match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
143                   'SERF_MINOR_VERSION ([0-9]+).*'
144                   'SERF_PATCH_VERSION ([0-9]+)',
145                   env.File('serf.h').get_contents(),
146                   re.DOTALL)
147 MAJOR, MINOR, PATCH = [int(x) for x in match.groups()]
148 env.Append(MAJOR=str(MAJOR))
149
150 # Calling external programs is okay if we're not cleaning or printing help.
151 # (cleaning: no sense in fetching information; help: we may not know where
152 # they are)
153 CALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help'))
154
155
156 # HANDLING OF OPTION VARIABLES
157
158 unknown = opts.UnknownVariables()
159 if unknown:
160   print 'Unknown variables:', ', '.join(unknown.keys())
161   Exit(1)
162
163 apr = str(env['APR'])
164 apu = str(env['APU'])
165 zlib = str(env['ZLIB'])
166 gssapi = env.get('GSSAPI', None)
167
168 if gssapi and os.path.isdir(gssapi):
169   krb5_config = os.path.join(gssapi, 'bin', 'krb5-config')
170   if os.path.isfile(krb5_config):
171     gssapi = krb5_config
172     env['GSSAPI'] = krb5_config
173
174 debug = env.get('DEBUG', None)
175 aprstatic = env.get('APR_STATIC', None)
176
177 Help(opts.GenerateHelpText(env))
178 opts.Save(SAVED_CONFIG, env)
179
180
181 # PLATFORM-SPECIFIC BUILD TWEAKS
182
183 thisdir = os.getcwd()
184 libdir = '$PREFIX/lib'
185 incdir = '$PREFIX/include/serf-$MAJOR'
186
187 LIBNAME = 'libserf-${MAJOR}'
188 if sys.platform != 'win32':
189   LIBNAMESTATIC = LIBNAME
190 else:
191   LIBNAMESTATIC = 'serf-${MAJOR}'
192
193 env.Append(RPATH=libdir,
194            PDB='${TARGET.filebase}.pdb')
195
196 if sys.platform == 'darwin':
197 #  linkflags.append('-Wl,-install_name,@executable_path/%s.dylib' % (LIBNAME,))
198   env.Append(LINKFLAGS='-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,))
199   # 'man ld' says positive non-zero for the first number, so we add one.
200   # Mac's interpretation of compatibility is the same as our MINOR version.
201   env.Append(LINKFLAGS='-Wl,-compatibility_version,%d' % (MINOR+1,))
202   env.Append(LINKFLAGS='-Wl,-current_version,%d.%d' % (MINOR+1, PATCH,))
203
204 if sys.platform != 'win32':
205   ### gcc only. figure out appropriate test / better way to check these
206   ### flags, and check for gcc.
207   env.Append(CFLAGS='-std=c89')
208   env.Append(CCFLAGS=[
209                '-Wdeclaration-after-statement',
210                '-Wmissing-prototypes',
211              ])
212
213   ### -Wall is not available on Solaris
214   if sys.platform != 'sunos5': 
215     env.Append(CCFLAGS='-Wall')
216
217   if debug:
218     env.Append(CCFLAGS='-g')
219     env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
220   else:
221     env.Append(CCFLAGS='-O2')
222     env.Append(CPPDEFINES='NDEBUG')
223
224   ### works for Mac OS. probably needs to change
225   env.Append(LIBS=['ssl', 'crypto', 'z', ])
226
227   if sys.platform == 'sunos5':
228     env.Append(LIBS='m')
229 else:
230   # Warning level 4, no unused argument warnings
231   env.Append(CCFLAGS=['/W4', '/wd4100'])
232
233   # Choose runtime and optimization
234   if debug:
235     # Disable optimizations for debugging, use debug DLL runtime
236     env.Append(CCFLAGS=['/Od', '/MDd'])
237     env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
238   else:
239     # Optimize for speed, use DLL runtime
240     env.Append(CCFLAGS=['/O2', '/MD'])
241     env.Append(CPPDEFINES='NDEBUG')
242
243 # PLAN THE BUILD
244 SHARED_SOURCES = []
245 if sys.platform == 'win32':
246   env.GenDef(['serf.h','serf_bucket_types.h', 'serf_bucket_util.h'])
247   SHARED_SOURCES.append(['serf.def'])
248
249 SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
250
251 lib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES)
252 lib_shared = env.SharedLibrary(LIBNAME, SOURCES + SHARED_SOURCES)
253
254 if aprstatic:
255   env.Append(CPPDEFINES=['APR_DECLARE_STATIC', 'APU_DECLARE_STATIC'])
256
257 if sys.platform == 'win32':
258   env.Append(LIBS=['user32.lib', 'advapi32.lib', 'gdi32.lib', 'ws2_32.lib',
259                    'crypt32.lib', 'mswsock.lib', 'rpcrt4.lib', 'secur32.lib'])
260
261   # Get apr/apu information into our build
262   env.Append(CPPDEFINES=['WIN32','WIN32_LEAN_AND_MEAN','NOUSER',
263                          'NOGDI', 'NONLS','NOCRYPT'])
264
265   if env.get('TARGET_ARCH', None) == 'x86_64':
266     env.Append(CPPDEFINES=['WIN64'])
267
268   if aprstatic:
269     apr_libs='apr-1.lib'
270     apu_libs='aprutil-1.lib'
271   else:
272     apr_libs='libapr-1.lib'
273     apu_libs='libaprutil-1.lib'
274
275   env.Append(LIBS=[apr_libs, apu_libs])
276   if not env.get('SOURCE_LAYOUT', None):
277     env.Append(LIBPATH=['$APR/lib', '$APU/lib'],
278                CPPPATH=['$APR/include/apr-1', '$APU/include/apr-1'])
279   elif aprstatic:
280     env.Append(LIBPATH=['$APR/LibR','$APU/LibR'],
281                CPPPATH=['$APR/include', '$APU/include'])
282   else:
283     env.Append(LIBPATH=['$APR/Release','$APU/Release'],
284                CPPPATH=['$APR/include', '$APU/include'])
285
286   # zlib
287   env.Append(LIBS='zlib.lib')
288   if not env.get('SOURCE_LAYOUT', None):
289     env.Append(CPPPATH='$ZLIB/include',
290                LIBPATH='$ZLIB/lib')
291   else:
292     env.Append(CPPPATH='$ZLIB',
293                LIBPATH='$ZLIB')
294
295   # openssl
296   env.Append(LIBS=['libeay32.lib', 'ssleay32.lib'])
297   if not env.get('SOURCE_LAYOUT', None):
298     env.Append(CPPPATH='$OPENSSL/include/openssl',
299                LIBPATH='$OPENSSL/lib')
300   elif 0: # opensslstatic:
301     env.Append(CPPPATH='$OPENSSL/inc32',
302                LIBPATH='$OPENSSL/out32')
303   else:
304     env.Append(CPPPATH='$OPENSSL/inc32',
305                LIBPATH='$OPENSSL/out32dll')
306 else:
307   if os.path.isdir(apr):
308     apr = os.path.join(apr, 'bin', 'apr-1-config')
309     env['APR'] = apr
310   if os.path.isdir(apu):
311     apu = os.path.join(apu, 'bin', 'apu-1-config')
312     env['APU'] = apu
313
314   ### we should use --cc, but that is giving some scons error about an implict
315   ### dependency upon gcc. probably ParseConfig doesn't know what to do with
316   ### the apr-1-config output
317   if CALLOUT_OKAY:
318     env.ParseConfig('$APR --cflags --cppflags --ldflags --includes'
319                     ' --link-ld --libs')
320     env.ParseConfig('$APU --ldflags --includes --link-ld --libs')
321
322   ### there is probably a better way to run/capture output.
323   ### env.ParseConfig() may be handy for getting this stuff into the build
324   if CALLOUT_OKAY:
325     apr_libs = os.popen(env.subst('$APR --link-libtool --libs')).read().strip()
326     apu_libs = os.popen(env.subst('$APU --link-libtool --libs')).read().strip()
327   else:
328     apr_libs = ''
329     apu_libs = ''
330
331   env.Append(CPPPATH='$OPENSSL/include')
332   env.Append(LIBPATH='$OPENSSL/lib')
333
334
335 # If build with gssapi, get its information and define SERF_HAVE_GSSAPI
336 if gssapi and CALLOUT_OKAY:
337     env.ParseConfig('$GSSAPI --libs gssapi')
338     env.Append(CPPDEFINES='SERF_HAVE_GSSAPI')
339 if sys.platform == 'win32':
340   env.Append(CPPDEFINES=['SERF_HAVE_SSPI'])
341
342 # On Solaris, the -R values that APR describes never make it into actual
343 # RPATH flags. We'll manually map all directories in LIBPATH into new
344 # flags to set RPATH values.
345 if sys.platform == 'sunos5':
346   for d in env['LIBPATH']:
347     env.Append(RPATH=d)
348
349 # Set up the construction of serf-*.pc
350 # TODO: add gssapi libs
351 pkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,),
352                          env.File('build/serf.pc.in'),
353                          SUBST_DICT = {
354                            '@MAJOR@': str(MAJOR),
355                            '@PREFIX@': '$PREFIX',
356                            '@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,),
357                            '@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH),
358                            '@LIBS@': '%s %s -lz' % (apu_libs, apr_libs),
359                            })
360
361 env.Default(lib_static, lib_shared, pkgconfig)
362
363 if CALLOUT_OKAY:
364   conf = Configure(env)
365
366   ### some configuration stuffs
367
368   env = conf.Finish()
369
370
371 # INSTALLATION STUFF
372
373 install_static = env.Install(libdir, lib_static)
374 install_shared = env.Install(libdir, lib_shared)
375
376 if sys.platform == 'darwin':
377   install_shared_path = install_shared[0].abspath
378   env.AddPostAction(install_shared, ('install_name_tool -id %s %s'
379                                      % (install_shared_path,
380                                         install_shared_path)))
381   ### construct shared lib symlinks. this also means install the lib
382   ### as libserf-2.1.0.0.dylib, then add the symlinks.
383   ### note: see InstallAs
384
385 env.Alias('install-lib', [install_static, install_shared,
386                           ])
387 env.Alias('install-inc', env.Install(incdir, HEADER_FILES))
388 env.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'),
389                                     pkgconfig))
390 env.Alias('install', ['install-lib', 'install-inc', 'install-pc', ])
391
392
393 # TESTS
394 ### make move to a separate scons file in the test/ subdir?
395
396 tenv = env.Clone()
397
398 TEST_PROGRAMS = [ 'serf_get', 'serf_response', 'serf_request', 'serf_spider',
399                   'test_all', 'serf_bwtp' ]
400 if sys.platform == 'win32':
401   TEST_EXES = [ os.path.join('test', '%s.exe' % (prog)) for prog in TEST_PROGRAMS ]
402 else:
403   TEST_EXES = [ os.path.join('test', '%s' % (prog)) for prog in TEST_PROGRAMS ]
404
405 env.AlwaysBuild(env.Alias('check', TEST_EXES, sys.executable + ' build/check.py',
406                           ENV={'PATH' : os.environ['PATH']}))
407
408 # Find the (dynamic) library in this directory
409 tenv.Replace(RPATH=thisdir)
410 tenv.Prepend(LIBS=[LIBNAMESTATIC, ],
411              LIBPATH=[thisdir, ])
412
413 testall_files = [
414         'test/test_all.c',
415         'test/CuTest.c',
416         'test/test_util.c',
417         'test/test_context.c',
418         'test/test_buckets.c',
419         'test/test_auth.c',
420         'test/mock_buckets.c',
421         'test/test_ssl.c',
422         'test/server/test_server.c',
423         'test/server/test_sslserver.c',
424         ]
425
426 for proggie in TEST_EXES:
427   if 'test_all' in proggie:
428     tenv.Program(proggie, testall_files )
429   else:
430     tenv.Program(target = proggie, source = [proggie.replace('.exe','') + '.c'])
431
432
433 # HANDLE CLEANING
434
435 if env.GetOption('clean'):
436   # When we're cleaning, we want the dependency tree to include "everything"
437   # that could be built. Thus, include all of the tests.
438   env.Default('check')