scons: move all configure options to 'scons configure' stage, using pickling to maintain configure options across builds

This commit is contained in:
Dane Springmeyer 2009-02-26 23:35:09 +00:00
parent 6a84586489
commit 9f40e90def
2 changed files with 513 additions and 483 deletions

View file

@ -19,8 +19,13 @@
# $Id$ # $Id$
import os, sys, platform import os
import sys
import platform
from glob import glob
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from SCons.SConf import SetCacheMode
import pickle
def color_print(color,text,newline=True): def color_print(color,text,newline=True):
# 1 - red # 1 - red
@ -40,17 +45,6 @@ def call(cmd):
else: else:
color_print(1,'Problem encounted with SCons scripts, please post bug report to: http://trac.mapnik.org') color_print(1,'Problem encounted with SCons scripts, please post bug report to: http://trac.mapnik.org')
# Helper function for uniquely appending paths to a SCons path listing.
def uniq_add(env, key, val):
if not val in env[key]: env[key].append(val)
# Helper function for building up paths to add for a lib (plugin or required)
def add_paths(prereq):
inc_path = env['%s_INCLUDES' % prereq]
lib_path = env['%s_LIBS' % prereq]
uniq_add(env, 'CPPPATH', inc_path)
uniq_add(env, 'LIBPATH', lib_path)
if platform.uname()[4] == 'x86_64': if platform.uname()[4] == 'x86_64':
LIBDIR_SCHEMA='lib64' LIBDIR_SCHEMA='lib64'
elif platform.uname()[4] == 'ppc64': elif platform.uname()[4] == 'ppc64':
@ -58,15 +52,12 @@ elif platform.uname()[4] == 'ppc64':
else: else:
LIBDIR_SCHEMA='lib' LIBDIR_SCHEMA='lib'
#### SCons build options and initial setup #### # local file to hold custom user configuration variables
SCONS_LOCAL_CONFIG = 'config.py' SCONS_LOCAL_CONFIG = 'config.py'
# local pickled file to cache configured environment
# Warn user of current set of build options. SCONS_CONFIGURE_CACHE = 'config.cache'
if os.path.exists(SCONS_LOCAL_CONFIG): # directory SCons uses to stash build tests
optfile = file(SCONS_LOCAL_CONFIG) SCONF_TEMP_DIR = '.sconf_temp'
print "Saved options:", optfile.read().replace("\n", ", ")[:-2]
optfile.close()
# Core plugin build configuration # Core plugin build configuration
# opts.AddVariables still hardcoded however... # opts.AddVariables still hardcoded however...
@ -89,14 +80,14 @@ for k,v in PLUGINS.items():
if v['default']: if v['default']:
DEFAULT_PLUGINS.append(k) DEFAULT_PLUGINS.append(k)
#### SCons build options and initial setup ####
color_print(4,'\nWelcome to Mapnik...\n')
env = Environment(ENV=os.environ)
# All of the following options may be modified at the command-line, for example: # All of the following options may be modified at the command-line, for example:
# `python scons/scons.py PREFIX=/opt` # `python scons/scons.py PREFIX=/opt`
opts = Variables() opts = Variables()
def OptionalPath(key, val, env):
if val:
PathOption.PathIsDir(key, val, env)
opts.AddVariables( opts.AddVariables(
# Compiler options # Compiler options
('CXX', 'The C++ compiler to use (defaults to g++).', 'g++'), ('CXX', 'The C++ compiler to use (defaults to g++).', 'g++'),
@ -108,8 +99,7 @@ opts.AddVariables(
# SCons build behavior options # SCons build behavior options
('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG), ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG),
BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'), BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'),
BoolVariable('SCONS_CACHE', 'Use SCons dependency caching to speed build process', 'False'), BoolVariable('FAST', "Make scons faster at the cost of less precise dependency tracking", 'False'),
BoolVariable('USE_USER_ENV', 'Allow the SCons build environment to inherit from the current user environment', 'True'),
# Install Variables # Install Variables
('PREFIX', 'The install path "prefix"', '/usr/local'), ('PREFIX', 'The install path "prefix"', '/usr/local'),
@ -163,92 +153,85 @@ opts.AddVariables(
ListVariable('BINDINGS','Language bindings to build','all',['python']), ListVariable('BINDINGS','Language bindings to build','all',['python']),
EnumVariable('THREADING','Set threading support','multi', ['multi','single']), EnumVariable('THREADING','Set threading support','multi', ['multi','single']),
EnumVariable('XMLPARSER','Set xml parser ','libxml2', ['tinyxml','spirit','libxml2']), EnumVariable('XMLPARSER','Set xml parser ','libxml2', ['tinyxml','spirit','libxml2']),
('JOBS', 'Set the number of parallel compilations', "1", lambda key, value, env: int(value), int),
) )
# Construct the SCons build environment as a union of the users environment and the `opts` # variables to pickle after successful configure step
# these include all scons core variables as well as custom
# env variables needed in Sconscript files
pickle_store = [# Scons internal variables
'CC',
'CXX',
'CCFLAGS',
'CPPDEFINES',
'CPPFLAGS',
'CPPPATH',
'CXXFLAGS',
'LIBPATH',
'LIBS',
'LINKFLAGS',
# Mapnik's SConstruct build variables
'ABI_VERSION',
'PLATFORM',
'BOOST_ABI',
'BOOST_APPEND',
'LIBDIR_SCHEMA',
'REQUESTED_PLUGINS',
'SUNCC',
'PYTHON_VERSION',
'PYTHON_INCLUDES',
'PYTHON_INSTALL_LOCATION',
]
# Add all other user configurable options to pickle pickle_store
# We add here more options than are needed for the build stage
# but helpful so that scons -h shows the exact cached options
for opt in opts.options:
if opt.key not in pickle_store:
pickle_store.append(opt.key)
# Build up base environment, then reinitiate based on user customizations. # Method of adding configure behavoir to Scons adapted from:
# http://freeorion.svn.sourceforge.net/svnroot/freeorion/trunk/FreeOrion/SConstruct
preconfigured = False
force_configure = False
command_line_args = sys.argv[1:]
# This method seems un-pythonic and a bit dodgy, but it works. if 'configure' in command_line_args:
# It seems that creating an alternative environment that loads user options force_configure = True
# and then updating the main env using those options is the more logical route elif ('-h' in command_line_args) or ('--help' in command_line_args):
# But my testing indicate that something like: preconfigured = True # this is just to ensure config gets skipped when help is requested
# >>>user_opts = Variables([env['CONFIG']])
# >>> user_opts.Update(env)
# does not seem to work as expected.
# Create clean environment with only the options within this SConstruct file if not force_configure:
color_print(4,'Constructing build environment...') if os.path.exists(SCONS_CONFIGURE_CACHE):
env = Environment(options=opts) try:
pickled_environment = open(SCONS_CONFIGURE_CACHE, 'r')
# Unless USE_USER_ENV=False, recreate the base environment pickled_values = pickle.load(pickled_environment)
# using all variables (for example) in the shell users .profile or /etc/profile for key, value in pickled_values.items():
if env['USE_USER_ENV']: #if key == 'BINDINGS': import pdb;pdb.set_trace()
env = Environment(ENV=os.environ,options=opts) env[key] = value
preconfigured = True
if ('-h' not in command_line_args) and ('--help' not in command_line_args):
color_print(4,'Using previous successful configuration...')
color_print(4,'Re-configure by running "python scons/scons.py configure".')
except:
# unpickling failed, so reconfigure as fallback
preconfigured = False
else: else:
# Default has been overridden, so print a warning preconfigured = False
color_print(4,'USER_USER_ENV specified as false, will not inherit variables from user environment...')
# Unless USE_USER_ENV=False, recreate the base environment
# using all variables (for example) in the shell users .profile or /etc/profile
user_conf = env['CONFIG']
if env['USE_CONFIG']: if preconfigured:
if not user_conf.endswith('.py'): if opts.args:
color_print(1,'SCons CONFIG file specified is not a python file, will not be read...') color_print(1,'Arguments ignored, please run "configure" with arguments to customize build')
Exit(0)
else: else:
# Accept more than one file as comma-delimited list # if we are not preconfigured update the environment based on commandline options
user_confs = user_conf.split(',') opts.Update(env)
# If they exist add the files to the existing `opts`
for conf in user_confs:
if os.path.exists(conf):
opts.files.append(conf)
color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf)
elif not conf == SCONS_LOCAL_CONFIG:
# if default missing, no worries
# but if the default is overridden and the file is not found, give warning
color_print(1,"SCons CONFIG not found: '%s'" % conf)
# Recreate the base environment using modified `opts`
env = Environment(ENV=os.environ,options=opts)
env['USE_CONFIG'] = True
else:
color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...')
env['MISSING_DEPS'] = []
env['SKIPPED_DEPS'] = []
env['LIBDIR_SCHEMA'] = LIBDIR_SCHEMA
env['PLATFORM'] = platform.uname()[0]
if env['DEBUG']:
mode = 'debug mode'
else:
mode = 'release mode'
color_print (4,"Building on %s in *%s*..." % (env['PLATFORM'],mode))
Help(opts.GenerateHelpText(env)) Help(opts.GenerateHelpText(env))
if env['SCONS_CACHE']:
# caching is 'auto' by default in SCons
# But let's also cache implicit deps...
SetOption('implicit_cache', 1)
# uncomment for more speed improvements
#env.Decider('MD5-timestamp')
#SetOption('max_drift', 1)
else: #### Custom Configure Checks ###
# Set the cache mode to 'force' unless requested, avoiding hidden caching of Scons 'opts' in '.sconsign.dblite'
# This allows for a SCONS_LOCAL_CONFIG, if present, to be used as the primary means of storing paths to successful build dependencies
from SCons.SConf import SetCacheMode
SetCacheMode('force')
thread_suffix = 'mt'
if env['PLATFORM'] == 'FreeBSD':
thread_suffix = ''
env.Append(LIBS = 'pthread')
def CheckPKGConfig(context, version): def CheckPKGConfig(context, version):
context.Message( 'Checking for pkg-config... ' ) context.Message( 'Checking for pkg-config... ' )
@ -333,32 +316,99 @@ int main()
major_version = version / 100000 major_version = version / 100000
return [major_version,minor_version,patch_level] return [major_version,minor_version,patch_level]
conf = Configure(env, custom_tests = { 'CheckPKGConfig' : CheckPKGConfig, conf_tests = { 'CheckPKGConfig' : CheckPKGConfig,
'CheckPKG' : CheckPKG, 'CheckPKG' : CheckPKG,
'CheckBoost' : CheckBoost, 'CheckBoost' : CheckBoost,
'GetBoostLibVersion' : GetBoostLibVersion, 'GetBoostLibVersion' : GetBoostLibVersion,
'GetMapnikLibVersion' : GetMapnikLibVersion }) 'GetMapnikLibVersion' : GetMapnikLibVersion
}
if not env.GetOption('clean'):
if not preconfigured:
color_print(4,'Configuring build environment...')
if env['USE_CONFIG']:
if not env['CONFIG'].endswith('.py'):
color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
else:
# Accept more than one file as comma-delimited list
user_confs = env['CONFIG'].split(',')
# If they exist add the files to the existing `opts`
for conf in user_confs:
if os.path.exists(conf):
opts.files.append(conf)
color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf)
optfile = file(conf)
print optfile.read().replace("\n", " ").replace("'","").replace(" = ","=")
optfile.close()
elif not conf == SCONS_LOCAL_CONFIG:
# if default missing, no worries
# but if the default is overridden and the file is not found, give warning
color_print(1,"SCons CONFIG not found: '%s'" % conf)
# Recreate the base environment using modified `opts`
env = Environment(ENV=os.environ,options=opts)
env['USE_CONFIG'] = True
else:
color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...')
conf = Configure(env, custom_tests = conf_tests)
if env['DEBUG']:
mode = 'debug mode'
else:
mode = 'release mode'
color_print (4,"Configuring on %s in *%s*..." % (env['PLATFORM'],mode))
env['MISSING_DEPS'] = []
env['SKIPPED_DEPS'] = []
env['LIBDIR_SCHEMA'] = LIBDIR_SCHEMA
env['PLATFORM'] = platform.uname()[0]
if env['FAST']:
# caching is 'auto' by default in SCons
# But let's also cache implicit deps...
EnsureSConsVersion(0,98)
SetOption('implicit_cache', 1)
env.Decider('MD5-timestamp')
SetOption('max_drift', 1)
else:
# Set the cache mode to 'force' unless requested, avoiding hidden caching of Scons 'opts' in '.sconsign.dblite'
# This allows for a SCONS_LOCAL_CONFIG, if present, to be used as the primary means of storing paths to successful build dependencies
SetCacheMode('force')
if env['JOBS'] > 1:
SetOption("num_jobs", env['JOBS'])
thread_suffix = 'mt'
if env['PLATFORM'] == 'FreeBSD':
thread_suffix = ''
env.Append(LIBS = 'pthread')
#### Libraries and headers dependency checks #### #### Libraries and headers dependency checks ####
# Libraries and headers dependency checks # Set up for libraries and headers dependency checks
env['CPPPATH'] = ['#include', '#'] env['CPPPATH'] = ['#include', '#']
env['LIBPATH'] = ['#src'] env['LIBPATH'] = ['#src']
# Solaris & Sun Studio settings (the `SUNCC` flag will only be # Solaris & Sun Studio settings (the `SUNCC` flag will only be
# set if the `CXX` option begins with `CC`) # set if the `CXX` option begins with `CC`)
SOLARIS = env['PLATFORM'] == 'SunOS' SOLARIS = env['PLATFORM'] == 'SunOS'
SUNCC = SOLARIS and env['CXX'].startswith('CC') env['SUNCC'] = SOLARIS and env['CXX'].startswith('CC')
# For Solaris include paths (e.g., for freetype2, ltdl, etc.). # For Solaris include paths (e.g., for freetype2, ltdl, etc.).
if SOLARIS: if SOLARIS:
blastwave_dir = '/opt/csw/%s' blastwave_dir = '/opt/csw/%s'
uniq_add(env, 'CPPPATH', blastwave_dir % 'include') env.AppendUnique(CPPPATH = blastwave_dir % 'include')
uniq_add(env, 'LIBPATH', blastwave_dir % LIBDIR_SCHEMA) env.AppendUnique(LIBPATH = blastwave_dir % LIBDIR_SCHEMA)
# If the Sun Studio C++ compiler (`CC`) is used instead of GCC. # If the Sun Studio C++ compiler (`CC`) is used instead of GCC.
if SUNCC: if env['SUNCC']:
env['CC'] = 'cc' env['CC'] = 'cc'
# To be compatible w/Boost everything needs to be compiled # To be compatible w/Boost everything needs to be compiled
# with the `-library=stlport4` flag (which needs to come # with the `-library=stlport4` flag (which needs to come
@ -370,7 +420,10 @@ if SUNCC:
# Adding the required prerequisite library directories to the include path for # Adding the required prerequisite library directories to the include path for
# compiling and the library path for linking, respectively. # compiling and the library path for linking, respectively.
for required in ('BOOST', 'PNG', 'JPEG', 'TIFF','PROJ'): for required in ('BOOST', 'PNG', 'JPEG', 'TIFF','PROJ'):
add_paths(required) inc_path = env['%s_INCLUDES' % required]
lib_path = env['%s_LIBS' % required]
env.AppendUnique(CPPPATH = inc_path)
env.AppendUnique(LIBPATH = lib_path)
try: try:
env.ParseConfig(env['FREETYPE_CONFIG'] + ' --libs --cflags') env.ParseConfig(env['FREETYPE_CONFIG'] + ' --libs --cflags')
@ -387,25 +440,22 @@ elif env['XMLPARSER'] == 'libxml2':
except OSError: except OSError:
env['MISSING_DEPS'].append(env['XML2_CONFIG']) env['MISSING_DEPS'].append(env['XML2_CONFIG'])
C_LIBSHEADERS = [
['m', 'math.h', True],
['ltdl', 'ltdl.h', True],
['png', 'png.h', True],
['tiff', 'tiff.h', True],
['z', 'zlib.h', True],
['jpeg', ['stdio.h', 'jpeglib.h'], True],
['proj', 'proj_api.h', True],
]
if env['CAIRO'] and conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('cairomm-1.0'): if env['CAIRO'] and conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('cairomm-1.0'):
env.ParseConfig('pkg-config --libs --cflags cairomm-1.0') env.ParseConfig('pkg-config --libs --cflags cairomm-1.0')
env.Append(CXXFLAGS = '-DHAVE_CAIRO') env.Append(CXXFLAGS = '-DHAVE_CAIRO')
else: else:
env['SKIPPED_DEPS'].extend(['cairo','cairomm','pycairo']) env['SKIPPED_DEPS'].extend(['cairo','cairomm'])
CXX_LIBSHEADERS = [ LIBSHEADERS = [
['icuuc','unicode/unistr.h',True], ['m', 'math.h', True,'C'],
['icudata','unicode/utypes.h' , True], ['ltdl', 'ltdl.h', True,'C'],
['png', 'png.h', True,'C'],
['tiff', 'tiff.h', True,'C'],
['z', 'zlib.h', True,'C'],
['jpeg', ['stdio.h', 'jpeglib.h'], True,'C'],
['proj', 'proj_api.h', True,'C'],
['icuuc','unicode/unistr.h',True,'C++'],
['icudata','unicode/utypes.h' , True,'C++'],
] ]
# get boost version from boost headers rather than previous approach # get boost version from boost headers rather than previous approach
@ -434,21 +484,10 @@ if env['THREADING'] == 'multi':
else: else:
thread_flag = '' thread_flag = ''
for libinfo in C_LIBSHEADERS: for libinfo in LIBSHEADERS:
if not conf.CheckLibWithHeader(libinfo[0], libinfo[1], 'C'): if not conf.CheckLibWithHeader(libinfo[0], libinfo[1], libinfo[3]):
if libinfo[0] == 'pq': if libinfo[0] == 'pq':
libinfo[0] = 'pq (postgres/postgis)' libinfo[0] = 'pq (postgres/postgis)'
if libinfo[2]:
color_print (1,'Could not find required header or shared library for %s' % libinfo[0])
env['MISSING_DEPS'].append(libinfo[0])
else:
color_print(4,'Could not find optional header or shared library for %s' % libinfo[0])
env['SKIPPED_DEPS'].append(libinfo[0])
for libinfo in CXX_LIBSHEADERS:
if not conf.CheckLibWithHeader(libinfo[0], libinfo[1], 'C++'):
if libinfo[0] == 'gdal' and libinfo[1] == 'ogrsf_frmts.h': if libinfo[0] == 'gdal' and libinfo[1] == 'ogrsf_frmts.h':
libinfo[0] = 'ogr' libinfo[0] = 'ogr'
if libinfo[2]: if libinfo[2]:
@ -465,7 +504,6 @@ for libinfo in CXX_LIBSHEADERS:
else: else:
print 'gdal raster support... enabled' print 'gdal raster support... enabled'
# Creating BOOST_APPEND according to the Boost library naming order, # Creating BOOST_APPEND according to the Boost library naming order,
# which goes <toolset>-<threading>-<abi>-<version>. See: # which goes <toolset>-<threading>-<abi>-<version>. See:
# http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html#library-naming # http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html#library-naming
@ -500,10 +538,10 @@ for count, libinfo in enumerate(BOOST_LIBSHEADERS):
color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0]) color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0])
env['SKIPPED_DEPS'].append('boost ' + libinfo[0]) env['SKIPPED_DEPS'].append('boost ' + libinfo[0])
requested_plugins = [ driver.strip() for driver in Split(env['INPUT_PLUGINS'])] env['REQUESTED_PLUGINS'] = [ driver.strip() for driver in Split(env['INPUT_PLUGINS'])]
color_print(4,'Checking for requested plugins dependencies...') color_print(4,'Checking for requested plugins dependencies...')
for plugin in requested_plugins: for plugin in env['REQUESTED_PLUGINS']:
details = PLUGINS[plugin] details = PLUGINS[plugin]
if details['path'] and details['lib'] and details['inc']: if details['path'] and details['lib'] and details['inc']:
backup = env.Clone().Dictionary() backup = env.Clone().Dictionary()
@ -536,6 +574,44 @@ if 'python' in env['BINDINGS']:
color_print(1,'Could not find required header files for boost python') color_print(1,'Could not find required header files for boost python')
env['MISSING_DEPS'].append('boost python') env['MISSING_DEPS'].append('boost python')
if env['CAIRO'] and conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'):
env.ParseConfig('pkg-config --cflags pycairo')
env.Append(CXXFLAGS = '-DHAVE_PYCAIRO')
else:
env['SKIPPED_DEPS'].extend(['pycairo'])
#### End Config Stage for Required Dependencies ####
if env['MISSING_DEPS']:
# if required dependencies are missing, print warnings and then let SCons finish without building or saving local config
color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join(env['MISSING_DEPS']))
color_print(1,"\nSee the 'config.log' for details on possible problems.")
if env['SKIPPED_DEPS']:
color_print(4,'\nAlso, these optional dependencies were not found:\n - %s' % '\n - '.join(env['SKIPPED_DEPS']))
color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG)
color_print(4," ie. $ python scons/scons.py BOOST_INCLUDES=/usr/local/include/boost-1_37 BOOST_LIBS=/usr/local/lib")
color_print(4, "\nOnce all required dependencies are found a local '%s' will be saved and then install:" % SCONS_LOCAL_CONFIG)
color_print(4," $ sudo python scons/scons.py install")
color_print(4,"\nTo view available path variables:\n $ python scons/scons.py --help or -h")
color_print(4,'\nTo view overall SCons help options:\n $ python scons/scons.py --help-options or -H\n')
color_print(4,'More info: http://trac.mapnik.org/wiki/MapnikInstallation')
Exit(0)
else:
# Save the custom variables in a SCONS_LOCAL_CONFIG
# that will be reloaded to allow for `install` without re-specifying custom variables
color_print(4,"\nAll Required dependencies found!\n")
if env['USE_CONFIG']:
if os.path.exists(SCONS_LOCAL_CONFIG):
action = 'Overwriting and re-saving'
os.unlink(SCONS_LOCAL_CONFIG)
else:
action = 'Saving new'
color_print(4,"%s file '%s'..." % (action,SCONS_LOCAL_CONFIG))
color_print(4,"Will hold custom path variables from commandline and python config file(s)...")
opts.Save(SCONS_LOCAL_CONFIG,env)
else:
color_print(4,"Did not use user config file, no custom path variables will be saved...")
# fetch the mapnik version header in order to set the # fetch the mapnik version header in order to set the
# ABI version used to build libmapnik.so on linux in src/SConscript # ABI version used to build libmapnik.so on linux in src/SConscript
abi = conf.GetMapnikLibVersion() abi = conf.GetMapnikLibVersion()
@ -546,141 +622,6 @@ if not abi:
else: else:
env['ABI_VERSION'] = abi env['ABI_VERSION'] = abi
#### End Config Stage ####
if env['MISSING_DEPS']:
# if required dependencies are missing, print warnings and then let SCons finish without building or saving local config
color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join(env['MISSING_DEPS']))
color_print(1,"\nSee the 'config.log' for details on possible problems.")
if env['SKIPPED_DEPS']:
color_print(4,'\nAlso, these optional dependencies were not found:\n - %s' % '\n - '.join(env['SKIPPED_DEPS']))
color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG)
color_print(4," ie. $ python scons/scons.py BOOST_INCLUDES=/usr/local/include/boost-1_37 BOOST_LIBS=/usr/local/lib")
color_print(4, "\nOnce all required dependencies are found a local '%s' will be saved and then install:" % SCONS_LOCAL_CONFIG)
color_print(4," $ sudo python scons/scons.py install")
color_print(4,"\nTo view available path variables:\n $ python scons/scons.py --help or -h")
color_print(4,'\nTo view overall SCons help options:\n $ python scons/scons.py --help-options or -H\n')
color_print(4,'More info: http://trac.mapnik.org/wiki/MapnikInstallation')
# Need some way to exit cleanly here...
# calling Exit() does not work because that will abort the users ability to get help
env = conf.Finish()
#Exit()
else:
# Save the custom variables in a SCONS_LOCAL_CONFIG that will be reloaded to allow for `install` without re-specifying custom variables
color_print(4,"All Required dependencies found!")
if env['USE_CONFIG']:
if os.path.exists(SCONS_LOCAL_CONFIG):
action = 'Overwriting and re-saving'
os.unlink(SCONS_LOCAL_CONFIG)
# Serialize all user customizations into local config file
else:
action = 'Saving new'
color_print(4,"%s file '%s', to hold successful path variables from commandline and python config file(s)..." % (action,SCONS_LOCAL_CONFIG))
opts.Save(SCONS_LOCAL_CONFIG,env)
else:
color_print(4,"Did not use user config file(s), therefore no local configurations will be saved...")
Export('env')
Export('conf')
bindings = [ binding.strip() for binding in Split(env['BINDINGS'])]
#### Build instructions & settings ####
# Build agg first, doesn't need anything special
if env['INTERNAL_LIBAGG']:
SConscript('agg/SConscript')
# Build the core library
SConscript('src/SConscript')
# Build shapeindex and remove its dependency from the LIBS
if 'boost_program_options%s' % env['BOOST_APPEND'] in env['LIBS']:
SConscript('utils/shapeindex/SConscript')
env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND'])
else :
color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' won't be available")
# Build the requested and able-to-be-compiled input plug-ins
if requested_plugins:
color_print(4,'Requested plugins to be built...',newline=False)
for plugin in requested_plugins:
details = PLUGINS[plugin]
if details['lib'] in env['LIBS']:
SConscript('plugins/input/%s/SConscript' % plugin)
env['LIBS'].remove(details['lib'])
color_print(4,'%s' % plugin,newline=False)
elif not details['lib']:
# build internal shape and raster plugins
SConscript('plugins/input/%s/SConscript' % plugin)
color_print(4,'%s' % plugin,newline=False)
if requested_plugins:
print
# Build the Python bindings.
if 'python' in env['BINDINGS']:
if not os.access(env['PYTHON'], os.X_OK):
color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON'])
Exit(1)
sys_prefix = "%s -c 'import sys; print sys.prefix'" % env['PYTHON']
env['PYTHON_SYS_PREFIX'] = call(sys_prefix)
# Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location
site_packages = "%s -c 'from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)'" % env['PYTHON']
env['PYTHON_SITE_PACKAGES'] = call(site_packages)
sys_version = "%s -c 'from distutils.sysconfig import get_python_version; print get_python_version()'" % env['PYTHON']
env['PYTHON_VERSION'] = call(sys_version)
py_includes = "%s -c 'from distutils.sysconfig import get_python_inc; print get_python_inc()'" % env['PYTHON']
env['PYTHON_INCLUDES'] = call(py_includes)
# if user-requested custom prefix fall back to manual concatenation for building subdirectories
py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/'
if env['PYTHON_PREFIX']:
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + '/' + env['PYTHON_PREFIX'] + '/' + py_relative_install
# TODO...
# When the env['PREFIX'] is changed should that
# also affect/override where to install python?
# Perhaps env['PREFIX'] should be None by default
# while 'usr/local' would be overridden in the code if
# env['PREFIX'] is set?
# This way we could more easily check for a 'custom' PREFIX
# code here but disabled...
#elif not env['PREFIX'] == '/usr/local':
# env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + '/' + env['PREFIX'] + '/' + py_relative_install
else:
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + '/' + env['PYTHON_SITE_PACKAGES']
majver, minver = env['PYTHON_VERSION'].split('.')
if (int(majver), int(minver)) < (2, 2):
color_print(1,"Python version 2.2 or greater required")
Exit(1)
color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION'])
color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX']))
color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION']))
SConscript('bindings/python/SConscript')
env = conf.Finish()
# Common C++ flags. # Common C++ flags.
if env['THREADING'] == 'multi' : if env['THREADING'] == 'multi' :
common_cxx_flags = '-D%s -DBOOST_SPIRIT_THREADSAFE -DMAPNIK_THREADSAFE ' % env['PLATFORM'].upper() common_cxx_flags = '-D%s -DBOOST_SPIRIT_THREADSAFE -DMAPNIK_THREADSAFE ' % env['PLATFORM'].upper()
@ -705,7 +646,7 @@ else:
# Customizing the C++ compiler flags depending on: # Customizing the C++ compiler flags depending on:
# (1) the C++ compiler used; and # (1) the C++ compiler used; and
# (2) whether debug binaries are requested. # (2) whether debug binaries are requested.
if SUNCC: if env['SUNCC']:
if env['DEBUG']: if env['DEBUG']:
env.Append(CXXFLAGS = common_cxx_flags + debug_flags) env.Append(CXXFLAGS = common_cxx_flags + debug_flags)
else: else:
@ -719,5 +660,95 @@ else:
else: else:
env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline %s' % (env['OPTIMIZATION'],ndebug_flags)) env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline %s' % (env['OPTIMIZATION'],ndebug_flags))
if 'python' in env['BINDINGS']:
if not os.access(env['PYTHON'], os.X_OK):
color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON'])
Exit(1)
sys_prefix = "%s -c 'import sys; print sys.prefix'" % env['PYTHON']
env['PYTHON_SYS_PREFIX'] = call(sys_prefix)
# Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location
site_packages = "%s -c 'from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)'" % env['PYTHON']
env['PYTHON_SITE_PACKAGES'] = call(site_packages)
sys_version = "%s -c 'from distutils.sysconfig import get_python_version; print get_python_version()'" % env['PYTHON']
env['PYTHON_VERSION'] = call(sys_version)
py_includes = "%s -c 'from distutils.sysconfig import get_python_inc; print get_python_inc()'" % env['PYTHON']
env['PYTHON_INCLUDES'] = call(py_includes)
# if user-requested custom prefix fall back to manual concatenation for building subdirectories
py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/'
if env['PYTHON_PREFIX']:
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + '/' + env['PYTHON_PREFIX'] + '/' + py_relative_install
else:
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + '/' + env['PYTHON_SITE_PACKAGES']
majver, minver = env['PYTHON_VERSION'].split('.')
if (int(majver), int(minver)) < (2, 2):
color_print(1,"Python version 2.2 or greater required")
Exit(1)
color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION'])
color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX']))
color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION']))
# finish config stage and pickle results
env = conf.Finish()
env_cache = open(SCONS_CONFIGURE_CACHE, 'w')
pickle_dict = {}
for i in pickle_store:
pickle_dict[i] = env.get(i)
pickle.dump(pickle_dict,env_cache)
env_cache.close()
# fix up permissions on pickled options
try:
os.chmod(SCONS_CONFIGURE_CACHE,0666)
except: pass
# clean up test build targets
if not env['FAST']:
try:
for test in glob('%s/*' % SCONF_TEMP_DIR):
os.unlink(test)
except: pass
if 'configure' in command_line_args:
Exit(0)
#### Builds ####
# export env so it is available in Sconscript files
Export('env')
# Build agg first, doesn't need anything special
if env['INTERNAL_LIBAGG']:
SConscript('agg/SConscript')
# Build the core library
SConscript('src/SConscript')
# Build shapeindex and remove its dependency from the LIBS
if 'boost_program_options%s' % env['BOOST_APPEND'] in env['LIBS']:
SConscript('utils/shapeindex/SConscript')
env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND'])
else :
color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' won't be available")
# Build the requested and able-to-be-compiled input plug-ins
for plugin in env['REQUESTED_PLUGINS']:
details = PLUGINS[plugin]
if details['lib'] in env['LIBS']:
SConscript('plugins/input/%s/SConscript' % plugin)
env['LIBS'].remove(details['lib'])
elif not details['lib']:
# build internal shape and raster plugins
SConscript('plugins/input/%s/SConscript' % plugin)
# Build the Python bindings
if 'python' in env['BINDINGS']:
SConscript('bindings/python/SConscript')
# Configure fonts and if requested install the bundled DejaVu fonts
SConscript('fonts/SConscript') SConscript('fonts/SConscript')

