From dd20b1a63cb9d45a2effac6fc580b639b4d765ab Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sat, 16 Mar 2024 23:53:29 +0200 Subject: [PATCH 1/8] [python] Fix MyPy compatibility with Python 3.12; fix #332 --- src/nunavut/lang/py/support/nunavut_support.j2 | 3 +++ verification/python/noxfile.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nunavut/lang/py/support/nunavut_support.j2 b/src/nunavut/lang/py/support/nunavut_support.j2 index 1fce3406..5a3525b9 100644 --- a/src/nunavut/lang/py/support/nunavut_support.j2 +++ b/src/nunavut/lang/py/support/nunavut_support.j2 @@ -18,6 +18,9 @@ To execute the tests, simply invoke PyTest on this file as follows:: pytest --doctest-modules nunavut_support.py """ +# This is necessary to enable compatibility across different Python versions. +# mypy: warn_unused_ignores=False + from __future__ import annotations import abc import sys diff --git a/verification/python/noxfile.py b/verification/python/noxfile.py index 01b9258e..de3fd546 100644 --- a/verification/python/noxfile.py +++ b/verification/python/noxfile.py @@ -9,7 +9,7 @@ import nox -PYTHONS = ["3.8", "3.9", "3.10", "3.11"] +PYTHONS = ["3.8", "3.9", "3.10", "3.11", "3.12"] nox.options.error_on_external_run = True From 1796f39292dcd8f53dea4aa4566ceef4afa5653a Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 17 Mar 2024 00:01:38 +0200 Subject: [PATCH 2/8] Upgrade testing dependencies; PyLint 2.7 can't be used with Py3.12 --- verification/python/noxfile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/verification/python/noxfile.py b/verification/python/noxfile.py index de3fd546..2c3beef5 100644 --- a/verification/python/noxfile.py +++ b/verification/python/noxfile.py @@ -50,10 +50,10 @@ def test(session): session.install("-e", ".") session.install("-r", "generated_code_requirements.txt") session.install( - "pytest ~= 7.3", - "coverage ~= 7.2", - "mypy ~= 1.2", - "pylint ~= 2.17", + "pytest ~= 8.1", + "coverage ~= 7.4", + "mypy ~= 1.9", + "pylint ~= 3.1", ) # The tmp dir will contain the DSDL-generated packages. We do not want to contaminate the source tree. From 4b3935a3ece85f70c0b5c3a5ccf7529343f55d8a Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 17 Mar 2024 00:18:51 +0200 Subject: [PATCH 3/8] =?UTF-8?q?Use=20colored=20output=20in=20Python=20veri?= =?UTF-8?q?fication=20=F0=9F=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36b99958..0ea60371 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -232,3 +232,5 @@ jobs: run: | cd verification/python nox + env: + FORCE_COLOR: 1 From 4ae7efec377cf03a76f9f7a34fdfebcf4d0afb90 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 17 Mar 2024 00:40:34 +0200 Subject: [PATCH 4/8] Add Python version diagnostics --- verification/python/noxfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/verification/python/noxfile.py b/verification/python/noxfile.py index 2c3beef5..6951bb74 100644 --- a/verification/python/noxfile.py +++ b/verification/python/noxfile.py @@ -4,6 +4,7 @@ # type: ignore import os +import sys import shutil from pathlib import Path import nox @@ -46,6 +47,8 @@ def clean(session): @nox.session(python=PYTHONS) def test(session): + # Log the Python version + session.run("python", "--version") session.install("-e", str(NUNAVUT_DIR)) session.install("-e", ".") session.install("-r", "generated_code_requirements.txt") From 174343409c01c9de094694c92b223f902a15ecc2 Mon Sep 17 00:00:00 2001 From: Scott Dixon Date: Thu, 30 May 2024 09:37:02 -0700 Subject: [PATCH 5/8] Updating github actions Seeing if this fixes the EACCESS issues with the sonarqube step... --- .devcontainer/devcontainer.json | 3 +- .github/verify.py | 144 ++++++----- .github/workflows/release.yml | 4 +- .github/workflows/test.yml | 35 ++- .gitignore | 4 +- .vscode/cmake-variants.json | 67 ++++- .vscode/launch.json | 62 +---- .vscode/settings.json | 1 - CONTRIBUTING.rst | 29 ++- submodules/unity | 2 +- tox.ini | 9 +- verification/.devcontainer/devcontainer.json | 8 +- verification/CMakeLists.txt | 86 +++---- .../cmake/compiler_flag_sets/common.cmake | 82 ++++-- .../cmake/compiler_flag_sets/native.cmake | 13 +- .../compiler_flag_sets/native_w_asan.cmake | 41 +++ .../compiler_flag_sets/native_w_cov.cmake | 17 +- verification/cmake/modules/Findlcov.cmake | 2 +- verification/cmake/modules/Findtox.cmake | 8 +- verification/cmake/utils.cmake | 236 +++++------------- 20 files changed, 417 insertions(+), 436 deletions(-) create mode 100644 verification/cmake/compiler_flag_sets/native_w_asan.cmake diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ba9c8008..0ff21fcf 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,8 +4,7 @@ "workspaceFolder": "/workspace", "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated", "mounts": [ - "source=root-vscode-server,target=/root/.vscode-server/extensions,type=volume", - "source=nunavut-tox,target=/workspace/.tox,type=volume" + "source=root-vscode-server,target=/root/.vscode-server/extensions,type=volume" ], "customizations": { "vscode": { diff --git a/.github/verify.py b/.github/verify.py index 04b9bcc6..68593ca9 100755 --- a/.github/verify.py +++ b/.github/verify.py @@ -208,7 +208,21 @@ def _make_parser() -> argparse.ArgumentParser: "-x", "--no-coverage", action="store_true", - help="Disables generation of test coverage data. This is enabled by default.", + help="Deprecated. Use compiler_flag_set instead.", + ) + + action_args.add_argument( + "-cfs", + "--compiler-flag-set", + default="native", + type=pathlib.Path, + help=textwrap.dedent( + """ + Select the compiler flag set to use. This will select the appropriate compiler flags + for the build. The default is 'native' which is the default compiler flags for the + build environment. Use 'native_w_cov' to enable coverage flags. + See cmake/compiler_flag_sets for available options. + """[1:]), ) action_args.add_argument( @@ -257,34 +271,36 @@ def _make_parser() -> argparse.ArgumentParser: def _apply_overrides(args: argparse.Namespace) -> argparse.Namespace: - if args.override is not None: - for override_list in args.override: - for override in override_list: - if not pathlib.Path(override).exists(): - raise RuntimeError('ini file "{}" does not exist.'.format(override)) - print( - textwrap.dedent( - """ - ***************************************************************** - About to apply override file : {} - ***************************************************************** - """ - ).format(override) + if args.override is None: + return args + + for override_list in args.override: + for override in override_list: + if not pathlib.Path(override).exists(): + raise RuntimeError(f'ini file "{override}" does not exist.') + print( + textwrap.dedent( + f""" + ***************************************************************** + About to apply override file : {override} + ***************************************************************** + """ ) + ) - overrides = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation()) - overrides.read(override) - if "overrides" not in overrides: - raise RuntimeError('ini file "{}" did not contain an overrides section.'.format(override)) - for key, value in overrides["overrides"].items(): - corrected_key = key.replace("-", "_") - if value.lower() == "true" or value.lower() == "false": - setattr(args, corrected_key, bool(value)) - else: - try: - setattr(args, corrected_key, int(value)) - except ValueError: - setattr(args, corrected_key, value) + overrides = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation()) + overrides.read(override) + if "overrides" not in overrides: + raise RuntimeError(f'ini file "{override}" did not contain an overrides section.') + for key, value in overrides["overrides"].items(): + corrected_key = key.replace("-", "_") + if value.lower() == "true" or value.lower() == "false": + setattr(args, corrected_key, bool(value)) + else: + try: + setattr(args, corrected_key, int(value)) + except ValueError: + setattr(args, corrected_key, value) return args @@ -322,11 +338,11 @@ def _cmake_run( logging.debug(" Using Environment:") for key, value in copy_of_env.items(): overridden = key in env if env is not None else False - logging.debug(" {} = {}{}".format(key, value, (" (override)" if overridden else ""))) + logging.debug(" %s = %s%s", key, value, (" (override)" if overridden else "")) logging.debug(" *****************************************************************\n") if not dry_run: - return subprocess.run(cmake_args, cwd=cmake_dir, env=copy_of_env).returncode + return subprocess.run(cmake_args, cwd=cmake_dir, env=copy_of_env, check=True).returncode else: return 0 @@ -339,7 +355,7 @@ def _handle_build_dir(args: argparse.Namespace, cmake_dir: pathlib.Path) -> None if args.remove_first and cmake_dir.exists(): okay_to_remove = False if not args.force: - response = input("Are you sure you want to delete {}? [y/N]:".format(cmake_dir)) + response = input(f"Are you sure you want to delete {cmake_dir}? [y/N]:") if (len(response) == 1 and response.lower() == "y") or (len(response) == 3 and response.lower() == "yes"): okay_to_remove = True else: @@ -347,10 +363,10 @@ def _handle_build_dir(args: argparse.Namespace, cmake_dir: pathlib.Path) -> None if okay_to_remove: if not args.dry_run: - logging.info("Removing directory {}".format(cmake_dir)) + logging.info("Removing directory %s", cmake_dir) shutil.rmtree(cmake_dir) else: - logging.info("Is dry-run. Would have removed directory {}".format(cmake_dir)) + logging.info("Is dry-run. Would have removed directory %s", cmake_dir) else: raise RuntimeError( """ @@ -364,12 +380,12 @@ def _handle_build_dir(args: argparse.Namespace, cmake_dir: pathlib.Path) -> None if not cmake_dir.exists(): if not args.dry_run: - logging.info("Creating build directory at {}".format(cmake_dir)) + logging.info("Creating build directory at %s", cmake_dir) cmake_dir.mkdir() else: - logging.info("Dry run: Would have created build directory at {}".format(cmake_dir)) + logging.info("Dry run: Would have created build directory at %s", cmake_dir) else: - logging.info("Using existing build directory at {}".format(cmake_dir)) + logging.info("Using existing build directory at %s", cmake_dir) def _cmake_configure(args: argparse.Namespace, cmake_args: typing.List[str], cmake_dir: pathlib.Path) -> int: @@ -396,20 +412,20 @@ def _cmake_configure(args: argparse.Namespace, cmake_args: typing.List[str], cma cmake_configure_args = cmake_args.copy() - cmake_configure_args.append("--log-level={}".format(cmake_logging_level)) - cmake_configure_args.append("-DNUNAVUT_VERIFICATION_LANG={}".format(args.language)) + cmake_configure_args.append(f"--log-level={cmake_logging_level}") + cmake_configure_args.append(f"-DNUNAVUT_VERIFICATION_LANG={args.language}") if args.language_standard is not None: - cmake_configure_args.append("-DNUNAVUT_VERIFICATION_LANG_STANDARD={}".format(args.language_standard)) + cmake_configure_args.append(f"-DNUNAVUT_VERIFICATION_LANG_STANDARD={args.language_standard}") if args.build_type is not None: - cmake_configure_args.append("-DCMAKE_BUILD_TYPE={}".format(args.build_type)) + cmake_configure_args.append(f"-DCMAKE_BUILD_TYPE={args.build_type}") if args.endianness is not None: - cmake_configure_args.append("-DNUNAVUT_VERIFICATION_TARGET_ENDIANNESS={}".format(args.endianness)) + cmake_configure_args.append(f"-DNUNAVUT_VERIFICATION_TARGET_ENDIANNESS={args.endianness}") if args.platform is not None: - cmake_configure_args.append("-DNUNAVUT_VERIFICATION_TARGET_PLATFORM={}".format(args.platform)) + cmake_configure_args.append(f"-DNUNAVUT_VERIFICATION_TARGET_PLATFORM={args.platform}") if args.disable_asserts: cmake_configure_args.append("-DNUNAVUT_VERIFICATION_SER_ASSERT:BOOL=OFF") @@ -424,12 +440,14 @@ def _cmake_configure(args: argparse.Namespace, cmake_args: typing.List[str], cma cmake_configure_args.append("-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON") flag_set_dir = pathlib.Path("cmake") / pathlib.Path("compiler_flag_sets") - if args.no_coverage: - flagset_file = (flag_set_dir / pathlib.Path("native")).with_suffix(".cmake") - else: - flagset_file = (flag_set_dir / pathlib.Path("native_w_cov")).with_suffix(".cmake") + flagset_file = (flag_set_dir / args.compiler_flag_set).with_suffix(".cmake") + compiler_flag_set = (pathlib.Path(args.verification_dir) / flagset_file).resolve() + if not compiler_flag_set.exists(): + raise RuntimeError( + f"Compiler flag set file {str(compiler_flag_set)} does not exist in the verification directory." + ) - cmake_configure_args.append("-DNUNAVUT_FLAGSET={}".format(str(flagset_file))) + cmake_configure_args.append(f"-DNUNAVUT_FLAGSET={str(compiler_flag_set)}") if args.toolchain_family != "none": toolchain_dir = pathlib.Path("cmake") / pathlib.Path("toolchains") @@ -438,7 +456,7 @@ def _cmake_configure(args: argparse.Namespace, cmake_args: typing.List[str], cma else: toolchain_file = toolchain_dir / pathlib.Path("gcc-native").with_suffix(".cmake") - cmake_configure_args.append("-DCMAKE_TOOLCHAIN_FILE={}".format(str(toolchain_file))) + cmake_configure_args.append(f"-DCMAKE_TOOLCHAIN_FILE={str(toolchain_file)}") if not args.use_default_generator: cmake_configure_args.append("-DCMAKE_GENERATOR=Ninja") @@ -459,7 +477,7 @@ def _cmake_build(args: argparse.Namespace, cmake_args: typing.List[str], cmake_d cmake_build_args += ["--build", ".", "--target", "all"] if args.jobs is not None and args.jobs > 0: - cmake_build_args += ["--", "-j{}".format(args.jobs)] + cmake_build_args += ["--", f"-j{args.jobs}"] return _cmake_run(cmake_build_args, cmake_dir, args.verbose, args.dry_run) @@ -476,10 +494,10 @@ def _cmake_test(args: argparse.Namespace, cmake_args: typing.List[str], cmake_di cmake_test_args += ["--build", ".", "--target"] - if args.no_coverage: - cmake_test_args.append("test_all") - else: + if args.compiler_flag_set.stem == "native_w_cov": cmake_test_args.append("cov_all_archive") + else: + cmake_test_args.append("test_all") return _cmake_run(cmake_test_args, cmake_dir, args.verbose, args.dry_run) @@ -487,21 +505,21 @@ def _cmake_test(args: argparse.Namespace, cmake_args: typing.List[str], cmake_di def _create_build_dir_name(args: argparse.Namespace) -> str: - name = "build_{}".format(args.language) + name = f"build_{args.language}" if args.language_standard is not None: - name += "_{}".format(args.language_standard) + name += f"_{args.language_standard}" - name += "_{}".format(args.toolchain_family) + name += f"_{args.toolchain_family}" if args.platform is not None: - name += "_{}".format(args.platform) + name += f"_{args.platform}" if args.build_type is not None: - name += "_{}".format(args.build_type) + name += f"_{args.build_type}" if args.endianness is not None: - name += "_{}".format(args.endianness) + name += f"_{args.endianness}" if args.disable_asserts: name += "_noassert" @@ -517,10 +535,10 @@ def _create_build_dir_name(args: argparse.Namespace) -> str: @functools.lru_cache(maxsize=None) def _get_version_string() -> typing.Tuple[str, str, str]: - with open("src/nunavut/_version.py", "r") as version_py: - exec(version_py.read()) + with open("src/nunavut/_version.py", "r", encoding="UTF-8") as version_py: + exec(version_py.read()) # pylint: disable=exec-used - version_string = typing.cast(str, eval("__version__")) + version_string = typing.cast(str, eval("__version__")) # pylint: disable=eval-used version_array = version_string.split(".") return (version_array[0], version_array[1], version_array[2]) @@ -538,7 +556,7 @@ def main() -> int: if args.major_minor_version_only: version = _get_version_string() - sys.stdout.write("{}.{}".format(version[0], version[1])) + sys.stdout.write(f"{version[0]}.{version[1]}") sys.stdout.flush() return 0 @@ -554,10 +572,10 @@ def main() -> int: if args.version_check_only is not None: version_as_string = ".".join(_get_version_string()) logging.debug( - "Comparing nunavut version {} to provided version {} ({})".format( + "Comparing nunavut version %s to provided version %s (%s)", version_as_string, args.version_check_only, - "matches" if (version_as_string == args.version_check_only) else "no-match")) + "matches" if (version_as_string == args.version_check_only) else "no-match") return 0 if (version_as_string == args.version_check_only) else 1 logging.debug( diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e2593d3..c2f36627 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/opencyphal/toxic:tx22.4.2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' - name: version-check diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 36af9173..54fa1018 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/opencyphal/toxic:tx22.4.2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: lint @@ -27,17 +27,17 @@ jobs: - name: package run: tox -e package - name: upload-coverage-reports - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: coverage-reports path: .tox/report/tmp/* - name: upload-xunit-results - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: xunit-results path: .tox/py310-test/tmp/xunit-result.xml - name: upload-package - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: pypi-package path: .tox/package/dist/* @@ -45,19 +45,18 @@ jobs: sonar: runs-on: ubuntu-latest needs: test - container: sonarsource/sonar-scanner-cli steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # Disabling shallow clone is recommended for improving relevancy of reporting fetch-depth: 0 - name: download-converage-reports - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: coverage-reports path: .tox/report/tmp/ - name: download-xunit-results - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: xunit-results path: .tox/py310-test/tmp/ @@ -104,11 +103,11 @@ jobs: runs-on: ${{ matrix.python3-platform }} needs: test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: setup python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.${{ matrix.python3-version }} - name: setup tox @@ -124,7 +123,7 @@ jobs: container: ghcr.io/opencyphal/toxic:tx22.4.2 needs: test steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: python3.${{ matrix.python3-version }} test @@ -133,7 +132,7 @@ jobs: language-verification-c: runs-on: ubuntu-latest needs: test - container: ghcr.io/opencyphal/toolshed:ts22.4.2 + container: ghcr.io/opencyphal/toolshed:ts22.4.8 strategy: matrix: build_type: [Debug, Release, MinSizeRel] @@ -147,7 +146,7 @@ jobs: - build_type: Release flag: --disable-asserts steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: verify @@ -163,7 +162,7 @@ jobs: language-verification-cpp-14: runs-on: ubuntu-latest needs: test - container: ghcr.io/opencyphal/toolshed:ts22.4.1 + container: ghcr.io/opencyphal/toolshed:ts22.4.8 strategy: matrix: build_type: [Debug, Release, MinSizeRel] @@ -178,7 +177,7 @@ jobs: flag: --disable-asserts steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: verify @@ -195,7 +194,7 @@ jobs: language-verification-cpp-17: runs-on: ubuntu-latest needs: test - container: ghcr.io/opencyphal/toolshed:ts22.4.1 + container: ghcr.io/opencyphal/toolshed:ts22.4.8 strategy: matrix: build_type: [Debug, Release, MinSizeRel] @@ -210,7 +209,7 @@ jobs: flag: --disable-asserts steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: verify @@ -229,7 +228,7 @@ jobs: needs: test container: ghcr.io/opencyphal/toxic:tx22.4.2 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: verify diff --git a/.gitignore b/.gitignore index 2ebdd67f..f702413f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ __pycache__ .pytest_cache *.egg-info *.patch -.tox +.tox* .nox .coverage* .venv @@ -27,7 +27,7 @@ dist .DS_Store prof out -venv +venv* # Eclipse .metadata diff --git a/.vscode/cmake-variants.json b/.vscode/cmake-variants.json index 47f8b5cb..825d9264 100644 --- a/.vscode/cmake-variants.json +++ b/.vscode/cmake-variants.json @@ -3,15 +3,37 @@ "default": "debug", "description": "Variant for verification build kits.", "choices": { + "asan": { + "short": "Asan", + "long": "Address sanitizer builds.", + "buildType": "Debug", + "settings": { + "NUNAVUT_FLAGSET": "${workspaceFolder}/verification/cmake/compiler_flag_sets/native_w_asan.cmake" + } + }, + "coverage": { + "short": "Cov", + "long": "Coverage builds.", + "buildType": "Debug", + "settings": { + "NUNAVUT_FLAGSET": "${workspaceFolder}/verification/cmake/compiler_flag_sets/native_w_cov.cmake" + } + }, "debug": { "short": "Debug", "long": "Debug builds, no optimizations.", - "buildType": "Debug" + "buildType": "Debug", + "settings": { + "NUNAVUT_FLAGSET": "${workspaceFolder}/verification/cmake/compiler_flag_sets/native.cmake" + } }, "release": { "short": "Release", "long": "Release builds, some optimizations", - "buildType": "Release" + "buildType": "Release", + "settings": { + "NUNAVUT_FLAGSET": "${workspaceFolder}/verification/cmake/compiler_flag_sets/native.cmake" + } } } }, @@ -38,11 +60,50 @@ } } }, + "endianness":{ + "default": "any", + "choices": { + "any": { + "short": "any", + "long": "Generate code that works on either big or little endianness." + }, + "little": { + "short": "little", + "long": "Generate code for little-endian targets.", + "settings": { + "NUNAVUT_VERIFICATION_TARGET_ENDIANNESS": "little" + } + }, + "big": { + "short": "big", + "long": "Generate code for big-endian targets.", + "settings": { + "NUNAVUT_VERIFICATION_TARGET_ENDIANNESS": "big" + } + } + } + }, "language":{ "default": "C++14", "choices": { "C": { - "short": "--std=c11", + "short": "(c default)", + "long": "Compile and link using the C11 standard.", + "settings": { + "NUNAVUT_VERIFICATION_LANG": "c", + "NUNAVUT_VERIFICATION_LANG_STANDARD": "" + } + }, + "C11": { + "short": "-std=c11", + "long": "Compile and link using the C11 standard.", + "settings": { + "NUNAVUT_VERIFICATION_LANG": "c", + "NUNAVUT_VERIFICATION_LANG_STANDARD": "c11" + } + }, + "Cgnu17": { + "short": "-std=gnu17", "long": "Compile and link using the C11 standard.", "settings": { "NUNAVUT_VERIFICATION_LANG": "c", diff --git a/.vscode/launch.json b/.vscode/launch.json index b7419f4c..9ace3fc9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,62 +48,16 @@ "cwd": "${workspaceFolder}" }, { - "name": "Verification: test_var_len_arr", - "type": "cppdbg", + "type": "lldb", "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/native-gcc-cpp/suite/test_var_len_arr", + "program": "${command:cmake.launchTargetPath}", + "name": "lldb: cmake.launchTargetPath", + "args": [], "cwd": "${workspaceFolder}", - "osx": { - "MIMode": "lldb", - "externalConsole": false - } - }, - { - "name": "Verification: test_support", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/linux-gcc-c/suite/test_support", - "cwd": "${workspaceFolder}" - }, - { - "name": "Verification: test_serialization", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/linux-gcc-c/suite/test_serialization", - "cwd": "${workspaceFolder}" - }, - { - "name": "Verification(clang): test_constant", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/native-clang-c/suite/test_constant", - "cwd": "${workspaceFolder}", - "osx": { - "MIMode": "lldb", - "externalConsole": false - } - }, - { - "name": "Verification(clang): test_support", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/native-clang-c/suite/test_support", - "cwd": "${workspaceFolder}", - "osx": { - "MIMode": "lldb", - "externalConsole": false - } - }, - { - "name": "Verification (clang): test_serialization", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceRoot}/verification/build_vscode/native-clang-c/suite/test_serialization", - "cwd": "${workspaceFolder}", - "osx": { - "MIMode": "lldb", - "externalConsole": false - } + "initCommands": ["settings set target.process.thread.step-avoid-regexp \"\""], + "env": { + "PATH": "$PATH:${command:cmake.launchTargetDirectory}", + }, } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 2132ab87..1bfed645 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,4 @@ { - "python.defaultInterpreterPath": "${workspaceFolder}/.tox/local", "python.testing.cwd": "${workspaceFolder}", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index cb715996..c58f9b0e 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -80,8 +80,8 @@ skip the docker invocations and use ``tox run -s``. To run the language verification build you'll need to use a different docker container:: - docker pull ghcr.io/opencyphal/toolshed:ts22.4.5 - docker run --rm -it -v $PWD:/workspace ghcr.io/opencyphal/toolshed:ts22.4.5 + docker pull ghcr.io/opencyphal/toolshed:ts22.4.8 + docker run --rm -it -v $PWD:/workspace ghcr.io/opencyphal/toolshed:ts22.4.8 cd /workspace ./.github/verify.py -l c ./.github/verify.py -l cpp @@ -94,6 +94,17 @@ If you get a "denied" response from ghcr your ip might be getting rate-limited. you'll have to login to get around any rate-limiting for your local site. See [the github docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) for how to setup a docker client login. + +If you get the following error:: + + gcc: error: unrecognized command-line option ‘-m32’ + +...it may mean you are trying to run one of our 32-bit platform tests using an armv8 docker image. For these builds +you might need to override the target platform and pull the x86 version of the container explicitly. For example:: + + docker run --rm -it --platform linux/amd64 -v $PWD:/workspace ghcr.io/opencyphal/toolshed:ts22.4.8 + + Files Generated by the Tests ================================================ @@ -188,10 +199,10 @@ We rely on `read the docs`_ to build our documentation from github but we also v as part of our tox build. This means you can view a local copy after completing a full, successful test run (See `Running The Tests`_) or do :code:`docker run --rm -t -v $PWD:/repo ghcr.io/opencyphal/toxic:tx22.4.2 /bin/sh -c "tox run -e docs"` to build -the docs target. You can open the index.html under ``.tox/docs/tmp/index.html`` or run a local +the docs target. You can open the index.html under ``.tox_{host platform}/docs/tmp/index.html`` or run a local web-server:: - python3 -m http.server --directory .tox/docs/tmp & + python3 -m http.server --directory .tox_{host platform}/docs/tmp & open http://localhost:8000/docs/index.html Of course, you can just use `Visual Studio Code`_ to build and preview the docs using @@ -203,15 +214,15 @@ Coverage and Linting Reports ************************************************ We publish the results of our coverage data to `sonarcloud`_ and the tox build will fail for any mypy -or black errors but you can view additional reports locally under the :code:`.tox` dir. +or black errors but you can view additional reports locally under the :code:`.tox_{host platform}` dir. Coverage ================================================ -We generate a local html coverage report. You can open the index.html under .tox/report/tmp +We generate a local html coverage report. You can open the index.html under .tox_{host platform}/report/tmp or run a local web-server:: - python -m http.server --directory .tox/report/tmp & + python -m http.server --directory .tox_{host platform}/report/tmp & open http://localhost:8000/index.html Mypy @@ -219,8 +230,8 @@ Mypy At the end of the mypy run we generate the following summaries: -- .tox/mypy/tmp/mypy-report-lib/index.txt -- .tox/mypy/tmp/mypy-report-script/index.txt +- .tox_{host platform}/mypy/tmp/mypy-report-lib/index.txt +- .tox_{host platform}/mypy/tmp/mypy-report-script/index.txt ************************************************ Nunavut Verification Suite diff --git a/submodules/unity b/submodules/unity index 98045925..1d28a998 160000 --- a/submodules/unity +++ b/submodules/unity @@ -1 +1 @@ -Subproject commit 98045925af4409942d43ac348aeab5a0554c9c7f +Subproject commit 1d28a9981207fa03be19018f60b23d5dca53cabc diff --git a/tox.ini b/tox.ini index 852888f3..e42a6061 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,6 @@ [tox] envlist = {py37,py38,py39,py310,py311,py312}-{test,nnvg,doctest,rstdoctest},lint,report,docs - [base] deps = Sybil @@ -41,7 +40,7 @@ log_file = pytest.log log_level = DEBUG log_cli = true log_cli_level = WARNING -norecursedirs = submodules .* build* verification .tox +norecursedirs = submodules .* build* verification {toxworkdir} addopts = -p no:doctest [coverage:run] @@ -51,7 +50,7 @@ parallel=True relative_files = True include = src/nunavut/* - .tox/*/site-packages/nunavut/* + {toxworkdir}/*/site-packages/nunavut/* omit = */jinja2/* @@ -64,8 +63,8 @@ omit = [coverage:paths] source = src - .tox/*/site-packages - .tox/*/bin + {toxworkdir}/*/site-packages + {toxworkdir}/*/bin [coverage:report] diff --git a/verification/.devcontainer/devcontainer.json b/verification/.devcontainer/devcontainer.json index 533a16a2..0a121a80 100644 --- a/verification/.devcontainer/devcontainer.json +++ b/verification/.devcontainer/devcontainer.json @@ -1,12 +1,8 @@ { "name": "C/C++ verification environment", - "image": "ghcr.io/opencyphal/toolshed:ts22.4.5", + "image": "ghcr.io/opencyphal/toolshed:ts22.4.8", "workspaceFolder": "/workspace", "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspace,type=bind,consistency=delegated", - "mounts": [ - "source=root-vscode-server,target=/root/.vscode-server/extensions,type=volume", - "source=nunavut-tox,target=/workspace/.tox,type=volume" - ], "customizations": { "vscode": { "extensions": [ @@ -24,5 +20,5 @@ ] } }, - "postCreateCommand": "git submodule update --init --recursive && tox -e local" + "postCreateCommand": "git submodule update --init --recursive" } diff --git a/verification/CMakeLists.txt b/verification/CMakeLists.txt index 63fbfcd6..88f748cd 100644 --- a/verification/CMakeLists.txt +++ b/verification/CMakeLists.txt @@ -1,6 +1,7 @@ # -# Copyright (C) 2014 Pavel Kirienko -# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT # cmake_minimum_required(VERSION 3.10.0) @@ -85,6 +86,7 @@ else() set(NUNAVUT_FLAGSET "${CMAKE_SOURCE_DIR}/cmake/compiler_flag_sets/native_w_cov.cmake") message(STATUS "Setting (default) NUNAVUT_FLAGSET = ${NUNAVUT_FLAGSET}") endif() +include("${NUNAVUT_FLAGSET}") # # Tell cmake where to find our custom scripts. @@ -107,22 +109,6 @@ set(NUNAVUT_VERIFICATIONS_BINARY_DIR ${CMAKE_BINARY_DIR}/suite) file(WRITE ${NUNAVUT_VERIFICATIONS_BINARY_DIR}/README.txt "All test binaries and output will appear under here.") -# -# Handle other inputs that translate to compiler flags. -# -set(NUNAVUT_VERIFICATION_EXTRA_COMPILE_CFLAGS "") - -if(DEFINED NUNAVUT_VERIFICATION_TARGET_PLATFORM) - if(${NUNAVUT_VERIFICATION_TARGET_PLATFORM} STREQUAL "native32") - list(APPEND NUNAVUT_VERIFICATION_EXTRA_COMPILE_CFLAGS "-m32") - message(STATUS "Configuring for native32 platform.") - elseif(${NUNAVUT_VERIFICATION_TARGET_PLATFORM} STREQUAL "native64") - list(APPEND NUNAVUT_VERIFICATION_EXTRA_COMPILE_CFLAGS "-m64") - message(STATUS "Configuring for native64 platform.") - else() - message(FATAL_ERROR "\"${NUNAVUT_VERIFICATION_TARGET_PLATFORM}\" is not a supported value.") - endif() -endif() # +---------------------------------------------------------------------------+ # | BUILD ENVIRONMENT @@ -135,7 +121,7 @@ find_package(lcov REQUIRED) find_package(genhtml REQUIRED) # -# We need tox to enable a reproducable python environment. +# We need tox to enable a reproducible python environment. # find_package(tox REQUIRED) @@ -338,14 +324,6 @@ else() list(APPEND LOCAL_ADDITIONAL_DSDL_LIBS "") endif() -# -# Load all our compile flag sets into the appropriate places. -# -apply_flag_set("${NUNAVUT_FLAGSET}" - "${LOCAL_VERIFICATION_LANG_STANDARD_C}" - "${LOCAL_VERIFICATION_LANG_STANDARD_CXX}") - - # +---------------------------------------------------------------------------+ # | VERIFICATION SUITE # +---------------------------------------------------------------------------+ @@ -382,28 +360,25 @@ function(runTestCpp) set(NATIVE_TEST "${NUNAVUT_VERIFICATION_LANG}/suite/${runTestCpp_TEST_FILE}") get_filename_component(NATIVE_TEST_NAME ${NATIVE_TEST} NAME_WE) - set(${NATIVE_TEST_NAME}_CPP_EXTRA_FLAGS, "") - list(APPEND ${NATIVE_TEST_NAME}_CPP_EXTRA_FLAGS ${NUNAVUT_VERIFICATION_EXTRA_COMPILE_CFLAGS}) - + define_native_unit_test(FRAMEWORK "gtest" + TEST_NAME ${NATIVE_TEST_NAME} + TEST_SOURCE ${NATIVE_TEST} + OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR} + DSDL_TARGETS + ${runTestCpp_LINK} + ${LOCAL_ADDITIONAL_DSDL_LIBS} + ) if(NUNAVUT_VERIFICATION_LANG STREQUAL "c") - # - # If we are testing C headers with C++ tests we have to disable - # certain checks to allow the inline code to compile without - # warnings. - # - list(APPEND ${NATIVE_TEST_NAME}_CPP_EXTRA_FLAGS "-Wno-old-style-cast") + # + # If we are testing C headers with C++ tests we have to disable + # certain checks to allow the inline code to compile without + # warnings. + # + target_compile_options(${NATIVE_TEST_NAME} PRIVATE "-Wno-old-style-cast") endif() - - define_native_unit_test("gtest" - ${NATIVE_TEST_NAME} - ${NATIVE_TEST} - ${NUNAVUT_VERIFICATIONS_BINARY_DIR} - "${${NATIVE_TEST_NAME}_CPP_EXTRA_FLAGS}" - ${runTestCpp_LINK} - ${LOCAL_ADDITIONAL_DSDL_LIBS} - o1heap) + target_link_libraries(${NATIVE_TEST_NAME} PUBLIC o1heap) target_include_directories(${NATIVE_TEST_NAME} PUBLIC "${NUNAVUT_PROJECT_ROOT}/submodules/CETL/include") - define_native_test_run(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") @@ -440,16 +415,15 @@ function(runTestC) set(NATIVE_TEST "${NUNAVUT_VERIFICATION_ROOT}/suite/${runTestC_TEST_FILE}") get_filename_component(NATIVE_TEST_NAME ${NATIVE_TEST} NAME_WE) - set(${NATIVE_TEST_NAME}_C_EXTRA_FLAGS, "") - list(APPEND ${NATIVE_TEST_NAME}_C_EXTRA_FLAGS ${NUNAVUT_VERIFICATION_EXTRA_COMPILE_CFLAGS}) - - define_native_unit_test("unity" - ${NATIVE_TEST_NAME} - ${NATIVE_TEST} - ${NUNAVUT_VERIFICATIONS_BINARY_DIR} - "${${NATIVE_TEST_NAME}_C_EXTRA_FLAGS}" - ${runTestC_LINK}) - define_native_test_run(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + + define_native_unit_test(FRAMEWORK "unity" + TEST_NAME ${NATIVE_TEST_NAME} + TEST_SOURCE ${NATIVE_TEST} + OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR} + DSDL_TARGETS + ${runTestC_LINK} + ) + define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") diff --git a/verification/cmake/compiler_flag_sets/common.cmake b/verification/cmake/compiler_flag_sets/common.cmake index 2216f262..49b5c582 100644 --- a/verification/cmake/compiler_flag_sets/common.cmake +++ b/verification/cmake/compiler_flag_sets/common.cmake @@ -1,23 +1,23 @@ # -# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# C, CXX, LD, and AS flags for native targets. +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT # +# C, CXX, LD, and AS flags for building native unit tests. These flags also include +# instrumentation for code coverage. # -# Flags for C and C++ -# -set(C_AND_CXX_FLAG_SET "") -set(C_FLAG_SET "") -set(CXX_FLAG_SET "") -set(ASM_FLAG_SET "") + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(C_FLAG_SET ) set(EXE_LINKER_FLAG_SET ) set(DEFINITIONS_SET ) # # Diagnostics for C and C++ # -list(APPEND C_AND_CXX_FLAG_SET +list(APPEND C_FLAG_SET "-pedantic" "-Wall" "-Wextra" @@ -33,16 +33,24 @@ list(APPEND C_AND_CXX_FLAG_SET "-Wdouble-promotion" "-Wswitch-enum" "-Wtype-limits" - "-Wno-error=array-bounds" ) -# -# General C++ only flags -# -list(APPEND CXX_FLAG_SET - "-std=c++14" - "-fno-rtti" -) +if(DEFINED NUNAVUT_VERIFICATION_TARGET_PLATFORM) + if(${NUNAVUT_VERIFICATION_TARGET_PLATFORM} STREQUAL "native32") + list(APPEND C_FLAG_SET "-m32") + list(APPEND EXE_LINKER_FLAG_SET "-m32") + message(STATUS "Configuring for native32 platform.") + elseif(${NUNAVUT_VERIFICATION_TARGET_PLATFORM} STREQUAL "native64") + list(APPEND C_FLAG_SET "-m64") + list(APPEND EXE_LINKER_FLAG_SET "-m64") + message(STATUS "Configuring for native64 platform.") + else() + message(FATAL_ERROR "\"${NUNAVUT_VERIFICATION_TARGET_PLATFORM}\" is not a supported value.") + endif() +endif() + +set(CXX_FLAG_SET ${C_FLAG_SET}) +set(ASM_FLAG_SET ${C_FLAG_SET}) # # C++ only diagnostics @@ -56,9 +64,35 @@ list(APPEND CXX_FLAG_SET "-Woverloaded-virtual" ) -# -# General C only flags -# -list(APPEND C_FLAG_SET - "-std=c11" -) +if (CMAKE_BUILD_TYPE STREQUAL "Release") + message(STATUS "Release build. Setting optimization flags.") + list(APPEND C_FLAG_SET + "-O2" + # "-D_FORTIFY_SOURCE=3" # TODO: 3 if gcc12 or later otherwise 2 + ) +else() + + message(STATUS "Not a Release build. Setting debug flags.") + list(APPEND C_FLAG_SET + "-Og" + "-DDEBUG" + "-ggdb" + ) + +endif() + +if (CETLVAST_DISABLE_CPP_EXCEPTIONS) + message(STATUS "CETLVAST_DISABLE_CPP_EXCEPTIONS is true. Adding -fno-exceptions to compiler flags.") + list(APPEND CXX_FLAG_SET + "-fno-exceptions") +endif() + +list(APPEND CXX_FLAG_SET ${C_FLAG_SET}) +list(APPEND ASM_FLAG_SET ${C_FLAG_SET}) + +add_compile_options("$<$:${C_FLAG_SET}>") +add_compile_options("$<$:${CXX_FLAG_SET}>") +add_compile_options("$<$:${ASM_FLAG_SET}>") +add_link_options(${EXE_LINKER_FLAG_SET}) +add_definitions(${DEFINITIONS_SET}) +set(CMAKE_C_EXTENSIONS OFF) diff --git a/verification/cmake/compiler_flag_sets/native.cmake b/verification/cmake/compiler_flag_sets/native.cmake index 6421335f..9e8d95d7 100644 --- a/verification/cmake/compiler_flag_sets/native.cmake +++ b/verification/cmake/compiler_flag_sets/native.cmake @@ -1,14 +1,7 @@ # -# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# C, CXX, LD, and AS flags for native targets. +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT # -# -# Flags for C and C++ -# include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) - -list(APPEND C_FLAG_SET ${C_AND_CXX_FLAG_SET}) -list(APPEND CXX_FLAG_SET ${C_AND_CXX_FLAG_SET}) -list(APPEND ASM_FLAG_SET ${C_AND_CXX_FLAG_SET}) diff --git a/verification/cmake/compiler_flag_sets/native_w_asan.cmake b/verification/cmake/compiler_flag_sets/native_w_asan.cmake new file mode 100644 index 00000000..9c27d55e --- /dev/null +++ b/verification/cmake/compiler_flag_sets/native_w_asan.cmake @@ -0,0 +1,41 @@ +# +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT +# + +# +# Enable undefined behaviour sanitizer +# + +include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) + + +list(APPEND LOCAL_SANITIZER_OPTIONS + "-fsanitize=address" + "-fsanitize=pointer-compare" + "-fsanitize=pointer-subtract" + "-fsanitize=undefined" + "-fsanitize=alignment" + "-fsanitize=null" + "-fsanitize=pointer-compare" + "-fsanitize=pointer-subtract" + "-fsanitize=pointer-overflow" + "-fsanitize=bounds" + "-fsanitize=signed-integer-overflow" + "-fsanitize=shift" + "-fsanitize=shift-exponent" + "-fsanitize=shift-base" + "-fsanitize=float-divide-by-zero" + "-fsanitize=float-cast-overflow" + "-fsanitize=pointer-overflow" + "-fsanitize=builtin" +) + +add_compile_options( + ${LOCAL_SANITIZER_OPTIONS} +) + +add_link_options( + ${LOCAL_SANITIZER_OPTIONS} +) diff --git a/verification/cmake/compiler_flag_sets/native_w_cov.cmake b/verification/cmake/compiler_flag_sets/native_w_cov.cmake index ddff9607..9d09df11 100644 --- a/verification/cmake/compiler_flag_sets/native_w_cov.cmake +++ b/verification/cmake/compiler_flag_sets/native_w_cov.cmake @@ -1,20 +1,21 @@ # -# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# C, CXX, LD, and AS flags for native targets. +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT # # -# Flags for C and C++ +# Enable code coverage instrumentation for C and C++ code # include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) -list(APPEND C_AND_CXX_FLAG_SET +add_compile_options( "-fprofile-arcs" "-ftest-coverage" ) -list(APPEND C_FLAG_SET ${C_AND_CXX_FLAG_SET}) -list(APPEND CXX_FLAG_SET ${C_AND_CXX_FLAG_SET}) -list(APPEND ASM_FLAG_SET ${C_AND_CXX_FLAG_SET}) +add_link_options( + "-fprofile-arcs" + "-ftest-coverage" +) diff --git a/verification/cmake/modules/Findlcov.cmake b/verification/cmake/modules/Findlcov.cmake index a3faaa45..171570cb 100644 --- a/verification/cmake/modules/Findlcov.cmake +++ b/verification/cmake/modules/Findlcov.cmake @@ -57,7 +57,7 @@ if(LCOV) # param: ARG_TEST_NAME string - The name of the test to run. A target will be created # with the name run_${ARG_TEST_NAME}_with_lcov # param: ARG_OUTDIR path - The path where the test binaries live. - # param: ARG_SOURCE_FILTER_DIR pattern - pattern for paths to include (exclusivly) in the coverage + # param: ARG_SOURCE_FILTER_DIR pattern - pattern for paths to include (exclusively) in the coverage # data. # function(define_native_test_run_with_lcov ARG_TEST_NAME ARG_OUTDIR ARG_SOURCE_FILTER_DIR) diff --git a/verification/cmake/modules/Findtox.cmake b/verification/cmake/modules/Findtox.cmake index 71c5ec50..7def0adf 100644 --- a/verification/cmake/modules/Findtox.cmake +++ b/verification/cmake/modules/Findtox.cmake @@ -9,9 +9,8 @@ find_program(TOX tox) if(TOX) - set(TOX_LOCAL_OUTPUT ${NUNAVUT_PROJECT_ROOT}/.tox/local) - - set(TOX_LOCAL_PYTHON_BIN ${TOX_LOCAL_OUTPUT}/bin) + set(TOX_LOCAL_VENV_PATH ${NUNAVUT_PROJECT_ROOT}/venv_${CMAKE_HOST_SYSTEM}) + set(TOX_LOCAL_PYTHON_BIN ${TOX_LOCAL_VENV_PATH}/bin) execute_process(COMMAND ${TOX} --version OUTPUT_VARIABLE TOX_VERSION @@ -23,7 +22,8 @@ if(TOX) message(WARNING "${TOX} --version command failed.") endif() - execute_process(COMMAND ${TOX} -e local + execute_process(COMMAND ${TOX} d ${TOX_LOCAL_VENV_PATH} + --workdir ${NUNAVUT_PROJECT_ROOT}/.tox_${CMAKE_HOST_SYSTEM} WORKING_DIRECTORY ${NUNAVUT_PROJECT_ROOT} RESULT_VARIABLE TOX_LOCAL_RESULT) diff --git a/verification/cmake/utils.cmake b/verification/cmake/utils.cmake index 21e23305..689f39ff 100644 --- a/verification/cmake/utils.cmake +++ b/verification/cmake/utils.cmake @@ -1,136 +1,8 @@ # -# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright (C) OpenCyphal Development Team +# Copyright Amazon.com Inc. or its affiliates. +# SPDX-License-Identifier: MIT # -# Helpers and utilities used in our CMakeLists.txt. Put it in here to keep from -# cluttering that file up. -# - -# +===========================================================================+ -# | flag replacement -# +===========================================================================+ -# -# :function: replace_c_std -# Add a given C -std argument within a string or add it if its not found -# -# :param str ARG_REPLACE_IN: The string to do the replacement within. -# :param str ARG_OVERRIDE_C_STD: The flag value to replace (i.e. just "c99" not "-std=c99") -function(replace_c_std ARG_OVERRIDE_C_STD - ARG_REPLACE_INOUT) - - string(REGEX REPLACE "-std=[a-fA-F0-9+:]+" - "-std=${ARG_OVERRIDE_C_STD}" - LOCAL_RESULT - ${${ARG_REPLACE_INOUT}}) - set(${ARG_REPLACE_INOUT} ${LOCAL_RESULT} PARENT_SCOPE) -endfunction() - -# -# :function: replace_cxx_std -# Add a given C++ -std argument within a string or add it if its not found -# -# :param str ARG_REPLACE_IN: The string to do the replacement within. -# :param str ARG_OVERRIDE_CXX_STD: The flag value to replace (i.e. just "c++14" not "-std=c++14") -function(replace_cxx_std ARG_OVERRIDE_CXX_STD - ARG_REPLACE_INOUT) - - # Convert the Nunavut CLI language standard into the underlying C++ compiler language standard flag - if(ARG_OVERRIDE_CXX_STD STREQUAL "cetl++14-17") - set(ARG_OVERRIDE_CXX_STD "c++14") - elseif(ARG_OVERRIDE_CXX_STD STREQUAL "c++17-pmr") - set(ARG_OVERRIDE_CXX_STD "c++17") - endif() - - string(REGEX REPLACE "-std=[a-fA-F0-9+:]+" - "-std=${ARG_OVERRIDE_CXX_STD}" - LOCAL_RESULT - ${${ARG_REPLACE_INOUT}}) - set(${ARG_REPLACE_INOUT} ${LOCAL_RESULT} PARENT_SCOPE) -endfunction() - -# +===========================================================================+ -# | Flag set handling -# +===========================================================================+ -# -# :function: apply_flag_set -# CMake 3.10 compatible routine for loading this project's compiler flag sets -# (found under cmake/compiler_flag_sets) and properly setting the following cmake build variables: -# - CMAKE_C_FLAGS -# - CMAKE_CXX_FLAGS -# - CMAKE_EXE_LINKER_FLAGS -# - CMAKE_ASM_FLAGS -# -# :param Path ARG_FLAG_SET: The flagset file to include. -# :param str ARG_OVERRIDE_C_STD: Locally overridden -std flag for C. -# :param str ARG_OVERRIDE_CXX_STD: Locally overridden -std flag for C++. -function(apply_flag_set ARG_FLAG_SET - ARG_OVERRIDE_C_STD - ARG_OVERRIDE_CXX_STD) - include(${ARG_FLAG_SET}) - - # list(JOIN ) is a thing in cmake 3.12 but we only require 3.10. - # Why 3.10? Because this is the version in Ubuntu 18.04 LTS. - string(REPLACE ";" " " LOCAL_CMAKE_C_FLAGS "${C_FLAG_SET}") - string(REPLACE ";" " " LOCAL_CMAKE_CXX_FLAGS "${CXX_FLAG_SET}") - string(REPLACE ";" " " LOCAL_CMAKE_EXE_LINKER_FLAGS "${EXE_LINKER_FLAG_SET}") - string(REPLACE ";" " " LOCAL_CMAKE_ASM_FLAGS "${ASM_FLAG_SET}") - - if (NOT ARG_OVERRIDE_C_STD STREQUAL "") - replace_c_std(${ARG_OVERRIDE_C_STD} LOCAL_CMAKE_C_FLAGS) - message(STATUS "Overriding C standard from flag set ${ARG_FLAG_SET} with ${ARG_OVERRIDE_C_STD}") - endif() - - if (NOT ARG_OVERRIDE_CXX_STD STREQUAL "") - replace_cxx_std(${ARG_OVERRIDE_CXX_STD} LOCAL_CMAKE_CXX_FLAGS) - message(STATUS "Overriding C++ standard from flag set ${ARG_FLAG_SET} with ${ARG_OVERRIDE_CXX_STD}") - endif() - - # +-----------------------------------------------------------------------+ - # | CONFIGURABLE DEFINITIONS - # +-----------------------------------------------------------------------+ - if(NOT DEFINED NUNAVUT_CPP_ENABLE_EXCEPTIONS AND "-fexceptions" IN_LIST CXX_FLAG_SET) - set(NUNAVUT_CPP_ENABLE_EXCEPTIONS 1) - endif() - - if(DEFINED NUNAVUT_CPP_ENABLE_EXCEPTIONS) - set(LOCAL_CMAKE_C_FLAGS "${LOCAL_CMAKE_C_FLAGS} -DNUNAVUT_CPP_ENABLE_EXCEPTIONS=${NUNAVUT_CPP_ENABLE_EXCEPTIONS}") - set(LOCAL_CMAKE_CXX_FLAGS "${LOCAL_CMAKE_CXX_FLAGS} -DNUNAVUT_CPP_ENABLE_EXCEPTIONS=${NUNAVUT_CPP_ENABLE_EXCEPTIONS}") - endif() - - if(NOT DEFINED NUNAVUT_CPP_ENABLE_EXCEPTIONS AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(NUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT 1) - endif() - - if(DEFINED NUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT) - set(LOCAL_CMAKE_C_FLAGS "${LOCAL_CMAKE_C_FLAGS} -DNUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT=${NUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT}") - set(LOCAL_CMAKE_CXX_FLAGS "${LOCAL_CMAKE_CXX_FLAGS} -DNUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT=${NUNAVUT_CPP_INTROSPECTION_ENABLE_ASSERT}") - endif() - - if(NOT DEFINED NUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(NUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE 1) - endif() - - if(DEFINED NUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE) - set(LOCAL_CMAKE_C_FLAGS "${LOCAL_CMAKE_C_FLAGS} -DNUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE=${NUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE}") - set(LOCAL_CMAKE_CXX_FLAGS "${LOCAL_CMAKE_CXX_FLAGS} -DNUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE=${NUNAVUT_CPP_INTROSPECTION_TRACE_ENABLE}") - endif() - - # +-----------------------------------------------------------------------+ - - set(CMAKE_C_FLAGS ${LOCAL_CMAKE_C_FLAGS} PARENT_SCOPE) - message(STATUS "apply_flag_set: CMAKE_C_FLAGS=${LOCAL_CMAKE_C_FLAGS}") - - set(CMAKE_CXX_FLAGS ${LOCAL_CMAKE_CXX_FLAGS} PARENT_SCOPE) - message(STATUS "apply_flag_set: CMAKE_CXX_FLAGS=${LOCAL_CMAKE_CXX_FLAGS}") - - set(CMAKE_EXE_LINKER_FLAGS ${LOCAL_CMAKE_EXE_LINKER_FLAGS} PARENT_SCOPE) - message(STATUS "apply_flag_set: CMAKE_EXE_LINKER_FLAGS=${LOCAL_CMAKE_EXE_LINKER_FLAGS}") - - set(CMAKE_ASM_FLAGS ${LOCAL_CMAKE_ASM_FLAGS} PARENT_SCOPE) - message(STATUS "apply_flag_set: CMAKE_ASM_FLAGS=${LOCAL_CMAKE_ASM_FLAGS}") - - add_definitions(${DEFINITIONS_SET}) - -endfunction() # +===========================================================================+ # | UNIT TESTING @@ -139,49 +11,45 @@ endfunction() # function: define_native_unit_test - creates an executable target and links it # to the "all" target to build a gtest binary for the given test source. # -# param: ARG_FRAMEWORK string - The name of the test framework to use. -# param: ARG_TEST_NAME string - The name to give the test binary. -# param: ARG_TEST_SOURCE List[path] - A list of source files to compile into -# the test binary. -# param: ARG_OUTDIR path - A path to output test binaries and coverage data under. -# param: ARG_EXTRA_COMPILE_FLAGS string - Additional compile arguments to set for -# the ARG_TEST_SOURCE files in addition to the arguments -# used for the current toolchain and language. -# param: ... List[str] - Zero to many targets that generate types under test. +# param: FRAMEWORK [gtest|unity] - The name of the test framework to use. +# param: TEST_NAME string - The name to give the test target. +# param: TEST_SOURCE List[path] - A list of source files to compile into +# the test binary. +# param: OUTDIR path - A path to output test binaries and coverage data under. +# param: DSDL_TARGETS List[str] - Zero to many targets that generate types under test. # -function(define_native_unit_test - ARG_FRAMEWORK - ARG_TEST_NAME - ARG_TEST_SOURCE - ARG_OUTDIR - ARG_EXTRA_COMPILE_FLAGS) - - add_executable(${ARG_TEST_NAME} ${ARG_TEST_SOURCE}) +function(define_native_unit_test) + + # +--[ INPUTS ]-----------------------------------------------------------+ + set(options "") + set(monoValues FRAMEWORK TEST_NAME OUTDIR) + set(multiValues TEST_SOURCE DSDL_TARGETS) + + cmake_parse_arguments( + ARG + "${options}" + "${monoValues}" + "${multiValues}" + ${ARGN} + ) - if(NOT "${ARG_EXTRA_COMPILE_FLAGS}" STREQUAL "") - string(REPLACE ";" " " LOCAL_${ARG_TEST_NAME}_COMPILE_FLAGS "${ARG_EXTRA_COMPILE_FLAGS}") - set_source_files_properties(${ARG_TEST_SOURCE} - PROPERTIES - COMPILE_FLAGS - ${LOCAL_${ARG_TEST_NAME}_COMPILE_FLAGS} - ) - endif() + # +--[ BODY ]------------------------------------------------------------+ + # TODO: we need to find a way to run this without googletest or unity. It they are orders of magnitude too complex + # to run on gtest or unity binaries (may take hours to run). + # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer>") + # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer-checker=taint>") - set(LOCAL_${ARG_TEST_NAME}_LINK_LIBS "") + add_executable(${ARG_TEST_NAME} ${ARG_TEST_SOURCE}) - if (${ARGC} GREATER 5) - MATH(EXPR ARG_N_LAST "${ARGC}-1") - foreach(ARG_N RANGE 5 ${ARG_N_LAST}) - list(APPEND LOCAL_${ARG_TEST_NAME}_LINK_LIBS ${ARGV${ARG_N}}) - endforeach(ARG_N) + if (ARG_DSDL_TARGETS) + add_dependencies(${ARG_TEST_NAME} ${ARG_DSDL_TARGETS}) + target_link_libraries(${ARG_TEST_NAME} PUBLIC ${ARG_DSDL_TARGETS}) endif() - target_link_libraries(${ARG_TEST_NAME} ${LOCAL_${ARG_TEST_NAME}_LINK_LIBS} "${ARG_EXTRA_COMPILE_FLAGS}") - if (${ARG_FRAMEWORK} STREQUAL "gtest") - target_link_libraries(${ARG_TEST_NAME} gmock_main) + target_link_libraries(${ARG_TEST_NAME} PUBLIC gmock_main) elseif (${ARG_FRAMEWORK} STREQUAL "unity") - target_link_libraries(${ARG_TEST_NAME} unity_core) + target_link_libraries(${ARG_TEST_NAME} PUBLIC unity_core) else() message(FATAL_ERROR "${ARG_FRAMEWORK} isn't a supported unit test framework. Currently we support gtest and unity.") endif() @@ -191,6 +59,26 @@ function(define_native_unit_test RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTDIR}" ) + target_link_options(${ARG_TEST_NAME} PUBLIC + "$<$:-Wl,-Map=${ARG_OUTDIR}/${ARG_TEST_NAME}.map,--cref>" + "$<$:-Wl,-Map,${ARG_OUTDIR}/${ARG_TEST_NAME}.map>" + ) + + add_custom_command(OUTPUT ${ARG_OUTDIR}/${ARG_TEST_NAME}-disassembly.S + DEPENDS ${ARG_TEST_NAME} + COMMAND ${CMAKE_OBJDUMP} -d ${ARG_OUTDIR}/${ARG_TEST_NAME} + --demangle + --disassemble-zeroes + --disassembler-options=reg-names-std + --syms + --special-syms + --all-headers + --wide > ${ARG_OUTDIR}/${ARG_TEST_NAME}-disassembly.S + COMMENT "Creating disassembly from ${ARG_TEST_NAME}" + ) + + add_custom_target(${ARG_TEST_NAME}-disassembly DEPENDS ${ARG_OUTDIR}/${ARG_TEST_NAME}-disassembly.S) + endfunction() @@ -202,7 +90,21 @@ endfunction() # with the name run_${ARG_TEST_NAME} # param: ARG_OUTDIR path - The path where the test binaries live. # -function(define_native_test_run ARG_TEST_NAME ARG_OUTDIR) +function(define_native_test_run) + # +--[ INPUTS ]-----------------------------------------------------------+ + set(options "") + set(monoValues TEST_NAME OUTDIR) + set(multiValues "") + + cmake_parse_arguments( + ARG + "${options}" + "${monoValues}" + "${multiValues}" + ${ARGN} + ) + + # +--[ BODY ]------------------------------------------------------------+ add_custom_target( run_${ARG_TEST_NAME} COMMAND From bb8ff57d02d700a150331eb2be269d7994d6dc5e Mon Sep 17 00:00:00 2001 From: Scott Dixon Date: Tue, 4 Jun 2024 11:43:17 -0700 Subject: [PATCH 6/8] Patch for issue #337 Applies workaround for GCC12 compiler bug --- src/nunavut/lang/c/support/serialization.j2 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nunavut/lang/c/support/serialization.j2 b/src/nunavut/lang/c/support/serialization.j2 index 769ce473..70d0e547 100644 --- a/src/nunavut/lang/c/support/serialization.j2 +++ b/src/nunavut/lang/c/support/serialization.j2 @@ -168,7 +168,10 @@ static inline void nunavutCopyBits(void* const dst, // offsets be under 8 bits. Fewer constraints reduce the chance of API misuse. const uint8_t* const psrc = (src_offset_bits / 8U) + (const uint8_t*) src; // NOSONAR NOLINT uint8_t* const pdst = (dst_offset_bits / 8U) + (uint8_t*) dst; // NOSONAR NOLINT - (void) memmove(pdst, psrc, length_bytes); + if (length_bytes > 0U) // issue #337 workaround + { + (void) memmove(pdst, psrc, length_bytes); + } const uint8_t length_mod = (uint8_t)(length_bits % 8U); if (0U != length_mod) // If the length is unaligned, the last byte requires special treatment. { From 118e86e993c7666d4c0c76e45e338a2f735a8365 Mon Sep 17 00:00:00 2001 From: Scott Dixon Date: Tue, 4 Jun 2024 13:37:13 -0700 Subject: [PATCH 7/8] Fix for issue #338 Fixing incorrect runtime asserts in generated C serialization code --- src/nunavut/lang/c/support/serialization.j2 | 4 +- verification/CMakeLists.txt | 54 ++++---- verification/c/suite/test_simple.c | 134 +++++++++++++++++++ verification/c/suite/test_support.c | 44 ++++-- verification/c/suite/test_support_assert.cpp | 48 +++++++ verification/cmake/modules/Findgenhtml.cmake | 4 +- verification/cmake/utils.cmake | 14 +- 7 files changed, 256 insertions(+), 46 deletions(-) create mode 100644 verification/c/suite/test_simple.c create mode 100644 verification/c/suite/test_support_assert.cpp diff --git a/src/nunavut/lang/c/support/serialization.j2 b/src/nunavut/lang/c/support/serialization.j2 index 70d0e547..dd84131b 100644 --- a/src/nunavut/lang/c/support/serialization.j2 +++ b/src/nunavut/lang/c/support/serialization.j2 @@ -194,10 +194,10 @@ static inline void nunavutCopyBits(void* const dst, {{ typename_unsigned_bit_length }} dst_off = dst_offset_bits; const {{ typename_unsigned_bit_length }} last_bit = src_off + length_bits; {{ assert( - '((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)pdst) : 1)' + '((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)pdst) : 1)' ) }} {{ assert( - '((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)psrc) : 1)' + '((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)psrc) : 1)' ) }} while (last_bit > src_off) { diff --git a/verification/CMakeLists.txt b/verification/CMakeLists.txt index 88f748cd..ee52f182 100644 --- a/verification/CMakeLists.txt +++ b/verification/CMakeLists.txt @@ -37,6 +37,20 @@ else() set(NUNAVUT_VERIFICATION_LANG "unspecified" CACHE STRING "The Nunavut output language to verify.") endif() +if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp") + set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp") + message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})") + message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") +elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c") + set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c") + message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})") + message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") +else() + message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]") +endif() + +string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG) + set(NUNAVUT_SUBMODULES_ROOT "${NUNAVUT_PROJECT_ROOT}/submodules" CACHE STRING "The path to git submodules for the project.") if(NOT DEFINED NUNAVUT_VERIFICATION_LANG_STANDARD) @@ -47,6 +61,12 @@ if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp" AND NOT NUNAVUT_VERIFICATION_LANG_S set(NUNAVUT_VERIFICATION_LANG_STANDARD "c++20") endif() +if (NUNAVUT_VERIFICATION_LANG STREQUAL "c" AND NOT NUNAVUT_VERIFICATION_LANG_STANDARD) + set(NUNAVUT_VERIFICATION_LANG_STANDARD "c11") +endif() + +message(STATUS "NUNAVUT_VERIFICATION_LANG_STANDARD is ${NUNAVUT_VERIFICATION_LANG_STANDARD}") + if(NOT DEFINED NUNAVUT_VERIFICATION_TARGET_ENDIANNESS) set(NUNAVUT_VERIFICATION_TARGET_ENDIANNESS "any" CACHE STRING "The endianess for the target verification architecture.") endif() @@ -63,20 +83,6 @@ if(NOT DEFINED NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE) set(NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE OFF CACHE BOOL "Enable or disable override variable array capacity in generated support code.") endif() -if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp") - set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp") - message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})") - message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") -elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c") - set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c") - message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})") - message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}") -else() - message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]") -endif() - -string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG) - if(DEFINED ENV{NUNAVUT_FLAGSET}) set(NUNAVUT_FLAGSET "$ENV{NUNAVUT_FLAGSET}") message(STATUS "Using ${NUNAVUT_FLAGSET} from environment for NUNAVUT_FLAGSET") @@ -380,7 +386,7 @@ function(runTestCpp) target_include_directories(${NATIVE_TEST_NAME} PUBLIC "${NUNAVUT_PROJECT_ROOT}/submodules/CETL/include") define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) - define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov") list(APPEND ALL_TEST_COVERAGE "--add-tracefile") @@ -402,13 +408,13 @@ endif() function(runTestC) set(options "") - set(oneValueArgs TEST_FILE) + set(oneValueArgs TEST_FILE FRAMEWORK) set(multiValueArgs LINK LANGUAGE_FLAVORS) cmake_parse_arguments(runTestC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Skip tests not relevant to the specified language standard list(FIND runTestC_LANGUAGE_FLAVORS "${NUNAVUT_VERIFICATION_LANG_STANDARD}" FIND_INDEX) - if (${FIND_INDEX} GREATER -1) + if (${FIND_INDEX} EQUAL -1) message(STATUS "Skipping ${runTestC_TEST_FILE}") return() endif() @@ -416,7 +422,7 @@ function(runTestC) set(NATIVE_TEST "${NUNAVUT_VERIFICATION_ROOT}/suite/${runTestC_TEST_FILE}") get_filename_component(NATIVE_TEST_NAME ${NATIVE_TEST} NAME_WE) - define_native_unit_test(FRAMEWORK "unity" + define_native_unit_test(FRAMEWORK ${runTestC_FRAMEWORK} TEST_NAME ${NATIVE_TEST_NAME} TEST_SOURCE ${NATIVE_TEST} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR} @@ -425,7 +431,7 @@ function(runTestC) ) define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*) - define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) + define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR}) list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}") list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov") list(APPEND ALL_TEST_COVERAGE "--add-tracefile") @@ -437,10 +443,12 @@ endfunction() if (NUNAVUT_VERIFICATION_LANG STREQUAL "c") runTestCpp(TEST_FILE test_canard.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) - runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) + runTestCpp(TEST_FILE test_support_assert.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11) + runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity") + runTestC( TEST_FILE test_simple.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "none") endif() # +---------------------------------------------------------------------------+ diff --git a/verification/c/suite/test_simple.c b/verification/c/suite/test_simple.c new file mode 100644 index 00000000..233e8051 --- /dev/null +++ b/verification/c/suite/test_simple.c @@ -0,0 +1,134 @@ +// Copyright (c) 2020 OpenCyphal Development Team. +// This software is distributed under the terms of the MIT License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_ASSERT_EQUAL(A, B) do {\ + if ((A) != (B)) { \ + abort(); \ + } \ +} while(0) + +#define TEST_ASSERT_TRUE(A) TEST_ASSERT_EQUAL(A, true) + +/// A test to run with no test framework linked in. This allows some sanity checking but mostly is useful to support +/// analysis or instrumentation of the code while debugging. +static void testStructDelimited(void) +{ + regulated_delimited_A_1_0 obj; + regulated_delimited_A_1_0_initialize_(&obj); + regulated_delimited_A_1_0_select_del_(&obj); + regulated_delimited_A_1_0_select_del_(NULL); // No action. + obj.del.var.count = 2; + obj.del.var.elements[0].a.count = 2; + obj.del.var.elements[0].a.elements[0] = 1; + obj.del.var.elements[0].a.elements[1] = 2; + obj.del.var.elements[0].b = 0; + obj.del.var.elements[1].a.count = 1; + obj.del.var.elements[1].a.elements[0] = 3; + obj.del.var.elements[1].a.elements[1] = 123; // ignored + obj.del.var.elements[1].b = 4; + obj.del.fix.count = 1; + obj.del.fix.elements[0].a[0] = 5; + obj.del.fix.elements[0].a[1] = 6; + + const uint8_t reference[] = { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + 0x01U, 0x17U, 0x00U, 0x00U, 0x00U, 0x02U, 0x04U, 0x00U, 0x00U, 0x00U, 0x02U, 0x01U, 0x02U, 0x00U, 0x03U, 0x00U, + 0x00U, 0x00U, 0x01U, 0x03U, 0x04U, 0x01U, 0x02U, 0x00U, 0x00U, 0x00U, 0x05U, 0x06U, + // END OF SERIALIZED REPRESENTATION + 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, + 0xAAU, + }; + static_assert(sizeof(reference) == regulated_delimited_A_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_, ""); + + uint8_t buf[1024] = {0}; + (void) memset(&buf[0], 0xAAU, sizeof(buf)); // Fill out the canaries + size_t size = sizeof(buf); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_serialize_(&obj, &buf[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + + // Deserialize back from the reference using the same type and compare the field values. + regulated_delimited_A_1_0_initialize_(&obj); // Erase prior state. + size = sizeof(reference); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &reference[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj)); + TEST_ASSERT_EQUAL(2, obj.del.var.count); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(1, obj.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.elements[1]); + TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b); + TEST_ASSERT_EQUAL(1, obj.del.var.elements[1].a.count); + TEST_ASSERT_EQUAL(3, obj.del.var.elements[1].a.elements[0]); + TEST_ASSERT_EQUAL(4, obj.del.var.elements[1].b); + TEST_ASSERT_EQUAL(1, obj.del.fix.count); + TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]); + TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]); + + // Deserialize using a different type to test extensibility enabled by delimited serialization. + regulated_delimited_A_1_1 dif; + size = sizeof(reference); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_deserialize_(&dif, &reference[0], &size)); + TEST_ASSERT_EQUAL(28U, size); + TEST_ASSERT_TRUE(regulated_delimited_A_1_1_is_del_(&dif)); + TEST_ASSERT_EQUAL(2, dif.del.var.count); + TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(1, dif.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.elements[1]); + // b implicitly truncated away + TEST_ASSERT_EQUAL(1, dif.del.var.elements[1].a.count); + TEST_ASSERT_EQUAL(3, dif.del.var.elements[1].a.elements[0]); + // b implicitly truncated away + TEST_ASSERT_EQUAL(1, dif.del.fix.count); + TEST_ASSERT_EQUAL(5, dif.del.fix.elements[0].a[0]); + TEST_ASSERT_EQUAL(6, dif.del.fix.elements[0].a[1]); + TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].a[2]); // 3rd element is implicitly zero-extended + TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].b); // b is implicitly zero-extended + + // Reverse version switch -- serialize v1.1 and then deserialize back using v1.0. + dif.del.var.count = 1; + dif.del.var.elements[0].a.count = 2; + dif.del.var.elements[0].a.elements[0] = 11; + dif.del.var.elements[0].a.elements[1] = 22; + dif.del.fix.count = 2; + dif.del.fix.elements[0].a[0] = 5; + dif.del.fix.elements[0].a[1] = 6; + dif.del.fix.elements[0].a[2] = 7; + dif.del.fix.elements[0].b = 8; + dif.del.fix.elements[1].a[0] = 100; + dif.del.fix.elements[1].a[1] = 200; + dif.del.fix.elements[1].a[2] = 123; + dif.del.fix.elements[1].b = 99; + size = sizeof(buf); + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_serialize_(&dif, &buf[0], &size)); + TEST_ASSERT_EQUAL(30U, size); // the reference size was computed by hand + TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &buf[0], &size)); + TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj)); + TEST_ASSERT_EQUAL(1, obj.del.var.count); + TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count); + TEST_ASSERT_EQUAL(11, obj.del.var.elements[0].a.elements[0]); + TEST_ASSERT_EQUAL(22, obj.del.var.elements[0].a.elements[1]); + TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b); // b is implicitly zero-extended + TEST_ASSERT_EQUAL(2, obj.del.fix.count); + TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]); // 3rd is implicitly truncated, b is implicitly truncated + TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]); + TEST_ASSERT_EQUAL(100, obj.del.fix.elements[1].a[0]); // 3rd is implicitly truncated, b is implicitly truncated + TEST_ASSERT_EQUAL(200, obj.del.fix.elements[1].a[1]); +} + +int main(void) +{ + testStructDelimited(); + return 0; +} diff --git a/verification/c/suite/test_support.c b/verification/c/suite/test_support.c index feaf76bc..710b251c 100644 --- a/verification/c/suite/test_support.c +++ b/verification/c/suite/test_support.c @@ -21,6 +21,30 @@ static void testNunavutCopyBits(void) } } +static void testNunavutCopyAdjacentBitsForward(void) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[0], 0xFF, sizeof(uintptr_t)); + memset(&data[1], 0x00, sizeof(uintptr_t)); + nunavutCopyBits(&data[1], word_size_bits - 1, 1, &data[0], 1); + TEST_ASSERT_EQUAL(expected, data[1]); +} + +static void testNunavutCopyAdjacentBitsBackward(void) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[1], 0xFF, sizeof(uintptr_t)); + memset(&data[0], 0x00, sizeof(uintptr_t)); + nunavutCopyBits(&data[0], word_size_bits - 1, 1, &data[1], 1); + TEST_ASSERT_EQUAL(expected, data[0]); +} + static void testNunavutCopyBitsWithAlignedOffset(void) { const uint8_t src[] = { 1, 2, 3, 4, 5 }; @@ -502,7 +526,7 @@ static void helperPackUnpack(float source_value, uint16_t compare_mask, size_t i for(size_t i = 0; i < iterations; ++i) { repacked = nunavutFloat16Pack(nunavutFloat16Unpack(repacked)); - snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", source_value, compare_mask, i); + snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", (double)source_value, compare_mask, i); TEST_ASSERT_EQUAL_HEX16_MESSAGE(packed & compare_mask, repacked & compare_mask, message_buffer); } } @@ -727,20 +751,20 @@ static void testNunavutSetF64(void) helperAssertSerFloat64SameAsIEEE(-3.141592653589793, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, -NAN); - helperAssertSerFloat64SameAsIEEE(-NAN, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, -(double)NAN); + helperAssertSerFloat64SameAsIEEE(-(double)NAN, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, NAN); - helperAssertSerFloat64SameAsIEEE(NAN, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, (double)NAN); + helperAssertSerFloat64SameAsIEEE((double)NAN, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, INFINITY); - helperAssertSerFloat64SameAsIEEE(INFINITY, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, (double)INFINITY); + helperAssertSerFloat64SameAsIEEE((double)INFINITY, buffer); memset(buffer, 0, sizeof(buffer)); - nunavutSetF64(buffer, sizeof(buffer), 0, -INFINITY); - helperAssertSerFloat64SameAsIEEE(-INFINITY, buffer); + nunavutSetF64(buffer, sizeof(buffer), 0, -(double)INFINITY); + helperAssertSerFloat64SameAsIEEE(-(double)INFINITY, buffer); } // +--------------------------------------------------------------------------+ @@ -762,6 +786,8 @@ int main(void) UNITY_BEGIN(); RUN_TEST(testNunavutCopyBits); + RUN_TEST(testNunavutCopyAdjacentBitsForward); + RUN_TEST(testNunavutCopyAdjacentBitsBackward); RUN_TEST(testNunavutCopyBitsWithAlignedOffset); RUN_TEST(testNunavutCopyBitsWithUnalignedOffset); RUN_TEST(testNunavutSaturateBufferFragmentBitLength); diff --git a/verification/c/suite/test_support_assert.cpp b/verification/c/suite/test_support_assert.cpp new file mode 100644 index 00000000..a78002e1 --- /dev/null +++ b/verification/c/suite/test_support_assert.cpp @@ -0,0 +1,48 @@ +/// @file +/// Googletest death tests for serialization.h +/// +/// @copyright +/// Copyright (C) OpenCyphal Development Team +/// Copyright Amazon.com Inc. or its affiliates. +/// SPDX-License-Identifier: MIT +/// + +#include "gtest/gtest.h" +#include "gmock/gmock.h" +#include "nunavut/support/serialization.h" + +// +----------------------------------------------------------------------+ +// | ☠️ DEATH TESTS ☠️ +// +----------------------------------------------------------------------+ +#ifndef NDEBUG + +// covers https://github.com/OpenCyphal/nunavut/issues/338 +TEST(NunavutSupportCopyBitsDeathTest, nunavutCopyBits) +{ + uintptr_t data[2]; + uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul)); + const size_t word_size_bytes = sizeof(uintptr_t); + const size_t word_size_bits = word_size_bytes * 8u; + memset(&data[1], 0xFF, sizeof(uintptr_t)); + memset(&data[0], 0x00, sizeof(uintptr_t)); + + for(size_t i = 0; i < word_size_bits; ++i) { + nunavutCopyBits(&data[0], i, 1, &data[1], 1); + } + + ASSERT_DEATH( + nunavutCopyBits(&data[0], word_size_bits, 1, &data[1], 1), + "(psrc > pdst)" + ); + + for(size_t i = 0; i < word_size_bits; ++i) { + nunavutCopyBits(&data[1], 1, i, &data[0], 1); + } + + ASSERT_DEATH( + nunavutCopyBits(&data[1], 1, word_size_bits, &data[0], 1), + "(psrc < pdst)" + ); +} + +#endif diff --git a/verification/cmake/modules/Findgenhtml.cmake b/verification/cmake/modules/Findgenhtml.cmake index 0f6cda6c..84df68b8 100644 --- a/verification/cmake/modules/Findgenhtml.cmake +++ b/verification/cmake/modules/Findgenhtml.cmake @@ -7,14 +7,14 @@ find_program(GENHTML genhtml) if(GENHTML) # - # function: define_natve_test_coverage - creates makefile targets to generate coverage + # function: define_native_test_coverage - creates makefile targets to generate coverage # data for an individual test. # # param: ARG_TEST_NAME string - The name of the test to generate coverage data for. # param: ARG_OUTDIR path - The path where the test binaries live and where the coverage # data will be stored. # - function(define_natve_test_coverage ARG_TEST_NAME ARG_OUTDIR) + function(define_native_test_coverage ARG_TEST_NAME ARG_OUTDIR) add_custom_target( cov_${ARG_TEST_NAME} diff --git a/verification/cmake/utils.cmake b/verification/cmake/utils.cmake index 689f39ff..aa40d7b7 100644 --- a/verification/cmake/utils.cmake +++ b/verification/cmake/utils.cmake @@ -34,11 +34,6 @@ function(define_native_unit_test) ) # +--[ BODY ]------------------------------------------------------------+ - # TODO: we need to find a way to run this without googletest or unity. It they are orders of magnitude too complex - # to run on gtest or unity binaries (may take hours to run). - # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer>") - # target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer-checker=taint>") - add_executable(${ARG_TEST_NAME} ${ARG_TEST_SOURCE}) if (ARG_DSDL_TARGETS) @@ -50,6 +45,10 @@ function(define_native_unit_test) target_link_libraries(${ARG_TEST_NAME} PUBLIC gmock_main) elseif (${ARG_FRAMEWORK} STREQUAL "unity") target_link_libraries(${ARG_TEST_NAME} PUBLIC unity_core) + elseif (${ARG_FRAMEWORK} STREQUAL "none") + message(STATUS "${ARG_TEST_NAME}: No test framework") + target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer>") + target_compile_options(${ARG_TEST_NAME} PRIVATE "$<$:-fanalyzer-checker=taint>") else() message(FATAL_ERROR "${ARG_FRAMEWORK} isn't a supported unit test framework. Currently we support gtest and unity.") endif() @@ -59,11 +58,6 @@ function(define_native_unit_test) RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTDIR}" ) - target_link_options(${ARG_TEST_NAME} PUBLIC - "$<$:-Wl,-Map=${ARG_OUTDIR}/${ARG_TEST_NAME}.map,--cref>" - "$<$:-Wl,-Map,${ARG_OUTDIR}/${ARG_TEST_NAME}.map>" - ) - add_custom_command(OUTPUT ${ARG_OUTDIR}/${ARG_TEST_NAME}-disassembly.S DEPENDS ${ARG_TEST_NAME} COMMAND ${CMAKE_OBJDUMP} -d ${ARG_OUTDIR}/${ARG_TEST_NAME} From f3333f6dca73e1b9c5a034ca80bbbbe3f0882e58 Mon Sep 17 00:00:00 2001 From: Scott Dixon Date: Fri, 7 Jun 2024 16:30:52 -0700 Subject: [PATCH 8/8] Fix for issue #339 Disabling a GCC warning that appears broken in GCC12 --- verification/cmake/compiler_flag_sets/common.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/verification/cmake/compiler_flag_sets/common.cmake b/verification/cmake/compiler_flag_sets/common.cmake index 49b5c582..55d83b3f 100644 --- a/verification/cmake/compiler_flag_sets/common.cmake +++ b/verification/cmake/compiler_flag_sets/common.cmake @@ -93,6 +93,7 @@ list(APPEND ASM_FLAG_SET ${C_FLAG_SET}) add_compile_options("$<$:${C_FLAG_SET}>") add_compile_options("$<$:${CXX_FLAG_SET}>") add_compile_options("$<$:${ASM_FLAG_SET}>") +add_compile_options("$<$:-Wno-stringop-overflow>") add_link_options(${EXE_LINKER_FLAG_SET}) add_definitions(${DEFINITIONS_SET}) set(CMAKE_C_EXTENSIONS OFF)