Skip to content

Commit

Permalink
Merge pull request #7 from lsst/tickets/DM-3200
Browse files Browse the repository at this point in the history
Tickets/dm 3200

* Support OS X El Capitan by allowing DYLD_LIBRARY_PATH to be passed to tests.
* Allow the #! to be rewritten on certain platforms.
* Fixes to allow spaces in directory paths.
* PEP-8 fixes.
  • Loading branch information
timj committed Nov 10, 2015
2 parents a4d6864 + c06de5a commit 3ed848b
Show file tree
Hide file tree
Showing 8 changed files with 309 additions and 144 deletions.
49 changes: 32 additions & 17 deletions python/lsst/sconsUtils/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import re
import fnmatch
import pipes

import SCons.Script
from SCons.Script.SConscript import SConsEnvironment
Expand All @@ -16,6 +17,7 @@
from .installation import determineVersion, getFingerprint
from . import state


## @brief Like SharedLibrary, but don't insist that all symbols are resolved
@memberOf(SConsEnvironment)
def SharedLibraryIncomplete(self, target, source, **keywords):
Expand All @@ -24,26 +26,29 @@ def SharedLibraryIncomplete(self, target, source, **keywords):
myenv['SHLINKFLAGS'] += ["-undefined", "suppress", "-flat_namespace", "-headerpad_max_install_names"]
return myenv.SharedLibrary(target, source, **keywords)


## @brief Like LoadableModule, but don't insist that all symbols are resolved, and set
## some SWIG-specific flags.
@memberOf(SConsEnvironment)
def SwigLoadableModule(self, target, source, **keywords):
myenv = self.Clone()
if myenv['PLATFORM'] == 'darwin':
myenv.Append(LDMODULEFLAGS = ["-undefined", "suppress", "-flat_namespace", "-headerpad_max_install_names"])
myenv.Append(LDMODULEFLAGS=["-undefined", "suppress",
"-flat_namespace", "-headerpad_max_install_names"])
#
# Swig-generated .cc files cast pointers to long longs and back,
# which is illegal. This flag tells g++ about the sin
#
try:
if myenv.whichCc == "gcc":
myenv.Append(CCFLAGS = ["-fno-strict-aliasing",])
myenv.Append(CCFLAGS=["-fno-strict-aliasing"])
except AttributeError:
pass
return myenv.LoadableModule(target, source, **keywords)

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-


##
# @brief Prepare the list of files to be passed to a SharedLibrary constructor
#
Expand All @@ -67,14 +72,14 @@ def SourcesForSharedLibrary(self, files):
return files

if self.get("optFiles"):
optFiles = self["optFiles"].replace(".", r"\.") # it'll be used in an RE
optFiles = self["optFiles"].replace(".", r"\.") # it'll be used in an RE
optFiles = SCons.Script.Split(optFiles.replace(",", " "))
optFilesRe = "/(%s)$" % "|".join(optFiles)
else:
optFilesRe = None

if self.get("noOptFiles"):
noOptFiles = self["noOptFiles"].replace(".", r"\.") # it'll be used in an RE
noOptFiles = self["noOptFiles"].replace(".", r"\.") # it'll be used in an RE
noOptFiles = SCons.Script.Split(noOptFiles.replace(",", " "))
noOptFilesRe = "/(%s)$" % "|".join(noOptFiles)
else:
Expand All @@ -89,7 +94,7 @@ def SourcesForSharedLibrary(self, files):
opt = 3

CCFLAGS_OPT = re.sub(r"-O(\d|s)\s*", "-O%d " % opt, " ".join(self["CCFLAGS"]))
CCFLAGS_NOOPT = re.sub(r"-O(\d|s)\s*", "-O0 ", " ".join(self["CCFLAGS"])) # remove -O flags from CCFLAGS
CCFLAGS_NOOPT = re.sub(r"-O(\d|s)\s*", "-O0 ", " ".join(self["CCFLAGS"])) # remove -O flags from CCFLAGS

sources = []
for ccFile in files:
Expand All @@ -105,6 +110,7 @@ def SourcesForSharedLibrary(self, files):
sources.sort()
return sources


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

