10 from __future__
import absolute_import
15 from .
import eupsForScons
16 from SCons.Script.SConscript
import SConsEnvironment
18 from .
import installation
39 def configure(packageName, versionString=None, eupsProduct=None, eupsProductPath=None, noCfgFile=False):
40 if not state.env.GetOption(
"no_progress"):
41 state.log.info(
"Setting up environment to build package '%s'." % packageName)
42 if eupsProduct
is None:
43 eupsProduct = packageName
44 if versionString
is None:
46 state.env[
'eupsProduct'] = eupsProduct
47 state.env[
'packageName'] = packageName
51 SCons.Script.Help(state.opts.GenerateHelpText(state.env))
52 state.env.installing = [t
for t
in SCons.Script.BUILD_TARGETS
if t ==
"install"]
53 state.env.declaring = [t
for t
in SCons.Script.BUILD_TARGETS
if t ==
"declare" or t ==
"current"]
54 state.env.linkFarmDir = state.env.GetOption(
"linkFarmDir")
55 if state.env.linkFarmDir:
56 state.env.linkFarmDir = os.path.abspath(os.path.expanduser(state.env.linkFarmDir))
57 prefix = installation.setPrefix(state.env, versionString, eupsProductPath)
58 state.env[
'prefix'] = prefix
59 state.env[
"libDir"] =
"%s/lib" % prefix
60 state.env[
"pythonDir"] =
"%s/python" % prefix
64 state.log.traceback = state.env.GetOption(
"traceback")
65 state.log.verbose = state.env.GetOption(
"verbose")
66 packages =
PackageTree(packageName, noCfgFile=noCfgFile)
68 state.env.libs = {
"main": [],
"python": [],
"test": []}
69 state.env.doxygen = {
"tags": [],
"includes": []}
70 state.env[
'CPPPATH'] = []
71 state.env[
'LIBPATH'] = []
75 state.env[
'XCPPPATH'] = []
81 state.env[
'XCPPPREFIX'] =
"-isystem "
83 state.env[
'_CPPINCFLAGS'] = \
84 "$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"\
85 " ${_concat(XCPPPREFIX, XCPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)"
86 state.env[
'_SWIGINCFLAGS'] = state.env[
'_CPPINCFLAGS'] \
87 .replace(
"CPPPATH",
"SWIGPATH") \
88 .replace(
"XCPPPREFIX",
"SWIGINCPREFIX")
90 if state.env.linkFarmDir:
91 for d
in [state.env.linkFarmDir,
"#"]:
92 state.env.Append(CPPPATH=os.path.join(d,
"include"))
93 state.env.Append(LIBPATH=os.path.join(d,
"lib"))
94 state.env[
'SWIGPATH'] = state.env[
'CPPPATH']
96 if not state.env.GetOption(
"clean")
and not state.env.GetOption(
"help"):
97 packages.configure(state.env, check=state.env.GetOption(
"checkDependencies"))
98 for target
in state.env.libs:
99 state.log.info(
"Libraries in target '%s': %s" % (target, state.env.libs[target]))
100 state.env.dependencies = packages
125 dir, file = os.path.split(cfgFile)
126 name, ext = os.path.splitext(file)
127 return name, os.path.abspath(os.path.join(dir,
".."))
131 version, eupsPathDir, productDir, table, flavor = eupsForScons.getEups().
findSetupVersion(eupsProduct)
132 if productDir
is None:
133 productDir = eupsForScons.productDir(eupsProduct)
134 return version, productDir
162 def __init__(self, cfgFile, headers=(), libs=
None, hasSwigFiles=
True,
163 includeFileDirs=[
"include"], libFileDirs=[
"lib"],
164 hasDoxygenInclude=
False, hasDoxygenTag=
True, eupsProduct=
None):
166 if eupsProduct
is None:
167 eupsProduct = self.name
170 if version
is not None:
172 if productDir
is None:
173 state.log.warn(
"Could not find EUPS product dir for '%s'; using %s."
176 self.
root = os.path.realpath(productDir)
179 "tags": ([os.path.join(self.
root,
"doc",
"%s.tag" % self.name)]
180 if hasDoxygenTag
else []),
182 "includes": ([os.path.join(self.
root,
"doc",
"%s.inc" % self.name)]
183 if hasDoxygenInclude
else [])
197 self.
libs = {
"main": libs,
"python": [],
"test": []}
200 self.
paths[
"SWIGPATH"] = [os.path.join(self.
root,
"python")]
202 self.
paths[
"SWIGPATH"] = []
204 for pathName, subDirs
in [(
"CPPPATH", includeFileDirs),
205 (
"LIBPATH", libFileDirs)]:
206 self.
paths[pathName] = []
208 if state.env.linkFarmDir:
211 for subDir
in subDirs:
212 pathDir = os.path.join(self.
root, subDir)
213 if os.path.isdir(pathDir):
214 self.
paths[pathName].append(pathDir)
217 "headers": tuple(headers),
218 "libs": tuple(self.
libs[
"main"])
248 def configure(self, conf, packages, check=False, build=True):
249 assert(
not (check
and build))
250 conf.env.PrependUnique(**self.
paths)
251 state.log.info(
"Configuring package '%s'." % self.name)
252 conf.env.doxygen[
"includes"].extend(self.
doxygen[
"includes"])
254 conf.env.doxygen[
"tags"].extend(self.
doxygen[
"tags"])
255 for target
in self.
libs:
256 if target
not in conf.env.libs:
257 conf.env.libs[target] = self.
libs[target].copy()
258 state.log.info(
"Adding '%s' libraries to target '%s'." % (self.
libs[target], target))
260 for lib
in self.
libs[target]:
261 if lib
not in conf.env.libs[target]:
262 conf.env.libs[target].append(lib)
263 state.log.info(
"Adding '%s' library to target '%s'." % (lib, target))
265 for header
in self.
provides[
"headers"]:
266 if not conf.CheckCXXHeader(header):
268 for lib
in self.
libs[
"main"]:
269 if not conf.CheckLib(lib, autoadd=
False, language=
"C++"):
304 def __init__(self, cfgFile, headers=(), libs=
None, eupsProduct=
None):
305 Configuration.__init__(self, cfgFile, headers, libs, eupsProduct=eupsProduct, hasSwigFiles=
False,
306 hasDoxygenTag=
False, hasDoxygenInclude=
False)
307 self.
paths[
"XCPPPATH"] = self.
paths[
"CPPPATH"]
308 del self.
paths[
"CPPPATH"]
323 context.Message(
"Checking if C compiler supports " + flag +
" flag ")
324 ccflags = context.env[
"CCFLAGS"]
325 context.env.Append(CCFLAGS=flag)
326 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".c")
327 context.Result(result)
328 if not append
or not result:
329 context.env.Replace(CCFLAGS=ccflags)
343 context.Message(
"Checking if C++ compiler supports " + flag +
" flag ")
344 cxxflags = context.env[
"CXXFLAGS"]
345 context.env.Append(CXXFLAGS=flag)
346 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".cc")
347 context.Result(result)
348 if not append
or not result:
349 context.env.Replace(CXXFLAGS=cxxflags)
363 context.Message(message)
366 if (env.GetOption(
"clean")
or env.GetOption(
"help")
or env.GetOption(
"no_exec")):
369 result = context.TryCompile(source, extension)
371 context.Result(result)
386 context.Message(message)
387 result = context.TryLink(source, extension)
388 context.Result(result)
424 "CustomCFlagCheck": CustomCFlagCheck,
425 "CustomCppFlagCheck": CustomCppFlagCheck,
426 "CustomCompileCheck": CustomCompileCheck,
427 "CustomLinkCheck": CustomLinkCheck,
436 state.log.fail(
"Failed to load primary package configuration for %s." % primaryName)
439 for dependency
in self.primary.dependencies.get(
"required", ()):
441 missingDeps.append(dependency)
443 state.log.fail(
"Failed to load required dependencies: \"%s\"" %
'", "'.join(missingDeps))
446 for dependency
in self.primary.dependencies.get(
"buildRequired", ()):
448 missingDeps.append(dependency)
450 state.log.fail(
"Failed to load required build dependencies: \"%s\"" %
'", "'.join(missingDeps))
452 for dependency
in self.primary.dependencies.get(
"optional", ()):
455 for dependency
in self.primary.dependencies.get(
"buildOptional", ()):
458 name = property(
lambda self: self.primary.config.name)
462 conf = env.Configure(custom_tests=self.
customTests)
463 for name, module
in self.packages.items():
465 state.log.info(
"Skipping missing optional package %s." % name)
467 if not module.config.configure(conf, packages=self.
packages, check=check, build=
False):
468 state.log.fail(
"%s was found but did not pass configuration checks." % name)
470 self.primary.config.configure(conf, packages=self.
packages, check=
False, build=
True)
471 env.AppendUnique(SWIGPATH=env[
"CPPPATH"])
472 env.AppendUnique(XSWIGPATH=env[
"XCPPPATH"])
476 for target
in env.libs:
477 env.libs[target].reverse()
484 has_key = __contains__
487 if name == self.
name:
492 def get(self, name, default=None):
493 if name == self.
name:
496 return self.packages.get(name)
499 k = self.packages.keys()
504 """Search for and import an individual configuration module from file."""
506 filename = os.path.join(path, name +
".cfg")
507 if os.path.exists(filename):
509 module = imp.load_source(name +
"_cfg", filename)
510 except Exception
as e:
511 state.log.warn(
"Error loading configuration %s (%s)" % (filename, e))
513 state.log.info(
"Using configuration for package '%s' at '%s'." % (name, filename))
514 if not hasattr(module,
"dependencies")
or not isinstance(module.dependencies, dict):
515 state.log.warn(
"Configuration module for package '%s' lacks a dependencies dict." % name)
517 if not hasattr(module,
"config")
or not isinstance(module.config, Configuration):
518 state.log.warn(
"Configuration module for package '%s' lacks a config object." % name)
523 state.log.info(
"Failed to import configuration for optional package '%s'." % name)
526 """Recursively load a dependency."""
528 state.log.fail(
"Detected recursive dependency involving package '%s'" % name)
530 self._current.add(name)
532 self._current.remove(name)
533 return self.
packages[name]
is not None
537 self._current.remove(name)
539 for dependency
in module.dependencies.get(
"required", ()):
544 self._current.remove(name)
545 state.log.warn(
"Could not load all dependencies for package '%s' (missing %s)." %
548 for dependency
in module.dependencies.get(
"optional", ()):
552 self._current.remove(name)
573 for category
in categories.split():
574 if category ==
"self":
577 for lib
in env.libs[category]:
582 libs.remove(env[
"packageName"])
587 SConsEnvironment.getLibs = getLibs
Base class for defining how to configure an LSST sconsUtils package.
def CustomCppFlagCheck
A configuration test that checks whether a C++ compiler supports a particular flag.
def CustomLinkCheck
A configuration test that checks whether the given source code compiles and links.
def configure
Recursively configure a package using ups/.cfg files.
def getLibs
Get the libraries the package should be linked with.
def configure
Update an SCons environment to make use of the package.
def __init__
Recursively load *.cfg files for packageName and all its dependencies.
def CustomCompileCheck
A configuration test that checks whether the given source code compiles.
def __init__
Initialize the configuration object.
def CustomCFlagCheck
A configuration test that checks whether a C compiler supports a particular flag. ...
def __init__
Initialize the configuration object.
A class for loading and managing the dependency tree of a package, as defined by its configuration mo...
A Configuration subclass for external (third-party) packages.
def addCustomTests
Add custom SCons configuration tests to the Configure Context passed to the configure() method...