7 from __future__
import absolute_import, division, print_function
13 from SCons.Script.SConscript
import SConsEnvironment
15 from .utils
import memberOf
16 from .installation
import determineVersion, getFingerprint
23 if myenv[
'PLATFORM'] ==
'darwin':
24 myenv[
'SHLINKFLAGS'] += [
"-undefined",
"suppress",
"-flat_namespace",
"-headerpad_max_install_names"]
25 return myenv.SharedLibrary(target, source, **keywords)
32 if myenv[
'PLATFORM'] ==
'darwin':
33 myenv.Append(LDMODULEFLAGS = [
"-undefined",
"suppress",
"-flat_namespace",
"-headerpad_max_install_names"])
39 if myenv.whichCc ==
"gcc":
40 myenv.Append(CCFLAGS = [
"-fno-strict-aliasing",])
41 except AttributeError:
43 return myenv.LoadableModule(target, source, **keywords)
63 files = [SCons.Script.File(file)
for file
in files]
65 if not (self.get(
"optFiles")
or self.get(
"noOptFiles")):
69 if self.get(
"optFiles"):
70 optFiles = self[
"optFiles"].replace(
".",
r"\.")
71 optFiles = SCons.Script.Split(optFiles.replace(
",",
" "))
72 optFilesRe =
"/(%s)$" %
"|".join(optFiles)
76 if self.get(
"noOptFiles"):
77 noOptFiles = self[
"noOptFiles"].replace(
".",
r"\.")
78 noOptFiles = SCons.Script.Split(noOptFiles.replace(
",",
" "))
79 noOptFilesRe =
"/(%s)$" %
"|".join(noOptFiles)
84 opt = int(self[
"opt"])
91 CCFLAGS_OPT = re.sub(
r"-O(\d|s)\s*",
"-O%d " % opt,
" ".join(self[
"CCFLAGS"]))
92 CCFLAGS_NOOPT = re.sub(
r"-O(\d|s)\s*",
"-O0 ",
" ".join(self[
"CCFLAGS"]))
96 if optFilesRe
and re.search(optFilesRe, ccFile.abspath):
97 self.SharedObject(ccFile, CCFLAGS=CCFLAGS_OPT)
98 ccFile = os.path.splitext(ccFile.abspath)[0] + self[
"SHOBJSUFFIX"]
99 elif noOptFilesRe
and re.search(noOptFilesRe, ccFile.abspath):
100 self.SharedObject(ccFile, CCFLAGS=CCFLAGS_NOOPT)
101 ccFile = os.path.splitext(ccFile.abspath)[0] + self[
"SHOBJSUFFIX"]
103 sources.append(ccFile)
119 if root
is None: root =
"."
120 if fileRegex
is None: fileRegex =
r"^[a-zA-Z0-9_].*\.(cc|h(pp)?|py)$"
121 if ignoreDirs
is None: ignoreDirs = [
"examples",
"tests"]
123 if "TAGS" not in SCons.Script.COMMAND_LINE_TARGETS:
127 for dirpath, dirnames, filenames
in os.walk(root):
129 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(%s)$" %
"|".join(ignoreDirs), d)]
131 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(\.svn)$", d)]
135 candidates = [f
for f
in filenames
if re.search(fileRegex, f)]
139 for swigFile
in [f
for f
in filenames
if re.search(
r"\.i$", f)]:
140 name = os.path.splitext(swigFile)[0]
141 candidates = [f
for f
in candidates
if not re.search(
r"%s(_wrap\.cc?|\.py)$" % name, f)]
143 files += [os.path.join(dirpath, f)
for f
in candidates]
154 def BuildETags(env, root=None, fileRegex=None, ignoreDirs=None):
155 toTag =
filesToTag(root, fileRegex, ignoreDirs)
157 return env.Command(
"TAGS", toTag,
"etags -o $TARGET $SOURCES")
171 def CleanTree(self, files, dir=".", recurse=True, verbose=False):
176 for file
in SCons.Script.Split(files):
180 files_expr +=
"-name %s" % re.sub(
r"(^|[^\\])([[*])",
r"\1\\\2",file)
184 action =
"find %s" % dir
185 action +=
r" \( -name .svn -prune -o -name \* \) "
187 action +=
" ! -name . -prune"
189 file_action =
"rm -f"
191 action +=
r" \( %s \) -exec %s {} \;" % \
192 (files_expr, file_action)
201 action +=
" ; rm -rf .sconf_temp .sconsign.dblite .sconsign.tmp config.log"
205 if "clean" in SCons.Script.COMMAND_LINE_TARGETS:
206 state.log.fail(
"'scons clean' is no longer supported; please use 'scons --clean'.")
207 elif not SCons.Script.COMMAND_LINE_TARGETS
and self.GetOption(
"clean"):
208 self.Execute(self.Action([action]))
214 from .
import eupsForScons
220 _productDirs = eupsForScons.productDir(eupsenv=eupsForScons.getEups())
224 pdir = _productDirs.get(product)
226 pdir = eupsForScons.productDir(product)
241 self.__dict__.update(kw)
246 self.
inputs = list(SCons.Script.Entry(item).abspath
for item
in self.
inputs)
248 self.
outputPaths = list(SCons.Script.Dir(item)
for item
in self.outputs)
253 inConfigNode = SCons.Script.File(config)
254 outConfigName, ext = os.path.splitext(inConfigNode.abspath)
255 outConfigNode = SCons.Script.File(outConfigName)
257 tagNode = SCons.Script.File(self.
makeTag)
259 self.targets.append(tagNode)
260 config = env.Command(target=outConfigNode, source=inConfigNode
if os.path.exists(config)
else None,
262 env.AlwaysBuild(config)
264 action=
"doxygen %s" % outConfigNode.abspath)
267 env.Depends(doc, config)
268 self.results.extend(config)
269 self.results.extend(doc)
274 if os.path.isdir(path):
275 for root, dirs, files
in os.walk(path):
276 if os.path.abspath(root)
in self.
excludes:
279 if not self.recursive:
284 if relDir.startswith(
"."):
286 absDir = os.path.abspath(os.path.join(root, relDir))
288 toKeep.append(relDir)
291 for relFile
in files:
292 base, ext = os.path.splitext(relFile)
294 self.excludes.append(os.path.join(root, base +
".py"))
295 self.excludes.append(os.path.join(root, base +
"_wrap.cc"))
296 for relFile
in files:
297 absFile = os.path.abspath(os.path.join(root, relFile))
300 for pattern
in self.patterns:
301 if fnmatch.fnmatch(relFile, pattern):
302 self.sources.append(SCons.Script.File(absFile))
304 elif os.path.isfile(path):
305 self.sources.append(SCons.Script.File(path))
308 for item
in self.outputs:
309 self.targets.append(SCons.Script.Dir(item))
312 outConfigFile = open(target[0].abspath,
"w")
314 docDir, tagFile = os.path.split(tagPath)
315 htmlDir = os.path.join(docDir,
"html")
316 outConfigFile.write(
'TAGFILES += "%s=%s"\n' % (tagPath, htmlDir))
317 self.sources.append(SCons.Script.Dir(docDir))
320 for incPath
in self.includes:
321 docDir, incFile = os.path.split(incPath)
322 docPaths.append(
'"%s"' % docDir)
323 incFiles.append(
'"%s"' % incFile)
324 self.sources.append(SCons.Script.File(incPath))
326 outConfigFile.write(
'@INCLUDE_PATH = %s\n' %
" ".join(docPaths))
327 for incFile
in incFiles:
328 outConfigFile.write(
'@INCLUDE = %s\n' % incFile)
329 if self.projectName
is not None:
330 outConfigFile.write(
"PROJECT_NAME = %s\n" % self.projectName)
331 if self.projectNumber
is not None:
332 outConfigFile.write(
"PROJECT_NUMBER = %s\n" % self.projectNumber)
333 outConfigFile.write(
"INPUT = %s\n" %
" ".join(self.
inputs))
334 outConfigFile.write(
"EXCLUDE = %s\n" %
" ".join(self.
excludes))
335 outConfigFile.write(
"FILE_PATTERNS = %s\n" %
" ".join(self.patterns))
336 outConfigFile.write(
"RECURSIVE = YES\n" if self.recursive
else "RECURSIVE = NO\n")
337 allOutputs = set((
"html",
"latex",
"man",
"rtf",
"xml"))
338 for output, path
in zip(self.outputs, self.
outputPaths):
340 allOutputs.remove(output.lower())
342 state.log.fail(
"Unknown Doxygen output format '%s'." % output)
344 outConfigFile.write(
"GENERATE_%s = YES\n" % output.upper())
345 outConfigFile.write(
"%s_OUTPUT = %s\n" % (output.upper(), path.abspath))
346 for output
in allOutputs:
347 outConfigFile.write(
"GENERATE_%s = NO\n" % output.upper())
349 outConfigFile.write(
"GENERATE_TAGFILE = %s\n" % self.
makeTag)
354 with open(source[0].abspath,
"r") as inConfigFile:
355 outConfigFile.write(inConfigFile.read())
357 outConfigFile.close()
426 inputs = [d
for d
in [
"#doc",
"#include",
"#python",
"#src"]
427 if os.path.exists(SCons.Script.Entry(d).abspath)]
431 "patterns": [
"*.h",
"*.cc",
"*.py",
"*.dox"],
432 "outputs": [
"html",],
438 "projectNumber":
None,
442 if kw.get(k)
is None:
445 return builder(self, config)
449 if versionString
is None:
450 for n
in (
"git",
"hg",
"svn",):
451 if os.path.isdir(
".%s" % n):
454 if not versionString:
455 versionString =
"git"
457 def calcMd5(filename):
460 md5 = hashlib.md5(
"\n".join(open(filename).readlines())).hexdigest()
466 oldMd5 = calcMd5(filename)
468 def makeVersionModule(target, source, env):
473 parts = version.split(
"+")
476 with open(target[0].abspath,
"w")
as outFile:
477 outFile.write(
"#--------- This file is automatically generated by LSST's sconsUtils ---------#\n")
480 outFile.write(
"%s = '%s'\n" % (what, version))
483 what =
"__repo_version__"
484 outFile.write(
"%s = '%s'\n" % (what, parts[0]))
487 what =
"__repo_version__"
488 outFile.write(
"%s = '%s'\n" % (what, parts[0]))
491 what =
"__fingerprint__"
492 outFile.write(
"%s = '%s'\n" % (what,
getFingerprint(versionString)))
496 info = tuple(int(v)
for v
in parts[0].split(
"."))
497 what =
"__version_info__"
499 outFile.write(
"%s = %r\n" % (what, info))
505 what =
"__rebuild_version__"
506 outFile.write(
"%s = %s\n" % (what, int(parts[1])))
511 what =
"__dependency_versions__"
513 outFile.write(
"%s = {\n" % (what))
514 for name, mod
in env.dependencies.packages.items():
516 outFile.write(
" '%s': None,\n" % name)
517 elif hasattr(mod.config,
"version"):
518 outFile.write(
" '%s': '%s',\n" % (name, mod.config.version))
520 outFile.write(
" '%s': 'unknown',\n" % name)
523 outFile.write(
"__all__ = %r\n" % (tuple(names),))
525 if calcMd5(target[0].abspath) != oldMd5:
526 state.log.info(
"makeVersionModule([\"%s\"], [])" % str(target[0]))
528 result = self.Command(filename, [], self.Action(makeVersionModule, strfunction=
lambda *args:
None))
530 self.AlwaysBuild(result)
def getFingerprint
Return a unique fingerprint for a version (e.g.
def memberOf
A Python decorator that injects functions into a class.
def filesToTag
Return a list of files that need to be scanned for tags, starting at directory root.
def CleanTree
Remove files matching the argument list starting at dir when scons is invoked with -c/–clean and no e...
def ProductDir
Return a product's PRODUCT_DIR, or None.
def determineVersion
Set a version ID from env, or a version control ID string ($name$ or $HeadURL$)
def Doxygen
Generate a Doxygen config file and run Doxygen on it.
def SharedLibraryIncomplete
Like SharedLibrary, but don't insist that all symbols are resolved.
def BuildETags
Build Emacs tags (see man etags for more information).
def SwigLoadableModule
Like LoadableModule, but don't insist that all symbols are resolved, and set some SWIG-specific flags...
def SourcesForSharedLibrary
Prepare the list of files to be passed to a SharedLibrary constructor.
A callable to be used as an SCons Action to run Doxygen.