View file

@ -24,15 +24,10 @@ import re
import os import os
Import('env') Import('env')
Import('conf')
prefix = env['PREFIX'] prefix = env['PREFIX']
install_prefix = env['DESTDIR'] + '/' + prefix install_prefix = env['DESTDIR'] + '/' + prefix
if env['CAIRO'] and conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'):
env.ParseConfig('pkg-config --cflags pycairo')
env.Append(CXXFLAGS = '-DHAVE_PYCAIRO');
linkflags = '' linkflags = ''
libraries = ['mapnik','png','jpeg'] libraries = ['mapnik','png','jpeg']
libraries.append('boost_python%s' % env['BOOST_APPEND']) libraries.append('boost_python%s' % env['BOOST_APPEND'])
@ -72,6 +67,10 @@ exp = r"%s{2,}" % os.sep
mapnik_lib_path = re.sub(exp,os.sep, prefix + '/' + env['LIBDIR_SCHEMA'] + env['LIB_DIR_NAME']) mapnik_lib_path = re.sub(exp,os.sep, prefix + '/' + env['LIBDIR_SCHEMA'] + env['LIB_DIR_NAME'])
file('mapnik/paths.py','w').write(paths % (mapnik_lib_path)) file('mapnik/paths.py','w').write(paths % (mapnik_lib_path))
try:
os.chmod('mapnik/paths.py',0666)
except: pass
# install the core mapnik python files, including '__init__.py' and 'paths.py' # install the core mapnik python files, including '__init__.py' and 'paths.py'
init_files = glob.glob('mapnik/*.py') init_files = glob.glob('mapnik/*.py')
init_module = env.Install(env['PYTHON_INSTALL_LOCATION'] + '/mapnik', init_files) init_module = env.Install(env['PYTHON_INSTALL_LOCATION'] + '/mapnik', init_files)