##
Expand All @@ -116,9 +122,12 @@ def SourcesForSharedLibrary(self, files):
# This routine won't do anything unless you specified a "TAGS" target
##
def filesToTag(root=None, fileRegex=None, ignoreDirs=None):
if root is None: root = "."
if fileRegex is None: fileRegex = r"^[a-zA-Z0-9_].*\.(cc|h(pp)?|py)$"
if ignoreDirs is None: ignoreDirs = ["examples", "tests"]
if root is None:
root = "."
if fileRegex is None:
fileRegex = r"^[a-zA-Z0-9_].*\.(cc|h(pp)?|py)$"
if ignoreDirs is None:
ignoreDirs = ["examples", "tests"]

if "TAGS" not in SCons.Script.COMMAND_LINE_TARGETS:
return []
Expand All @@ -128,7 +137,7 @@ def filesToTag(root=None, fileRegex=None, ignoreDirs=None):
if dirpath == ".":
dirnames[:] = [d for d in dirnames if not re.search(r"^(%s)$" % "|".join(ignoreDirs), d)]

dirnames[:] = [d for d in dirnames if not re.search(r"^(\.svn)$", d)] # ignore .svn tree
dirnames[:] = [d for d in dirnames if not re.search(r"^(\.svn)$", d)] # ignore .svn tree
#
# List of possible files to tag, but there's some cleanup required for machine-generated files
#
Expand All @@ -144,6 +153,7 @@ def filesToTag(root=None, fileRegex=None, ignoreDirs=None):

return files


##
# @brief Build Emacs tags (see man etags for more information).
#
Expand All @@ -156,6 +166,7 @@ def BuildETags(env, root=None, fileRegex=None, ignoreDirs=None):
if toTag:
return env.Command("TAGS", toTag, "etags -o $TARGET $SOURCES")


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

##
Expand All @@ -177,7 +188,7 @@ def CleanTree(self, files, dir=".", recurse=True, verbose=False):
if files_expr:
files_expr += " -o "

files_expr += "-name %s" % re.sub(r"(^|[^\\])([[*])", r"\1\\\2",file) # quote unquoted * and []
files_expr += "-name %s" % re.sub(r"(^|[^\\])([[*])", r"\1\\\2", file) # quote unquoted * and []
#
# don't use xargs --- who knows what needs quoting?
#
Expand Down Expand Up @@ -208,6 +219,7 @@ def CleanTree(self, files, dir=".", recurse=True, verbose=False):
self.Execute(self.Action([action]))
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


## @brief Return a product's PRODUCT_DIR, or None
@memberOf(SConsEnvironment)
def ProductDir(env, product):
Expand All @@ -228,6 +240,7 @@ def ProductDir(env, product):
pdir = None
return pdir


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

##
Expand Down Expand Up @@ -261,7 +274,7 @@ def __call__(self, env, config):
action=self.buildConfig)
env.AlwaysBuild(config)
doc = env.Command(target=self.targets, source=self.sources,
action="doxygen %s" % outConfigNode.abspath)
action="doxygen %s" % pipes.quote(outConfigNode.abspath))
for path in self.outputPaths:
env.Clean(doc, path)
env.Depends(doc, config)
Expand Down Expand Up @@ -330,8 +343,8 @@ def buildConfig(self, target, source, env):
outConfigFile.write("PROJECT_NAME = %s\n" % self.projectName)
if self.projectNumber is not None:
outConfigFile.write("PROJECT_NUMBER = %s\n" % self.projectNumber)
outConfigFile.write("INPUT = %s\n" % " ".join(self.inputs))
outConfigFile.write("EXCLUDE = %s\n" % " ".join(self.excludes))
outConfigFile.write("INPUT = %s\n" % " ".join('"{}"'.format(s) for s in self.inputs))
outConfigFile.write("EXCLUDE = %s\n" % " ".join('"{}"'.format(s) for s in self.excludes))
outConfigFile.write("FILE_PATTERNS = %s\n" % " ".join(self.patterns))
outConfigFile.write("RECURSIVE = YES\n" if self.recursive else "RECURSIVE = NO\n")
allOutputs = set(("html", "latex", "man", "rtf", "xml"))
Expand All @@ -342,11 +355,11 @@ def buildConfig(self, target, source, env):
state.log.fail("Unknown Doxygen output format '%s'." % output)
state.log.finish()
outConfigFile.write("GENERATE_%s = YES\n" % output.upper())
outConfigFile.write("%s_OUTPUT = %s\n" % (output.upper(), path.abspath))
outConfigFile.write('%s_OUTPUT = "%s"\n' % (output.upper(), path.abspath))
for output in allOutputs:
outConfigFile.write("GENERATE_%s = NO\n" % output.upper())
if self.makeTag is not None:
outConfigFile.write("GENERATE_TAGFILE = %s\n" % self.makeTag)
outConfigFile.write('GENERATE_TAGFILE = "%s"\n' % self.makeTag)
#
# Append the local overrides (usually doxygen.conf.in)
#
Expand All @@ -356,6 +369,7 @@ def buildConfig(self, target, source, env):

