7 from __future__
import absolute_import, division, print_function
14 from SCons.Script.SConscript
import SConsEnvironment
16 from .utils
import memberOf
17 from .installation
import determineVersion, getFingerprint
25 if myenv[
'PLATFORM'] ==
'darwin':
26 myenv[
'SHLINKFLAGS'] += [
"-undefined",
"suppress",
"-flat_namespace",
"-headerpad_max_install_names"]
27 return myenv.SharedLibrary(target, source, **keywords)
35 if myenv[
'PLATFORM'] ==
'darwin':
36 myenv.Append(LDMODULEFLAGS=[
"-undefined",
"suppress",
37 "-flat_namespace",
"-headerpad_max_install_names"])
43 if myenv.whichCc ==
"gcc":
44 myenv.Append(CCFLAGS=[
"-fno-strict-aliasing"])
45 except AttributeError:
47 return myenv.LoadableModule(target, source, **keywords)
68 files = [SCons.Script.File(file)
for file
in files]
70 if not (self.get(
"optFiles")
or self.get(
"noOptFiles")):
74 if self.get(
"optFiles"):
75 optFiles = self[
"optFiles"].replace(
".",
r"\.")
76 optFiles = SCons.Script.Split(optFiles.replace(
",",
" "))
77 optFilesRe =
"/(%s)$" %
"|".join(optFiles)
81 if self.get(
"noOptFiles"):
82 noOptFiles = self[
"noOptFiles"].replace(
".",
r"\.")
83 noOptFiles = SCons.Script.Split(noOptFiles.replace(
",",
" "))
84 noOptFilesRe =
"/(%s)$" %
"|".join(noOptFiles)
89 opt = int(self[
"opt"])
96 CCFLAGS_OPT = re.sub(
r"-O(\d|s)\s*",
"-O%d " % opt,
" ".join(self[
"CCFLAGS"]))
97 CCFLAGS_NOOPT = re.sub(
r"-O(\d|s)\s*",
"-O0 ",
" ".join(self[
"CCFLAGS"]))
101 if optFilesRe
and re.search(optFilesRe, ccFile.abspath):
102 self.SharedObject(ccFile, CCFLAGS=CCFLAGS_OPT)
103 ccFile = os.path.splitext(ccFile.abspath)[0] + self[
"SHOBJSUFFIX"]
104 elif noOptFilesRe
and re.search(noOptFilesRe, ccFile.abspath):
105 self.SharedObject(ccFile, CCFLAGS=CCFLAGS_NOOPT)
106 ccFile = os.path.splitext(ccFile.abspath)[0] + self[
"SHOBJSUFFIX"]
108 sources.append(ccFile)
127 if fileRegex
is None:
128 fileRegex =
r"^[a-zA-Z0-9_].*\.(cc|h(pp)?|py)$"
129 if ignoreDirs
is None:
130 ignoreDirs = [
"examples",
"tests"]
132 if "TAGS" not in SCons.Script.COMMAND_LINE_TARGETS:
136 for dirpath, dirnames, filenames
in os.walk(root):
138 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(%s)$" %
"|".join(ignoreDirs), d)]
140 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(\.svn)$", d)]
144 candidates = [f
for f
in filenames
if re.search(fileRegex, f)]
148 for swigFile
in [f
for f
in filenames
if re.search(
r"\.i$", f)]:
149 name = os.path.splitext(swigFile)[0]
150 candidates = [f
for f
in candidates
if not re.search(
r"%s(_wrap\.cc?|\.py)$" % name, f)]
152 files += [os.path.join(dirpath, f)
for f
in candidates]
164 def BuildETags(env, root=None, fileRegex=None, ignoreDirs=None):
165 toTag =
filesToTag(root, fileRegex, ignoreDirs)
167 return env.Command(
"TAGS", toTag,
"etags -o $TARGET $SOURCES")
182 def CleanTree(self, files, dir=".", recurse=True, verbose=False):
187 for file
in SCons.Script.Split(files):
191 files_expr +=
"-name %s" % re.sub(
r"(^|[^\\])([[*])",
r"\1\\\2", file)
195 action =
"find %s" % dir
196 action +=
r" \( -name .svn -prune -o -name \* \) "
198 action +=
" ! -name . -prune"
200 file_action =
"rm -f"
202 action +=
r" \( %s \) -exec %s {} \;" % \
203 (files_expr, file_action)
212 action +=
" ; rm -rf .sconf_temp .sconsign.dblite .sconsign.tmp config.log"
216 if "clean" in SCons.Script.COMMAND_LINE_TARGETS:
217 state.log.fail(
"'scons clean' is no longer supported; please use 'scons --clean'.")
218 elif not SCons.Script.COMMAND_LINE_TARGETS
and self.GetOption(
"clean"):
219 self.Execute(self.Action([action]))
226 from .
import eupsForScons
232 _productDirs = eupsForScons.productDir(eupsenv=eupsForScons.getEups())
236 pdir = _productDirs.get(product)
238 pdir = eupsForScons.productDir(product)
254 self.__dict__.update(kw)
259 self.
inputs = list(SCons.Script.Entry(item).abspath
for item
in self.
inputs)
261 self.
outputPaths = list(SCons.Script.Dir(item)
for item
in self.outputs)
266 inConfigNode = SCons.Script.File(config)
267 outConfigName, ext = os.path.splitext(inConfigNode.abspath)
268 outConfigNode = SCons.Script.File(outConfigName)
270 tagNode = SCons.Script.File(self.
makeTag)
272 self.targets.append(tagNode)
273 config = env.Command(target=outConfigNode, source=inConfigNode
if os.path.exists(config)
else None,
275 env.AlwaysBuild(config)
277 action=
"doxygen %s" % pipes.quote(outConfigNode.abspath))
280 env.Depends(doc, config)
281 self.results.extend(config)
282 self.results.extend(doc)
287 if os.path.isdir(path):
288 for root, dirs, files
in os.walk(path):
289 if os.path.abspath(root)
in self.
excludes:
292 if not self.recursive:
297 if relDir.startswith(
"."):
299 absDir = os.path.abspath(os.path.join(root, relDir))
301 toKeep.append(relDir)
304 for relFile
in files:
305 base, ext = os.path.splitext(relFile)
307 self.excludes.append(os.path.join(root, base +
".py"))
308 self.excludes.append(os.path.join(root, base +
"_wrap.cc"))
309 for relFile
in files:
310 absFile = os.path.abspath(os.path.join(root, relFile))
313 for pattern
in self.patterns:
314 if fnmatch.fnmatch(relFile, pattern):
315 self.sources.append(SCons.Script.File(absFile))
317 elif os.path.isfile(path):
318 self.sources.append(SCons.Script.File(path))
321 for item
in self.outputs:
322 self.targets.append(SCons.Script.Dir(item))
325 outConfigFile = open(target[0].abspath,
"w")
333 def _quote_path(path):
334 if " " in path
and not path.startswith(
'"')
and not path.endswith(
'"'):
335 return '"{}"'.
format(path)
338 def _quote_paths(pathList):
339 return " ".join(_quote_path(p)
for p
in pathList)
342 docDir, tagFile = os.path.split(tagPath)
343 htmlDir = os.path.join(docDir,
"html")
344 outConfigFile.write(
'TAGFILES += "%s=%s"\n' % (tagPath, htmlDir))
345 self.sources.append(SCons.Script.Dir(docDir))
348 for incPath
in self.includes:
349 docDir, incFile = os.path.split(incPath)
350 docPaths.append(
'"%s"' % docDir)
351 incFiles.append(
'"%s"' % incFile)
352 self.sources.append(SCons.Script.File(incPath))
354 outConfigFile.write(
'@INCLUDE_PATH = %s\n' % _quote_paths(docPaths))
355 for incFile
in incFiles:
356 outConfigFile.write(
'@INCLUDE = %s\n' % _quote_path(incFile))
357 if self.projectName
is not None:
358 outConfigFile.write(
"PROJECT_NAME = %s\n" % self.projectName)
359 if self.projectNumber
is not None:
360 outConfigFile.write(
"PROJECT_NUMBER = %s\n" % self.projectNumber)
361 outConfigFile.write(
"INPUT = %s\n" % _quote_paths(self.
inputs))
362 outConfigFile.write(
"EXCLUDE = %s\n" % _quote_paths(self.
excludes))
363 outConfigFile.write(
"FILE_PATTERNS = %s\n" %
" ".join(self.patterns))
364 outConfigFile.write(
"RECURSIVE = YES\n" if self.recursive
else "RECURSIVE = NO\n")
365 allOutputs = set((
"html",
"latex",
"man",
"rtf",
"xml"))
366 for output, path
in zip(self.outputs, self.
outputPaths):
368 allOutputs.remove(output.lower())
370 state.log.fail(
"Unknown Doxygen output format '%s'." % output)
372 outConfigFile.write(
"GENERATE_%s = YES\n" % output.upper())
373 outConfigFile.write(
"%s_OUTPUT = %s\n" % (output.upper(), _quote_path(path.abspath)))
374 for output
in allOutputs:
375 outConfigFile.write(
"GENERATE_%s = NO\n" % output.upper())
377 outConfigFile.write(
"GENERATE_TAGFILE = %s\n" % _quote_path(self.
makeTag))
382 with open(source[0].abspath,
"r") as inConfigFile:
383 outConfigFile.write(inConfigFile.read())
385 outConfigFile.close()
455 inputs = [d
for d
in [
"#doc",
"#include",
"#python",
"#src"]
456 if os.path.exists(SCons.Script.Entry(d).abspath)]
460 "patterns": [
"*.h",
"*.cc",
"*.py",
"*.dox"],
461 "outputs": [
"html",
"xml"],
467 "projectNumber":
None,
471 if kw.get(k)
is None:
474 return builder(self, config)
479 if versionString
is None:
480 for n
in (
"git",
"hg",
"svn",):
481 if os.path.isdir(
".%s" % n):
484 if not versionString:
485 versionString =
"git"
487 def calcMd5(filename):
490 md5 = hashlib.md5(
"\n".join(open(filename).readlines())).hexdigest()
496 oldMd5 = calcMd5(filename)
498 def makeVersionModule(target, source, env):
503 parts = version.split(
"+")
506 with open(target[0].abspath,
"w")
as outFile:
507 outFile.write(
"#--------- This file is automatically generated by LSST's sconsUtils ---------#\n")
510 outFile.write(
"%s = '%s'\n" % (what, version))
513 what =
"__repo_version__"
514 outFile.write(
"%s = '%s'\n" % (what, parts[0]))
517 what =
"__fingerprint__"
518 outFile.write(
"%s = '%s'\n" % (what,
getFingerprint(versionString)))
522 info = tuple(int(v)
for v
in parts[0].split(
"."))
523 what =
"__version_info__"
525 outFile.write(
"%s = %r\n" % (what, info))
531 what =
"__rebuild_version__"
532 outFile.write(
"%s = %s\n" % (what, int(parts[1])))
537 what =
"__dependency_versions__"
539 outFile.write(
"%s = {\n" % (what))
540 for name, mod
in env.dependencies.packages.items():
542 outFile.write(
" '%s': None,\n" % name)
543 elif hasattr(mod.config,
"version"):
544 outFile.write(
" '%s': '%s',\n" % (name, mod.config.version))
546 outFile.write(
" '%s': 'unknown',\n" % name)
549 outFile.write(
"__all__ = %r\n" % (tuple(names),))
551 if calcMd5(target[0].abspath) != oldMd5:
552 state.log.info(
"makeVersionModule([\"%s\"], [])" % str(target[0]))
554 result = self.Command(filename, [], self.Action(makeVersionModule, strfunction=
lambda *args:
None))
556 self.AlwaysBuild(result)
def memberOf
A Python decorator that injects functions into a class.
def CleanTree
Remove files matching the argument list starting at dir when scons is invoked with -c/–clean and no e...
def Doxygen
Generate a Doxygen config file and run Doxygen on it.
def SharedLibraryIncomplete
def BuildETags
Build Emacs tags (see man etags for more information).
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.