@@ -20,30 +20,36 @@ SCons construction environment can be customized in sconscript.local script.
2020"""
2121
2222import os
23+ from os .path import join as pjoin
2324import re
2425import subprocess
2526import platform
2627
28+
2729def subdictionary (d , keyset ):
2830 return dict (kv for kv in d .items () if kv [0 ] in keyset )
2931
32+
3033def getsyspaths (* names ):
3134 pall = sum ((os .environ .get (n , '' ).split (os .pathsep ) for n in names ), [])
3235 rv = [p for p in pall if os .path .exists (p )]
3336 return rv
3437
38+
3539def pyoutput (cmd ):
3640 proc = subprocess .Popen ([env ['python' ], '-c' , cmd ],
3741 stdout = subprocess .PIPE ,
3842 universal_newlines = True )
3943 out = proc .communicate ()[0 ]
4044 return out .rstrip ()
4145
46+
4247def pyconfigvar (name ):
4348 cmd = ('from distutils.sysconfig import get_config_var\n '
4449 'print(get_config_var(%r))\n ' ) % name
4550 return pyoutput (cmd )
4651
52+
4753# copy system environment variables related to compilation
4854DefaultEnvironment (ENV = subdictionary (os .environ , '''
4955 PATH PYTHONPATH GIT_DIR
@@ -53,7 +59,7 @@ DefaultEnvironment(ENV=subdictionary(os.environ, '''
5359 _PYTHON_SYSCONFIGDATA_NAME
5460 _CONDA_PYTHON_SYSCONFIGDATA_NAME
5561 ''' .split ())
56- )
62+ )
5763
5864# Create construction environment
5965env = DefaultEnvironment ().Clone ()
@@ -64,18 +70,35 @@ env.EnsureSConsVersion(0, 98)
6470# Customizable compile variables
6571vars = Variables ('sconsvars.py' )
6672
67- vars .Add (PathVariable ('prefix' ,
68- 'installation prefix directory' , None ))
73+ # Set PREFIX for installation and linking
74+ # TODO: also amend paths when VIRTUAL_ENV variable exists ?
75+ if 'PREFIX' in os .environ :
76+ # building with a set prefix
77+ vars .Add (PathVariable (
78+ 'prefix' ,
79+ 'installation prefix directory' ,
80+ os .environ ['PREFIX' ]))
81+ elif 'CONDA_PREFIX' in os .environ :
82+ # building for a conda environment
83+ vars .Add (PathVariable (
84+ 'prefix' ,
85+ 'installation prefix directory' ,
86+ os .environ ['CONDA_PREFIX' ]))
87+ else :
88+ vars .Add (PathVariable ('prefix' ,
89+ 'installation prefix directory' , None ))
90+ vars .Update (env )
91+
6992vars .Add (EnumVariable ('build' ,
70- 'compiler settings' , 'fast' ,
71- allowed_values = ('debug' , 'fast' )))
93+ 'compiler settings' , 'fast' ,
94+ allowed_values = ('debug' , 'fast' )))
7295vars .Add (EnumVariable ('tool' ,
73- 'C++ compiler toolkit to be used' , 'default' ,
74- allowed_values = ('default' , 'intelc' )))
96+ 'C++ compiler toolkit to be used' , 'default' ,
97+ allowed_values = ('default' , 'intelc' , 'clang' , 'clangxx ' )))
7598vars .Add (BoolVariable ('profile' ,
76- 'build with profiling information' , False ))
99+ 'build with profiling information' , False ))
77100vars .Add ('python' ,
78- 'Python executable to use for installation.' , 'python' )
101+ 'Python executable to use for installation.' , 'python' )
79102vars .Update (env )
80103env .Help (MY_SCONS_HELP % vars .GenerateHelpText (env ))
81104
@@ -89,78 +112,120 @@ if env['tool'] == 'intelc':
89112 env .Tool ('intelc' , topdir = icpc [:icpc .rfind ('/bin' )])
90113
91114# Figure out compilation switches, filter away C-related items.
92- good_python_flag = lambda n : (
93- not isinstance (n , str ) or
94- not re .match (r'(-g|-Wstrict-prototypes|-O\d|-fPIC)$' , n ))
115+ good_python_flag = lambda n : (
116+ not isinstance (n , str ) or
117+ not re .match (r'(-g|-Wstrict-prototypes|-O\d|-fPIC)$' , n ))
95118
96119# Determine python-config script name.
97- pyversion = pyoutput ('import sys; print("%i.%i" % sys.version_info[:2])' )
98- pycfgname = 'python%s-config' % (pyversion if pyversion [0 ] == '3' else '' )
99- # realpath gets the real path if exec is a link (e.g. in a python environment)
100- xpython = os .path .realpath (env .WhereIs (env ['python' ]))
101- pybindir = os .path .dirname (xpython )
102- pythonconfig = os .path .join (pybindir , pycfgname )
103-
104- # Verify python-config comes from the same path as the target python.
105- xpythonconfig = env .WhereIs (pythonconfig )
106- if os .path .dirname (xpython ) != os .path .dirname (xpythonconfig ):
107- print ("Inconsistent paths of %r and %r" % (xpython , xpythonconfig ))
108- Exit (1 )
109- # Process the python-config flags here.
110- env .ParseConfig (pythonconfig + " --cflags" )
111- env .Replace (CCFLAGS = [f for f in env ['CCFLAGS' ] if good_python_flag (f )])
112- env .Replace (CPPDEFINES = 'BOOST_ERROR_CODE_HEADER_ONLY' )
113- # the CPPPATH directories are checked by scons dependency scanner
114- cpppath = getsyspaths ('CPLUS_INCLUDE_PATH' , 'CPATH' )
115- env .AppendUnique (CPPPATH = cpppath )
116- # Insert LIBRARY_PATH explicitly because some compilers
117- # ignore it in the system environment.
118- env .PrependUnique (LIBPATH = getsyspaths ('LIBRARY_PATH' ))
119- # Add shared libraries.
120- # Note: ObjCryst and boost_python are added from SConscript.configure.
121-
122- fast_linkflags = ['-s' ]
123- fast_shlinkflags = pyconfigvar ('LDSHARED' ).split ()[1 :]
124-
125- # Specify minimum C++ standard. Allow later standard from sconscript.local.
126- # In case of multiple `-std` options the last option holds.
127- env .PrependUnique (CXXFLAGS = '-std=c++11' , delete_existing = 1 )
128-
129- # Need this to avoid missing symbol with boost<1.66
130- env .PrependUnique (CXXFLAGS = ['-DBOOST_ERROR_CODE_HEADER_ONLY' ])
131-
132- # Platform specific intricacies.
133- if env ['PLATFORM' ] == 'darwin' :
134- darwin_shlinkflags = [n for n in env ['SHLINKFLAGS' ]
135- if n != '-dynamiclib' ]
136- env .Replace (SHLINKFLAGS = darwin_shlinkflags )
137- env .AppendUnique (SHLINKFLAGS = ['-bundle' ])
138- env .AppendUnique (SHLINKFLAGS = ['-undefined' , 'dynamic_lookup' ])
139- fast_linkflags [:] = []
140-
141- # Compiler specific options
142- if icpc :
143- # options for Intel C++ compiler on hpc dev-intel07
144- env .AppendUnique (CCFLAGS = ['-w1' , '-fp-model' , 'precise' ])
145- env .PrependUnique (LIBS = ['imf' ])
146- fast_optimflags = ['-fast' , '-no-ipo' ]
120+ if 'PY_VER' in os .environ :
121+ pyversion = os .environ ['PY_VER' ]
122+ else :
123+ pyversion = pyoutput ('import sys; print("%i.%i" % sys.version_info[:2])' )
124+
125+ if 'CONDA_BUILD' in os .environ and 'PY_VER' in os .environ :
126+ # Messy: if CONDA_BUILD and PY_VER are in the path, we are building a conda package
127+ # using several environment. Make sure python3.X-config points to the destination
128+ # (host) environment
129+ pythonconfig = pjoin (os .environ ['PREFIX' ], 'bin' , 'python%s-config' % os .environ ['PY_VER' ])
130+ print ("Using $PREFIX and $PY_VER to determine python-config pth: %s" % pythonconfig )
131+ xpython = pjoin (os .environ ['PREFIX' ], 'bin' , 'python' )
132+ pyversion = os .environ ['PY_VER' ]
133+ else :
134+ pycfgname = 'python%s-config' % (pyversion if pyversion [0 ] == '3' else '' )
135+ # realpath gets the real path if exec is a link (e.g. in a python environment)
136+ xpython = os .path .realpath (env .WhereIs (env ['python' ]))
137+ pybindir = os .path .dirname (xpython )
138+ pythonconfig = pjoin (pybindir , pycfgname )
139+
140+ # for k in sorted(os.environ.keys()):
141+ # print(" ", k, os.environ[k])
142+
143+ if platform .system ().lower () == "windows" :
144+ # See https://scons.org/faq.html#Linking_on_Windows_gives_me_an_error
145+ env ['ENV' ]['TMP' ] = os .environ ['TMP' ]
146+ # the CPPPATH directories are checked by scons dependency scanner
147+ cpppath = getsyspaths ('CPLUS_INCLUDE_PATH' , 'CPATH' )
148+ env .AppendUnique (CPPPATH = cpppath )
149+ # Insert LIBRARY_PATH explicitly because some compilers
150+ # ignore it in the system environment.
151+ env .PrependUnique (LIBPATH = getsyspaths ('LIBRARY_PATH' ))
152+ if env ['prefix' ] is not None :
153+ env .Append (CPPPATH = [pjoin (env ['prefix' ], 'include' )])
154+ env .Append (CPPPATH = [pjoin (env ['prefix' ], 'Library' , 'include' )])
155+ # Windows conda library paths are a MESS ('lib', 'libs', 'Library\lib'...)
156+ env .Append (LIBPATH = [pjoin (env ['prefix' ], 'Library' , 'lib' )])
157+ env .Append (LIBPATH = [pjoin (env ['prefix' ], 'libs' )])
158+ # This disable automated versioned named e.g. libboost_date_time-vc142-mt-s-x64-1_73.lib
159+ # so we can use conda-installed libraries
160+ env .AppendUnique (CPPDEFINES = 'BOOST_ALL_NO_LIB' )
161+ # Prevent the generation of an import lib (.lib) in addition to the dll
162+ # env.AppendUnique(no_import_lib=1)
163+ env .PrependUnique (CCFLAGS = ['/Ox' , '/EHsc' , '/MD' ])
164+ env .AppendUnique (CPPDEFINES = {'NDEBUG' : None })
147165else :
148- # g++ options
149- env .AppendUnique (CCFLAGS = ['-Wall' ])
150- fast_optimflags = ['-ffast-math' ]
151-
152- # Configure build variants
153- if env ['build' ] == 'debug' :
154- env .AppendUnique (CCFLAGS = '-g' )
155- elif env ['build' ] == 'fast' :
156- env .AppendUnique (CCFLAGS = ['-O3' ] + fast_optimflags )
157- env .AppendUnique (CPPDEFINES = 'NDEBUG' )
158- env .AppendUnique (LINKFLAGS = fast_linkflags )
159- env .AppendUnique (SHLINKFLAGS = fast_shlinkflags )
160-
161- if env ['profile' ]:
162- env .AppendUnique (CCFLAGS = '-pg' )
163- env .AppendUnique (LINKFLAGS = '-pg' )
166+ if 'CONDA_BUILD' not in os .environ :
167+ # Verify python-config comes from the same path as the target python.
168+ xpythonconfig = env .WhereIs (pythonconfig )
169+ if os .path .dirname (xpython ) != os .path .dirname (xpythonconfig ):
170+ print ("Inconsistent paths of %r and %r" % (xpython , xpythonconfig ))
171+ Exit (1 )
172+ # Process the python-config flags here.
173+ env .ParseConfig (pythonconfig + " --cflags" )
174+ env .Replace (CCFLAGS = [f for f in env ['CCFLAGS' ] if good_python_flag (f )])
175+ env .Replace (CPPDEFINES = 'BOOST_ERROR_CODE_HEADER_ONLY' )
176+ # the CPPPATH directories are checked by scons dependency scanner
177+ cpppath = getsyspaths ('CPLUS_INCLUDE_PATH' , 'CPATH' )
178+ env .AppendUnique (CPPPATH = cpppath )
179+ # Insert LIBRARY_PATH explicitly because some compilers
180+ # ignore it in the system environment.
181+ env .PrependUnique (LIBPATH = getsyspaths ('LIBRARY_PATH' ))
182+ # Add shared libraries.
183+ # Note: ObjCryst and boost_python are added from SConscript.configure.
184+
185+ fast_linkflags = ['-s' ]
186+ fast_shlinkflags = pyconfigvar ('LDSHARED' ).split ()[1 :]
187+
188+ # Specify minimum C++ standard. Allow later standard from sconscript.local.
189+ # In case of multiple `-std` options the last option holds.
190+ env .PrependUnique (CXXFLAGS = '-std=c++11' , delete_existing = 1 )
191+
192+ # Need this to avoid missing symbol with boost<1.66
193+ env .PrependUnique (CXXFLAGS = ['-DBOOST_ERROR_CODE_HEADER_ONLY' ])
194+
195+ # Platform specific intricacies.
196+ if env ['PLATFORM' ] == 'darwin' :
197+ darwin_shlinkflags = [n for n in env ['SHLINKFLAGS' ] if n != '-dynamiclib' ]
198+ env .Replace (SHLINKFLAGS = darwin_shlinkflags )
199+ env .AppendUnique (SHLINKFLAGS = ['-bundle' ])
200+ env .AppendUnique (SHLINKFLAGS = ['-undefined' , 'dynamic_lookup' ])
201+ fast_linkflags [:] = []
202+
203+ # Compiler specific options
204+ if icpc :
205+ # options for Intel C++ compiler on hpc dev-intel07
206+ env .AppendUnique (CCFLAGS = ['-w1' , '-fp-model' , 'precise' ])
207+ env .PrependUnique (LIBS = ['imf' ])
208+ fast_optimflags = ['-fast' , '-no-ipo' ]
209+ else :
210+ # g++ options
211+ env .AppendUnique (CCFLAGS = ['-Wall' , '-fno-strict-aliasing' ])
212+ fast_optimflags = ['-ffast-math' ]
213+
214+ # Configure build variants
215+ if env ['build' ] == 'debug' :
216+ env .AppendUnique (CCFLAGS = '-g' )
217+ elif env ['build' ] == 'fast' :
218+ env .AppendUnique (CCFLAGS = ['-O3' ] + fast_optimflags )
219+ env .AppendUnique (CPPDEFINES = 'NDEBUG' )
220+ env .AppendUnique (LINKFLAGS = fast_linkflags )
221+ env .AppendUnique (SHLINKFLAGS = fast_shlinkflags )
222+
223+ if env ['profile' ]:
224+ env .AppendUnique (CCFLAGS = '-pg' )
225+ env .AppendUnique (LINKFLAGS = '-pg' )
226+
227+ env .Append (CPPPATH = [pjoin (env ['prefix' ], 'include' )])
228+ env .Append (LIBPATH = [pjoin (env ['prefix' ], 'lib' )])
164229
165230builddir = env .Dir ('build/%s-%s' % (env ['build' ], platform .machine ()))
166231
0 commit comments