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")):
71 objs = [self.SharedObject(ccFile)
for ccFile
in sorted(state.env.Flatten(files), key=str)]
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 obj = self.SharedObject(ccFile, CCFLAGS=CCFLAGS_OPT)
103 elif noOptFilesRe
and re.search(noOptFilesRe, ccFile.abspath):
104 obj = self.SharedObject(ccFile, CCFLAGS=CCFLAGS_NOOPT)
106 obj = self.SharedObject(ccFile)
109 objs = sorted(state.env.Flatten(sources), key=str)
126 if fileRegex
is None:
127 fileRegex =
r"^[a-zA-Z0-9_].*\.(cc|h(pp)?|py)$"
128 if ignoreDirs
is None:
129 ignoreDirs = [
"examples",
"tests"]
131 if "TAGS" not in SCons.Script.COMMAND_LINE_TARGETS:
135 for dirpath, dirnames, filenames
in os.walk(root):
137 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(%s)$" %
"|".join(ignoreDirs), d)]
139 dirnames[:] = [d
for d
in dirnames
if not re.search(
r"^(\.svn)$", d)]
143 candidates = [f
for f
in filenames
if re.search(fileRegex, f)]
147 for swigFile
in [f
for f
in filenames
if re.search(
r"\.i$", f)]:
148 name = os.path.splitext(swigFile)[0]
149 candidates = [f
for f
in candidates
if not re.search(
r"%s(_wrap\.cc?|\.py)$" % name, f)]
151 files += [os.path.join(dirpath, f)
for f
in candidates]
163 def BuildETags(env, root=None, fileRegex=None, ignoreDirs=None):
164 toTag =
filesToTag(root, fileRegex, ignoreDirs)
166 return env.Command(
"TAGS", toTag,
"etags -o $TARGET $SOURCES")
181 def CleanTree(self, files, dir=".", recurse=True, verbose=False):
186 for file
in SCons.Script.Split(files):
190 files_expr +=
"-name %s" % re.sub(
r"(^|[^\\])([[*])",
r"\1\\\2", file)
194 action =
"find %s" % dir
195 action +=
r" \( -name .svn -prune -o -name \* \) "
197 action +=
" ! -name . -prune"
199 file_action =
"rm -f"
201 action +=
r" \( %s \) -exec %s {} \;" % \
202 (files_expr, file_action)
211 action +=
" ; rm -rf .sconf_temp .sconsign.dblite .sconsign.tmp config.log"
215 if "clean" in SCons.Script.COMMAND_LINE_TARGETS:
216 state.log.fail(
"'scons clean' is no longer supported; please use 'scons --clean'.")
217 elif not SCons.Script.COMMAND_LINE_TARGETS
and self.GetOption(
"clean"):
218 self.Execute(self.Action([action]))
225 from .
import eupsForScons
231 _productDirs = eupsForScons.productDir(eupsenv=eupsForScons.getEups())
235 pdir = _productDirs.get(product)
237 pdir = eupsForScons.productDir(product)
253 self.__dict__.update(kw)
258 self.
inputs = list(SCons.Script.Entry(item).abspath
for item
in self.
inputs)
260 self.
outputPaths = list(SCons.Script.Dir(item)
for item
in self.outputs)
265 inConfigNode = SCons.Script.File(config)
266 outConfigName, ext = os.path.splitext(inConfigNode.abspath)
267 outConfigNode = SCons.Script.File(outConfigName)
269 tagNode = SCons.Script.File(self.
makeTag)
271 self.targets.append(tagNode)
272 config = env.Command(target=outConfigNode, source=inConfigNode
if os.path.exists(config)
else None,
274 env.AlwaysBuild(config)
276 action=
"doxygen %s" % pipes.quote(outConfigNode.abspath))
279 env.Depends(doc, config)
280 self.results.extend(config)
281 self.results.extend(doc)
286 if os.path.isdir(path):
287 for root, dirs, files
in os.walk(path):
288 if os.path.abspath(root)
in self.
excludes:
291 if not self.recursive:
296 if relDir.startswith(
"."):
298 absDir = os.path.abspath(os.path.join(root, relDir))
300 toKeep.append(relDir)
303 for relFile
in files:
304 base, ext = os.path.splitext(relFile)
306 self.excludes.append(os.path.join(root, base +
".py"))
307 self.excludes.append(os.path.join(root, base +
"_wrap.cc"))
308 for relFile
in files:
309 absFile = os.path.abspath(os.path.join(root, relFile))
312 for pattern
in self.patterns:
313 if fnmatch.fnmatch(relFile, pattern):
314 self.sources.append(SCons.Script.File(absFile))
316 elif os.path.isfile(path):
317 self.sources.append(SCons.Script.File(path))
320 for item
in self.outputs:
321 self.targets.append(SCons.Script.Dir(item))
324 outConfigFile = open(target[0].abspath,
"w")
332 def _quote_path(path):
333 if " " in path
and not path.startswith(
'"')
and not path.endswith(
'"'):
334 return '"{}"'.
format(path)
337 def _quote_paths(pathList):
338 return " ".join(_quote_path(p)
for p
in pathList)
341 docDir, tagFile = os.path.split(tagPath)
342 htmlDir = os.path.join(docDir,
"html")
343 outConfigFile.write(
'TAGFILES += "%s=%s"\n' % (tagPath, htmlDir))
344 self.sources.append(SCons.Script.Dir(docDir))
347 for incPath
in self.includes:
348 docDir, incFile = os.path.split(incPath)
349 docPaths.append(
'"%s"' % docDir)
350 incFiles.append(
'"%s"' % incFile)
351 self.sources.append(SCons.Script.File(incPath))
353 outConfigFile.write(
'@INCLUDE_PATH = %s\n' % _quote_paths(docPaths))
354 for incFile
in incFiles:
355 outConfigFile.write(
'@INCLUDE = %s\n' % _quote_path(incFile))
356 if self.projectName
is not None:
357 outConfigFile.write(
"PROJECT_NAME = %s\n" % self.projectName)
358 if self.projectNumber
is not None:
359 outConfigFile.write(
"PROJECT_NUMBER = %s\n" % self.projectNumber)
360 outConfigFile.write(
"INPUT = %s\n" % _quote_paths(self.
inputs))
361 outConfigFile.write(
"EXCLUDE = %s\n" % _quote_paths(self.
excludes))
362 outConfigFile.write(
"FILE_PATTERNS = %s\n" %
" ".join(self.patterns))
363 outConfigFile.write(
"RECURSIVE = YES\n" if self.recursive
else "RECURSIVE = NO\n")
364 allOutputs = set((
"html",
"latex",
"man",
"rtf",
"xml"))
365 for output, path
in zip(self.outputs, self.
outputPaths):
367 allOutputs.remove(output.lower())
369 state.log.fail(
"Unknown Doxygen output format '%s'." % output)
371 outConfigFile.write(
"GENERATE_%s = YES\n" % output.upper())
372 outConfigFile.write(
"%s_OUTPUT = %s\n" % (output.upper(), _quote_path(path.abspath)))
373 for output
in allOutputs:
374 outConfigFile.write(
"GENERATE_%s = NO\n" % output.upper())
376 outConfigFile.write(
"GENERATE_TAGFILE = %s\n" % _quote_path(self.
makeTag))
381 with open(source[0].abspath,
"r") as inConfigFile:
382 outConfigFile.write(inConfigFile.read())
384 outConfigFile.close()
454 inputs = [d
for d
in [
"#doc",
"#include",
"#python",
"#src"]
455 if os.path.exists(SCons.Script.Entry(d).abspath)]
459 "patterns": [
"*.h",
"*.cc",
"*.py",
"*.dox"],
460 "outputs": [
"html",
"xml"],
466 "projectNumber":
None,
470 if kw.get(k)
is None:
473 return builder(self, config)
478 if versionString
is None:
479 for n
in (
"git",
"hg",
"svn",):
480 if os.path.isdir(
".%s" % n):
483 if not versionString:
484 versionString =
"git"
486 def calcMd5(filename):
489 md5 = hashlib.md5(
"\n".join(open(filename).readlines())).hexdigest()
495 oldMd5 = calcMd5(filename)
497 def makeVersionModule(target, source, env):
502 parts = version.split(
"+")
505 with open(target[0].abspath,
"w")
as outFile:
506 outFile.write(
"#--------- This file is automatically generated by LSST's sconsUtils ---------#\n")
509 outFile.write(
"%s = '%s'\n" % (what, version))
512 what =
"__repo_version__"
513 outFile.write(
"%s = '%s'\n" % (what, parts[0]))
516 what =
"__fingerprint__"
517 outFile.write(
"%s = '%s'\n" % (what,
getFingerprint(versionString)))
521 info = tuple(int(v)
for v
in parts[0].split(
"."))
522 what =
"__version_info__"
524 outFile.write(
"%s = %r\n" % (what, info))
530 what =
"__rebuild_version__"
531 outFile.write(
"%s = %s\n" % (what, int(parts[1])))
536 what =
"__dependency_versions__"
538 outFile.write(
"%s = {\n" % (what))
539 for name, mod
in env.dependencies.packages.items():
541 outFile.write(
" '%s': None,\n" % name)
542 elif hasattr(mod.config,
"version"):
543 outFile.write(
" '%s': '%s',\n" % (name, mod.config.version))
545 outFile.write(
" '%s': 'unknown',\n" % name)
548 outFile.write(
"__all__ = %r\n" % (tuple(names),))
550 if calcMd5(target[0].abspath) != oldMd5:
551 state.log.info(
"makeVersionModule([\"%s\"], [])" % str(target[0]))
553 result = self.Command(filename, [], self.Action(makeVersionModule, strfunction=
lambda *args:
None))
555 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.