3 # Copyright 2011-2012 Justin Erenkrantz and Greg Stein
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
22 HEADER_FILES = ['serf.h',
23 'serf_bucket_types.h',
27 # where we save the configuration variables
28 SAVED_CONFIG = '.saved_config'
30 # Variable class that does no validation on the input
40 def RawListVariable(key, help, default):
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
46 return (key, '%s' % (help), default, None, lambda val: _converter(val))
49 if sys.platform == 'win32':
51 default_prefix='Debug'
54 default_prefix='/usr/local'
56 opts = Variables(files=[SAVED_CONFIG])
58 PathVariable('PREFIX',
59 'Directory to install under',
61 PathVariable.PathIsDir),
63 "Path to apr-1-config, or to APR's install area",
65 PathVariable.PathAccept),
67 "Path to apu-1-config, or to APR's install area",
69 PathVariable.PathAccept),
70 PathVariable('OPENSSL',
71 "Path to OpenSSL's install area",
73 PathVariable.PathIsDir),
75 "Path to zlib's install area",
77 PathVariable.PathIsDir),
78 PathVariable('GSSAPI',
79 "Path to GSSAPI's install area",
83 "Enable debugging info and strict compile warnings",
85 BoolVariable('APR_STATIC',
86 "Enable using a static compiled APR",
88 RawListVariable('CC', "Command name or path of the C compiler", None),
89 RawListVariable('CFLAGS', "Extra flags for the C compiler (comma separated)",
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)",
95 RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor "
96 "(comma separated)", None),
99 if sys.platform == 'win32':
101 # By default SCons builds for the host platform on Windows, when using
102 # a supported compiler (E.g. VS2010/VS2012). Allow overriding
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)",
109 allowed_values=('x86', 'x86_64', 'ia64'),
117 EnumVariable('MSVC_VERSION',
118 "Visual C++ to use for building (E.g. 11.0, 9.0)",
120 allowed_values=('12.0', '11.0', '10.0', '9.0', '8.0', '6.0')
123 # We always documented that we handle an install layout, but in fact we
124 # hardcoded source layouts. Allow disabling this behavior.
126 BoolVariable('SOURCE_LAYOUT',
127 "Assume a source layout instead of install layout",
131 env = Environment(variables=opts,
132 tools=('default', 'textfile',),
136 env.Append(BUILDERS = {
138 Builder(action = sys.executable + ' build/gen_def.py $SOURCES > $TARGET',
139 suffix='.def', src_suffix='.h')
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(),
147 MAJOR, MINOR, PATCH = [int(x) for x in match.groups()]
148 env.Append(MAJOR=str(MAJOR))
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
153 CALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help'))
156 # HANDLING OF OPTION VARIABLES
158 unknown = opts.UnknownVariables()
160 print 'Unknown variables:', ', '.join(unknown.keys())
163 apr = str(env['APR'])
164 apu = str(env['APU'])
165 zlib = str(env['ZLIB'])
166 gssapi = env.get('GSSAPI', None)
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):
172 env['GSSAPI'] = krb5_config
174 debug = env.get('DEBUG', None)
175 aprstatic = env.get('APR_STATIC', None)
177 Help(opts.GenerateHelpText(env))
178 opts.Save(SAVED_CONFIG, env)
181 # PLATFORM-SPECIFIC BUILD TWEAKS
183 thisdir = os.getcwd()
184 libdir = '$PREFIX/lib'
185 incdir = '$PREFIX/include/serf-$MAJOR'
187 LIBNAME = 'libserf-${MAJOR}'
188 if sys.platform != 'win32':
189 LIBNAMESTATIC = LIBNAME
191 LIBNAMESTATIC = 'serf-${MAJOR}'
193 env.Append(RPATH=libdir,
194 PDB='${TARGET.filebase}.pdb')
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,))
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')
209 '-Wdeclaration-after-statement',
210 '-Wmissing-prototypes',
213 ### -Wall is not available on Solaris
214 if sys.platform != 'sunos5':
215 env.Append(CCFLAGS='-Wall')
218 env.Append(CCFLAGS='-g')
219 env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
221 env.Append(CCFLAGS='-O2')
222 env.Append(CPPDEFINES='NDEBUG')
224 ### works for Mac OS. probably needs to change
225 env.Append(LIBS=['ssl', 'crypto', 'z', ])
227 if sys.platform == 'sunos5':
230 # Warning level 4, no unused argument warnings
231 env.Append(CCFLAGS=['/W4', '/wd4100'])
233 # Choose runtime and optimization
235 # Disable optimizations for debugging, use debug DLL runtime
236 env.Append(CCFLAGS=['/Od', '/MDd'])
237 env.Append(CPPDEFINES=['DEBUG', '_DEBUG'])
239 # Optimize for speed, use DLL runtime
240 env.Append(CCFLAGS=['/O2', '/MD'])
241 env.Append(CPPDEFINES='NDEBUG')
245 if sys.platform == 'win32':
246 env.GenDef(['serf.h','serf_bucket_types.h', 'serf_bucket_util.h'])
247 SHARED_SOURCES.append(['serf.def'])
249 SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
251 lib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES)
252 lib_shared = env.SharedLibrary(LIBNAME, SOURCES + SHARED_SOURCES)
255 env.Append(CPPDEFINES=['APR_DECLARE_STATIC', 'APU_DECLARE_STATIC'])
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'])
261 # Get apr/apu information into our build
262 env.Append(CPPDEFINES=['WIN32','WIN32_LEAN_AND_MEAN','NOUSER',
263 'NOGDI', 'NONLS','NOCRYPT'])
265 if env.get('TARGET_ARCH', None) == 'x86_64':
266 env.Append(CPPDEFINES=['WIN64'])
270 apu_libs='aprutil-1.lib'
272 apr_libs='libapr-1.lib'
273 apu_libs='libaprutil-1.lib'
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'])
280 env.Append(LIBPATH=['$APR/LibR','$APU/LibR'],
281 CPPPATH=['$APR/include', '$APU/include'])
283 env.Append(LIBPATH=['$APR/Release','$APU/Release'],
284 CPPPATH=['$APR/include', '$APU/include'])
287 env.Append(LIBS='zlib.lib')
288 if not env.get('SOURCE_LAYOUT', None):
289 env.Append(CPPPATH='$ZLIB/include',
292 env.Append(CPPPATH='$ZLIB',
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')
304 env.Append(CPPPATH='$OPENSSL/inc32',
305 LIBPATH='$OPENSSL/out32dll')
307 if os.path.isdir(apr):
308 apr = os.path.join(apr, 'bin', 'apr-1-config')
310 if os.path.isdir(apu):
311 apu = os.path.join(apu, 'bin', 'apu-1-config')
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
318 env.ParseConfig('$APR --cflags --cppflags --ldflags --includes'
320 env.ParseConfig('$APU --ldflags --includes --link-ld --libs')
322 ### there is probably a better way to run/capture output.
323 ### env.ParseConfig() may be handy for getting this stuff into the build
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()
331 env.Append(CPPPATH='$OPENSSL/include')
332 env.Append(LIBPATH='$OPENSSL/lib')
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'])
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']:
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'),
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),
361 env.Default(lib_static, lib_shared, pkgconfig)
364 conf = Configure(env)
366 ### some configuration stuffs
373 install_static = env.Install(libdir, lib_static)
374 install_shared = env.Install(libdir, lib_shared)
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
385 env.Alias('install-lib', [install_static, install_shared,
387 env.Alias('install-inc', env.Install(incdir, HEADER_FILES))
388 env.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'),
390 env.Alias('install', ['install-lib', 'install-inc', 'install-pc', ])
394 ### make move to a separate scons file in the test/ subdir?
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 ]
403 TEST_EXES = [ os.path.join('test', '%s' % (prog)) for prog in TEST_PROGRAMS ]
405 env.AlwaysBuild(env.Alias('check', TEST_EXES, sys.executable + ' build/check.py',
406 ENV={'PATH' : os.environ['PATH']}))
408 # Find the (dynamic) library in this directory
409 tenv.Replace(RPATH=thisdir)
410 tenv.Prepend(LIBS=[LIBNAMESTATIC, ],
417 'test/test_context.c',
418 'test/test_buckets.c',
420 'test/mock_buckets.c',
422 'test/server/test_server.c',
423 'test/server/test_sslserver.c',
426 for proggie in TEST_EXES:
427 if 'test_all' in proggie:
428 tenv.Program(proggie, testall_files )
430 tenv.Program(target = proggie, source = [proggie.replace('.exe','') + '.c'])
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.