-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathSConstruct
More file actions
216 lines (173 loc) · 6.71 KB
/
SConstruct
File metadata and controls
216 lines (173 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# This SConstruct is for faster parallel builds.
# Use "setup.py" for normal installation.
MY_SCONS_HELP = """\
SCons rules for compiling and installing pyobjcryst.
Compile and install the pyobjcryst Python extension.
For faster builds, run with parallel jobs, e.g.:
scons -j4
Usage:
scons [target] [var=value]
Targets:
(default) Build the Python extension module `_pyobjcryst.so` (or `.pyd` on Windows)
dev install extension module into `src/pyobjcryst/` (development mode)
test Run pytest on the package with the installed extension
Build configuration variables:
%s
Variables can be also assigned in a user script sconsvars.py.
SCons construction environment can be customized in sconscript.local script.
"""
import os
from os.path import join as pjoin
import re
import sys
def subdictionary(d, keyset):
return dict(kv for kv in d.items() if kv[0] in keyset)
def getsyspaths(*names):
pall = sum((os.environ.get(n, '').split(os.pathsep) for n in names), [])
rv = [p for p in pall if os.path.exists(p)]
return rv
def ftpyflag(flags):
# Figure out compilation switches, filter away fancy flags.
pattern = re.compile(r'^(-g|-Wstrict-prototypes|-O\d|-fPIC)$')
return [f for f in flags if not (isinstance(f, str) and pattern.match(f))]
# copy system environment variables related to compilation
DefaultEnvironment(ENV=subdictionary(os.environ, '''
PATH PYTHONPATH GIT_DIR HOMEPATH HOMEDRIVE
CPATH CPLUS_INCLUDE_PATH LIBRARY_PATH LD_RUN_PATH
LD_LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH
MACOSX_DEPLOYMENT_TARGET LANG
_PYTHON_SYSCONFIGDATA_NAME
_CONDA_PYTHON_SYSCONFIGDATA_NAME
CONDA_PREFIX
'''.split())
)
# Create construction environment
env = DefaultEnvironment().Clone()
# Variables definitions below work only with 0.98 or later.
env.EnsureSConsVersion(0, 98)
# Customizable compile variables
vars = Variables('sconsvars.py')
# Customizable build variables
vars.Add(EnumVariable(
'build',
'compiler settings',
'fast', allowed_values=('debug', 'fast')))
vars.Add(EnumVariable(
'tool',
'C++ compiler toolkit to be used',
'default', allowed_values=('default', 'intelc')))
vars.Add(BoolVariable(
'profile',
'build with profiling information', False))
vars.Update(env)
# Use C++ compiler specified by the 'tool' option.
if env['tool'] == 'intelc':
icpc = env.WhereIs('icpc')
if not icpc:
print("Cannot find the Intel C/C++ compiler 'icpc'.")
Exit(1)
env.Tool('intelc', topdir=icpc[:icpc.rfind('/bin')])
env=env.Clone()
# Default use scons auto found compiler
# Get prefixes, make sure current interpreter is in conda env so thus is the target.
if 'PREFIX' in os.environ:
default_prefix = os.environ['PREFIX']
elif 'CONDA_PREFIX' in os.environ:
default_prefix = os.environ['CONDA_PREFIX']
else:
print("Environment variable PREFIX or CONDA_PREFIX must be set."
" Activate conda environment.")
Exit(1)
vars.Add(PathVariable(
'prefix',
'installation prefix directory',
default_prefix))
vars.Update(env)
# Set paths
if env['PLATFORM'] == "win32":
include_path = pjoin(env['prefix'], 'Library', 'include')
lib_path = pjoin(env['prefix'], 'Library', 'lib')
shared_path = pjoin(env['prefix'], 'Library', 'share')
env.AppendUnique(CPPPATH=[ pjoin(env['prefix'], 'include') ]) # for python headers
env.AppendUnique(LIBPATH=[ pjoin(env['prefix'], 'libs') ]) # for python libs
env['ENV']['TMP'] = os.environ.get('TMP', env['ENV'].get('TMP', ''))
else:
include_path = pjoin(env['prefix'], 'include')
lib_path = pjoin(env['prefix'], 'lib')
shared_path = pjoin(env['prefix'], 'share')
vars.Add(PathVariable(
'includedir',
'installation directory for C++ header files',
include_path,
PathVariable.PathAccept))
vars.Add(PathVariable(
'libdir',
'installation directory for compiled programs',
lib_path,
PathVariable.PathAccept))
vars.Add(PathVariable(
'datadir',
'installation directory for architecture independent data',
shared_path,
PathVariable.PathAccept))
vars.Update(env)
env.AppendUnique(CPPPATH=[include_path])
env.AppendUnique(LIBPATH=[lib_path])
env.Help(MY_SCONS_HELP % vars.GenerateHelpText(env))
# Determine python-config script name.
pyversion = os.environ.get('PY_VER') or f"{sys.version_info.major}.{sys.version_info.minor}"
if env['PLATFORM'] != 'win32':
pythonconfig = pjoin(env['prefix'], 'bin', f'python{pyversion}-config')
xpython = pjoin(env['prefix'], 'bin', 'python')
else:
# use sysconfig on Windows
pythonconfig = None
xpython = pjoin(env['prefix'], 'python.exe')
print(f"Using python-config: {pythonconfig} from {xpython}")
common_cppdefs = ['REAL=double', 'BOOST_ERROR_CODE_HEADER_ONLY']
env.AppendUnique(CPPDEFINES=common_cppdefs)
if env['PLATFORM'] == 'win32':
env.AppendUnique(CPPDEFINES=['BOOST_ALL_NO_LIB'])
env.AppendUnique(CCFLAGS=['/EHsc', '/MD'])
if env['build'] == 'debug':
env.Append(CCFLAGS=['/Zi', '/Od', '/FS'])
env.Append(LINKFLAGS=['/DEBUG'])
elif env['build'] == 'fast':
env.Append(CCFLAGS=['/Ox', '/GL'])
env.Append(LINKFLAGS=['/LTCG', '/OPT:REF', '/OPT:ICF'])
else:
# get python flags from python-config script
# not using sysconfig here because of parsing issues
env.ParseConfig(f"{pythonconfig} --cflags")
env.Replace(CCFLAGS=ftpyflag(env['CCFLAGS']))
env.PrependUnique(CCFLAGS=['-Wextra'])
env.PrependUnique(CXXFLAGS=['-std=c++11'])
if env['tool'] == 'intelc':
# options for Intel C++ compiler on hpc dev-intel07
env.AppendUnique(CCFLAGS=['-w1', '-fp-model', 'precise'])
env.PrependUnique(LIBS=['imf'])
fast_opts = ['-fast', '-no-ipo']
else:
env.AppendUnique(CCFLAGS=['-fno-strict-aliasing'])
fast_opts = ['-ffast-math']
if env['PLATFORM'] == 'darwin':
# macOS bundle
sh = [f for f in env['SHLINKFLAGS'] if f != '-dynamiclib']
env.Replace(SHLINKFLAGS=sh + ['-bundle', '-undefined', 'dynamic_lookup'])
fast_link = [] # no strip on macOS bundles
else:
fast_link = ['-s']
if env['build'] == 'debug':
# Python has NDEBUG defined in release builds.
cppdefs = env.get('CPPDEFINES', [])
env.Replace(CPPDEFINES=[d for d in cppdefs if d != 'NDEBUG'])
env.Append(CCFLAGS=['-g', '-O0'])
elif env['build'] == 'fast':
env.Append(CCFLAGS=['-O3'] + fast_opts)
env.Append(LINKFLAGS=fast_link)
builddir = env.Dir('build/%s-%s' % (env['build'], env['PLATFORM']))
Export('env', 'pyversion')
if os.path.isfile('sconscript.local'):
env.SConscript('sconscript.local')
env.SConscript('src/extensions/SConscript', variant_dir=builddir)
# vim: ft=python