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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
|
# -*- coding: utf-8 -*-
import os.path, sys, re
# exceptions
from simula_scons.Errors import PkgconfigError, PkgconfigMissing, CommandError, _configError
# import the local 'scons'
import simula_scons as scons
# Here, the main program will be written. The logic must be _visible_, and the
# code should be short and simple.
# import the default env and configure objects created in SConstruct
Import("env", "configure")
# Set the default env in our local scons utility module.
scons.setDefaultEnv(env)
python_version = "python-%d" % (sys.version_info[0])
# Add non-standard paths with pkg-config
#configuredPackages = {}
# determine which packages that should be disabled:
disabled_packages = []
if not env["enablePetsc"]:
disabled_packages.append("petsc")
disabled_packages.append("slepc")
if not env["enableSlepc"]:
disabled_packages.append("slepc")
if not env["enableScotch"]:
disabled_packages.append("scotch")
if not env["enableGts"]:
disabled_packages.append("gts")
if not env["enableUmfpack"]:
disabled_packages.append("umfpack")
if not env["enableTrilinos"]:
disabled_packages.append("trilinos")
# Find modules in the project and dependencies:
# only modules and configuredPackages will be used in this code:
modules, dependencies, alldependencies, configuredPackages, packcfgObjs = \
scons.getModulesAndDependencies(disabled_packages=disabled_packages)
# we will not use the 'dependencies' and 'alldependencies' here.
# TODO: Consider removing it from the API.
dependencies = None
alldependencies = None
# See if dependencies can be resolved with PkgConfig.
# for d in alldependencies.keys():
# try:
# packcfg = scons.pkgconfig.PkgConfig(d, env=env)
# configuredPackages[d] = scons.Customize.Dependency(cppPath=packcfg.includeDirs(), \
# libPath=packcfg.libDirs(), libs=packcfg.libs(),\
# version=packcfg.version())
# except:
# pass
# resolve modules according to detected dependencies.
# if a dependency can not be found, the module will not be built:
#modules = scons.resolveModuleDependencies(modules, configuredPackages)
modules, env = scons.resolveModuleDependencies(modules, configuredPackages, packcfgObjs, sconsEnv=env)
if env["PLATFORM"] == "darwin":
env = scons.Customize.darwinCxx(env)
if env["enablePydolfin"]:
# Make sure we can find both SWIG and Python header files (Python.h):
try:
out, err = scons.runCommand("swig", "-version")
except Exception, err:
print "*** Unable to find SWIG."
print "*** Install SWIG or disable PyDOLFIN with enablePydolfin=no"
Exit(1)
py_ver = "%s.%s" % (sys.version_info[0],sys.version_info[1])
py_inc = os.path.join(sys.prefix,"include","python"+py_ver)
if not os.path.isfile(os.path.join(py_inc, "Python.h")):
print "*** Unable to find Python development files on your system."
print "*** Perhaps you need to install the package python%s-dev?" % py_ver
Exit(1)
if env["enablePydolfin"]:
print "Enabling compilation of PyDOLFIN"
swigFlags = "-python -c++ -shadow -Iinclude/swig".split()
out, err = scons.runCommand("swig", "-version")
# Determine swig version, v 1.3.28 and later supports -O flag
m = re.match(r"SWIG Version (.+)", out, re.M)
#if scons.checkVersion(m.group(1), "1.3.28"):
# swigFlags.append("-O")
swigEnv = env.Copy()
swigEnv["SWIGFLAGS"] = swigFlags
swigEnv["SHLIBPREFIX"] = "_"
if env["PLATFORM"] == "darwin":
swigEnv = scons.Customize.darwinSwig(swigEnv)
cFileBldr, cxxFileBldr = swigEnv["BUILDERS"]["CFile"], swigEnv["BUILDERS"]["CXXFile"]
for bldr in cFileBldr, cxxFileBldr:
bldr.add_emitter(".i", scons.Customize.swigEmitter)
swigEnv.Prepend(SCANNERS=scons.Customize.swigscanner)
else:
print "Disabling compilation of PyDOLFIN"
# stencil for return-values:
ret = {"shlibs": [], "extModules": [], "docs": [], "headers": [], "pythonModules": [], \
"pythonScripts": [], "pkgconfig": [], "pythonPackageDirs": [], "data": [], "tests": [], \
"progs": [], "demos": [], "dolfin_header": "", "swigfiles": []}
#### XXX
#### Messy code
#### TODO
#### Fix and move to a better location.
####
# build rpath for paths for all modules, stored in the Module objects.
#
# Used for building test-binaries (aka AppSources)
rpathdirs=[Dir("#%s/%s" % (env["projectname"],m.path)).abspath for m in modules.values()]
#### End TODO
for modName, mod in modules.items():
libs, libPath, linkOpts, cppPath, frameworks = [], [], [], [], []
swiglibs, swigframeworks, swiglinkOpts, swiglibPath, swigcppPath = [], [], [], [], []
for d in mod.dependencies:
if d in modules:
# Internal dependency
libs.append(d)
libPath.insert(0, modules[d].path)
elif d in configuredPackages:
# External (configured) dependency
dep = configuredPackages[d]
libs += dep.libs[0] # The libs
frameworks += list(dep.libs[1]) # The frameworks (Darwin)
libPath += dep.libPath
linkOpts += dep.linkOpts
cppPath += dep.cppPath
# on Darwin, automatically add all regular external deps to
# swig deps. Strictly speaking, it is only required if the
# external dep consist of shared libraries.
scons.addToDependencies(mod.swigDependencies,d)
for d in mod.swigDependencies:
if d in modules:
# not sure what to do with that... Or maybe not relevant
print "Internal module %s as swigDependency in module %s is undefined" % (modules[d].modName,modName)
elif d in configuredPackages:
swigdep = configuredPackages[d]
swiglibs += swigdep.libs[0]
swigframeworks += list(swigdep.libs[1])
swiglibPath += swigdep.libPath
swigcppPath += swigdep.cppPath
if mod.libSources:
# Register shared library targets in the module
modEnv = env.Copy(CXXFLAGS=mod.cxxFlags, LINKFLAGS=mod.linkFlags)
# Prepend the CPPPATH so that directories containing headers are searched before those
# they are to be installed into, otherwise SCons might think it necessary to install
# them first
modEnv.Prepend(CPPPATH=[Dir("#").abspath] + cppPath, LIBPATH=libPath)
modEnv.Append(LIBS=libs)
modEnv.Append(LINKFLAGS=linkOpts)
if env["PLATFORM"] == "darwin":
modEnv.Append(FRAMEWORKS=frameworks)
shlib = modEnv.SharedLibrary(target=os.path.join(mod.path, modName), source=\
[os.path.join(mod.path, s) for s in mod.libSources])
# The builder returns a node list
ret["shlibs"].append(shlib[0])
if mod.swigSources and env["enablePydolfin"]:
# Register swig wrapper targets in the module
mod.cxxFlags += " -fno-strict-aliasing"
modEnv = swigEnv.Copy(CXXFLAGS=mod.cxxFlags, LINKFLAGS=mod.linkFlags + linkOpts)
modEnv.Append(SWIGFLAGS=mod.swigFlags + ["-I%s" % i for i in swigcppPath])
### uncomment the following line to remove -Werror from the CXXFLAGS:
#modEnv["CXXFLAGS"] = re.sub("-Werror","",modEnv["CXXFLAGS"])
# Add python dependency (always required in python wrappers)
pyPkg = configuredPackages[python_version]
cppPath += pyPkg.cppPath + swigcppPath
libPath += pyPkg.libPath + swiglibPath
libs += pyPkg.libs[0] + swiglibs
frameworks += pyPkg.libs[1] + swigframeworks
# Add the directories of the module and its dependencies to swig's include path, so
# that it can resolve included headers
modEnv.Prepend(CPPPATH=[Dir("#").abspath] + cppPath, \
LIBPATH=[mod.path] + swiglibPath, LIBS=swiglibs)
if mod.libSources:
modEnv.Append(LIBS=modName)
else:
# This is a standalone swig'ed module
modEnv.Append(LIBPATH=libPath, LIBS=libs)
if env["PLATFORM"] == "darwin":
modEnv.Append(FRAMEWORKS=frameworks)
wrapCxx, wrapPy = modEnv.CXXFile(target=os.path.join(mod.path, "swig", modName), source=[os.path.join(mod.path, s) for s in mod.swigSources])
swig = modEnv.SharedLibrary(target=os.path.join(mod.path, "swig", modName), source=wrapCxx)[0]
# The builder returns a node list
ret["extModules"].append(swig)
ret["pythonModules"].append(wrapPy)
for progName, progSources in mod.progSources.items():
# Register program targets in the module
modEnv = env.Copy(CXXFLAGS=mod.cxxFlags, LINKFLAGS=mod.linkFlags)
# Prepend the CPPPATH so that directories containing headers are searched before those
# they are to be installed into, otherwise SCons might think it necessary to install
# them first
# disable building of apps' on macosx as those only cause problems...
#if env["PLATFORM"] == "darwin":
# continue
modEnv.Prepend(CPPPATH=[Dir("#").abspath] + cppPath)
if mod.libSources and env["PLATFORM"] != "darwin":
# Link against module library if defined
modEnv.Append(LIBS=modName, LIBPATH=mod.path, RPATH=rpathdirs)
elif mod.libSources and env["PLATFORM"] == "darwin":
# Do not use rpath on darwin, as it doesn't work
modEnv.Append(LIBS=[modName] + libs, LIBPATH=[mod.path] + libPath)
modEnv.Append(FRAMEWORKS=frameworks)
prog = modEnv.Program(target=os.path.join(mod.path, progName), source=\
[os.path.join(mod.path, s) for s in progSources])
# The builder returns a node list
ret["progs"].append(prog[0])
# Register headers to be installed for the module
ret["headers"] += [File(h, mod.path) for h in mod.libHeaders]
## Need to detect the 'dolfin.h' header file, and treat differently
#for h in mod.libHeaders:
# if h.endswith("dolfin.h"):
# ret["main_header"] = File(h, mod.path)
# The 'dolfin.h' header file is treated differently
ret["dolfin_header"] = File("dolfin.h", '.')
# set pythonScripts we want to install
ret["pythonScripts"] += scons.globFiles(Dir("#/app").srcnode().abspath, "*.py")
# set python packagedirs we want to install (in site-packages)
ret["pythonPackageDirs"] += [Dir("#site-packages")]
if env["enablePydolfin"]:
# set SWIG interface files we want to install
ret["swigfiles"] += scons.globFiles(Dir("#/dolfin/swig").srcnode().abspath, "*.i")
# read SConscript in data.
data = env.SConscript(os.path.join("#data", "SConscript"), exports=["env"])
# set information about data we want to install
ret["data"].extend([File(os.path.join("#data", f)) for f in data])
## read SConscript for tests
#tests = env.SConscript(os.path.join("#test", "SConscript"), exports=["env", "modules", "configuredPackages"])
#ret["tests"].extend([File(os.path.join("#test", f)) for f in tests["pytests"]])
## join the cpptests with regular progs.
#ret["progs"].append([t for t in tests["cpptests"]])
# read the SConscript for tests if enabled
ret["tests"] = []
if env["enableTests"]:
# make sure CppUnit is found:
try:
scons.runCommand("pkg-config", "--exists cppunit")
except Exception:
print "*** Unable to find the Unit Testing Library for C++"
print "*** Install CppUnit (libcppunit-dev) or disable testing with enableTests=no"
Exit(1)
ret["tests"] += env.SConscript(os.path.join("#test", "SConscript"),
exports=["env", "modules", "configuredPackages"])
# read SConscript for docs if enabled
ret["docs"] = []
if env["enableDocs"]:
ret["docs"] += env.SConscript(os.path.join("#doc", "SConscript"), exports=["env"])
# read the SConscript for demos if enabled (or if tests are enabled)
ret["demos"] = []
if env["enableDemos"] or env["enableTests"]:
ret["demos"] += env.SConscript(os.path.join("#demo", "SConscript"),
exports=["env", "modules", "configuredPackages"])
# generate a builder for the pycc pkg-config file.
# TODO: The template-based generator can maybe be replaced with the
# "builtin" generator (in simula-scons/_module
# But look out for strange names... The default-name used by that
# functionality is projectname_module -> dolfin_dolfin.pc...
# sticking to the "old-style" (but renowed) for now:
replacements = {}
# set the dolfin-version. Bad place to have it, consider moving this!
replacements['PACKAGE_VERSION'] = "0.7.3"
# make all dependencies into a list, based on the configured Packages.
replacements['PACKAGE_REQUIRES'] = " ".join(configuredPackages.keys())
# set CXX flags:
cxxflags = ""
for mod in modules.values():
cxxflags += " " + mod.cxxFlags
replacements['PACKAGE_CXXFLAGS'] = cxxflags
# set CXX compiler:
replacements['CXX'] = env["CXX"]
scons.pkgconfig.generate(env, replace=replacements)
ret["pkgconfig"] = env.PkgConfigGenerator("%s.pc.in" % (env["projectname"]))
# the dolfin.pc file needs to be regenerated if there are changes to the
# configured packages, installation prefix, any CXXFLAGS, or the compiler
pkgconfig_deps = [configuredPackages.keys(),env["prefix"],cxxflags,env["CXX"]]
env.Depends(ret["pkgconfig"][0], Value(pkgconfig_deps))
# We also like to install all generated pkg-config files.
ret["pkgconfig"] += scons.globFiles(Dir("#/scons/pkgconfig/").srcnode().abspath, "*.pc")
# Return the big data dictionary. Actual targets will be run in SConstruct based
# on this information.
Return("ret")
# vim:ft=python sw=2 ts=2
|