16 from SCons.Script.SConscript
import SConsEnvironment
18 from .
import installation
38 def configure(packageName, versionString=None, eupsProduct=None, eupsProductPath=None, noCfgFile=False):
39 if not state.env.GetOption(
"no_progress"):
40 state.log.info(
"Setting up environment to build package '%s'." % packageName)
41 if eupsProduct
is None:
42 eupsProduct = packageName
43 if versionString
is None:
45 state.env[
'eupsProduct'] = eupsProduct
46 state.env[
'packageName'] = packageName
50 SCons.Script.Help(state.opts.GenerateHelpText(state.env))
51 state.env.installing = filter(
lambda t: t ==
"install", SCons.Script.BUILD_TARGETS)
52 state.env.declaring = filter(
lambda t: t ==
"declare" or t ==
"current", SCons.Script.BUILD_TARGETS)
53 state.env.linkFarmDir = state.env.GetOption(
"linkFarmDir")
54 if state.env.linkFarmDir:
55 state.env.linkFarmDir = os.path.abspath(os.path.expanduser(state.env.linkFarmDir))
56 prefix = installation.setPrefix(state.env, versionString, eupsProductPath)
57 state.env[
'prefix'] = prefix
58 state.env[
"libDir"] =
"%s/lib" % prefix
59 state.env[
"pythonDir"] =
"%s/python" % prefix
63 state.log.traceback = state.env.GetOption(
"traceback")
64 state.log.verbose = state.env.GetOption(
"verbose")
65 packages =
PackageTree(packageName, noCfgFile=noCfgFile)
67 state.env.libs = {
"main":[],
"python":[],
"test":[]}
68 state.env.doxygen = {
"tags":[],
"includes":[]}
69 state.env[
'CPPPATH'] = []
70 state.env[
'LIBPATH'] = []
74 state.env[
'XCPPPATH'] = []
75 state.env[
'_CPPINCFLAGS'] = \
76 "$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)}"\
77 " ${_concat(INCPREFIX, XCPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)"
78 state.env[
'_SWIGINCFLAGS'] = state.env[
'_CPPINCFLAGS'].replace(
"CPPPATH",
"SWIGPATH")
80 if state.env.linkFarmDir:
81 for d
in [state.env.linkFarmDir,
"#"]:
82 state.env.Append(CPPPATH=os.path.join(d,
"include"))
83 state.env.Append(LIBPATH=os.path.join(d,
"lib"))
84 state.env[
'SWIGPATH'] = state.env[
'CPPPATH']
86 if not state.env.GetOption(
"clean")
and not state.env.GetOption(
"help"):
87 packages.configure(state.env, check=state.env.GetOption(
"checkDependencies"))
88 for target
in state.env.libs:
89 state.log.info(
"Libraries in target '%s': %s" % (target, state.env.libs[target]))
90 state.env.dependencies = packages
114 dir, file = os.path.split(cfgFile)
115 name, ext = os.path.splitext(file)
116 return name, os.path.abspath(os.path.join(dir,
".."))
120 version, eupsPathDir, productDir, table, flavor = eupsForScons.getEups().
findSetupVersion(eupsProduct)
121 if productDir
is None:
122 productDir = eupsForScons.productDir(eupsProduct)
123 return version, productDir
151 def __init__(self, cfgFile, headers=(), libs=
None, hasSwigFiles=
True,
152 includeFileDirs=[
"include",], libFileDirs=[
"lib",],
153 hasDoxygenInclude=
False, hasDoxygenTag=
True, eupsProduct=
None):
155 if eupsProduct
is None:
156 eupsProduct = self.name
159 if version
is not None:
161 if productDir
is None:
162 state.log.warn(
"Could not find EUPS product dir for '%s'; using %s."
165 self.
root = os.path.realpath(productDir)
168 "tags": ([os.path.join(self.
root,
"doc",
"%s.tag" % self.name)]
169 if hasDoxygenTag
else []),
171 "includes": ([os.path.join(self.
root,
"doc",
"%s.inc" % self.name)]
172 if hasDoxygenInclude
else [])
186 self.
libs = {
"main": libs,
"python": [],
"test": []}
189 self.
paths[
"SWIGPATH"] = [os.path.join(self.
root,
"python")]
191 self.
paths[
"SWIGPATH"] = []
193 for pathName, subDirs
in [(
"CPPPATH", includeFileDirs),
194 (
"LIBPATH", libFileDirs),]:
195 self.
paths[pathName] = []
197 if state.env.linkFarmDir:
200 for subDir
in subDirs:
201 pathDir = os.path.join(self.
root, subDir)
202 if os.path.isdir(pathDir):
203 self.
paths[pathName].append(pathDir)
206 "headers": tuple(headers),
207 "libs": tuple(self.
libs[
"main"])
237 def configure(self, conf, packages, check=False, build=True):
238 assert(
not (check
and build))
239 conf.env.PrependUnique(**self.
paths)
240 state.log.info(
"Configuring package '%s'." % self.name)
241 conf.env.doxygen[
"includes"].extend(self.
doxygen[
"includes"])
243 conf.env.doxygen[
"tags"].extend(self.
doxygen[
"tags"])
244 for target
in self.
libs:
245 if target
not in conf.env.libs:
246 conf.env.libs[target] = lib[target].
copy()
247 state.log.info(
"Adding '%s' libraries to target '%s'." % (self.
libs[target], target))
249 for lib
in self.
libs[target]:
250 if lib
not in conf.env.libs[target]:
251 conf.env.libs[target].append(lib)
252 state.log.info(
"Adding '%s' library to target '%s'." % (lib, target))
254 for header
in self.
provides[
"headers"]:
255 if not conf.CheckCXXHeader(header):
return False
256 for lib
in self.
libs[
"main"]:
257 if not conf.CheckLib(lib, autoadd=
False, language=
"C++"):
return False
288 def __init__(self, cfgFile, headers=(), libs=
None, eupsProduct=
None):
289 Configuration.__init__(self, cfgFile, headers, libs, eupsProduct=eupsProduct, hasSwigFiles=
False,
290 hasDoxygenTag=
False, hasDoxygenInclude=
False)
291 self.
paths[
"XCPPPATH"] = self.
paths[
"CPPPATH"]
292 del self.
paths[
"CPPPATH"]
306 context.Message(
"Checking if C compiler supports " + flag +
" flag ")
307 ccflags = context.env[
"CCFLAGS"];
308 context.env.Append(CCFLAGS = flag)
309 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".c")
310 context.Result(result)
311 if not append
or not result:
312 context.env.Replace(CCFLAGS = ccflags)
325 context.Message(
"Checking if C++ compiler supports " + flag +
" flag ")
326 cxxflags = context.env[
"CXXFLAGS"];
327 context.env.Append(CXXFLAGS = flag)
328 result = context.TryCompile(
"int main(int argc, char **argv) { return 0; }",
".cc")
329 context.Result(result)
330 if not append
or not result:
331 context.env.Replace(CXXFLAGS = cxxflags)
344 context.Message(message)
347 if (env.GetOption(
"clean")
or env.GetOption(
"help")
or env.GetOption(
"no_exec")):
350 result = context.TryCompile(source, extension)
352 context.Result(result)
366 context.Message(message)
367 result = context.TryLink(source, extension)
368 context.Result(result)
403 "CustomCFlagCheck" : CustomCFlagCheck,
404 "CustomCppFlagCheck" : CustomCppFlagCheck,
405 "CustomCompileCheck" : CustomCompileCheck,
406 "CustomLinkCheck" : CustomLinkCheck,
415 state.log.fail(
"Failed to load primary package configuration for %s." % primaryName)
418 for dependency
in self.primary.dependencies.get(
"required", ()):
420 missingDeps.append(dependency)
422 state.log.fail(
"Failed to load required dependencies: \"%s\"" %
'", "'.join(missingDeps))
425 for dependency
in self.primary.dependencies.get(
"buildRequired", ()):
427 missingDeps.append(dependency)
429 state.log.fail(
"Failed to load required build dependencies: \"%s\"" %
'", "'.join(missingDeps))
431 for dependency
in self.primary.dependencies.get(
"optional", ()):
434 for dependency
in self.primary.dependencies.get(
"buildOptional", ()):
437 name = property(
lambda self: self.primary.config.name)
441 conf = env.Configure(custom_tests=self.
customTests)
442 for name, module
in self.packages.iteritems():
444 state.log.info(
"Skipping missing optional package %s." % name)
446 if not module.config.configure(conf, packages=self.
packages, check=check, build=
False):
447 state.log.fail(
"%s was found but did not pass configuration checks." % name)
449 self.primary.config.configure(conf, packages=self.
packages, check=
False, build=
True)
450 env.AppendUnique(SWIGPATH=env[
"CPPPATH"])
451 env.AppendUnique(XSWIGPATH=env[
"XCPPPATH"])
455 for target
in env.libs:
456 env.libs[target].reverse()
463 has_key = __contains__
466 if name == self.
name:
471 def get(self, name, default=None):
472 if name == self.
name:
475 return self.packages.get(name)
478 k = self.packages.keys()
483 """Search for and import an individual configuration module from file."""
485 envVars = (
"%s_DIR_EXTRA" % name.upper(),
"%s_DIR" % name.upper())
486 paths = [os.path.join(os.environ[v],
"ups")
for v
in envVars
if v
in os.environ]
489 filename = os.path.join(path, name +
".cfg")
490 if os.path.exists(filename):
492 module = imp.load_source(name +
"_cfg", filename)
494 state.log.warn(
"Error loading configuration %s (%s)" % (filename, e))
496 state.log.info(
"Using configuration for package '%s' at '%s'." % (name, filename))
497 if not hasattr(module,
"dependencies")
or not isinstance(module.dependencies, dict):
498 state.log.warn(
"Configuration module for package '%s' lacks a dependencies dict." % name)
500 if not hasattr(module,
"config")
or not isinstance(module.config, Configuration):
501 state.log.warn(
"Configuration module for package '%s' lacks a config object." % name)
506 state.log.info(
"Failed to import configuration for optional package '%s'." % name)
509 """Recursively load a dependency."""
511 state.log.fail(
"Detected recursive dependency involving package '%s'" % name)
513 self._current.add(name)
515 self._current.remove(name)
516 return self.
packages[name]
is not None
520 self._current.remove(name)
522 for dependency
in module.dependencies.get(
"required", ()):
527 self._current.remove(name)
528 state.log.warn(
"Could not load all dependencies for package '%s' (missing %s)." %
531 for dependency
in module.dependencies.get(
"optional", ()):
535 self._current.remove(name)
555 for category
in categories.split():
556 if category ==
"self":
559 for lib
in env.libs[category]:
564 libs.remove(env[
"packageName"])
569 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.