1253893Speter# -*- python -*- 2253893Speter# 3253893Speter# Copyright 2011-2012 Justin Erenkrantz and Greg Stein 4253893Speter# 5253893Speter# Licensed under the Apache License, Version 2.0 (the "License"); 6253893Speter# you may not use this file except in compliance with the License. 7253893Speter# You may obtain a copy of the License at 8253893Speter# 9253893Speter# http://www.apache.org/licenses/LICENSE-2.0 10253893Speter# 11253893Speter# Unless required by applicable law or agreed to in writing, software 12253893Speter# distributed under the License is distributed on an "AS IS" BASIS, 13253893Speter# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14253893Speter# See the License for the specific language governing permissions and 15253893Speter# limitations under the License. 16253893Speter# 17253893Speter 18253893Speterimport sys 19253893Speterimport os 20253893Speterimport re 21253893Speter 22253893SpeterHEADER_FILES = ['serf.h', 23253893Speter 'serf_bucket_types.h', 24253893Speter 'serf_bucket_util.h', 25253893Speter ] 26253893Speter 27253893Speter# where we save the configuration variables 28253893SpeterSAVED_CONFIG = '.saved_config' 29253893Speter 30253893Speter# Variable class that does no validation on the input 31253893Speterdef _converter(val): 32253893Speter """ 33253893Speter """ 34253893Speter if val == 'none': 35253893Speter val = [] 36253893Speter else: 37253893Speter val = val.split(',') 38253893Speter return val 39253893Speter 40253893Speterdef RawListVariable(key, help, default): 41253893Speter """ 42253893Speter The input parameters describe a 'raw string list' option. This class 43253893Speter accepts a comma separated list and converts it to a space separated 44253893Speter list. 45253893Speter """ 46253893Speter return (key, '%s' % (help), default, None, lambda val: _converter(val)) 47253893Speter 48253893Speter# default directories 49253893Speterif sys.platform == 'win32': 50253893Speter default_libdir='..' 51253893Speter default_prefix='Debug' 52253893Speterelse: 53253893Speter default_libdir='/usr' 54253893Speter default_prefix='/usr/local' 55253893Speter 56253893Speteropts = Variables(files=[SAVED_CONFIG]) 57253893Speteropts.AddVariables( 58253893Speter PathVariable('PREFIX', 59253893Speter 'Directory to install under', 60253893Speter default_prefix, 61253893Speter PathVariable.PathIsDir), 62253893Speter PathVariable('APR', 63253893Speter "Path to apr-1-config, or to APR's install area", 64253893Speter default_libdir, 65253893Speter PathVariable.PathAccept), 66253893Speter PathVariable('APU', 67253893Speter "Path to apu-1-config, or to APR's install area", 68253893Speter default_libdir, 69253893Speter PathVariable.PathAccept), 70253893Speter PathVariable('OPENSSL', 71253893Speter "Path to OpenSSL's install area", 72253893Speter default_libdir, 73253893Speter PathVariable.PathIsDir), 74253893Speter PathVariable('ZLIB', 75253893Speter "Path to zlib's install area", 76253893Speter default_libdir, 77253893Speter PathVariable.PathIsDir), 78253893Speter PathVariable('GSSAPI', 79253893Speter "Path to GSSAPI's install area", 80253893Speter None, 81253893Speter None), 82253893Speter BoolVariable('DEBUG', 83253893Speter "Enable debugging info and strict compile warnings", 84253893Speter False), 85253893Speter BoolVariable('APR_STATIC', 86253893Speter "Enable using a static compiled APR", 87253893Speter False), 88253893Speter RawListVariable('CC', "Command name or path of the C compiler", None), 89253893Speter RawListVariable('CFLAGS', "Extra flags for the C compiler (comma separated)", 90253893Speter None), 91253893Speter RawListVariable('LIBS', "Extra libraries passed to the linker, " 92253893Speter "e.g. -l<library> (comma separated)", None), 93253893Speter RawListVariable('LINKFLAGS', "Extra flags for the linker (comma separated)", 94253893Speter None), 95253893Speter RawListVariable('CPPFLAGS', "Extra flags for the C preprocessor " 96253893Speter "(comma separated)", None), 97253893Speter ) 98253893Speter 99253893Speterif sys.platform == 'win32': 100253893Speter opts.AddVariables( 101253893Speter # By default SCons builds for the host platform on Windows, when using 102253893Speter # a supported compiler (E.g. VS2010/VS2012). Allow overriding 103253893Speter 104253893Speter # Note that Scons 1.3 only supports this on Windows and only when 105253893Speter # constructing Environment(). Later changes to TARGET_ARCH are ignored 106253893Speter EnumVariable('TARGET_ARCH', 107253893Speter "Platform to build for (x86|x64|win32|x86_64)", 108253893Speter 'x86', 109253893Speter allowed_values=('x86', 'x86_64', 'ia64'), 110253893Speter map={'X86' : 'x86', 111253893Speter 'win32': 'x86', 112253893Speter 'Win32': 'x86', 113253893Speter 'x64' : 'x86_64', 114253893Speter 'X64' : 'x86_64' 115253893Speter }), 116253893Speter 117253893Speter EnumVariable('MSVC_VERSION', 118253893Speter "Visual C++ to use for building (E.g. 11.0, 9.0)", 119253893Speter None, 120253893Speter allowed_values=('12.0', '11.0', '10.0', '9.0', '8.0', '6.0') 121253893Speter ), 122253893Speter 123253893Speter # We always documented that we handle an install layout, but in fact we 124253893Speter # hardcoded source layouts. Allow disabling this behavior. 125253893Speter # ### Fix default? 126253893Speter BoolVariable('SOURCE_LAYOUT', 127253893Speter "Assume a source layout instead of install layout", 128253893Speter True), 129253893Speter ) 130253893Speter 131253893Speterenv = Environment(variables=opts, 132253893Speter tools=('default', 'textfile',), 133253893Speter CPPPATH=['.', ], 134253893Speter ) 135253893Speter 136253893Speterenv.Append(BUILDERS = { 137253893Speter 'GenDef' : 138253893Speter Builder(action = sys.executable + ' build/gen_def.py $SOURCES > $TARGET', 139253893Speter suffix='.def', src_suffix='.h') 140253893Speter }) 141253893Speter 142253893Spetermatch = re.search('SERF_MAJOR_VERSION ([0-9]+).*' 143253893Speter 'SERF_MINOR_VERSION ([0-9]+).*' 144253893Speter 'SERF_PATCH_VERSION ([0-9]+)', 145253893Speter env.File('serf.h').get_contents(), 146253893Speter re.DOTALL) 147253893SpeterMAJOR, MINOR, PATCH = [int(x) for x in match.groups()] 148253893Speterenv.Append(MAJOR=str(MAJOR)) 149253893Speter 150253893Speter# Calling external programs is okay if we're not cleaning or printing help. 151253893Speter# (cleaning: no sense in fetching information; help: we may not know where 152253893Speter# they are) 153253893SpeterCALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help')) 154253893Speter 155253893Speter 156253893Speter# HANDLING OF OPTION VARIABLES 157253893Speter 158253893Speterunknown = opts.UnknownVariables() 159253893Speterif unknown: 160253893Speter print 'Unknown variables:', ', '.join(unknown.keys()) 161253893Speter Exit(1) 162253893Speter 163253893Speterapr = str(env['APR']) 164253893Speterapu = str(env['APU']) 165253893Speterzlib = str(env['ZLIB']) 166253893Spetergssapi = env.get('GSSAPI', None) 167253893Speter 168253893Speterif gssapi and os.path.isdir(gssapi): 169253893Speter krb5_config = os.path.join(gssapi, 'bin', 'krb5-config') 170253893Speter if os.path.isfile(krb5_config): 171253893Speter gssapi = krb5_config 172253893Speter env['GSSAPI'] = krb5_config 173253893Speter 174253893Speterdebug = env.get('DEBUG', None) 175253893Speteraprstatic = env.get('APR_STATIC', None) 176253893Speter 177253893SpeterHelp(opts.GenerateHelpText(env)) 178253893Speteropts.Save(SAVED_CONFIG, env) 179253893Speter 180253893Speter 181253893Speter# PLATFORM-SPECIFIC BUILD TWEAKS 182253893Speter 183253893Speterthisdir = os.getcwd() 184253893Speterlibdir = '$PREFIX/lib' 185253893Speterincdir = '$PREFIX/include/serf-$MAJOR' 186253893Speter 187253893SpeterLIBNAME = 'libserf-${MAJOR}' 188253893Speterif sys.platform != 'win32': 189253893Speter LIBNAMESTATIC = LIBNAME 190253893Speterelse: 191253893Speter LIBNAMESTATIC = 'serf-${MAJOR}' 192253893Speter 193253893Speterenv.Append(RPATH=libdir, 194253893Speter PDB='${TARGET.filebase}.pdb') 195253893Speter 196253893Speterif sys.platform == 'darwin': 197253893Speter# linkflags.append('-Wl,-install_name,@executable_path/%s.dylib' % (LIBNAME,)) 198253893Speter env.Append(LINKFLAGS='-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,)) 199253893Speter # 'man ld' says positive non-zero for the first number, so we add one. 200253893Speter # Mac's interpretation of compatibility is the same as our MINOR version. 201253893Speter env.Append(LINKFLAGS='-Wl,-compatibility_version,%d' % (MINOR+1,)) 202253893Speter env.Append(LINKFLAGS='-Wl,-current_version,%d.%d' % (MINOR+1, PATCH,)) 203253893Speter 204253893Speterif sys.platform != 'win32': 205253893Speter ### gcc only. figure out appropriate test / better way to check these 206253893Speter ### flags, and check for gcc. 207253893Speter env.Append(CFLAGS='-std=c89') 208253893Speter env.Append(CCFLAGS=[ 209253893Speter '-Wdeclaration-after-statement', 210253893Speter '-Wmissing-prototypes', 211253893Speter ]) 212253893Speter 213253893Speter ### -Wall is not available on Solaris 214253893Speter if sys.platform != 'sunos5': 215253893Speter env.Append(CCFLAGS='-Wall') 216253893Speter 217253893Speter if debug: 218253893Speter env.Append(CCFLAGS='-g') 219253893Speter env.Append(CPPDEFINES=['DEBUG', '_DEBUG']) 220253893Speter else: 221253893Speter env.Append(CCFLAGS='-O2') 222253893Speter env.Append(CPPDEFINES='NDEBUG') 223253893Speter 224253893Speter ### works for Mac OS. probably needs to change 225253893Speter env.Append(LIBS=['ssl', 'crypto', 'z', ]) 226253893Speter 227253893Speter if sys.platform == 'sunos5': 228253893Speter env.Append(LIBS='m') 229253893Speterelse: 230253893Speter # Warning level 4, no unused argument warnings 231253893Speter env.Append(CCFLAGS=['/W4', '/wd4100']) 232253893Speter 233253893Speter # Choose runtime and optimization 234253893Speter if debug: 235253893Speter # Disable optimizations for debugging, use debug DLL runtime 236253893Speter env.Append(CCFLAGS=['/Od', '/MDd']) 237253893Speter env.Append(CPPDEFINES=['DEBUG', '_DEBUG']) 238253893Speter else: 239253893Speter # Optimize for speed, use DLL runtime 240253893Speter env.Append(CCFLAGS=['/O2', '/MD']) 241253893Speter env.Append(CPPDEFINES='NDEBUG') 242253893Speter 243253893Speter# PLAN THE BUILD 244253893SpeterSHARED_SOURCES = [] 245253893Speterif sys.platform == 'win32': 246253893Speter env.GenDef(['serf.h','serf_bucket_types.h', 'serf_bucket_util.h']) 247253893Speter SHARED_SOURCES.append(['serf.def']) 248253893Speter 249253893SpeterSOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c') 250253893Speter 251253893Speterlib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES) 252253893Speterlib_shared = env.SharedLibrary(LIBNAME, SOURCES + SHARED_SOURCES) 253253893Speter 254253893Speterif aprstatic: 255253893Speter env.Append(CPPDEFINES=['APR_DECLARE_STATIC', 'APU_DECLARE_STATIC']) 256253893Speter 257253893Speterif sys.platform == 'win32': 258253893Speter env.Append(LIBS=['user32.lib', 'advapi32.lib', 'gdi32.lib', 'ws2_32.lib', 259253893Speter 'crypt32.lib', 'mswsock.lib', 'rpcrt4.lib', 'secur32.lib']) 260253893Speter 261253893Speter # Get apr/apu information into our build 262253893Speter env.Append(CPPDEFINES=['WIN32','WIN32_LEAN_AND_MEAN','NOUSER', 263253893Speter 'NOGDI', 'NONLS','NOCRYPT']) 264253893Speter 265253893Speter if env.get('TARGET_ARCH', None) == 'x86_64': 266253893Speter env.Append(CPPDEFINES=['WIN64']) 267253893Speter 268253893Speter if aprstatic: 269253893Speter apr_libs='apr-1.lib' 270253893Speter apu_libs='aprutil-1.lib' 271253893Speter else: 272253893Speter apr_libs='libapr-1.lib' 273253893Speter apu_libs='libaprutil-1.lib' 274253893Speter 275253893Speter env.Append(LIBS=[apr_libs, apu_libs]) 276253893Speter if not env.get('SOURCE_LAYOUT', None): 277253893Speter env.Append(LIBPATH=['$APR/lib', '$APU/lib'], 278253893Speter CPPPATH=['$APR/include/apr-1', '$APU/include/apr-1']) 279253893Speter elif aprstatic: 280253893Speter env.Append(LIBPATH=['$APR/LibR','$APU/LibR'], 281253893Speter CPPPATH=['$APR/include', '$APU/include']) 282253893Speter else: 283253893Speter env.Append(LIBPATH=['$APR/Release','$APU/Release'], 284253893Speter CPPPATH=['$APR/include', '$APU/include']) 285253893Speter 286253893Speter # zlib 287253893Speter env.Append(LIBS='zlib.lib') 288253893Speter if not env.get('SOURCE_LAYOUT', None): 289253893Speter env.Append(CPPPATH='$ZLIB/include', 290253893Speter LIBPATH='$ZLIB/lib') 291253893Speter else: 292253893Speter env.Append(CPPPATH='$ZLIB', 293253893Speter LIBPATH='$ZLIB') 294253893Speter 295253893Speter # openssl 296253893Speter env.Append(LIBS=['libeay32.lib', 'ssleay32.lib']) 297253893Speter if not env.get('SOURCE_LAYOUT', None): 298253893Speter env.Append(CPPPATH='$OPENSSL/include/openssl', 299253893Speter LIBPATH='$OPENSSL/lib') 300253893Speter elif 0: # opensslstatic: 301253893Speter env.Append(CPPPATH='$OPENSSL/inc32', 302253893Speter LIBPATH='$OPENSSL/out32') 303253893Speter else: 304253893Speter env.Append(CPPPATH='$OPENSSL/inc32', 305253893Speter LIBPATH='$OPENSSL/out32dll') 306253893Speterelse: 307253893Speter if os.path.isdir(apr): 308253893Speter apr = os.path.join(apr, 'bin', 'apr-1-config') 309253893Speter env['APR'] = apr 310253893Speter if os.path.isdir(apu): 311253893Speter apu = os.path.join(apu, 'bin', 'apu-1-config') 312253893Speter env['APU'] = apu 313253893Speter 314253893Speter ### we should use --cc, but that is giving some scons error about an implict 315253893Speter ### dependency upon gcc. probably ParseConfig doesn't know what to do with 316253893Speter ### the apr-1-config output 317253893Speter if CALLOUT_OKAY: 318253893Speter env.ParseConfig('$APR --cflags --cppflags --ldflags --includes' 319253893Speter ' --link-ld --libs') 320253893Speter env.ParseConfig('$APU --ldflags --includes --link-ld --libs') 321253893Speter 322253893Speter ### there is probably a better way to run/capture output. 323253893Speter ### env.ParseConfig() may be handy for getting this stuff into the build 324253893Speter if CALLOUT_OKAY: 325253893Speter apr_libs = os.popen(env.subst('$APR --link-libtool --libs')).read().strip() 326253893Speter apu_libs = os.popen(env.subst('$APU --link-libtool --libs')).read().strip() 327253893Speter else: 328253893Speter apr_libs = '' 329253893Speter apu_libs = '' 330253893Speter 331253893Speter env.Append(CPPPATH='$OPENSSL/include') 332253893Speter env.Append(LIBPATH='$OPENSSL/lib') 333253893Speter 334253893Speter 335253893Speter# If build with gssapi, get its information and define SERF_HAVE_GSSAPI 336253893Speterif gssapi and CALLOUT_OKAY: 337253893Speter env.ParseConfig('$GSSAPI --libs gssapi') 338253893Speter env.Append(CPPDEFINES='SERF_HAVE_GSSAPI') 339253893Speterif sys.platform == 'win32': 340253893Speter env.Append(CPPDEFINES=['SERF_HAVE_SSPI']) 341253893Speter 342253893Speter# On Solaris, the -R values that APR describes never make it into actual 343253893Speter# RPATH flags. We'll manually map all directories in LIBPATH into new 344253893Speter# flags to set RPATH values. 345253893Speterif sys.platform == 'sunos5': 346253893Speter for d in env['LIBPATH']: 347253893Speter env.Append(RPATH=d) 348253893Speter 349253893Speter# Set up the construction of serf-*.pc 350253893Speter# TODO: add gssapi libs 351253893Speterpkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,), 352253893Speter env.File('build/serf.pc.in'), 353253893Speter SUBST_DICT = { 354253893Speter '@MAJOR@': str(MAJOR), 355253893Speter '@PREFIX@': '$PREFIX', 356253893Speter '@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,), 357253893Speter '@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH), 358253893Speter '@LIBS@': '%s %s -lz' % (apu_libs, apr_libs), 359253893Speter }) 360253893Speter 361253893Speterenv.Default(lib_static, lib_shared, pkgconfig) 362253893Speter 363253893Speterif CALLOUT_OKAY: 364253893Speter conf = Configure(env) 365253893Speter 366253893Speter ### some configuration stuffs 367253893Speter 368253893Speter env = conf.Finish() 369253893Speter 370253893Speter 371253893Speter# INSTALLATION STUFF 372253893Speter 373253893Speterinstall_static = env.Install(libdir, lib_static) 374253893Speterinstall_shared = env.Install(libdir, lib_shared) 375253893Speter 376253893Speterif sys.platform == 'darwin': 377253893Speter install_shared_path = install_shared[0].abspath 378253893Speter env.AddPostAction(install_shared, ('install_name_tool -id %s %s' 379253893Speter % (install_shared_path, 380253893Speter install_shared_path))) 381253893Speter ### construct shared lib symlinks. this also means install the lib 382253893Speter ### as libserf-2.1.0.0.dylib, then add the symlinks. 383253893Speter ### note: see InstallAs 384253893Speter 385253893Speterenv.Alias('install-lib', [install_static, install_shared, 386253893Speter ]) 387253893Speterenv.Alias('install-inc', env.Install(incdir, HEADER_FILES)) 388253893Speterenv.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'), 389253893Speter pkgconfig)) 390253893Speterenv.Alias('install', ['install-lib', 'install-inc', 'install-pc', ]) 391253893Speter 392253893Speter 393253893Speter# TESTS 394253893Speter### make move to a separate scons file in the test/ subdir? 395253893Speter 396253893Spetertenv = env.Clone() 397253893Speter 398253893SpeterTEST_PROGRAMS = [ 'serf_get', 'serf_response', 'serf_request', 'serf_spider', 399253893Speter 'test_all', 'serf_bwtp' ] 400253893Speterif sys.platform == 'win32': 401253893Speter TEST_EXES = [ os.path.join('test', '%s.exe' % (prog)) for prog in TEST_PROGRAMS ] 402253893Speterelse: 403253893Speter TEST_EXES = [ os.path.join('test', '%s' % (prog)) for prog in TEST_PROGRAMS ] 404253893Speter 405253893Speterenv.AlwaysBuild(env.Alias('check', TEST_EXES, sys.executable + ' build/check.py', 406253893Speter ENV={'PATH' : os.environ['PATH']})) 407253893Speter 408253893Speter# Find the (dynamic) library in this directory 409253893Spetertenv.Replace(RPATH=thisdir) 410253893Spetertenv.Prepend(LIBS=[LIBNAMESTATIC, ], 411253893Speter LIBPATH=[thisdir, ]) 412253893Speter 413253893Spetertestall_files = [ 414253893Speter 'test/test_all.c', 415253893Speter 'test/CuTest.c', 416253893Speter 'test/test_util.c', 417253893Speter 'test/test_context.c', 418253893Speter 'test/test_buckets.c', 419253893Speter 'test/test_auth.c', 420253893Speter 'test/mock_buckets.c', 421253893Speter 'test/test_ssl.c', 422253893Speter 'test/server/test_server.c', 423253893Speter 'test/server/test_sslserver.c', 424253893Speter ] 425253893Speter 426253893Speterfor proggie in TEST_EXES: 427253893Speter if 'test_all' in proggie: 428253893Speter tenv.Program(proggie, testall_files ) 429253893Speter else: 430253893Speter tenv.Program(target = proggie, source = [proggie.replace('.exe','') + '.c']) 431253893Speter 432253893Speter 433253893Speter# HANDLE CLEANING 434253893Speter 435253893Speterif env.GetOption('clean'): 436253893Speter # When we're cleaning, we want the dependency tree to include "everything" 437253893Speter # that could be built. Thus, include all of the tests. 438253893Speter env.Default('check') 439