10 from __future__
import absolute_import
16 from .
import eupsForScons
17 from SCons.Script.SConscript
import SConsEnvironment
19 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'] = []
76 state.env[
'_CPPINCFLAGS'] = \
77 "$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"\
78 " ${_concat(INCPREFIX, XCPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)"
79 state.env[
'_SWIGINCFLAGS'] = state.env[
'_CPPINCFLAGS'].replace(
"CPPPATH",
"SWIGPATH")
81 if state.env.linkFarmDir:
82 for d
in [state.env.linkFarmDir,
"#"]:
83 state.env.Append(CPPPATH=os.path.join(d,
"include"))
84 state.env.Append(LIBPATH=os.path.join(d,
"lib"))
85 state.env[
'SWIGPATH'] = state.env[
'CPPPATH']
87 if not state.env.GetOption(
"clean")
and not state.env.GetOption(
"help"):
88 packages.configure(state.env, check=state.env.GetOption(
"checkDependencies"))
89 for target
in state.env.libs:
90 state.log.info(
"Libraries in target '%s': %s" % (target, state.env.libs[target]))
91 state.env.dependencies = packages
115 dir, file = os.path.split(cfgFile)
116 name, ext = os.path.splitext(file)
117 return name, os.path.abspath(os.path.join(dir,
".."))
121 version, eupsPathDir, productDir, table, flavor = eupsForScons.getEups().
findSetupVersion(eupsProduct)
122 if productDir
is None:
123 productDir = eupsForScons.productDir(eupsProduct)
124 return version, productDir
152 def __init__(self, cfgFile, headers=(), libs=
None, hasSwigFiles=
True,
153 includeFileDirs=[
"include",], libFileDirs=[
"lib",],
154 hasDoxygenInclude=
False, hasDoxygenTag=
True, eupsProduct=
None):
156 if eupsProduct
is None:
157 eupsProduct = self.name
160 if version
is not None:
162 if productDir
is None:
163 state.log.warn(
"Could not find EUPS product dir for '%s'; using %s."
166 self.
root = os.path.realpath(productDir)
169 "tags": ([os.path.join(self.
root,
"doc",
"%s.tag" % self.name)]
170 if hasDoxygenTag
else []),
172 "includes": ([os.path.join(self.
root,
"doc",
"%s.inc" % self.name)]
173 if hasDoxygenInclude
else [])
187 self.
libs = {
"main": libs,
"python": [],
"test": []}
190 self.
paths[
"SWIGPATH"] = [os.path.join(self.
root,
"python")]
192 self.
paths[
"SWIGPATH"] = []
194 for pathName, subDirs
in [(
"CPPPATH", includeFileDirs),
195 (
"LIBPATH", libFileDirs),]:
196 self.
paths[pathName] = []
198 if state.env.linkFarmDir:
201 for subDir
in subDirs:
202 pathDir = os.path.join(self.
root, subDir)
203 if os.path.isdir(pathDir):
204 self.
paths[pathName].append(pathDir)
207 "headers": tuple(headers),
208 "libs": tuple(self.
libs[
"main"])
238 def configure(self, conf, packages, check=False, build=True):
239 assert(
not (check
and build))
240 conf.env.PrependUnique(**self.
paths)
241 state.log.info(
"Configuring package '%s'." % self.name)
242 conf.env.doxygen[
"includes"].extend(self.
doxygen[
"includes"])
244 conf.env.doxygen[
"tags"].extend(self.
doxygen[
"tags"])
245 for target
in self.
libs:
246 if target
not in conf.env.libs:
247 conf.env.libs[target] = lib[target].
copy()
248 state.log.info(
"Adding '%s' libraries to target '%s'." % (self.
libs[target], target))
250 for lib
in self.
libs[target]:
251 if lib
not in conf.env.libs[target]:
252 conf.env.libs[target].append(lib)
253 state.log.info(
"Adding '%s' library to target '%s'." % (lib, target))
255 for header
in self.
provides[
"headers"]:
256 if not conf.CheckCXXHeader(header):
return False
257 for lib
in self.
libs[
"main"]:
258 if not conf.CheckLib(lib, autoadd=
False, language=
"C++"):
return False
289 def __init__(self, cfgFile, headers=(), libs=
None, eupsProduct=
None):
290 Configuration.__init__(self, cfgFile, headers, libs, eupsProduct=eupsProduct, hasSwigFiles=
False,
291 hasDoxygenTag=
False, hasDoxygenInclude=
False)
292 self.
paths[
"XCPPPATH"] = self.
paths[
"CPPPATH"]
293 del self.
paths[
"CPPPATH"]
307 context.Message(
"Checking if C compiler supports " + flag +
" flag ")
308 ccflags = context.env[
"CCFLAGS"];
309 context.env.Append(CCFLAGS = flag)
310 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".c")
311 context.Result(result)
312 if not append
or not result:
313 context.env.Replace(CCFLAGS = ccflags)
326 context.Message(
"Checking if C++ compiler supports " + flag +
" flag ")
327 cxxflags = context.env[
"CXXFLAGS"];
328 context.env.Append(CXXFLAGS = flag)
329 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".cc")
330 context.Result(result)
331 if not append
or not result:
332 context.env.Replace(CXXFLAGS = cxxflags)
345 context.Message(message)
348 if (env.GetOption(
"clean")
or env.GetOption(
"help")
or env.GetOption(
"no_exec")):
351 result = context.TryCompile(source, extension)
353 context.Result(result)
367 context.Message(message)
368 result = context.TryLink(source, extension)
369 context.Result(result)
404 "CustomCFlagCheck" : CustomCFlagCheck,
405 "CustomCppFlagCheck" : CustomCppFlagCheck,
406 "CustomCompileCheck" : CustomCompileCheck,
407 "CustomLinkCheck" : CustomLinkCheck,
416 state.log.fail(
"Failed to load primary package configuration for %s." % primaryName)
419 for dependency
in self.primary.dependencies.get(
"required", ()):
421 missingDeps.append(dependency)
423 state.log.fail(
"Failed to load required dependencies: \"%s\"" %
'", "'.join(missingDeps))
426 for dependency
in self.primary.dependencies.get(
"buildRequired", ()):
428 missingDeps.append(dependency)
430 state.log.fail(
"Failed to load required build dependencies: \"%s\"" %
'", "'.join(missingDeps))
432 for dependency
in self.primary.dependencies.get(
"optional", ()):
435 for dependency
in self.primary.dependencies.get(
"buildOptional", ()):
438 name = property(
lambda self: self.primary.config.name)
442 conf = env.Configure(custom_tests=self.
customTests)
443 for name, module
in self.packages.items():
445 state.log.info(
"Skipping missing optional package %s." % name)
447 if not module.config.configure(conf, packages=self.
packages, check=check, build=
False):
448 state.log.fail(
"%s was found but did not pass configuration checks." % name)
450 self.primary.config.configure(conf, packages=self.
packages, check=
False, build=
True)
451 env.AppendUnique(SWIGPATH=env[
"CPPPATH"])
452 env.AppendUnique(XSWIGPATH=env[
"XCPPPATH"])
456 for target
in env.libs:
457 env.libs[target].reverse()
464 has_key = __contains__
467 if name == self.
name:
472 def get(self, name, default=None):
473 if name == self.
name:
476 return self.packages.get(name)
479 k = self.packages.keys()
484 """Search for and import an individual configuration module from file."""
486 filename = os.path.join(path, name +
".cfg")
487 if os.path.exists(filename):
489 module = imp.load_source(name +
"_cfg", filename)
490 except Exception
as e:
491 state.log.warn(
"Error loading configuration %s (%s)" % (filename, e))
493 state.log.info(
"Using configuration for package '%s' at '%s'." % (name, filename))
494 if not hasattr(module,
"dependencies")
or not isinstance(module.dependencies, dict):
495 state.log.warn(
"Configuration module for package '%s' lacks a dependencies dict." % name)
497 if not hasattr(module,
"config")
or not isinstance(module.config, Configuration):
498 state.log.warn(
"Configuration module for package '%s' lacks a config object." % name)
503 state.log.info(
"Failed to import configuration for optional package '%s'." % name)
506 """Recursively load a dependency."""
508 state.log.fail(
"Detected recursive dependency involving package '%s'" % name)
510 self._current.add(name)
512 self._current.remove(name)
513 return self.
packages[name]
is not None
517 self._current.remove(name)
519 for dependency
in module.dependencies.get(
"required", ()):
524 self._current.remove(name)
525 state.log.warn(
"Could not load all dependencies for package '%s' (missing %s)." %
528 for dependency
in module.dependencies.get(
"optional", ()):
532 self._current.remove(name)
552 for category
in categories.split():
553 if category ==
"self":
556 for lib
in env.libs[category]:
561 libs.remove(env[
"packageName"])
566 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.
SelectEigenView< T >::Type copy(Eigen::EigenBase< T > const &other)
Copy an arbitrary Eigen expression into a new EigenView.
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 configure
Configure the entire dependency tree in order.
def addCustomTests
Add custom SCons configuration tests to the Configure Context passed to the configure() method...
def parseFilename
Parse the name of a .cfg file, returning the package name and root directory.