diff --git a/.flake8 b/.flake8 index 140404565..4592939f2 100644 --- a/.flake8 +++ b/.flake8 @@ -7,6 +7,3 @@ ignore = E712, # line break before binary operator W503 -per-file-ignores = - # flake8 is just plain wrong here, contradicting black - .github/generate-job-matrix.py:E225,E231 diff --git a/.github/generate-job-matrix.py b/.github/generate-job-matrix.py index 1c4d4b2bb..2326da0b5 100644 --- a/.github/generate-job-matrix.py +++ b/.github/generate-job-matrix.py @@ -1,15 +1,95 @@ import argparse +import dataclasses import json import os import random import typing +from dataclasses import dataclass from types import SimpleNamespace -from job_matrix import CombinationCollector, Compiler, Configuration +from job_matrix_builder import CombinationCollector -def make_gcc_config(version: int) -> Configuration: - return Configuration( +@dataclass(frozen=True, order=True, kw_only=True) +class Compiler: + type: typing.Literal["GCC", "CLANG", "APPLE_CLANG", "MSVC"] + version: str | int + cc: str + cxx: str + + +@dataclass(frozen=True, order=True, kw_only=True) +class Features: + cxx_modules: bool = False + std_format: bool = False + import_std: bool = False + freestanding: bool = False + + +@dataclass(frozen=True, order=True, kw_only=True) +class Platform: + """This is really mainly the compiler.""" + + name: str + os: str + compiler: Compiler + lib: typing.Literal["libc++", "libstdc++"] | None = None + feature_support: Features + + def __str__(self): + return self.name + + def for_github(self): + ret = dataclasses.asdict(self) + del ret["feature_support"] + return ret + + +@dataclass(frozen=True, order=True, kw_only=True) +class Configuration(Features): + platform: Platform + std: typing.Literal[20, 23] + contracts: typing.Literal["none", "gsl-lite", "ms-gsl"] + build_type: typing.Literal["Release", "Debug"] + + @property + def is_supported(self) -> bool: + # check if selected features are supported by the platform + s = self.platform.feature_support + for field in dataclasses.fields(Features): + if getattr(self, field.name) and not getattr(s, field.name): + return False + # additional checks for import_std + if self.import_std: + if self.std < 23: + return False + if not self.cxx_modules: + return False + if not self.std_format: + return False + if self.contracts != "none": + return False + return True + + def for_github(self): + features = { + field.name: str(getattr(self, field.name)) + for field in dataclasses.fields(Features) + } + ret = { + field.name: getattr(self, field.name) + for field in dataclasses.fields(self) + if field.name not in features + } + ret["platform"] = self.platform.for_github() + ret["formatting"] = "std::format" if self.std_format else "fmtlib" + features["contracts"] = self.contracts + ret["conan-config"] = " ".join(f"-o '&:{k}={v}'" for k, v in features.items()) + return ret + + +def make_gcc_platform(version: int) -> Platform: + return Platform( name=f"GCC-{version}", os="ubuntu-24.04", compiler=Compiler( @@ -18,25 +98,31 @@ def make_gcc_config(version: int) -> Configuration: cc=f"gcc-{version}", cxx=f"g++-{version}", ), - cxx_modules=False, - std_format_support=version >= 13, + feature_support=Features( + std_format=version >= 13, + freestanding=True, + ), ) -def make_clang_config( - version: int, platform: typing.Literal["x86-64", "arm64"] = "x86-64" -) -> Configuration: +def make_clang_platform( + version: int, architecture: typing.Literal["x86-64", "arm64"] = "x86-64" +) -> Platform: cfg = SimpleNamespace( - name=f"Clang-{version} ({platform})", + name=f"Clang-{version} ({architecture})", compiler=SimpleNamespace( type="CLANG", version=version, ), lib="libc++", - cxx_modules=version >= 17, - std_format_support=version >= 17, + feature_support=Features( + cxx_modules=version >= 17, + std_format=version >= 17, + import_std=version >= 18, + freestanding=True, + ), ) - match platform: + match architecture: case "x86-64": cfg.os = "ubuntu-22.04" if version < 17 else "ubuntu-24.04" cfg.compiler.cc = f"clang-{version}" @@ -47,16 +133,16 @@ def make_clang_config( cfg.compiler.cc = f"{pfx}/clang" cfg.compiler.cxx = f"{pfx}/clang++" case _: - raise KeyError(f"Unsupported platform {platform!r} for Clang") + raise KeyError(f"Unsupported architecture {architecture!r} for Clang") ret = cfg ret.compiler = Compiler(**vars(cfg.compiler)) - return Configuration(**vars(ret)) + return Platform(**vars(ret)) -def make_apple_clang_config( +def make_apple_clang_platform( os: str, version: str, std_format_support: bool -) -> Configuration: - ret = Configuration( +) -> Platform: + ret = Platform( name=f"Apple Clang {version}", os=os, compiler=Compiler( @@ -65,14 +151,13 @@ def make_apple_clang_config( cc="clang", cxx="clang++", ), - cxx_modules=False, - std_format_support=std_format_support, + feature_support=Features(std_format=std_format_support), ) return ret -def make_msvc_config(release: str, version: int) -> Configuration: - ret = Configuration( +def make_msvc_platform(release: str, version: int) -> Platform: + ret = Platform( name=f"MSVC {release}", os="windows-2022", compiler=Compiler( @@ -81,38 +166,42 @@ def make_msvc_config(release: str, version: int) -> Configuration: cc="", cxx="", ), - cxx_modules=False, - std_format_support=True, + feature_support=Features( + std_format=True, + ), ) return ret -configs = { - c.name: c - for c in [make_gcc_config(ver) for ver in [12, 13, 14]] +platforms = { + p.name: p + for p in [make_gcc_platform(ver) for ver in [12, 13, 14]] + [ - make_clang_config(ver, platform) + make_clang_platform(ver, arch) for ver in [16, 17, 18] - for platform in ["x86-64", "arm64"] + for arch in ["x86-64", "arm64"] # arm64 runners are expensive; only consider one version - if ver == 18 or platform != "arm64" + if ver == 18 or arch != "arm64" ] + [ - make_apple_clang_config("macos-13", ver, std_format_support=False) + make_apple_clang_platform("macos-13", ver, std_format_support=False) for ver in ["15.2"] ] # std::format is available in Xcode 16.1 or later + [ - make_apple_clang_config("macos-14", ver, std_format_support=True) + make_apple_clang_platform("macos-14", ver, std_format_support=True) for ver in ["16.1"] ] - + [make_msvc_config(release="14.4", version=194)] + + [make_msvc_platform(release="14.4", version=194)] } full_matrix = dict( - config=list(configs.values()), + platform=list(platforms.values()), std=[20, 23], - formatting=["std::format", "fmtlib"], + std_format=[False, True], + import_std=[False, True], + cxx_modules=[False, True], + freestanding=[False, True], contracts=["none", "gsl-lite", "ms-gsl"], build_type=["Release", "Debug"], ) @@ -122,51 +211,91 @@ def main(): parser = argparse.ArgumentParser() # parser.add_argument("-I","--include",nargs="+",action="append") # parser.add_argument("-X","--exclude",nargs="+",action="append") - parser.add_argument("--seed", type=int, default=42) + parser.add_argument("--seed", type=int, default=None) parser.add_argument("--preset", default=None) parser.add_argument("--debug", nargs="+", default=["combinations"]) parser.add_argument("--suppress-output", default=False, action="store_true") args = parser.parse_args() + if not args.seed: + args.seed = random.randint(0, (1 << 32) - 1) + + print(f"Random-seed for this matrix is {args.seed}") + rgen = random.Random(args.seed) collector = CombinationCollector( - full_matrix, - hard_excludes=lambda e: ( - e.formatting == "std::format" and not e.config.std_format_support + full_matrix=full_matrix, + configuration_element_type=Configuration, + hard_excludes=lambda c: (not c.is_supported) + or ( + # TODO For some reason Clang-18 Debug with -ffreestanding does not pass CMakeTestCXXCompiler + c.freestanding + and c.platform.name.startswith("Clang-18") + and c.build_type == "Debug" ), ) + if args.preset: + # whatever the preset; we always want to have a test that does import_std; + # that requires a very specific configuration + collector.sample_combinations( + rgen=rgen, + min_samples=1, + std_format=True, + import_std=True, + cxx_modules=True, + freestanding=args.preset == "freestanding", + std=23, + contracts="none", + platform=platforms["Clang-18 (x86-64)"], + ) match args.preset: case None: pass case "all": collector.all_combinations() case "conan" | "cmake": - collector.all_combinations( - formatting="std::format", + config = dict( contracts="gsl-lite", build_type="Debug", std=20, + freestanding=False, ) collector.all_combinations( - filter=lambda me: not me.config.std_format_support, - formatting="fmtlib", - contracts="gsl-lite", - build_type="Debug", - std=20, + std_format=True, + **config, + ) + # fmtlib for those platforms where we don't support std_format + collector.all_combinations( + filter=lambda me: not me.platform.feature_support.std_format, + std_format=False, + **config, + ) + collector.sample_combinations( + rgen=rgen, + min_samples_per_value=1, + freestanding=False, + ) + # add more coverage to import_std=False configurations; + collector.sample_combinations( + rgen=rgen, + min_samples_per_value=2, + import_std=False, + freestanding=False, ) - collector.sample_combinations(rgen=rgen, min_samples_per_value=2) case "clang-tidy": - collector.all_combinations(config=configs["Clang-18 (x86-64)"]) + collector.sample_combinations( + rgen=rgen, + min_samples_per_value=1, + platform=platforms["Clang-18 (x86-64)"], + freestanding=False, + ) case "freestanding": - # TODO For some reason Clang-18 Debug with -ffreestanding does not pass CMakeTestCXXCompiler collector.all_combinations( - filter=lambda e: not ( - e.config.name.startswith("Clang-18") and e.build_type == "Debug" - ), - config=[configs[c] for c in ["GCC-14", "Clang-18 (x86-64)"]], + platform=[platforms[c] for c in ["GCC-14", "Clang-18 (x86-64)"]], contracts="none", + freestanding=True, std=23, ) case _: @@ -177,7 +306,7 @@ def main(): data = sorted(collector.combinations) - json_data = [e.as_json() for e in data] + json_data = [e.for_github() for e in data] output_file = os.environ.get("GITHUB_OUTPUT") if not args.suppress_output: @@ -199,13 +328,16 @@ def main(): print(json.dumps(json_data, indent=4)) case "combinations": for e in data: + std_format = "yes" if e.std_format else "no " + cxx_modules = "yes" if e.cxx_modules else "no " + import_std = "yes" if e.import_std else "no " print( - f"{e.config!s:17s} c++{e.std:2d} {e.formatting:11s} {e.contracts:8s} {e.build_type:8s}" + f"{e.platform!s:17s} c++{e.std:2d} " + f"{std_format=:3s} {cxx_modules=:3s} {import_std=:3s} " + f"{e.contracts:8s} {e.build_type:8s}" ) case "counts": print(f"Total combinations {len(data)}") - for (k, v), n in sorted(collector.per_value_counts.items()): - print(f" {k}={v}: {n}") case "none": pass case _: diff --git a/.github/job_matrix.py b/.github/job_matrix.py deleted file mode 100644 index 0458a1e9e..000000000 --- a/.github/job_matrix.py +++ /dev/null @@ -1,139 +0,0 @@ -import dataclasses -import itertools -import random -import typing -from dataclasses import dataclass - - -@dataclass(frozen=True, order=True) -class Compiler: - type: typing.Literal["GCC", "CLANG", "APPLE_CLANG", "MSVC"] - version: str | int - cc: str - cxx: str - - -@dataclass(frozen=True, order=True) -class Configuration: - name: str - os: str - compiler: Compiler - cxx_modules: bool - std_format_support: bool - conan_config: str = "" - lib: typing.Literal["libc++", "libstdc++"] | None = None - - def __str__(self): - return self.name - - -@dataclass(frozen=True, order=True) -class MatrixElement: - config: Configuration - std: typing.Literal[20, 23] - formatting: typing.Literal["std::format", "fmtlib"] - contracts: typing.Literal["none", "gsl-lite", "ms-gsl"] - build_type: typing.Literal["Release", "Debug"] - - def as_json(self): - def dataclass_to_json(obj): - """Convert dataclasses to something json-serialisable""" - if dataclasses.is_dataclass(obj): - return { - k: dataclass_to_json(v) for k, v in dataclasses.asdict(obj).items() - } - return obj - - ret = dataclass_to_json(self) - # patch boolean conan configuration options - config = ret["config"] - for k in ["cxx_modules"]: - config[k] = "True" if config[k] else "False" - return ret - - -class CombinationCollector: - """Incremental builder of MatrixElements, allowing successive selection of entries.""" - - def __init__( - self, - full_matrix: dict[str, list[typing.Any]], - *, - hard_excludes: typing.Callable[[MatrixElement], bool] | None = None, - ): - self.full_matrix = full_matrix - self.hard_excludes = hard_excludes - self.combinations: set[MatrixElement] = set() - self.per_value_counts: dict[tuple[str, typing.Any], int] = { - (k, v): 0 for k, options in full_matrix.items() for v in options - } - - def _make_submatrix(self, **overrides): - new_matrix = dict(self.full_matrix) - for k, v in overrides.items(): - if not isinstance(v, list): - v = [v] - new_matrix[k] = v - return new_matrix - - def _add_combination(self, e: MatrixElement): - if e in self.combinations or ( - self.hard_excludes is not None and self.hard_excludes(e) - ): - return - self.combinations.add(e) - # update per_value_counts - for k, v in vars(e).items(): - idx = (k, v) - self.per_value_counts[idx] = self.per_value_counts.get(idx, 0) + 1 - - def all_combinations( - self, - *, - filter: typing.Callable[[MatrixElement], bool] | None = None, - **overrides, - ): - """Adds all combinations in the submatrix defined by `overrides`.""" - matrix = self._make_submatrix(**overrides) - keys = tuple(matrix.keys()) - for combination in itertools.product(*matrix.values()): - cand = MatrixElement(**dict(zip(keys, combination))) - if filter and not filter(cand): - continue - self._add_combination(cand) - - def sample_combinations( - self, - *, - rgen: random.Random, - min_samples_per_value: int = 1, - filter: typing.Callable[[MatrixElement], bool] | None = None, - **overrides, - ): - """Adds samples from the submatrix defined by `overrides`, - ensuring each individual value appears at least n times. - """ - matrix = self._make_submatrix(**overrides) - missing: dict[tuple[str, typing.Any], int] = {} - for key, options in matrix.items(): - for value in options: - idx = (key, value) - missing[idx] = min_samples_per_value - self.per_value_counts.get(idx, 0) - while missing: - (force_key, force_option), remaining = next(iter(missing.items())) - if remaining <= 0: - missing.pop((force_key, force_option)) - continue - choice = {} - for key, options in matrix.items(): - choice[key] = force_option if key == force_key else rgen.choice(options) - cand = MatrixElement(**choice) - if filter and not filter(cand): - continue - self._add_combination(cand) - for idx in choice.items(): - if missing.pop(idx, 0) <= 0: - continue - remaining = min_samples_per_value - self.per_value_counts.get(idx, 0) - if remaining > 0: - missing[idx] = remaining diff --git a/.github/job_matrix_builder.py b/.github/job_matrix_builder.py new file mode 100644 index 000000000..c3ec646dd --- /dev/null +++ b/.github/job_matrix_builder.py @@ -0,0 +1,144 @@ +import itertools +import random +import typing + +T = typing.TypeVar("T") + + +class CombinationCollector(typing.Generic[T]): + """Incremental builder of MatrixElements, allowing successive selection of entries.""" + + def __init__( + self, + *, + full_matrix: dict[str, list[typing.Any]], + configuration_element_type: type[T], + hard_excludes: typing.Callable[[T], bool] | None = None, + ): + self.full_matrix = full_matrix + self.configuration_element_type = configuration_element_type + self.hard_excludes = hard_excludes + self.combinations: set[T] = set() + + def _make_submatrix(self, **overrides): + new_matrix = dict(self.full_matrix) + for k, v in overrides.items(): + if not isinstance(v, list): + v = [v] + new_matrix[k] = v + return new_matrix + + def _add_combination(self, e: T): + if e in self.combinations or ( + self.hard_excludes is not None and self.hard_excludes(e) + ): + return False + self.combinations.add(e) + return True + + def all_combinations( + self, + *, + filter: typing.Callable[[T], bool] | None = None, + **overrides, + ): + """Adds all combinations in the submatrix defined by `overrides`.""" + matrix = self._make_submatrix(**overrides) + keys = tuple(matrix.keys()) + for combination in itertools.product(*matrix.values()): + cand = self.configuration_element_type(**dict(zip(keys, combination))) + if filter and not filter(cand): + continue + self._add_combination(cand) + + def sample_combinations( + self, + *, + rgen: random.Random, + min_samples_per_value: int = 0, + min_samples: int = 0, + filter: typing.Callable[[T], bool] | None = None, + **overrides, + ): + """Adds samples from the submatrix defined by `overrides`, + ensuring each individual value appears at least n times. + """ + matrix = self._make_submatrix(**overrides) + missing: dict[tuple[str, typing.Any], int] = {} + for key, options in matrix.items(): + for value in options: + idx = (key, value) + missing[idx] = min_samples_per_value + n_in_submatrix = 0 + for e in self.combinations: + for k, v in vars(e).items(): + if v not in matrix[k]: + break + else: + # this combination is in the submatrix + n_in_submatrix += 1 + for k, v in vars(e).items(): + if v in matrix[k]: + missing[k, v] -= 1 + for done in [idx for idx, n in missing.items() if n <= 0]: + del missing[done] + n_failed_tries = 0 + failed_cand = set() + + def try_handle_choice(choice): + nonlocal n_failed_tries, n_in_submatrix + cand = self.configuration_element_type(**choice) + if filter is None or filter(cand): + added = self._add_combination(cand) + else: + added = False + if added: + n_failed_tries = 0 + failed_cand.clear() + else: + if cand not in self.combinations: + failed_cand.add(cand) + n_failed_tries += 1 + return + n_in_submatrix += 1 + for idx in choice.items(): + remaining = missing.pop(idx, 0) - 1 + if remaining <= 0: + continue + missing[idx] = remaining + + while missing: + (force_key, force_option), remaining = next(iter(missing.items())) + if remaining <= 0: + missing.pop((force_key, force_option)) + continue + choice = {} + for key, options in matrix.items(): + choice[key] = force_option if key == force_key else rgen.choice(options) + try_handle_choice(choice) + if n_failed_tries > 100: + tries = "\n".join( # noqa: F841 + ", ".join(f"{k}:{v!s}" for k, v in vars(cand).items()) + + f" -> {cand.is_supported=}" + for cand in sorted(failed_cand) + ) + print( + "Unable to reach the requested minimum number of samples," + f" {missing=}" + ) + n_failed_tries = 0 + failed_cand.clear() + break + while n_in_submatrix < min_samples: + choice = {} + for key, options in matrix.items(): + choice[key] = rgen.choice(options) + try_handle_choice(choice) + if n_failed_tries > 100: + print( + "Unable to reach the requested minimum number of samples," + f" {n_in_submatrix=}" + ) + n_failed_tries = 0 + failed_cand.clear() + break diff --git a/.github/workflows/ci-clang-tidy.yml b/.github/workflows/ci-clang-tidy.yml index ac4d01701..0e6f5f1ca 100644 --- a/.github/workflows/ci-clang-tidy.yml +++ b/.github/workflows/ci-clang-tidy.yml @@ -33,6 +33,13 @@ on: - '**' paths-ignore: - "docs/**" + workflow_dispatch: + inputs: + matrix-seed: + description: The random seed for the subset of the full test-matrix to be run (set to '0' to select one at random) + required: true + type: number + default: 0 concurrency: @@ -52,10 +59,10 @@ jobs: with: python-version: 3.x - id: set-matrix - run: python .github/generate-job-matrix.py --preset clang-tidy --seed 42 --debug combinations counts + run: python .github/generate-job-matrix.py --preset clang-tidy --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts build: - name: "${{ matrix.config.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" - runs-on: ${{ matrix.config.os }} + name: "${{ matrix.platform.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" + runs-on: ${{ matrix.platform.os }} needs: generate-matrix strategy: fail-fast: false @@ -63,8 +70,8 @@ jobs: include: ${{fromJson(needs.generate-matrix.outputs.matrix)}} env: - CC: ${{ matrix.config.compiler.cc }} - CXX: ${{ matrix.config.compiler.cxx }} + CC: ${{ matrix.platform.compiler.cc }} + CXX: ${{ matrix.platform.compiler.cxx }} steps: - uses: actions/checkout@v4 @@ -76,35 +83,35 @@ jobs: cache-name: cache-conan-data with: path: ~/.conan2/p - key: clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} + key: clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} restore-keys: | - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- - clang-tidy-${{ matrix.config.os }}-${{ matrix.formatting }}- - clang-tidy-${{ matrix.config.os }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- + clang-tidy-${{ matrix.platform.os }}-${{ matrix.formatting }}- + clang-tidy-${{ matrix.platform.os }}- - uses: hendrikmuhs/ccache-action@v1.2 if: runner.os == 'Linux' with: - key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }} + key: ${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }} max-size: 50M - name: Install Clang - if: matrix.config.compiler.type == 'CLANG' + if: matrix.platform.compiler.type == 'CLANG' shell: bash working-directory: ${{ env.HOME }} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.config.compiler.version }} - sudo apt install -y clang-tools-${{ matrix.config.compiler.version }} + sudo ./llvm.sh ${{ matrix.platform.compiler.version }} + sudo apt install -y clang-tools-${{ matrix.platform.compiler.version }} - name: Install Libc++ - if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.lib == 'libc++' shell: bash run: | - sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev + sudo apt install -y libc++-${{ matrix.platform.compiler.version }}-dev libc++abi-${{ matrix.platform.compiler.version }}-dev libunwind-${{ matrix.platform.compiler.version }}-dev - name: Set up Python uses: actions/setup-python@v5 with: @@ -121,23 +128,18 @@ jobs: shell: bash run: | conan profile detect --force - if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then - sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default + if [[ "${{ matrix.platform.compiler.type }}" == "CLANG" ]]; then + sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.platform.lib }}/' ~/.conan2/profiles/default fi sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default conan profile show -pr default - - name: Set 'std_format' and 'import_std' environment variables - shell: bash - run: | - echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - echo "import_std=$([ "${{ matrix.std }}" -ge "23" ] && [ "${{ matrix.config.cxx_modules }}" == "True" ] && [ "${{ matrix.config.contracts }}" == "none" ] && [ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - name: Run clang-tidy shell: bash run: | conan build . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \ -c user.mp-units.build:all=True -c user.mp-units.analyze:clang-tidy=True -c tools.build:skip_test=True \ - '-o &:cxx_modules=${{ matrix.config.cxx_modules }}' -o '&:import_std=${{ env.import_std }}' -o '&:std_format=${{ env.std_format }}' -o '&:contracts=${{ matrix.contracts }}' ${{ matrix.config.conan-config }} + ${{ matrix.conan-config }} - name: Clean Conan cache before backup shell: bash run: | diff --git a/.github/workflows/ci-conan.yml b/.github/workflows/ci-conan.yml index 186660aff..36ecd5a53 100644 --- a/.github/workflows/ci-conan.yml +++ b/.github/workflows/ci-conan.yml @@ -29,6 +29,13 @@ on: pull_request: paths-ignore: - "docs/**" + workflow_dispatch: + inputs: + matrix-seed: + description: The random seed for the subset of the full test-matrix to be run (set to '0' to select one at random) + required: true + type: number + default: 0 env: CHANNEL: ${{ fromJSON('["testing", "stable"]')[github.ref_type == 'tag' && startsWith(github.ref_name, 'v')] }} @@ -50,18 +57,18 @@ jobs: with: python-version: 3.x - id: set-matrix - run: python .github/generate-job-matrix.py --preset conan --seed 42 --debug combinations counts + run: python .github/generate-job-matrix.py --preset conan --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts build: - name: "${{ matrix.config.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" - runs-on: ${{ matrix.config.os }} + name: "${{ matrix.platform.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" + runs-on: ${{ matrix.platform.os }} needs: generate-matrix strategy: fail-fast: false matrix: include: ${{fromJson(needs.generate-matrix.outputs.matrix)}} env: - CC: ${{ matrix.config.compiler.cc }} - CXX: ${{ matrix.config.compiler.cxx }} + CC: ${{ matrix.platform.compiler.cc }} + CXX: ${{ matrix.platform.compiler.cxx }} steps: - uses: actions/checkout@v4 - name: Generate unique cache id @@ -74,50 +81,50 @@ jobs: cache-name: cache-conan-data with: path: ~/.conan2/p - key: conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} + key: conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} restore-keys: | - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- - conan-${{ matrix.config.os }}-${{ matrix.formatting }}- - conan-${{ matrix.config.os }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- + conan-${{ matrix.platform.os }}-${{ matrix.formatting }}- + conan-${{ matrix.platform.os }}- - uses: hendrikmuhs/ccache-action@v1.2 if: runner.os == 'Linux' with: - key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }} + key: ${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }} max-size: 50M - name: Install gcc-13 - if: matrix.config.compiler.type == 'GCC' && matrix.config.compiler.version == '13' + if: matrix.platform.compiler.type == 'GCC' && matrix.platform.compiler.version == '13' shell: bash run: | - sudo apt install -y g++-${{ matrix.config.compiler.version }} + sudo apt install -y g++-${{ matrix.platform.compiler.version }} - name: Install Clang with apt - if: matrix.config.compiler.type == 'CLANG' && matrix.config.os != 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.os != 'macos-14' shell: bash working-directory: ${{ env.HOME }} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.config.compiler.version }} - sudo apt install -y clang-tools-${{ matrix.config.compiler.version }} + sudo ./llvm.sh ${{ matrix.platform.compiler.version }} + sudo apt install -y clang-tools-${{ matrix.platform.compiler.version }} - name: Install Clang using homebrew - if: matrix.config.compiler.type == 'CLANG' && matrix.config.os == 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.os == 'macos-14' shell: bash run: | brew install llvm@18 - name: Install Libc++ - if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++' && matrix.config.os != 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.lib == 'libc++' && matrix.platform.os != 'macos-14' shell: bash run: | - sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev + sudo apt install -y libc++-${{ matrix.platform.compiler.version }}-dev libc++abi-${{ matrix.platform.compiler.version }}-dev libunwind-${{ matrix.platform.compiler.version }}-dev - name: Select Xcode version - if: matrix.config.compiler.type == 'APPLE_CLANG' + if: matrix.platform.compiler.type == 'APPLE_CLANG' shell: bash run: | - sudo xcode-select -s /Applications/Xcode_${{ matrix.config.compiler.version }}.app && /usr/bin/xcodebuild -version + sudo xcode-select -s /Applications/Xcode_${{ matrix.platform.compiler.version }}.app && /usr/bin/xcodebuild -version - name: Set up Python uses: actions/setup-python@v5 with: @@ -134,31 +141,26 @@ jobs: shell: bash run: | conan profile detect --force - if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then - sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default + if [[ "${{ matrix.platform.compiler.type }}" == "CLANG" ]]; then + sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.platform.lib }}/' ~/.conan2/profiles/default fi sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default conan profile show -pr default - - name: Set 'std_format' and 'import_std' environment variables - shell: bash - run: | - echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - echo "import_std=$([ "${{ matrix.std }}" -ge "23" ] && [ "${{ matrix.config.cxx_modules }}" == "True" ] && [ "${{ matrix.config.contracts }}" == "none" ] && [ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - name: Create Conan package - if: matrix.config.compiler.type != 'MSVC' + if: matrix.platform.compiler.type != 'MSVC' shell: bash run: | conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \ -b mp-units/* -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.mp-units.build:all=True \ - -o '&:cxx_modules=${{ matrix.config.cxx_modules }}' -o '&:import_std=${{ env.import_std }}' -o '&:std_format=${{ env.std_format }}' -o '&:contracts=${{ matrix.contracts }}' ${{ matrix.config.conan_config }} + ${{ matrix.conan-config }} - name: Create Conan package - if: matrix.config.compiler.type == 'MSVC' + if: matrix.platform.compiler.type == 'MSVC' shell: bash run: | conan create . --user mpusz --channel ${CHANNEL} --lockfile-out=package.lock \ -b mp-units/* -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.mp-units.build:all=False \ - -o '&:cxx_modules=${{ matrix.config.cxx_modules }}' -o '&:import_std=${{ env.import_std }}' -o '&:std_format=${{ env.std_format }}' -o '&:contracts=${{ matrix.contracts }}' ${{ matrix.config.conan_config }} + ${{ matrix.conan-config }} - name: Obtain package reference id: get-package-ref shell: bash diff --git a/.github/workflows/ci-freestanding.yml b/.github/workflows/ci-freestanding.yml index ffdf5af54..3249212be 100644 --- a/.github/workflows/ci-freestanding.yml +++ b/.github/workflows/ci-freestanding.yml @@ -33,6 +33,13 @@ on: - '**' paths-ignore: - "docs/**" + workflow_dispatch: + inputs: + matrix-seed: + description: The random seed for the subset of the full test-matrix to be run (set to '0' to select one at random) + required: true + type: number + default: 0 concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -51,10 +58,10 @@ jobs: with: python-version: 3.x - id: set-matrix - run: python .github/generate-job-matrix.py --preset freestanding --seed 42 --debug combinations counts + run: python .github/generate-job-matrix.py --preset freestanding --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts build: - name: "${{ matrix.config.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" - runs-on: ${{ matrix.config.os }} + name: "${{ matrix.platform.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" + runs-on: ${{ matrix.platform.os }} needs: generate-matrix strategy: fail-fast: false @@ -62,8 +69,8 @@ jobs: include: ${{fromJson(needs.generate-matrix.outputs.matrix)}} env: - CC: ${{ matrix.config.compiler.cc }} - CXX: ${{ matrix.config.compiler.cxx }} + CC: ${{ matrix.platform.compiler.cc }} + CXX: ${{ matrix.platform.compiler.cxx }} steps: - uses: actions/checkout@v4 @@ -75,35 +82,35 @@ jobs: cache-name: cache-conan-data with: path: ~/.conan2/p - key: freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} + key: freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} restore-keys: | - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- - freestanding-${{ matrix.config.os }}-${{ matrix.formatting }}- - freestanding-${{ matrix.config.os }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- + freestanding-${{ matrix.platform.os }}-${{ matrix.formatting }}- + freestanding-${{ matrix.platform.os }}- - uses: hendrikmuhs/ccache-action@v1.2 if: runner.os == 'Linux' with: - key: ${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }} + key: ${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }} max-size: 50M - name: Install Clang - if: matrix.config.compiler.type == 'CLANG' + if: matrix.platform.compiler.type == 'CLANG' shell: bash working-directory: ${{ env.HOME }} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.config.compiler.version }} - sudo apt install -y clang-tools-${{ matrix.config.compiler.version }} + sudo ./llvm.sh ${{ matrix.platform.compiler.version }} + sudo apt install -y clang-tools-${{ matrix.platform.compiler.version }} - name: Install Libc++ - if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.lib == 'libc++' shell: bash run: | - sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev + sudo apt install -y libc++-${{ matrix.platform.compiler.version }}-dev libc++abi-${{ matrix.platform.compiler.version }}-dev libunwind-${{ matrix.platform.compiler.version }}-dev - name: Set up Python uses: actions/setup-python@v5 with: @@ -120,8 +127,8 @@ jobs: shell: bash run: | conan profile detect --force - if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then - sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default + if [[ "${{ matrix.platform.compiler.type }}" == "CLANG" ]]; then + sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.platform.lib }}/' ~/.conan2/profiles/default fi sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default @@ -132,7 +139,7 @@ jobs: run: | conan build . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" \ -c user.mp-units.build:all=True -c tools.build:cxxflags="['-ffreestanding']" \ - -o '&:cxx_modules=${{ matrix.config.cxx_modules }}' -o '&:std_format=${{ env.std_format }}' -o '&:contracts=${{ matrix.contracts }}' -o '&:freestanding=True' ${{ matrix.config.conan-config }} + ${{ matrix.conan-config }} - name: Clean Conan cache before backup shell: bash run: | diff --git a/.github/workflows/ci-test-package-cmake.yml b/.github/workflows/ci-test-package-cmake.yml index 5367355de..e466fe401 100644 --- a/.github/workflows/ci-test-package-cmake.yml +++ b/.github/workflows/ci-test-package-cmake.yml @@ -37,6 +37,13 @@ on: - "docs/**" - "example/**" - "test/**" + workflow_dispatch: + inputs: + matrix-seed: + description: The random seed for the subset of the full test-matrix to be run (set to '0' to select one at random) + required: true + type: number + default: 0 concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -55,10 +62,10 @@ jobs: with: python-version: 3.x - id: set-matrix - run: python .github/generate-job-matrix.py --preset conan --seed 42 --debug combinations counts + run: python .github/generate-job-matrix.py --preset conan --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts test_package: - name: "${{ matrix.config.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" - runs-on: ${{ matrix.config.os }} + name: "${{ matrix.platform.name }} C++${{ matrix.std }} ${{ matrix.formatting }} ${{ matrix.contracts }} ${{ matrix.build_type }}" + runs-on: ${{ matrix.platform.os }} needs: generate-matrix strategy: fail-fast: false @@ -66,8 +73,8 @@ jobs: include: ${{fromJson(needs.generate-matrix.outputs.matrix)}} env: - CC: ${{ matrix.config.compiler.cc }} - CXX: ${{ matrix.config.compiler.cxx }} + CC: ${{ matrix.platform.compiler.cc }} + CXX: ${{ matrix.platform.compiler.cxx }} steps: - name: Downcase 'build_type' @@ -86,45 +93,45 @@ jobs: cache-name: cache-conan-data with: path: ~/.conan2/p - key: cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} + key: cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}-${{ env.cache_id }} restore-keys: | - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}-${{ matrix.std }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}-${{ matrix.config.compiler.version }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}-${{ matrix.build_type }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}-${{ matrix.config.lib }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.config.compiler.type }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- - cmake-${{ matrix.config.os }}-${{ matrix.formatting }}- - cmake-${{ matrix.config.os }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}-${{ matrix.std }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}-${{ matrix.platform.compiler.version }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}-${{ matrix.build_type }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}-${{ matrix.platform.lib }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}-${{ matrix.platform.compiler.type }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}-${{ matrix.contracts }}- + cmake-${{ matrix.platform.os }}-${{ matrix.formatting }}- + cmake-${{ matrix.platform.os }}- - name: Install gcc-13 - if: matrix.config.compiler.type == 'GCC' && matrix.config.compiler.version == '13' + if: matrix.platform.compiler.type == 'GCC' && matrix.platform.compiler.version == '13' shell: bash run: | - sudo apt install -y g++-${{ matrix.config.compiler.version }} + sudo apt install -y g++-${{ matrix.platform.compiler.version }} - name: Install Clang with apt - if: matrix.config.compiler.type == 'CLANG' && matrix.config.os != 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.os != 'macos-14' shell: bash working-directory: ${{ env.HOME }} run: | wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh - sudo ./llvm.sh ${{ matrix.config.compiler.version }} - sudo apt install -y clang-tools-${{ matrix.config.compiler.version }} + sudo ./llvm.sh ${{ matrix.platform.compiler.version }} + sudo apt install -y clang-tools-${{ matrix.platform.compiler.version }} - name: Install Clang using homebrew - if: matrix.config.compiler.type == 'CLANG' && matrix.config.os == 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.os == 'macos-14' shell: bash run: | brew install llvm@18 - name: Install Libc++ - if: matrix.config.compiler.type == 'CLANG' && matrix.config.lib == 'libc++' && matrix.config.os != 'macos-14' + if: matrix.platform.compiler.type == 'CLANG' && matrix.platform.lib == 'libc++' && matrix.platform.os != 'macos-14' shell: bash run: | - sudo apt install -y libc++-${{ matrix.config.compiler.version }}-dev libc++abi-${{ matrix.config.compiler.version }}-dev libunwind-${{ matrix.config.compiler.version }}-dev + sudo apt install -y libc++-${{ matrix.platform.compiler.version }}-dev libc++abi-${{ matrix.platform.compiler.version }}-dev libunwind-${{ matrix.platform.compiler.version }}-dev - name: Select Xcode version - if: matrix.config.compiler.type == 'APPLE_CLANG' + if: matrix.platform.compiler.type == 'APPLE_CLANG' shell: bash run: | - sudo xcode-select -s /Applications/Xcode_${{ matrix.config.compiler.version }}.app && /usr/bin/xcodebuild -version + sudo xcode-select -s /Applications/Xcode_${{ matrix.platform.compiler.version }}.app && /usr/bin/xcodebuild -version - name: Set up Python uses: actions/setup-python@v5 with: @@ -142,29 +149,24 @@ jobs: run: | conan profile detect --force conan remote add artifactory https://mpusz.jfrog.io/artifactory/api/conan/conan-oss - if [[ "${{ matrix.config.compiler.type }}" == "CLANG" ]]; then - sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.config.lib }}/' ~/.conan2/profiles/default + if [[ "${{ matrix.platform.compiler.type }}" == "CLANG" ]]; then + sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.libcxx=.*/compiler.libcxx=${{ matrix.platform.lib }}/' ~/.conan2/profiles/default fi sed -i.backup '/^\[settings\]$/,/^\[/ s/^compiler.cppstd=.*/compiler.cppstd=${{ matrix.std }}/' ~/.conan2/profiles/default sed -i.backup '/^\[settings\]$/,/^\[/ s/^build_type=.*/build_type=${{ matrix.build_type }}/' ~/.conan2/profiles/default conan profile show -pr default - - name: Set 'std_format' and 'import_std' environment variables - shell: bash - run: | - echo "std_format=$([ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - echo "import_std=$([ "${{ matrix.std }}" -ge "23" ] && [ "${{ matrix.config.cxx_modules }}" == "True" ] && [ "${{ matrix.config.contracts }}" == "none" ] && [ "${{ matrix.formatting }}" == "std::format" ] && echo "True" || echo "False")" >> $GITHUB_ENV - name: Install Conan dependencies shell: bash run: | conan install . -b missing -c tools.cmake.cmaketoolchain:generator="Ninja Multi-Config" -c user.mp-units.build:all=False \ - -o '&:cxx_modules=${{ matrix.config.cxx_modules }}' -o '&:import_std=${{ env.import_std }}' -o '&:std_format=${{ env.std_format }}' -o '&:contracts=${{ matrix.contracts }}' + ${{ matrix.conan-config }} - name: Provide dependencies for the build shell: bash working-directory: src run: | echo -e '{\n "version": 4,\n "include": [\n "../CMakeUserPresets.json"\n ]\n}' | cat > CMakeUserPresets.json - name: Configure mp-units CMake - if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' + if: matrix.platform.compiler.type == 'VISUAL' || matrix.platform.compiler.type == 'MSVC' shell: cmd working-directory: src run: | @@ -172,7 +174,7 @@ jobs: call ..\build\generators\conanvcvars.bat cmake --preset conan-default -DCMAKE_INSTALL_PREFIX=../out - name: Configure mp-units CMake - if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' + if: matrix.platform.compiler.type != 'VISUAL' && matrix.platform.compiler.type != 'MSVC' shell: bash working-directory: src run: | @@ -189,7 +191,7 @@ jobs: run: | echo -e '{\n "version": 4,\n "include": [\n "../CMakeUserPresets.json"\n ]\n}' | cat > CMakeUserPresets.json - name: Build test_package CMake (local build) - if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' + if: matrix.platform.compiler.type == 'VISUAL' || matrix.platform.compiler.type == 'MSVC' shell: cmd working-directory: test_package run: | @@ -197,7 +199,7 @@ jobs: cmake --preset conan-default -Dmp-units_DIR=../build -Bbuild/local cmake --build build/local --config ${{ matrix.build_type }} - name: Build test_package CMake (local build) - if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' + if: matrix.platform.compiler.type != 'VISUAL' && matrix.platform.compiler.type != 'MSVC' shell: bash working-directory: test_package run: | @@ -215,7 +217,7 @@ jobs: run: | ./test_package - name: Build test_package CMake (installation) - if: matrix.config.compiler.type == 'VISUAL' || matrix.config.compiler.type == 'MSVC' + if: matrix.platform.compiler.type == 'VISUAL' || matrix.platform.compiler.type == 'MSVC' shell: cmd working-directory: test_package run: | @@ -223,7 +225,7 @@ jobs: cmake --preset conan-default -DCMAKE_INSTALL_PREFIX=../out -Bbuild/install cmake --build build/install --config ${{ matrix.build_type }} - name: Build test_package CMake (installation) - if: matrix.config.compiler.type != 'VISUAL' && matrix.config.compiler.type != 'MSVC' + if: matrix.platform.compiler.type != 'VISUAL' && matrix.platform.compiler.type != 'MSVC' shell: bash working-directory: test_package run: |