├── .clang-format ├── .clang-tidy ├── .devcontainer └── devcontainer.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── assets ├── docker-sharing.png ├── gcovr-report.png ├── github-action.png ├── vscode-container.png ├── vscode-rebuild.png ├── vscode-reload.png └── vscode-remote.png ├── builder.Dockerfile ├── clang-format.json ├── clang-tidy.json ├── include └── dummy │ └── dummy.h ├── makefile ├── readme.md ├── src └── dummy.c └── tests └── unittest ├── generated └── .gitkeep ├── project.yml ├── support └── unity_config.h └── test └── test_dummy.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 5 | # compare against `clang-format --style=webkit -dump-config > .clang-format` 6 | AccessModifierOffset: -4 7 | AlignAfterOpenBracket: AlwaysBreak 8 | AlignConsecutiveAssignments: Consecutive 9 | AlignConsecutiveBitFields: Consecutive 10 | AlignConsecutiveDeclarations: false 11 | AlignConsecutiveMacros: Consecutive 12 | AlignEscapedNewlines: Left 13 | AlignOperands: DontAlign 14 | AlignTrailingComments: true 15 | AllowAllArgumentsOnNextLine: true 16 | AllowAllParametersOfDeclarationOnNextLine: true 17 | AllowShortBlocksOnASingleLine: false 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortEnumsOnASingleLine: false 20 | AllowShortFunctionsOnASingleLine: None 21 | AllowShortIfStatementsOnASingleLine: false 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: MultiLine 27 | BinPackArguments: false 28 | BitFieldColonSpacing: Both 29 | BinPackParameters: false 30 | BraceWrapping: 31 | AfterClass: true 32 | AfterControlStatement: true 33 | AfterEnum: true 34 | AfterFunction: true 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: true 38 | AfterUnion: true 39 | BeforeCatch: true 40 | BeforeElse: true 41 | IndentBraces: false 42 | SplitEmptyFunction: true 43 | SplitEmptyRecord: true 44 | SplitEmptyNamespace: true 45 | AfterExternBlock: false 46 | BreakBeforeBinaryOperators: None 47 | BreakBeforeBraces: Custom 48 | BreakBeforeInheritanceComma: false 49 | BreakInheritanceList: BeforeComma 50 | BreakBeforeTernaryOperators: true 51 | BreakConstructorInitializersBeforeComma: true 52 | BreakConstructorInitializers: BeforeComma 53 | BreakAfterJavaFieldAnnotations: false 54 | BreakStringLiterals: true 55 | ColumnLimit: 120 56 | CommentPragmas: '^ IWYU pragma:' 57 | CompactNamespaces: false 58 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 59 | ConstructorInitializerIndentWidth: 4 60 | ContinuationIndentWidth: 4 61 | Cpp11BracedListStyle: true 62 | DerivePointerAlignment: false 63 | DisableFormat: false 64 | ExperimentalAutoDetectBinPacking: false 65 | FixNamespaceComments: false 66 | ForEachMacros: 67 | - foreach 68 | - Q_FOREACH 69 | - BOOST_FOREACH 70 | IncludeBlocks: Preserve 71 | IncludeCategories: 72 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 73 | Priority: 2 74 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 75 | Priority: 3 76 | - Regex: '.*' 77 | Priority: 1 78 | IncludeIsMainRegex: '(Test)?$' 79 | IndentCaseLabels: true 80 | IndentExternBlock: false 81 | IndentWidth: 4 82 | IndentWrappedFunctionNames: false 83 | JavaScriptQuotes: Leave 84 | JavaScriptWrapImports: true 85 | KeepEmptyLinesAtTheStartOfBlocks: false 86 | MacroBlockBegin: '' 87 | MacroBlockEnd: '' 88 | MaxEmptyLinesToKeep: 1 89 | NamespaceIndentation: All 90 | ObjCBinPackProtocolList: Auto 91 | ObjCBlockIndentWidth: 2 92 | ObjCSpaceAfterProperty: false 93 | ObjCSpaceBeforeProtocolList: true 94 | PenaltyBreakAssignment: 350 95 | PenaltyBreakBeforeFirstCallParameter: 20 96 | PenaltyBreakComment: 300 # 100 97 | PenaltyBreakFirstLessLess: 120 98 | PenaltyBreakString: 1000 99 | PenaltyBreakTemplateDeclaration: 10 100 | PenaltyExcessCharacter: 1000000 101 | PenaltyReturnTypeOnItsOwnLine: 2000000 102 | PointerAlignment: Right 103 | ReferenceAlignment: Right 104 | ReflowComments: true 105 | SortIncludes: true 106 | SortUsingDeclarations: true 107 | SpaceAfterCStyleCast: true 108 | SpaceAfterTemplateKeyword: true 109 | SpaceBeforeAssignmentOperators: true 110 | SpaceBeforeCpp11BracedList: true 111 | SpaceBeforeCtorInitializerColon: true 112 | SpaceBeforeInheritanceColon: true 113 | SpaceBeforeParens: ControlStatements 114 | SpaceBeforeRangeBasedForLoopColon: true 115 | SpaceInEmptyParentheses: false 116 | SpacesBeforeTrailingComments: 1 117 | SpacesInAngles: false 118 | SpacesInContainerLiterals: false 119 | SpacesInCStyleCastParentheses: false 120 | SpacesInParentheses: false 121 | SpacesInSquareBrackets: false 122 | SpaceBeforeSquareBrackets: false 123 | SpaceBeforeCaseColon: false 124 | SpaceInEmptyBlock: false 125 | SpacesInConditionalStatement: false 126 | Standard: Cpp11 127 | StatementMacros: 128 | - Q_UNUSED 129 | - QT_REQUIRE_VERSION 130 | # using a big tab-width so abuse is shown immediately 131 | TabWidth: 8 132 | UseTab: Never 133 | DeriveLineEnding: false 134 | UseCRLF: false 135 | ... 136 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | Checks: ' 3 | -*, 4 | clang-*, 5 | bugprone-assert-side-effect, 6 | bugprone-bool-pointer-implicit-conversion, 7 | bugprone-incorrect-roundings, 8 | bugprone-integer-division, 9 | bugprone-macro-parentheses, 10 | bugprone-macro-repeated-side-effects, 11 | bugprone-misplaced-widening-cast, 12 | bugprone-multiple-statement-macro, 13 | bugprone-sizeof-expression, 14 | bugprone-suspicious-enum-usage, 15 | bugprone-suspicious-missing-comma, 16 | bugprone-suspicious-semicolon, 17 | bugprone-terminating-continue, 18 | bugprone-too-small-loop-variable, 19 | cppcoreguidelines-avoid-goto, 20 | misc-definitions-in-headers, 21 | misc-misplaced-const, 22 | misc-redundant-expression, 23 | misc-unused-parameters, 24 | readability-braces-around-statements, 25 | readability-const-return-type, 26 | readability-else-after-return, 27 | readability-function-size, 28 | readability-implicit-bool-conversion, 29 | readability-inconsistent-declaration-parameter-name, 30 | readability-isolate-declaration, 31 | readability-magic-numbers, 32 | readability-misplaced-array-index, 33 | readability-named-parameter, 34 | readability-non-const-parameter, 35 | readability-redundant-control-flow, 36 | readability-redundant-declaration, 37 | readability-redundant-preprocessor, 38 | readability-uppercase-literal-suffix, 39 | readability-identifier-naming, 40 | ' 41 | WarningsAsErrors: ' 42 | bugprone-assert-side-effect, 43 | bugprone-bool-pointer-implicit-conversion, 44 | bugprone-incorrect-roundings, 45 | bugprone-integer-division, 46 | bugprone-macro-parentheses, 47 | bugprone-macro-repeated-side-effects, 48 | bugprone-misplaced-widening-cast, 49 | bugprone-multiple-statement-macro, 50 | bugprone-sizeof-expression, 51 | bugprone-suspicious-enum-usage, 52 | bugprone-suspicious-missing-comma, 53 | bugprone-suspicious-semicolon, 54 | bugprone-terminating-continue, 55 | bugprone-too-small-loop-variable, 56 | cppcoreguidelines-avoid-goto, 57 | misc-definitions-in-headers, 58 | misc-misplaced-const, 59 | misc-redundant-expression, 60 | misc-unused-parameters, 61 | readability-braces-around-statements, 62 | readability-const-return-type, 63 | readability-else-after-return, 64 | readability-function-size, 65 | readability-implicit-bool-conversion, 66 | readability-inconsistent-declaration-parameter-name, 67 | readability-isolate-declaration, 68 | readability-magic-numbers, 69 | readability-misplaced-array-index, 70 | readability-named-parameter, 71 | readability-non-const-parameter, 72 | readability-redundant-control-flow, 73 | readability-redundant-declaration, 74 | readability-redundant-preprocessor, 75 | readability-uppercase-literal-suffix, 76 | # readability-identifier-naming, 77 | ' 78 | 79 | # From the docs: "Output warnings from headers matching this filter" 80 | # But the goal should be to exclude(!) the headers for which clang-tidy is not called, 81 | # e.g., for naming convention checks. DO NOT USE this field if you don't want to analyze 82 | # header files just because they're included (seems to work). 83 | # HeaderFilterRegex: '$' 84 | # https://github.com/Kitware/CMake/blob/master/.clang-tidy 85 | HeaderFilterRegex: '.*\.(h|hxx|cxx)$' 86 | AnalyzeTemporaryDtors: false 87 | FormatStyle: none 88 | User: martin 89 | CheckOptions: 90 | - { key: bugprone-assert-side-effect.AssertMacros, value: assert } 91 | - { key: bugprone-assert-side-effect.CheckFunctionCalls, value: '0' } 92 | - { key: bugprone-misplaced-widening-cast.CheckImplicitCasts, value: '1' } 93 | - { key: bugprone-sizeof-expression.WarnOnSizeOfConstant, value: '1' } 94 | - { key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression, value: '1' } 95 | - { key: bugprone-sizeof-expression.WarnOnSizeOfThis, value: '1' } 96 | - { key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant, value: '1' } 97 | - { key: bugprone-suspicious-enum-usage.StrictMode, value: '0' } 98 | - { key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens, value: '5' } 99 | - { key: bugprone-suspicious-missing-comma.RatioThreshold, value: '0.200000' } 100 | - { key: bugprone-suspicious-missing-comma.SizeThreshold, value: '5' } 101 | - { key: misc-definitions-in-headers.HeaderFileExtensions, value: ',h,hh,hpp,hxx' } 102 | - { key: misc-definitions-in-headers.UseHeaderFileExtension, value: '1' } 103 | - { key: readability-braces-around-statements.ShortStatementLines, value: '1' } 104 | - { key: readability-function-size.LineThreshold, value: '500' } 105 | - { key: readability-function-size.StatementThreshold, value: '800' } 106 | - { key: readability-function-size.ParameterThreshold, value: '10' } 107 | - { key: readability-function-size.NestingThreshold, value: '6' } 108 | - { key: readability-function-size.VariableThreshold, value: '15' } 109 | - { key: readability-implicit-bool-conversion.AllowIntegerConditions, value: '0' } 110 | - { key: readability-implicit-bool-conversion.AllowPointerConditions, value: '0' } 111 | - { key: readability-implicit-bool-conversion.AllowPointerConditions, value: '0' } 112 | - { key: readability-inconsistent-declaration-parameter-name.IgnoreMacros, value: '1' } 113 | - { key: readability-inconsistent-declaration-parameter-name.Strict, value: '1' } 114 | - { key: readability-magic-numbers.IgnoredFloatingPointValues, value: '1.0;100.0;' } 115 | - { key: readability-magic-numbers.IgnoredIntegerValues, value: '1;2;3;4;' } 116 | - { key: readability-magic-numbers.IgnorePowersOf2IntegerValues, value: '0' } 117 | - { key: readability-magic-numbers.IgnoreAllFloatingPointValues, value: '0' } 118 | - { key: readability-redundant-declaration.IgnoreMacros, value: '1' } 119 | - { key: readability-redundant-function-ptr-dereference, value: '1' } 120 | - { key: readability-uppercase-literal-suffix.IgnoreMacros, value: '0' } 121 | - { key: readability-uppercase-literal-suffix.IgnoreMacros, value: '0' } 122 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.159.0/containers/cpp 3 | { 4 | "name": "C", 5 | "build": { 6 | "dockerfile": "../builder.Dockerfile" 7 | }, 8 | "runArgs": ["--platform=linux/amd64"], 9 | "customizations": { 10 | "vscode": { 11 | "settings": { 12 | "terminal.integrated.defaultProfile.linux": "bash", 13 | // Faster install of extensions - and currently seems to be problematic on macos 14 | // https://github.com/microsoft/vscode-remote-release/issues/8169 15 | "extensions.verifySignature": false 16 | }, 17 | "extensions": ["ms-vscode.cpptools", "ms-vscode.cmake-tools", "cschlosser.doxdocgen"] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | 2 | name: ci 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | schedule: 9 | - cron: '0 1 * * 0' 10 | 11 | concurrency: 12 | group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} 13 | cancel-in-progress: true 14 | 15 | # https://docs.docker.com/build/ci/github-actions/share-image-jobs/ 16 | # just using caches instead of artifact upload. 17 | jobs: 18 | docker-build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: docker/setup-buildx-action@v3 23 | - 24 | name: Create docker cache folder 25 | run: mkdir -p /tmp/docker 26 | - 27 | name: Restore docker image 28 | id: cache-docker 29 | uses: actions/cache@v4 30 | with: 31 | path: /tmp/docker 32 | key: ${{ runner.os }}-docker-${{ hashFiles('builder.Dockerfile') }} 33 | - 34 | name: Build docker builder-image 35 | if: steps.cache-docker.outputs.cache-hit != 'true' 36 | uses: docker/build-push-action@v5 37 | with: 38 | context: . 39 | file: builder.Dockerfile 40 | tags: cproject-builder:latest 41 | outputs: type=docker,dest=/tmp/docker/${{ runner.os }}-builder-image.tar 42 | 43 | build-and-test: 44 | runs-on: ubuntu-latest 45 | needs: docker-build 46 | steps: 47 | - uses: actions/checkout@v4 48 | - uses: docker/setup-buildx-action@v3 49 | - 50 | name: Restore docker image 51 | id: cache-docker 52 | uses: actions/cache@v4 53 | with: 54 | path: /tmp/docker 55 | key: ${{ runner.os }}-docker-${{ hashFiles('builder.Dockerfile') }} 56 | - 57 | name: Load image 58 | run: | 59 | docker load --input /tmp/docker/${{ runner.os }}-builder-image.tar 60 | docker image ls -a 61 | - 62 | name: Build library 63 | run: | 64 | docker run \ 65 | --rm \ 66 | --platform linux/amd64 \ 67 | --workdir /builder/mnt \ 68 | -v ${{ github.workspace }}:/builder/mnt \ 69 | cproject-builder:latest \ 70 | /bin/bash -c "rm -rf build; cmake -B build; cmake --build build" 71 | - 72 | name: Test library 73 | run: | 74 | docker run \ 75 | --rm \ 76 | --platform linux/amd64 \ 77 | --workdir /builder/mnt/tests/unittest \ 78 | -v ${{ github.workspace }}:/builder/mnt \ 79 | cproject-builder:latest \ 80 | /bin/bash -c "ceedling clobber; ceedling gcov:all; ceedling utils:gcov" 81 | - 82 | name: Archive coverage results 83 | shell: bash 84 | run: | 85 | staging="reports-${{github.run_number}}" 86 | mkdir -p "$staging" 87 | cp -r tests/unittest/build/artifacts/gcov "$staging" 88 | tar czf "$staging.tar.gz" "$staging" 89 | echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV 90 | - 91 | name: Archive artifacts 92 | uses: actions/upload-artifact@v4 93 | with: 94 | name: reports-${{github.run_number}} 95 | path: ${{ env.ASSET }} 96 | retention-days: 3 97 | 98 | # TODO: delete cache on merge. 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | thumbs.db 4 | *.zip 5 | *.pyc 6 | *_pb2.py 7 | *.bak 8 | *.hex 9 | *.[oa] 10 | *.pb.go 11 | .vscode/ipch/** 12 | !.gitkeep 13 | 14 | _build 15 | build 16 | 17 | artifacts 18 | doc/** 19 | .unison* 20 | node_modules 21 | go.sum 22 | **/_build 23 | **/parking 24 | 25 | test/**/build/ 26 | # tests/unittest/generated 27 | 28 | compile_commands.json 29 | # FIXME: remove this in case you want this to be available for everyone. 30 | .vscode/c_cpp_properties.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[c]": { 3 | "editor.formatOnSave": true 4 | }, 5 | "[cpp]": { 6 | "editor.formatOnSave": true 7 | }, 8 | "C_Cpp.default.compileCommands": "${workspaceFolder}/src/build/compile_commands.json", 9 | "cmake.configureOnOpen": true, 10 | "extensions.ignoreRecommendations": true 11 | } 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 3 | 4 | project( 5 | Dummy 6 | VERSION 0.1 7 | DESCRIPTION "Dummy - A dummy library" 8 | LANGUAGES C 9 | ) 10 | 11 | set_property( 12 | TARGET ${PROJECT} 13 | PROPERTY C_STANDARD 11 14 | ) 15 | 16 | add_library( 17 | ${PROJECT_NAME} 18 | src/dummy.c 19 | ) 20 | 21 | target_include_directories( 22 | ${PROJECT_NAME} 23 | PUBLIC 24 | include 25 | ) 26 | -------------------------------------------------------------------------------- /assets/docker-sharing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/docker-sharing.png -------------------------------------------------------------------------------- /assets/gcovr-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/gcovr-report.png -------------------------------------------------------------------------------- /assets/github-action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/github-action.png -------------------------------------------------------------------------------- /assets/vscode-container.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/vscode-container.png -------------------------------------------------------------------------------- /assets/vscode-rebuild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/vscode-rebuild.png -------------------------------------------------------------------------------- /assets/vscode-reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/vscode-reload.png -------------------------------------------------------------------------------- /assets/vscode-remote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/assets/vscode-remote.png -------------------------------------------------------------------------------- /builder.Dockerfile: -------------------------------------------------------------------------------- 1 | # update the base_tag to the version of the base image 2 | # e.g., "bullseye" is currently (2024-02) still the latest version for vscode devcontainers: 3 | # https://hub.docker.com/_/microsoft-vscode-devcontainers 4 | 5 | ARG base_tag=bullseye 6 | ARG base_img=mcr.microsoft.com/vscode/devcontainers/base:dev-${base_tag} 7 | # ARG base_img=debian:${base_tag} 8 | 9 | FROM --platform=linux/amd64 ${base_img} AS builder-install 10 | 11 | # the following shows how to install the latest version of a package. 12 | # you can determine the installed version with `apt-cache policy ` and fix 13 | # the version to install with = in the list below. 14 | 15 | # notice that ruby is being installed for ceedling and would otherwise most likely not be needed 16 | # https://www.throwtheswitch.org/ceedling 17 | 18 | RUN apt-get update --fix-missing && apt-get -y upgrade 19 | RUN apt-get install -y --no-install-recommends \ 20 | apt-utils \ 21 | curl \ 22 | cmake \ 23 | build-essential \ 24 | gcc \ 25 | g++-multilib \ 26 | locales \ 27 | make \ 28 | ruby \ 29 | gcovr \ 30 | wget \ 31 | && rm -rf /var/lib/apt/lists/* 32 | 33 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' 34 | 35 | RUN echo 'en_US.UTF-8 UTF-8' > /etc/locale.gen && /usr/sbin/locale-gen 36 | RUN echo "alias ll='ls -laGFh'" >> /root/.bashrc 37 | 38 | VOLUME ["/builder/mnt"] 39 | WORKDIR /builder/mnt 40 | 41 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 42 | # install clang tools 43 | 44 | ARG base_tag=bullseye 45 | ARG llvm_version=16 46 | RUN apt-get update --fix-missing && apt-get -y upgrade 47 | RUN apt-get install -y --no-install-recommends \ 48 | gnupg2 \ 49 | gnupg-agent \ 50 | ca-certificates \ 51 | && rm -rf /var/lib/apt/lists/* 52 | 53 | RUN curl --fail --silent --show-error --location https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - 54 | RUN echo "deb http://apt.llvm.org/$base_tag/ llvm-toolchain-$base_tag-$llvm_version main" >> /etc/apt/sources.list.d/llvm.list 55 | 56 | RUN apt-get update --fix-missing && apt-get -y upgrade 57 | RUN apt-get install -y --no-install-recommends \ 58 | clang-format-${llvm_version} \ 59 | clang-tidy-${llvm_version} \ 60 | && rm -rf /var/lib/apt/lists/* 61 | 62 | RUN ln -s /usr/bin/clang-format-${llvm_version} /usr/local/bin/clang-format 63 | RUN ln -s /usr/bin/clang-tidy-${llvm_version} /usr/local/bin/clang-tidy 64 | 65 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 66 | # option A: install rust and install clang wrappers via cargo 67 | # this option installs rust and cargo, and then compiles the clang wrappers from scratch. 68 | # this can take a significant amount of time (e.g., several minutes just to compile one tool), 69 | # and also increases the image size significantly. therefore, we go for option B below. 70 | 71 | # RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y 72 | # ENV PATH=/root/.cargo/bin:$PATH 73 | 74 | # Each takes around 280 s to build on an M2 macbook air 75 | # RUN cargo install run-clang-format 76 | # RUN cargo install run-clang-tidy 77 | 78 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 79 | # option B: install pre-built clang wrappers 80 | 81 | RUN mkdir -p /usr/local/run-clang-format 82 | RUN wget -O clang-utils.tgz "https://github.com/lmapii/run-clang-format/releases/download/v1.5.0/run-clang-format-v1.5.0-i686-unknown-linux-gnu.tar.gz" && \ 83 | tar -C /usr/local/run-clang-format -xzf clang-utils.tgz --strip-components 1 && \ 84 | rm clang-utils.tgz 85 | ENV PATH /usr/local/run-clang-format:$PATH 86 | RUN run-clang-format --version 87 | 88 | RUN mkdir -p /usr/local/run-clang-tidy 89 | RUN wget -O clang-utils.tgz "https://github.com/lmapii/run-clang-tidy/releases/download/v0.3.0/run-clang-tidy-v0.3.0-i686-unknown-linux-gnu.tar.gz" && \ 90 | tar -C /usr/local/run-clang-tidy -xzf clang-utils.tgz --strip-components 1 && \ 91 | rm clang-utils.tgz 92 | ENV PATH /usr/local/run-clang-tidy:$PATH 93 | RUN run-clang-tidy --version 94 | 95 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 96 | # install unity and ceedling 97 | 98 | # install unity cmock and ceedling (unit test environment) 99 | RUN gem install ceedling 100 | # set standard encoding to UTF-8 for ruby (and thus ceedling) 101 | ENV RUBYOPT "-KU -E utf-8:utf-8" 102 | 103 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 104 | # cleanup and vulnerability fixes 105 | 106 | # check all installed packages with "apt list", maybe remove packages. 107 | RUN apt remove -y \ 108 | wget 109 | 110 | # FIXME: remove more packages ... 111 | # RUN apt remove -y \ 112 | # python3-yaml \ 113 | # curl \ 114 | # unzip \ 115 | # cpp \ 116 | # cpp-10 \ 117 | # nano \ 118 | # vim 119 | -------------------------------------------------------------------------------- /clang-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": ["./src/**/*.[ch]", "./include/**/*.[ch]", "./tests/unittest/test/*.[ch]"], 3 | "filterPre": [".*"], 4 | "filterPost": ["./src/build/**", "./tests/unittest/build/**", "./tests/unittest/generated"] 5 | } 6 | -------------------------------------------------------------------------------- /clang-tidy.json: -------------------------------------------------------------------------------- 1 | { 2 | "paths": ["./src/**/*.[ch]"], 3 | "filterPre": [".*"], 4 | "filterPost": ["./build/**"], 5 | "buildRoot": "./build" 6 | } 7 | -------------------------------------------------------------------------------- /include/dummy/dummy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file dummy.h 3 | * 4 | * \brief A dummy subsystem. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | uint8_t dummy_random(void); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | project_name=cproject 2 | 3 | builder-build : 4 | docker build -f builder.Dockerfile -t $(project_name)-builder:latest . 5 | 6 | builder-run : 7 | docker run \ 8 | --rm \ 9 | -it \ 10 | --platform linux/amd64 \ 11 | --workdir /builder/mnt \ 12 | -v .:/builder/mnt \ 13 | $(project_name)-builder:latest \ 14 | /bin/bash 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://github.com/lmapii/cproject/actions/workflows/ci.yml/badge.svg)](https://github.com/lmapii/cproject/actions/workflows/ci.yml) 2 | 3 | # Example repository for a C development environment 4 | 5 | This is the example repository for a [post on the Interrupt blog](https://interrupt.memfault.com/blog/a-modern-c-dev-env). It is a demo development environment using Docker, CMake, Unity, and GitHub Actions. 6 | -------------------------------------------------------------------------------- /src/dummy.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file dummy.c 3 | */ 4 | 5 | #include "dummy/dummy.h" 6 | 7 | uint8_t dummy_random(void) 8 | { 9 | return 4U; // determined by fair dice roll. 10 | } 11 | -------------------------------------------------------------------------------- /tests/unittest/generated/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lmapii/cproject/5714e187adc996e0d43231da3a0f2273ea8eb028/tests/unittest/generated/.gitkeep -------------------------------------------------------------------------------- /tests/unittest/project.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Notes: 4 | # Sample project C code is not presently written to produce a release artifact. 5 | # As such, release build options are disabled. 6 | # This sample, therefore, only demonstrates running a collection of unit tests. 7 | 8 | # https://embeddedartistry.com/blog/2019/2/25/unit-testing-and-reporting-on-a-build-server-using-ceedling-and-unity 9 | 10 | 11 | :project: 12 | :use_exceptions: FALSE 13 | :use_test_preprocessor: TRUE 14 | :use_auxiliary_dependencies: TRUE 15 | :build_root: build 16 | :release_build: FALSE 17 | :test_file_prefix: test 18 | :which_ceedling: gem 19 | :default_tasks: 20 | - test:all 21 | 22 | :environment: 23 | 24 | :extension: 25 | :executable: .out 26 | 27 | :paths: 28 | :test: 29 | - +:test/** 30 | - -:support 31 | - -:generated 32 | :source: 33 | - ../../src/** 34 | - ../../include 35 | :support: 36 | - support 37 | - generated 38 | 39 | :defines: 40 | # in order to add common defines: 41 | # 1) remove the trailing [] from the :common: section 42 | # 2) add entries to the :common: section (e.g. :test: has TEST defined) 43 | :commmon: &common_defines # A nice typo, next to invisible :) 44 | :test: 45 | # - *common_defines 46 | - UNITY_INCLUDE_CONFIG_H 47 | - TEST 48 | :test_preprocess: 49 | # - *common_defines 50 | - TEST 51 | 52 | :cmock: 53 | :defines: 54 | - CMOCK_MEM_DYNAMIC 55 | - TEST 56 | # - UNITY_INT_WIDTH=32 57 | # - UNITY_LONG_WIDTH=32 58 | # - UNITY_POINTER_WIDTH=32 59 | :mock_prefix: mock_ 60 | :when_no_prototypes: :warn 61 | :enforce_strict_ordering: TRUE 62 | :plugins: 63 | - :ignore 64 | - :ignore_arg 65 | - :callback 66 | - :array 67 | :treat_as: 68 | uint8: HEX8 69 | uint16: HEX16 70 | uint32: UINT32 71 | int8: INT8 72 | bool: UINT8 73 | 74 | :gcov: 75 | :gcovr: 76 | # The root directory of your source files. Defaults to ".", the current directory. 77 | # File names are reported relative to this root. The report_root is the default report_include. 78 | :report_root: "../../" 79 | :reports: 80 | - HtmlDetailed 81 | :report_include: "^../../src/.*" 82 | :report_exclude: "^vendor.*|^build.*|^test.*|^lib.*|^.*_build.*" 83 | 84 | #:tools: 85 | # Ceedling defaults to using gcc for compiling, linking, etc. 86 | # As [:tools] is blank, gcc will be used (so long as it's in your system path) 87 | # See documentation to configure a given toolchain for use 88 | 89 | # required for math.h 90 | :tools_test_linker: 91 | :arguments: 92 | - -lm 93 | :tools_gcov_linker: 94 | :arguments: 95 | - -lm 96 | 97 | # https://gist.github.com/austinglaser/cb91ba7bb864a2fc87f72e7dc838cd6e 98 | :flags: 99 | :test: 100 | :compile: 101 | :*: 102 | - -Wall 103 | - -g0 104 | - -O3 105 | - -m32 106 | :link: 107 | :*: 108 | - -g0 109 | - -O3 110 | - -m32 111 | :gcov: 112 | :compile: 113 | :*: 114 | - -g0 115 | - -O3 116 | - -Wall 117 | - -m32 118 | :link: 119 | :*: 120 | - -g0 121 | - -O3 122 | - -m32 123 | 124 | 125 | # LIBRARIES 126 | # These libraries are automatically injected into the build process. Those specified as 127 | # common will be used in all types of builds. Otherwise, libraries can be injected in just 128 | # tests or releases. These options are MERGED with the options in supplemental yaml files. 129 | :libraries: 130 | :placement: :end 131 | :flag: "${1}" # or "-L ${1}" for example 132 | :common: &common_libraries [] 133 | :test: 134 | - *common_libraries 135 | :release: 136 | - *common_libraries 137 | 138 | :plugins: 139 | :load_paths: 140 | - "#{Ceedling.load_path}" 141 | :enabled: 142 | - stdout_pretty_tests_report 143 | - module_generator 144 | - xml_tests_report 145 | - gcov 146 | 147 | # :test_runner: 148 | # :cmdline_args: true -------------------------------------------------------------------------------- /tests/unittest/support/unity_config.h: -------------------------------------------------------------------------------- 1 | /* Unity Configuration 2 | * As of May 11th, 2016 at ThrowTheSwitch/Unity commit 837c529 3 | * Update: December 29th, 2016 4 | * See Also: Unity/docs/UnityConfigurationGuide.pdf 5 | * 6 | * Unity is designed to run on almost anything that is targeted by a C compiler. 7 | * It would be awesome if this could be done with zero configuration. While 8 | * there are some targets that come close to this dream, it is sadly not 9 | * universal. It is likely that you are going to need at least a couple of the 10 | * configuration options described in this document. 11 | * 12 | * All of Unity's configuration options are `#defines`. Most of these are simple 13 | * definitions. A couple are macros with arguments. They live inside the 14 | * unity_internals.h header file. We don't necessarily recommend opening that 15 | * file unless you really need to. That file is proof that a cross-platform 16 | * library is challenging to build. From a more positive perspective, it is also 17 | * proof that a great deal of complexity can be centralized primarily to one 18 | * place in order to provide a more consistent and simple experience elsewhere. 19 | * 20 | * Using These Options 21 | * It doesn't matter if you're using a target-specific compiler and a simulator 22 | * or a native compiler. In either case, you've got a couple choices for 23 | * configuring these options: 24 | * 25 | * 1. Because these options are specified via C defines, you can pass most of 26 | * these options to your compiler through command line compiler flags. Even 27 | * if you're using an embedded target that forces you to use their 28 | * overbearing IDE for all configuration, there will be a place somewhere in 29 | * your project to configure defines for your compiler. 30 | * 2. You can create a custom `unity_config.h` configuration file (present in 31 | * your toolchain's search paths). In this file, you will list definitions 32 | * and macros specific to your target. All you must do is define 33 | * `UNITY_INCLUDE_CONFIG_H` and Unity will rely on `unity_config.h` for any 34 | * further definitions it may need. 35 | */ 36 | 37 | #ifndef UNITY_CONFIG_H 38 | #define UNITY_CONFIG_H 39 | 40 | // #warning "unity-config.h" 41 | 42 | /* ************************* AUTOMATIC INTEGER TYPES *************************** 43 | * C's concept of an integer varies from target to target. The C Standard has 44 | * rules about the `int` matching the register size of the target 45 | * microprocessor. It has rules about the `int` and how its size relates to 46 | * other integer types. An `int` on one target might be 16 bits while on another 47 | * target it might be 64. There are more specific types in compilers compliant 48 | * with C99 or later, but that's certainly not every compiler you are likely to 49 | * encounter. Therefore, Unity has a number of features for helping to adjust 50 | * itself to match your required integer sizes. It starts off by trying to do it 51 | * automatically. 52 | **************************************************************************** */ 53 | 54 | /* The first attempt to guess your types is to check `limits.h`. Some compilers 55 | * that don't support `stdint.h` could include `limits.h`. If you don't 56 | * want Unity to check this file, define this to make it skip the inclusion. 57 | * Unity looks at UINT_MAX & ULONG_MAX, which were available since C89. 58 | */ 59 | /* #define UNITY_EXCLUDE_LIMITS_H */ 60 | #define UNITY_EXCLUDE_LIMITS_H 61 | 62 | /* The second thing that Unity does to guess your types is check `stdint.h`. 63 | * This file defines `UINTPTR_MAX`, since C99, that Unity can make use of to 64 | * learn about your system. It's possible you don't want it to do this or it's 65 | * possible that your system doesn't support `stdint.h`. If that's the case, 66 | * you're going to want to define this. That way, Unity will know to skip the 67 | * inclusion of this file and you won't be left with a compiler error. 68 | */ 69 | /* #define UNITY_EXCLUDE_STDINT_H */ 70 | #define UNITY_EXCLUDE_STDINT_H 71 | 72 | // somehow messes up cmock 73 | // #define UNITY_EXCLUDE_SETJMP_H 74 | 75 | #define UNITY_EXCLUDE_MATH_H 76 | 77 | /* ********************** MANUAL INTEGER TYPE DEFINITION *********************** 78 | * If you've disabled all of the automatic options above, you're going to have 79 | * to do the configuration yourself. There are just a handful of defines that 80 | * you are going to specify if you don't like the defaults. 81 | **************************************************************************** */ 82 | 83 | /* Define this to be the number of bits an `int` takes up on your system. The 84 | * default, if not auto-detected, is 32 bits. 85 | * 86 | * Example: 87 | */ 88 | /* #define UNITY_INT_WIDTH 16 */ 89 | 90 | /* Define this to be the number of bits a `long` takes up on your system. The 91 | * default, if not autodetected, is 32 bits. This is used to figure out what 92 | * kind of 64-bit support your system can handle. Does it need to specify a 93 | * `long` or a `long long` to get a 64-bit value. On 16-bit systems, this option 94 | * is going to be ignored. 95 | * 96 | * Example: 97 | */ 98 | /* #define UNITY_LONG_WIDTH 16 */ 99 | 100 | /* Define this to be the number of bits a pointer takes up on your system. The 101 | * default, if not autodetected, is 32-bits. If you're getting ugly compiler 102 | * warnings about casting from pointers, this is the one to look at. 103 | * 104 | * Example: 105 | */ 106 | /* #define UNITY_POINTER_WIDTH 64 */ 107 | 108 | /* Unity will automatically include 64-bit support if it auto-detects it, or if 109 | * your `int`, `long`, or pointer widths are greater than 32-bits. Define this 110 | * to enable 64-bit support if none of the other options already did it for you. 111 | * There can be a significant size and speed impact to enabling 64-bit support 112 | * on small targets, so don't define it if you don't need it. 113 | */ 114 | /* #define UNITY_INCLUDE_64 */ 115 | #ifdef UNITY_INCLUDE_64 116 | #undef UNITY_INCLUDE_64 117 | #endif 118 | 119 | /* *************************** FLOATING POINT TYPES **************************** 120 | * In the embedded world, it's not uncommon for targets to have no support for 121 | * floating point operations at all or to have support that is limited to only 122 | * single precision. We are able to guess integer sizes on the fly because 123 | * integers are always available in at least one size. Floating point, on the 124 | * other hand, is sometimes not available at all. Trying to include `float.h` on 125 | * these platforms would result in an error. This leaves manual configuration as 126 | * the only option. 127 | **************************************************************************** */ 128 | 129 | /* By default, Unity guesses that you will want single precision floating point 130 | * support, but not double precision. It's easy to change either of these using 131 | * the include and exclude options here. You may include neither, just float, 132 | * or both, as suits your needs. 133 | */ 134 | /* #define UNITY_EXCLUDE_FLOAT */ 135 | /* #define UNITY_INCLUDE_DOUBLE */ 136 | /* #define UNITY_EXCLUDE_DOUBLE */ 137 | 138 | /* For features that are enabled, the following floating point options also 139 | * become available. 140 | */ 141 | 142 | /* Unity aims for as small of a footprint as possible and avoids most standard 143 | * library calls (some embedded platforms don't have a standard library!). 144 | * Because of this, its routines for printing integer values are minimalist and 145 | * hand-coded. To keep Unity universal, though, we eventually chose to develop 146 | * our own floating point print routines. Still, the display of floating point 147 | * values during a failure are optional. By default, Unity will print the 148 | * actual results of floating point assertion failures. So a failed assertion 149 | * will produce a message like "Expected 4.0 Was 4.25". If you would like less 150 | * verbose failure messages for floating point assertions, use this option to 151 | * give a failure message `"Values Not Within Delta"` and trim the binary size. 152 | */ 153 | /* #define UNITY_EXCLUDE_FLOAT_PRINT */ 154 | 155 | /* If enabled, Unity assumes you want your `FLOAT` asserts to compare standard C 156 | * floats. If your compiler supports a specialty floating point type, you can 157 | * always override this behavior by using this definition. 158 | * 159 | * Example: 160 | */ 161 | /* #define UNITY_FLOAT_TYPE float16_t */ 162 | 163 | /* If enabled, Unity assumes you want your `DOUBLE` asserts to compare standard 164 | * C doubles. If you would like to change this, you can specify something else 165 | * by using this option. For example, defining `UNITY_DOUBLE_TYPE` to `long 166 | * double` could enable gargantuan floating point types on your 64-bit processor 167 | * instead of the standard `double`. 168 | * 169 | * Example: 170 | */ 171 | /* #define UNITY_DOUBLE_TYPE long double */ 172 | 173 | /* If you look up `UNITY_ASSERT_EQUAL_FLOAT` and `UNITY_ASSERT_EQUAL_DOUBLE` as 174 | * documented in the Unity Assertion Guide, you will learn that they are not 175 | * really asserting that two values are equal but rather that two values are 176 | * "close enough" to equal. "Close enough" is controlled by these precision 177 | * configuration options. If you are working with 32-bit floats and/or 64-bit 178 | * doubles (the normal on most processors), you should have no need to change 179 | * these options. They are both set to give you approximately 1 significant bit 180 | * in either direction. The float precision is 0.00001 while the double is 181 | * 10^-12. For further details on how this works, see the appendix of the Unity 182 | * Assertion Guide. 183 | * 184 | * Example: 185 | */ 186 | /* #define UNITY_FLOAT_PRECISION 0.001f */ 187 | /* #define UNITY_DOUBLE_PRECISION 0.001f */ 188 | 189 | /* *************************** TOOLSET CUSTOMIZATION *************************** 190 | * In addition to the options listed above, there are a number of other options 191 | * which will come in handy to customize Unity's behavior for your specific 192 | * toolchain. It is possible that you may not need to touch any of these but 193 | * certain platforms, particularly those running in simulators, may need to jump 194 | * through extra hoops to operate properly. These macros will help in those 195 | * situations. 196 | **************************************************************************** */ 197 | 198 | /* By default, Unity prints its results to `stdout` as it runs. This works 199 | * perfectly fine in most situations where you are using a native compiler for 200 | * testing. It works on some simulators as well so long as they have `stdout` 201 | * routed back to the command line. There are times, however, where the 202 | * simulator will lack support for dumping results or you will want to route 203 | * results elsewhere for other reasons. In these cases, you should define the 204 | * `UNITY_OUTPUT_CHAR` macro. This macro accepts a single character at a time 205 | * (as an `int`, since this is the parameter type of the standard C `putchar` 206 | * function most commonly used). You may replace this with whatever function 207 | * call you like. 208 | * 209 | * Example: 210 | * Say you are forced to run your test suite on an embedded processor with no 211 | * `stdout` option. You decide to route your test result output to a custom 212 | * serial `RS232_putc()` function you wrote like thus: 213 | */ 214 | /* #define UNITY_OUTPUT_CHAR(a) RS232_putc(a) */ 215 | /* #define UNITY_OUTPUT_CHAR_HEADER_DECLARATION RS232_putc(int) */ 216 | /* #define UNITY_OUTPUT_FLUSH() RS232_flush() */ 217 | /* #define UNITY_OUTPUT_FLUSH_HEADER_DECLARATION RS232_flush(void) */ 218 | /* #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0) */ 219 | /* #define UNITY_OUTPUT_COMPLETE() RS232_close() */ 220 | 221 | /* For some targets, Unity can make the otherwise required `setUp()` and 222 | * `tearDown()` functions optional. This is a nice convenience for test writers 223 | * since `setUp` and `tearDown` don't often actually _do_ anything. If you're 224 | * using gcc or clang, this option is automatically defined for you. Other 225 | * compilers can also support this behavior, if they support a C feature called 226 | * weak functions. A weak function is a function that is compiled into your 227 | * executable _unless_ a non-weak version of the same function is defined 228 | * elsewhere. If a non-weak version is found, the weak version is ignored as if 229 | * it never existed. If your compiler supports this feature, you can let Unity 230 | * know by defining `UNITY_SUPPORT_WEAK` as the function attributes that would 231 | * need to be applied to identify a function as weak. If your compiler lacks 232 | * support for weak functions, you will always need to define `setUp` and 233 | * `tearDown` functions (though they can be and often will be just empty). The 234 | * most common options for this feature are: 235 | */ 236 | /* #define UNITY_SUPPORT_WEAK weak */ 237 | /* #define UNITY_SUPPORT_WEAK __attribute__((weak)) */ 238 | /* #define UNITY_NO_WEAK */ 239 | 240 | /* Some compilers require a custom attribute to be assigned to pointers, like 241 | * `near` or `far`. In these cases, you can give Unity a safe default for these 242 | * by defining this option with the attribute you would like. 243 | * 244 | * Example: 245 | */ 246 | /* #define UNITY_PTR_ATTRIBUTE __attribute__((far)) */ 247 | /* #define UNITY_PTR_ATTRIBUTE near */ 248 | 249 | // #error "test" 250 | 251 | #endif /* UNITY_CONFIG_H */ 252 | -------------------------------------------------------------------------------- /tests/unittest/test/test_dummy.c: -------------------------------------------------------------------------------- 1 | /** \file test_dummy.c */ 2 | 3 | #include "dummy/dummy.h" 4 | #include "unity.h" 5 | 6 | void setUp(void) 7 | { 8 | } 9 | 10 | void tearDown(void) 11 | { 12 | } 13 | 14 | void test_dummy(void) 15 | { 16 | TEST_ASSERT_EQUAL(4U, dummy_random()); 17 | } 18 | --------------------------------------------------------------------------------