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.
This commit is contained in:
Adam J. Stewart 2018-07-18 13:11:10 -05:00 committed by scheibelp
parent af8dde4dda
commit a67139f6c5

View File

@ -1288,43 +1288,68 @@ def do_fake_install(self):
dump_packages(self.spec, packages_dir) dump_packages(self.spec, packages_dir)
def _if_make_target_execute(self, target): def _if_make_target_execute(self, target):
try: make = inspect.getmodule(self).make
# Check if we have a makefile
file = [x for x in ('Makefile', 'makefile') if os.path.exists(x)] # Check if we have a Makefile
file = file.pop() for makefile in ['GNUmakefile', 'Makefile', 'makefile']:
except IndexError: if os.path.exists(makefile):
break
else:
tty.msg('No Makefile found in the build directory') tty.msg('No Makefile found in the build directory')
return return
# Check if 'target' is in the makefile # Check if 'target' is a valid target
regex = re.compile('^' + target + ':') #
with open(file, 'r') as f: # -q, --question
matches = [line for line in f.readlines() if regex.match(line)] # ``Question mode''. Do not run any commands, or print anything;
# just return an exit status that is zero if the specified
if not matches: # targets are already up to date, nonzero otherwise.
tty.msg("Target '" + target + ":' not found in Makefile") #
# 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 return
# Execute target # Execute target
inspect.getmodule(self).make(target) make(target)
def _if_ninja_target_execute(self, 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'): 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 return
# Check if 'target' is in the ninja build script # Get a list of all targets in the Ninja build script
regex = re.compile('^build ' + target + ':') # https://ninja-build.org/manual.html#_extra_tools
with open('build.ninja', 'r') as f: all_targets = ninja('-t', 'targets', output=str).split('\n')
matches = [line for line in f.readlines() if regex.match(line)]
# Check if 'target' is a valid target
matches = [line for line in all_targets
if line.startswith(target + ':')]
if not matches: if not matches:
tty.msg("Target 'build " + target + ":' not found in build.ninja") tty.msg("Target '" + target + "' not found in build.ninja")
return return
# Execute target # Execute target
inspect.getmodule(self).ninja(target) ninja(target)
def _get_needed_resources(self): def _get_needed_resources(self):
resources = [] resources = []