blob: 111a666ed529d9b83424630922c12fac5512c814 [file] [log] [blame]
# -*- python -*-
#
# Copyright 2011-2012 Justin Erenkrantz and Greg Stein
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import os
import re
import platform
HEADER_FILES = ['serf.h',
'serf_bucket_types.h',
'serf_bucket_util.h',
]
# where we save the configuration variables
SAVED_CONFIG = '.saved_config'
opts = Variables(files=[SAVED_CONFIG])
opts.AddVariables(
PathVariable('PREFIX',
'Directory to install under',
'/usr/local',
PathVariable.PathIsDir),
PathVariable('APR',
"Path to apr-1-config, or to APR's install area",
'/usr',
PathVariable.PathAccept),
PathVariable('APU',
"Path to apu-1-config, or to APR's install area",
'/usr',
PathVariable.PathAccept),
PathVariable('ZLIB',
"Path to zlib's install area",
'/usr',
PathVariable.PathIsDir),
PathVariable('GSSAPI',
"Path to GSSAPI's install area",
None,
None),
BoolVariable('DEBUG',
"Enable debugging info and strict compile warnings",
False),
)
if sys.platform == 'darwin':
opts.AddVariables(
PathVariable('OPENSSL',
"Path to OpenSSL's install area",
None,
None))
else:
opts.AddVariables(
PathVariable('OPENSSL',
"Path to OpenSSL's install area",
'/usr',
PathVariable.PathIsDir))
env = Environment(variables=opts,
tools=('default', 'textfile',),
CPPPATH=['.', ],
)
match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
'SERF_MINOR_VERSION ([0-9]+).*'
'SERF_PATCH_VERSION ([0-9]+)',
env.File('serf.h').get_contents(),
re.DOTALL)
MAJOR, MINOR, PATCH = [int(x) for x in match.groups()]
env.Append(MAJOR=str(MAJOR))
# Calling external programs is okay if we're not cleaning or printing help.
# (cleaning: no sense in fetching information; help: we may not know where
# they are)
CALLOUT_OKAY = not (env.GetOption('clean') or env.GetOption('help'))
# HANDLING OF OPTION VARIABLES
unknown = opts.UnknownVariables()
if unknown:
print 'Unknown variables:', ', '.join(unknown.keys())
Exit(1)
apr = str(env['APR'])
apu = str(env['APU'])
zlib = str(env['ZLIB'])
gssapi = env.get('GSSAPI', None)
if gssapi and os.path.isdir(gssapi):
krb5_config = os.path.join(gssapi, 'bin', 'krb5-config')
if os.path.isfile(krb5_config):
gssapi = krb5_config
env['GSSAPI'] = krb5_config
openssl = env.get('OPENSSL', None)
if openssl and os.path.isdir(str(openssl)):
env.Append(CPPPATH='$OPENSSL/include')
env.Append(LIBPATH='$OPENSSL/lib')
env.Append(CFLAGS='-DSERF_HAVE_OPENSSL')
debug = env.get('DEBUG', None)
Help(opts.GenerateHelpText(env))
opts.Save(SAVED_CONFIG, env)
# PLATFORM-SPECIFIC BUILD TWEAKS
def link_rpath(d):
if sys.platform == 'sunos5':
return '-Wl,-R,%s' % (d,)
return '-Wl,-rpath,%s' % (d,)
thisdir = os.getcwd()
libdir = '$PREFIX/lib'
incdir = '$PREFIX/include/serf-$MAJOR'
LIBNAME = 'libserf-${MAJOR}'
if sys.platform != 'win32':
LIBNAMESTATIC = LIBNAME
else:
LIBNAMESTATIC = 'serf-${MAJOR}'
linkflags = []
if sys.platform != 'win32':
linkflags.append(link_rpath(libdir))
else:
linkflags.append(['/nologo'])
if sys.platform == 'darwin':
# linkflags.append('-Wl,-install_name,@executable_path/%s.dylib' % (LIBNAME,))
linkflags.append('-Wl,-install_name,%s/%s.dylib' % (thisdir, LIBNAME,))
# 'man ld' says positive non-zero for the first number, so we add one.
# Mac's interpretation of compatibility is the same as our MINOR version.
linkflags.append('-Wl,-compatibility_version,%d' % (MINOR+1,))
linkflags.append('-Wl,-current_version,%d.%d' % (MINOR+1, PATCH,))
# enable macosxssl_buckets only on Mac OS X 10.7+
macosxssl = False
ver, _, _ = platform.mac_ver()
ver = float('.'.join(ver.split('.')[:2]))
if ver >= 10.7:
macosxssl = True
env.Append(CFLAGS='-DSERF_HAVE_MACOSXSSL')
if sys.platform == 'win32':
### we should create serf.def for Windows DLLs and add it into the link
### step somehow.
pass
ccflags = [ ]
if sys.platform != 'win32':
### gcc only. figure out appropriate test / better way to check these
### flags, and check for gcc.
ccflags = ['-std=c89',
'-Wdeclaration-after-statement',
'-Wmissing-prototypes',
]
### -Wall is not available on Solaris
if sys.platform != 'sunos5':
ccflags.append(['-Wall', ])
if debug:
ccflags.append(['-g'])
else:
ccflags.append('-O2')
else:
ccflags.append(['/nologo', '/W4', '/Zi'])
if debug:
ccflags.append(['/Od'])
else:
ccflags.append(['/O2'])
libs = [ ]
if sys.platform != 'win32':
### works for Mac OS. probably needs to change
libs = ['ssl', 'crypto', 'z', ]
if macosxssl:
env.Append(FRAMEWORKS=['Security', 'SecurityInterface', 'CoreFoundation',
'AppKit'])
libs.append('objc')
if sys.platform == 'sunos5':
libs.append('m')
env.Replace(LINKFLAGS=linkflags,
CCFLAGS=ccflags,
LIBS=libs,
)
# PLAN THE BUILD
SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
if macosxssl:
SOURCES += ['buckets/macosxssl_helper.m']
lib_static = env.StaticLibrary(LIBNAMESTATIC, SOURCES)
lib_shared = env.SharedLibrary(LIBNAME, SOURCES)
if sys.platform == 'win32':
if debug:
env.Append(CFLAGS='/MDd')
else:
env.Append(CFLAGS='/MD')
env.Append(LIBS=['user32.lib', 'advapi32.lib', 'gdi32.lib', 'ws2_32.lib',
'crypt32.lib', 'mswsock.lib', 'rpcrt4.lib', 'secur32.lib'])
# Get apr/apu information into our build
env.Append(CFLAGS='-DWIN32 ' + \
'/I "$APR/include" /I "$APU/include" ' + \
'-DWIN32 -DWIN32_LEAN_AND_MEAN -DNOUSER' + \
'-DNOGDI -DNONLS -DNOCRYPT')
env.Append(LIBPATH=['$APR/Release','$APU/Release'],
LIBS=['libapr-1.lib', 'libaprutil-1.lib'])
apr_libs='libapr-1.lib'
apu_libs='libaprutil-1.lib'
# zlib
env.Append(CFLAGS='/I "$ZLIB"')
env.Append(LIBPATH='$ZLIB', LIBS='zlib.lib')
# openssl
env.Append(CPPPATH='$OPENSSL/inc32')
env.Append(LIBPATH='$OPENSSL/out32dll', LIBS=['libeay32.lib', 'ssleay32.lib'])
else:
if os.path.isdir(apr):
apr = os.path.join(apr, 'bin', 'apr-1-config')
env['APR'] = apr
if os.path.isdir(apu):
apu = os.path.join(apu, 'bin', 'apu-1-config')
env['APU'] = apu
### we should use --cc, but that is giving some scons error about an implict
### dependency upon gcc. probably ParseConfig doesn't know what to do with
### the apr-1-config output
if CALLOUT_OKAY:
env.ParseConfig('$APR --cflags --cppflags --ldflags --includes'
' --link-ld --libs')
env.ParseConfig('$APU --ldflags --includes --link-ld --libs')
### there is probably a better way to run/capture output.
### env.ParseConfig() may be handy for getting this stuff into the build
if CALLOUT_OKAY:
apr_libs = os.popen(env.subst('$APR --link-libtool --libs')).read().strip()
apu_libs = os.popen(env.subst('$APU --link-libtool --libs')).read().strip()
else:
apr_libs = ''
apu_libs = ''
env.Append(CPPPATH='$OPENSSL/include')
env.Append(LIBPATH='$OPENSSL/lib')
# If build with gssapi, get its information and define SERF_HAVE_GSSAPI
if gssapi and CALLOUT_OKAY:
env.ParseConfig('$GSSAPI --libs gssapi')
env.Append(CFLAGS='-DSERF_HAVE_GSSAPI')
if sys.platform == 'win32':
env.Append(CFLAGS='-DSERF_HAVE_SPNEGO -DSERF_HAVE_SSPI')
# On Solaris, the -R values that APR describes never make it into actual
# RPATH flags. We'll manually map all directories in LIBPATH into new
# flags to set RPATH values.
if sys.platform == 'sunos5':
for d in env['LIBPATH']:
env.Append(LINKFLAGS=link_rpath(d))
# Set up the construction of serf-*.pc
# TODO: add gssapi libs
pkgconfig = env.Textfile('serf-%d.pc' % (MAJOR,),
env.File('build/serf.pc.in'),
SUBST_DICT = {
'@MAJOR@': str(MAJOR),
'@PREFIX@': '$PREFIX',
'@INCLUDE_SUBDIR@': 'serf-%d' % (MAJOR,),
'@VERSION@': '%d.%d.%d' % (MAJOR, MINOR, PATCH),
'@LIBS@': '%s %s -lz' % (apu_libs, apr_libs),
})
env.Default(lib_static, lib_shared, pkgconfig)
if CALLOUT_OKAY:
conf = Configure(env)
### some configuration stuffs
env = conf.Finish()
# INSTALLATION STUFF
install_static = env.Install(libdir, lib_static)
install_shared = env.Install(libdir, lib_shared)
if sys.platform == 'darwin':
install_shared_path = install_shared[0].abspath
env.AddPostAction(install_shared, ('install_name_tool -id %s %s'
% (install_shared_path,
install_shared_path)))
### construct shared lib symlinks. this also means install the lib
### as libserf-2.1.0.0.dylib, then add the symlinks.
### note: see InstallAs
env.Alias('install-lib', [install_static, install_shared,
])
env.Alias('install-inc', env.Install(incdir, HEADER_FILES))
env.Alias('install-pc', env.Install(os.path.join(libdir, 'pkgconfig'),
pkgconfig))
env.Alias('install', ['install-lib', 'install-inc', 'install-pc', ])
# TESTS
### make move to a separate scons file in the test/ subdir?
tenv = env.Clone()
TEST_PROGRAMS = [
'test/serf_get',
'test/serf_response',
'test/serf_request',
'test/serf_spider',
'test/test_all',
'test/serf_bwtp',
]
env.AlwaysBuild(env.Alias('check', TEST_PROGRAMS, 'build/check.sh'))
# Find the (dynamic) library in this directory
linkflags = [link_rpath(thisdir,), ]
tenv.Replace(LINKFLAGS=linkflags)
tenv.Prepend(LIBS=['libserf-2', ],
LIBPATH=[thisdir, ])
for proggie in TEST_PROGRAMS:
if proggie.endswith('test_all'):
tenv.Program('test/test_all', [
'test/test_all.c',
'test/CuTest.c',
'test/test_util.c',
'test/test_context.c',
'test/test_buckets.c',
'test/test_auth.c',
'test/mock_buckets.c',
'test/test_ssl.c',
'test/server/test_server.c',
'test/server/test_sslserver.c',
])
else:
tenv.Program(proggie, [proggie + '.c'])
# HANDLE CLEANING
if env.GetOption('clean'):
# When we're cleaning, we want the dependency tree to include "everything"
# that could be built. Thus, include all of the tests.
env.Default('check')