outConfigFile.close()


##
# @brief Generate a Doxygen config file and run Doxygen on it.
#
Expand Down Expand Up @@ -429,7 +443,7 @@ def Doxygen(self, config, **kw):
"inputs": inputs,
"recursive": True,
"patterns": ["*.h", "*.cc", "*.py", "*.dox"],
"outputs": ["html",],
"outputs": ["html"],
"excludes": [],
"includes": [],
"useTags": [],
Expand All @@ -444,6 +458,7 @@ def Doxygen(self, config, **kw):
builder = DoxygenBuilder(**kw)
return builder(self, config)


@memberOf(SConsEnvironment)
def VersionModule(self, filename, versionString=None):
if versionString is None:
Expand Down Expand Up @@ -522,7 +537,7 @@ def makeVersionModule(target, source, env):

outFile.write("__all__ = %r\n" % (tuple(names),))

if calcMd5(target[0].abspath) != oldMd5: # only print if something's changed
if calcMd5(target[0].abspath) != oldMd5: # only print if something's changed
state.log.info("makeVersionModule([\"%s\"], [])" % str(target[0]))

result = self.Command(filename, [], self.Action(makeVersionModule, strfunction=lambda *args: None))
Expand Down
52 changes: 31 additions & 21 deletions python/lsst/sconsUtils/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
import os.path
import collections
import imp
import sys
import SCons.Script
from . import eupsForScons
from SCons.Script.SConscript import SConsEnvironment

from . import installation
from . import state


