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