summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAdam J. Stewart <ajstewart426@gmail.com>2018-07-18 13:11:10 -0500
committerscheibelp <scheibel1@llnl.gov>2018-07-18 11:11:10 -0700
commita67139f6c5ecd3acab4adaa5cdd5b9e387f4c6cb (patch)
tree4aca733a5d175fd3442ff5240423c68ad09fac52 /lib
parentaf8dde4ddaa20bdcc1f191fdc9976cbd8b2aa441 (diff)
downloadspack-a67139f6c5ecd3acab4adaa5cdd5b9e387f4c6cb.tar.gz
spack-a67139f6c5ecd3acab4adaa5cdd5b9e387f4c6cb.tar.bz2
spack-a67139f6c5ecd3acab4adaa5cdd5b9e387f4c6cb.tar.xz
spack-a67139f6c5ecd3acab4adaa5cdd5b9e387f4c6cb.zip
Better Makefile target detection (#8223)
Replace regex-based target detection for Makefiles with a preliminary "make -q" to check if a target exists. This does not work for NetBSD make; additional work is required to detect if NetBSD make is present and to use a regex in that case. The affected makefile target checks are only performed when the "--test" flag is added to a "spack install" invocation.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/package.py67
1 files changed, 46 insertions, 21 deletions
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index c79237dbef..b203551b07 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -1288,43 +1288,68 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
dump_packages(self.spec, packages_dir)
def _if_make_target_execute(self, target):
- try:
- # Check if we have a makefile
- file = [x for x in ('Makefile', 'makefile') if os.path.exists(x)]
- file = file.pop()
- except IndexError:
+ make = inspect.getmodule(self).make
+
+ # Check if we have a Makefile
+ for makefile in ['GNUmakefile', 'Makefile', 'makefile']:
+ if os.path.exists(makefile):
+ break
+ else:
tty.msg('No Makefile found in the build directory')
return
- # Check if 'target' is in the makefile
- regex = re.compile('^' + target + ':')
- with open(file, 'r') as f:
- matches = [line for line in f.readlines() if regex.match(line)]
-
- if not matches:
- tty.msg("Target '" + target + ":' not found in Makefile")
+ # Check if 'target' is a valid target
+ #
+ # -q, --question
+ # ``Question mode''. Do not run any commands, or print anything;
+ # just return an exit status that is zero if the specified
+ # targets are already up to date, nonzero otherwise.
+ #
+ # https://www.gnu.org/software/make/manual/html_node/Options-Summary.html
+ #
+ # The exit status of make is always one of three values:
+ #
+ # 0 The exit status is zero if make is successful.
+ #
+ # 2 The exit status is two if make encounters any errors.
+ # It will print messages describing the particular errors.
+ #
+ # 1 The exit status is one if you use the '-q' flag and make
+ # determines that some target is not already up to date.
+ #
+ # https://www.gnu.org/software/make/manual/html_node/Running.html
+ #
+ # NOTE: This only works for GNU Make, not NetBSD Make.
+ make('-q', target, fail_on_error=False)
+ if make.returncode == 2:
+ tty.msg("Target '" + target + "' not found in " + makefile)
return
# Execute target
- inspect.getmodule(self).make(target)
+ make(target)
def _if_ninja_target_execute(self, target):
- # Check if we have a ninja build script
+ ninja = inspect.getmodule(self).ninja
+
+ # Check if we have a Ninja build script
if not os.path.exists('build.ninja'):
- tty.msg('No ninja build script found in the build directory')
+ tty.msg('No Ninja build script found in the build directory')
return
- # Check if 'target' is in the ninja build script
- regex = re.compile('^build ' + target + ':')
- with open('build.ninja', 'r') as f:
- matches = [line for line in f.readlines() if regex.match(line)]
+ # Get a list of all targets in the Ninja build script
+ # https://ninja-build.org/manual.html#_extra_tools
+ all_targets = ninja('-t', 'targets', output=str).split('\n')
+
+ # Check if 'target' is a valid target
+ matches = [line for line in all_targets
+ if line.startswith(target + ':')]
if not matches:
- tty.msg("Target 'build " + target + ":' not found in build.ninja")
+ tty.msg("Target '" + target + "' not found in build.ninja")
return
# Execute target
- inspect.getmodule(self).ninja(target)
+ ninja(target)
def _get_needed_resources(self):
resources = []