|
97 | 97 | from easybuild.tools.toolchain.compiler import DEFAULT_OPT_LEVEL, OPTARCH_MAP_CHAR, OPTARCH_SEP, Compiler
|
98 | 98 | from easybuild.tools.toolchain.toolchain import SYSTEM_TOOLCHAIN_NAME
|
99 | 99 | from easybuild.tools.repository.repository import avail_repositories
|
100 |
| -from easybuild.tools.systemtools import UNKNOWN, check_python_version, get_cpu_architecture, get_cpu_family |
| 100 | +from easybuild.tools.systemtools import UNKNOWN, CPU_ARCHITECTURES, CPU_FAMILIES, CPU_VECTOR_EXTS |
| 101 | +from easybuild.tools.systemtools import check_python_version, get_cpu_architecture, get_cpu_family |
101 | 102 | from easybuild.tools.systemtools import get_cpu_features, get_system_info
|
102 | 103 | from easybuild.tools.version import this_is_easybuild
|
103 | 104 |
|
@@ -930,29 +931,67 @@ def postprocess(self):
|
930 | 931 | cleanup_and_exit(self.tmpdir)
|
931 | 932 |
|
932 | 933 | def _postprocess_optarch(self):
|
933 |
| - """Postprocess --optarch option.""" |
934 |
| - optarch_parts = self.options.optarch.split(OPTARCH_SEP) |
935 |
| - |
936 |
| - # we expect to find a ':' in every entry in optarch, in case optarch is specified on a per-compiler basis |
937 |
| - n_parts = len(optarch_parts) |
938 |
| - map_char_cnts = [p.count(OPTARCH_MAP_CHAR) for p in optarch_parts] |
939 |
| - if (n_parts > 1 and any(c != 1 for c in map_char_cnts)) or (n_parts == 1 and map_char_cnts[0] > 1): |
| 934 | + """ |
| 935 | + Postprocess --optarch option. |
| 936 | +
|
| 937 | + Format: map := <entry>(;<space>*<entry>)* |
| 938 | + entry := <compiler>(,<arch-spec)*:<flag-string> |
| 939 | + Example values: |
| 940 | + "GENERIC" |
| 941 | + "march=native" |
| 942 | + "Intel,x86:xHost; Intel,x86,AMD,AVX2:mavx2 -fma; GCC:march=native" |
| 943 | + """ |
| 944 | + # Split into entries, and each entry into key-value pairs |
| 945 | + optarch_parts = [i.strip().split(OPTARCH_MAP_CHAR) for i in self.options.optarch.split(OPTARCH_SEP)] |
| 946 | + |
| 947 | + # We should either have a single value or a list of key-value pairs, and nothing else |
| 948 | + is_single_value = len(optarch_parts) == 1 and len(optarch_parts[0]) == 1 |
| 949 | + if not is_single_value and any(len(i) != 2 for i in optarch_parts): |
940 | 950 | raise EasyBuildError("The optarch option has an incorrect syntax: %s", self.options.optarch)
|
| 951 | + |
| 952 | + # if there are options for different compilers, we set up a dict |
| 953 | + if is_single_value: |
| 954 | + # if optarch is not in mapping format, we do nothing and just keep the string |
| 955 | + self.log.info("Keeping optarch raw: %s", self.options.optarch) |
941 | 956 | else:
|
942 |
| - # if there are options for different compilers, we set up a dict |
943 |
| - if OPTARCH_MAP_CHAR in optarch_parts[0]: |
944 |
| - optarch_dict = {} |
945 |
| - for compiler, compiler_opt in [p.split(OPTARCH_MAP_CHAR) for p in optarch_parts]: |
946 |
| - if compiler in optarch_dict: |
947 |
| - raise EasyBuildError("The optarch option contains duplicated entries for compiler %s: %s", |
948 |
| - compiler, self.options.optarch) |
| 957 | + optarch_dict = {} |
| 958 | + for key, compiler_opt in optarch_parts: |
| 959 | + # key can be either a compiler (only) or compiler and archspec(s) |
| 960 | + key_parts = key.split(',') |
| 961 | + compiler = key_parts.pop(0) |
| 962 | + if key_parts: |
| 963 | + for part, allowed_values in zip(key_parts, (CPU_ARCHITECTURES, CPU_FAMILIES, CPU_VECTOR_EXTS)): |
| 964 | + if part not in allowed_values: |
| 965 | + raise EasyBuildError("The optarch option has an incorrect syntax: %s\n" |
| 966 | + "'%s' of '%s' is not in allowed values: %s", |
| 967 | + self.options.optarch, part, key, allowed_values) |
| 968 | + arch_specs = tuple(key_parts) if len(key_parts) > 1 else key_parts[0] |
| 969 | + else: |
| 970 | + arch_specs = None |
| 971 | + try: |
| 972 | + compiler_dict = optarch_dict[compiler] |
| 973 | + # Convert single entry to dict if required |
| 974 | + if not isinstance(compiler_dict, dict): |
| 975 | + compiler_dict = {None: compiler_dict} |
| 976 | + optarch_dict[compiler] = compiler_dict |
| 977 | + if arch_specs in compiler_dict: |
| 978 | + if arch_specs is None: |
| 979 | + raise EasyBuildError("The optarch option contains a duplicated entry for compiler %s: %s", |
| 980 | + compiler, self.options.optarch) |
| 981 | + else: |
| 982 | + raise EasyBuildError("The optarch option contains a duplicated entry %s " |
| 983 | + "for compiler %s: %s", |
| 984 | + arch_specs, compiler, self.options.optarch) |
949 | 985 | else:
|
| 986 | + compiler_dict[arch_specs] = compiler_opt |
| 987 | + except KeyError: |
| 988 | + # Keep the dict flat when no archspecs are given |
| 989 | + if arch_specs is None: |
950 | 990 | optarch_dict[compiler] = compiler_opt
|
951 |
| - self.options.optarch = optarch_dict |
952 |
| - self.log.info("Transforming optarch into a dict: %s", self.options.optarch) |
953 |
| - # if optarch is not in mapping format, we do nothing and just keep the string |
954 |
| - else: |
955 |
| - self.log.info("Keeping optarch raw: %s", self.options.optarch) |
| 991 | + else: |
| 992 | + optarch_dict[compiler] = {arch_specs: compiler_opt} |
| 993 | + self.options.optarch = optarch_dict |
| 994 | + self.log.info("Transforming optarch into a dict: %s", self.options.optarch) |
956 | 995 |
|
957 | 996 | def _postprocess_close_pr_reasons(self):
|
958 | 997 | """Postprocess --close-pr-reasons options"""
|
|
0 commit comments