##
# @brief Recursively configure a package using ups/.cfg files.
#
Expand Down Expand Up @@ -64,9 +64,9 @@ def configure(packageName, versionString=None, eupsProduct=None, eupsProductPath
state.log.traceback = state.env.GetOption("traceback")
state.log.verbose = state.env.GetOption("verbose")
packages = PackageTree(packageName, noCfgFile=noCfgFile)
state.log.flush() # if we've already hit a fatal error, die now.
state.env.libs = {"main":[], "python":[], "test":[]}
state.env.doxygen = {"tags":[], "includes":[]}
state.log.flush() # if we've already hit a fatal error, die now.
state.env.libs = {"main": [], "python": [], "test": []}
state.env.doxygen = {"tags": [], "includes": []}
state.env['CPPPATH'] = []
state.env['LIBPATH'] = []

Expand All @@ -91,6 +91,7 @@ def configure(packageName, versionString=None, eupsProduct=None, eupsProductPath
state.env.dependencies = packages
state.log.flush()


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

##
Expand Down Expand Up @@ -150,7 +151,7 @@ def getEupsData(eupsProduct):
# .cfg file.
##
def __init__(self, cfgFile, headers=(), libs=None, hasSwigFiles=True,
includeFileDirs=["include",], libFileDirs=["lib",],
includeFileDirs=["include"], libFileDirs=["lib"],
hasDoxygenInclude=False, hasDoxygenTag=True, eupsProduct=None):
self.name, self.root = self.parseFilename(cfgFile)
if eupsProduct is None:
Expand All @@ -177,9 +178,9 @@ def __init__(self, cfgFile, headers=(), libs=None, hasSwigFiles=True,
# Normal libraries provided by this package
"main": [self.name],
# Libraries provided that should only be linked with Python modules
"python":[],
"python": [],
# Libraries provided that should only be linked with unit test code
"test":[],
"test": [],
}
elif "main" in libs:
self.libs = libs
Expand All @@ -192,7 +193,7 @@ def __init__(self, cfgFile, headers=(), libs=None, hasSwigFiles=True,
self.paths["SWIGPATH"] = []

for pathName, subDirs in [("CPPPATH", includeFileDirs),
("LIBPATH", libFileDirs),]:
("LIBPATH", libFileDirs)]:
self.paths[pathName] = []

if state.env.linkFarmDir:
Expand Down Expand Up @@ -244,7 +245,7 @@ def configure(self, conf, packages, check=False, build=True):
conf.env.doxygen["tags"].extend(self.doxygen["tags"])
for target in self.libs:
if target not in conf.env.libs:
conf.env.libs[target] = lib[target].copy()
conf.env.libs[target] = self.libs[target].copy()
state.log.info("Adding '%s' libraries to target '%s'." % (self.libs[target], target))
else:
for lib in self.libs[target]:
Expand All @@ -253,11 +254,14 @@ def configure(self, conf, packages, check=False, build=True):
state.log.info("Adding '%s' library to target '%s'." % (lib, target))
if check:
for header in self.provides["headers"]:
if not conf.CheckCXXHeader(header): return False
if not conf.CheckCXXHeader(header):
return False
for lib in self.libs["main"]:
if not conf.CheckLib(lib, autoadd=False, language="C++"): return False
if not conf.CheckLib(lib, autoadd=False, language="C++"):
return False
return True


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

##
Expand Down Expand Up @@ -292,6 +296,7 @@ def __init__(self, cfgFile, headers=(), libs=None, eupsProduct=None):
self.paths["XCPPPATH"] = self.paths["CPPPATH"]
del self.paths["CPPPATH"]


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

##
Expand All @@ -305,14 +310,15 @@ def __init__(self, cfgFile, headers=(), libs=None, eupsProduct=None):
##
def CustomCFlagCheck(context, flag, append=True):
context.Message("Checking if C compiler supports " + flag + " flag ")
ccflags = context.env["CCFLAGS"];
context.env.Append(CCFLAGS = flag)
ccflags = context.env["CCFLAGS"]
context.env.Append(CCFLAGS=flag)
result = context.TryCompile("int main(int argc, char **argv) { return 0; }", ".c")
context.Result(result)
if not append or not result:
context.env.Replace(CCFLAGS = ccflags)
context.env.Replace(CCFLAGS=ccflags)
return result


##
# @brief A configuration test that checks whether a C++ compiler supports
# a particular flag.
Expand All @@ -324,14 +330,15 @@ def CustomCFlagCheck(context, flag, append=True):
##
def CustomCppFlagCheck(context, flag, append=True):
context.Message("Checking if C++ compiler supports " + flag + " flag ")
cxxflags = context.env["CXXFLAGS"];
context.env.Append(CXXFLAGS = flag)
cxxflags = context.env["CXXFLAGS"]
context.env.Append(CXXFLAGS=flag)
result = context.TryCompile("int main(int argc, char **argv) { return 0; }", ".cc")
context.Result(result)
if not append or not result:
context.env.Replace(CXXFLAGS = cxxflags)
context.env.Replace(CXXFLAGS=cxxflags)
return result


##
# @brief A configuration test that checks whether the given source code
# compiles.
Expand All @@ -354,6 +361,7 @@ def CustomCompileCheck(context, message, source, extension=".cc"):

return result


##
# @brief A configuration test that checks whether the given source code
# compiles and links.
Expand All @@ -369,6 +377,7 @@ def CustomLinkCheck(context, message, source, extension=".cc"):
context.Result(result)
return result


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

##
Expand Down Expand Up @@ -401,10 +410,10 @@ def __init__(self, primaryName, noCfgFile=False):
self.cfgPath = state.env.cfgPath
self.packages = collections.OrderedDict()
self.customTests = {
"CustomCFlagCheck" : CustomCFlagCheck,
"CustomCppFlagCheck" : CustomCppFlagCheck,
"CustomCompileCheck" : CustomCompileCheck,
"CustomLinkCheck" : CustomLinkCheck,
"CustomCFlagCheck": CustomCFlagCheck,
"CustomCppFlagCheck": CustomCppFlagCheck,
"CustomCompileCheck": CustomCompileCheck,
"CustomLinkCheck": CustomLinkCheck,
}
self._current = set([primaryName])
if noCfgFile:
Expand Down Expand Up @@ -532,6 +541,7 @@ def _recurse(self, name):
self._current.remove(name)
return True


#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

##
Expand Down

0 comments on commit 3ed848b

Please sign in to comment.