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:
parent
cdeecf2507
commit
a481087695
1 changed files with 51 additions and 62 deletions
|
@ -3,10 +3,9 @@
|
|||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import inspect
|
||||
import itertools
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
import stat
|
||||
from subprocess import PIPE
|
||||
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
|
||||
need to have these updated when installed on a newer architecture.
|
||||
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 (
|
||||
not self.spec.satisfies('target=ppc64le:') and
|
||||
not self.spec.satisfies('target=aarch64:')
|
||||
|
@ -121,70 +120,60 @@ def _do_patch_config_files(self):
|
|||
else:
|
||||
config_arch = 'local'
|
||||
|
||||
my_config_files = {'guess': None, 'sub': None}
|
||||
config_files = {'guess': None, 'sub': None}
|
||||
config_args = {'guess': [], 'sub': [config_arch]}
|
||||
def runs_ok(script_abs_path):
|
||||
# Construct the list of arguments for the call
|
||||
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
|
||||
try:
|
||||
check_call(args, stdout=PIPE, stderr=PIPE)
|
||||
except Exception as e:
|
||||
tty.debug(e)
|
||||
return False
|
||||
|
||||
if my_config_files[config_name] is not None:
|
||||
try:
|
||||
config_path = my_config_files[config_name]
|
||||
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:
|
||||
tty.debug(e)
|
||||
else:
|
||||
continue
|
||||
return True
|
||||
|
||||
# Look for a spack-installed automake package
|
||||
if 'automake' in self.spec:
|
||||
automake_dir = 'automake-' + str(self.spec['automake'].version)
|
||||
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]
|
||||
# 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)]
|
||||
|
||||
check_call([config_path] + config_args[config_name],
|
||||
stdout=PIPE, stderr=PIPE)
|
||||
# If there are no files to be patched, return early
|
||||
if not to_be_patched:
|
||||
return
|
||||
|
||||
m = os.stat(my_config_path).st_mode & 0o777 | stat.S_IWUSR
|
||||
os.chmod(my_config_path, m)
|
||||
shutil.copyfile(config_path, my_config_path)
|
||||
continue
|
||||
except Exception as e:
|
||||
tty.debug(e)
|
||||
# Directories where to search for files to be copied
|
||||
# over the failing ones
|
||||
good_file_dirs = ['/usr/share']
|
||||
if 'automake' in self.spec:
|
||||
good_file_dirs.insert(0, self.spec['automake'].prefix)
|
||||
|
||||
raise RuntimeError('Failed to find suitable ' + config_file)
|
||||
# List of files to be found in the directories above
|
||||
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)
|
||||
|
||||
# Check that we found everything we needed
|
||||
if to_be_found:
|
||||
msg = 'Failed to find suitable substitutes for {0}'
|
||||
raise RuntimeError(msg.format(', '.join(to_be_found)))
|
||||
|
||||
# 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')
|
||||
def _set_autotools_environment_variables(self):
|
||||
|
|
Loading…
Reference in a new issue