autotools: recursively patch config.guess and config.sub (#18347)

Previously config.guess and config.sub were patched only
in the root of the source path. 

This modification extend the previous behavior to patch every
config.guess or config.sub file even in subfolders, if need be.

Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
This commit is contained in:
Toyohisa Kameyama 2020-10-16 18:30:06 +09:00 committed by GitHub
parent cdeecf2507
commit a481087695
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3,10 +3,9 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import inspect import inspect
import itertools
import os import os
import os.path import os.path
import shutil
import stat
from subprocess import PIPE from subprocess import PIPE
from subprocess import check_call from subprocess import check_call
@ -103,8 +102,8 @@ def _do_patch_config_files(self):
"""Some packages ship with older config.guess/config.sub files and """Some packages ship with older config.guess/config.sub files and
need to have these updated when installed on a newer architecture. need to have these updated when installed on a newer architecture.
In particular, config.guess fails for PPC64LE for version prior In particular, config.guess fails for PPC64LE for version prior
to a 2013-06-10 build date (automake 1.13.4) and for ARM (aarch64).""" to a 2013-06-10 build date (automake 1.13.4) and for ARM (aarch64).
"""
if not self.patch_config_files or ( if not self.patch_config_files or (
not self.spec.satisfies('target=ppc64le:') and not self.spec.satisfies('target=ppc64le:') and
not self.spec.satisfies('target=aarch64:') not self.spec.satisfies('target=aarch64:')
@ -121,70 +120,60 @@ def _do_patch_config_files(self):
else: else:
config_arch = 'local' config_arch = 'local'
my_config_files = {'guess': None, 'sub': None} def runs_ok(script_abs_path):
config_files = {'guess': None, 'sub': None} # Construct the list of arguments for the call
config_args = {'guess': [], 'sub': [config_arch]} additional_args = {
'config.sub': [config_arch]
}
script_name = os.path.basename(script_abs_path)
args = [script_abs_path] + additional_args.get(script_name, [])
for config_name in config_files.keys():
config_file = 'config.{0}'.format(config_name)
if os.path.exists(config_file):
# First search the top-level source directory
my_config_files[config_name] = os.path.abspath(config_file)
else:
# Then search in all sub directories recursively.
# We would like to use AC_CONFIG_AUX_DIR, but not all packages
# ship with their configure.in or configure.ac.
config_path = next((os.path.abspath(os.path.join(r, f))
for r, ds, fs in os.walk('.') for f in fs
if f == config_file), None)
my_config_files[config_name] = config_path
if my_config_files[config_name] is not None:
try: try:
config_path = my_config_files[config_name] check_call(args, stdout=PIPE, stderr=PIPE)
check_call([config_path] + config_args[config_name],
stdout=PIPE, stderr=PIPE)
# The package's config file already runs OK, so just use it
continue
except Exception as e: except Exception as e:
tty.debug(e) tty.debug(e)
else: return False
continue
# Look for a spack-installed automake package return True
# Compute the list of files that needs to be patched
search_dir = self.stage.path
to_be_patched = fs.find(
search_dir, files=['config.sub', 'config.guess'], recursive=True
)
to_be_patched = [f for f in to_be_patched if not runs_ok(f)]
# If there are no files to be patched, return early
if not to_be_patched:
return
# Directories where to search for files to be copied
# over the failing ones
good_file_dirs = ['/usr/share']
if 'automake' in self.spec: if 'automake' in self.spec:
automake_dir = 'automake-' + str(self.spec['automake'].version) good_file_dirs.insert(0, self.spec['automake'].prefix)
automake_path = os.path.join(self.spec['automake'].prefix,
'share', automake_dir)
path = os.path.join(automake_path, config_file)
if os.path.exists(path):
config_files[config_name] = path
# Look for the system's config.guess
if (config_files[config_name] is None and
os.path.exists('/usr/share')):
automake_dir = [s for s in os.listdir('/usr/share') if
"automake" in s]
if automake_dir:
automake_path = os.path.join('/usr/share', automake_dir[0])
path = os.path.join(automake_path, config_file)
if os.path.exists(path):
config_files[config_name] = path
if config_files[config_name] is not None:
try:
config_path = config_files[config_name]
my_config_path = my_config_files[config_name]
check_call([config_path] + config_args[config_name], # List of files to be found in the directories above
stdout=PIPE, stderr=PIPE) to_be_found = list(set(os.path.basename(f) for f in to_be_patched))
substitutes = {}
for directory in good_file_dirs:
candidates = fs.find(directory, files=to_be_found, recursive=True)
candidates = [f for f in candidates if runs_ok(f)]
for name, good_files in itertools.groupby(
candidates, key=os.path.basename
):
substitutes[name] = next(good_files)
to_be_found.remove(name)
m = os.stat(my_config_path).st_mode & 0o777 | stat.S_IWUSR # Check that we found everything we needed
os.chmod(my_config_path, m) if to_be_found:
shutil.copyfile(config_path, my_config_path) msg = 'Failed to find suitable substitutes for {0}'
continue raise RuntimeError(msg.format(', '.join(to_be_found)))
except Exception as e:
tty.debug(e)
raise RuntimeError('Failed to find suitable ' + config_file) # Copy the good files over the bad ones
for abs_path in to_be_patched:
name = os.path.basename(abs_path)
fs.copy(substitutes[name], abs_path)
@run_before('configure') @run_before('configure')
def _set_autotools_environment_variables(self): def _set_autotools_environment_variables(self):