{"id":27402790,"url":"https://github.com/sourcemeta-research/noa","last_synced_at":"2026-02-08T10:33:14.755Z","repository":{"id":184269150,"uuid":"671584264","full_name":"sourcemeta-research/noa","owner":"sourcemeta-research","description":"A set of re-usable utilities for Sourcemeta projects","archived":false,"fork":false,"pushed_at":"2025-01-27T17:12:09.000Z","size":971,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-08T11:54:02.134Z","etag":null,"topics":["build-system","cmake","cpp"],"latest_commit_sha":null,"homepage":"http://noa.sourcemeta.com/","language":"CMake","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sourcemeta-research.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"sourcemeta"}},"created_at":"2023-07-27T16:47:53.000Z","updated_at":"2025-06-19T19:36:47.000Z","dependencies_parsed_at":"2024-03-13T15:57:33.918Z","dependency_job_id":"e95d7e9f-975e-4cf2-a6ac-07f06877fbdd","html_url":"https://github.com/sourcemeta-research/noa","commit_stats":null,"previous_names":["sourcemeta/noa","sourcemeta-research/noa"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sourcemeta-research/noa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sourcemeta-research%2Fnoa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sourcemeta-research%2Fnoa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sourcemeta-research%2Fnoa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sourcemeta-research%2Fnoa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sourcemeta-research","download_url":"https://codeload.github.com/sourcemeta-research/noa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sourcemeta-research%2Fnoa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29227745,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T09:43:19.170Z","status":"ssl_error","status_checked_at":"2026-02-08T09:42:55.556Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-system","cmake","cpp"],"created_at":"2025-04-14T04:31:21.249Z","updated_at":"2026-02-08T10:33:14.741Z","avatar_url":"https://github.com/sourcemeta-research.png","language":"CMake","funding_links":["https://github.com/sponsors/sourcemeta"],"categories":[],"sub_categories":[],"readme":"Noa\n===\n\nA set of re-usable and opinionated utilities for\n[Sourcemeta](https://www.sourcemeta.com) projects.\n\nInstallation\n------------\n\nWe recommend using [`vendorpull`](https://github.com/sourcemeta/vendorpull) to\ninclude Noa in your `vendor` directory.\n\n### Live at head\n\nLike projects such as [`GoogleTest`](https://github.com/google/googletest), Noa\nfollows the [Abseil Live at\nHead](https://abseil.io/about/philosophy#upgrade-support) philosophy. We\nrecommend always following the latest commit in the `main` branch.\n\nCMake\n-----\n\nTo load the CMake utilities, include `cmake/noa.cmake` as part of your project.\n\n### Defaults\n\nNoa will automatically set sane defaults for your project. You can check the\nlist of applied defaults\n[here](https://github.com/sourcemeta/noa/blob/main/cmake/noa/defaults.cmake).\n**Note that these are only defaults. You can always override them after\nincluding Noa.**\n\n### Functions\n\n#### `noa_executable`\n\nInstantiate a C++ executable with an opinionated target name and default options.\n\n```cmake\nnoa_library(\n  [NAMESPACE [namespace]]\n  PROJECT [project]\n  NAME [name]\n  VARIANT [variant]\n  FOLDER [folder]\n  SOURCES [globs...]\n  [OUTPUT [output-variable]])\n```\n\nCalling this function will result in the following:\n\n- A target called `[\u003cnamespace\u003e_]\u003cproject\u003e_\u003cname\u003e`\n\nIf `OUTPUT` is declared, such variable will contain the target name created by\nthis function.\n\n#### `noa_library`\n\nInstantiate a C++ library with an opinionated structure and configuration.\n\n```cmake\nnoa_library(\n  [NAMESPACE [namespace]]\n  PROJECT [project]\n  NAME [name]\n  VARIANT [variant]\n  FOLDER [folder]\n  [PRIVATE_HEADERS [headers...]]\n  [SOURCES [globs...]])\n```\n\nIf `NAMESPACE` is declared, the files in `PRIVATE_HEADERS` are resolved\nrelatively to `include/\u003cnamespace\u003e/\u003cname\u003e/\u003cname\u003e_`. Otherwise, they are\nresolved relatively to `include/\u003cname\u003e/\u003cname\u003e_`.\n\nIf `NAMESPACE` is declared, the expected structure is as follows:\n\n```\ninclude/\n  \u003cnamespace\u003e/\n    \u003cproject\u003e/\n      \u003cname\u003e.h\n      \u003cname\u003e_\u003cprivate_header\u003e.h\n\u003csources...\u003e.cc\n\u003csources...\u003e.h\n```\n\nIf `NAMESPACE` is not declared, the expected structure is as follows:\n\n```\ninclude/\n  \u003cproject\u003e/\n    \u003cname\u003e.h\n    \u003cname\u003e_\u003cprivate_header\u003e.h\n\u003csources...\u003e.cc\n\u003csources...\u003e.h\n```\n\nIf `VARIANT` is declared, it allows for creating sub-libraries or variants\nof a main library. The expected structure changes as follows:\n\n```\n\u003cname\u003e/\n  include/\n    \u003cnamespace\u003e/\n      \u003cproject\u003e/\n        \u003cname\u003e.h\n        \u003cname\u003e_\u003cprivate_header\u003e.h\n  \u003cvariant\u003e/\n    \u003csources...\u003e.cc\n    \u003csources...\u003e.h\n```\n\nIf `NAMESPACE` is declared, calling this function will result in the following:\n\n- A target called `\u003cnamespace\u003e_\u003cproject\u003e_\u003cname\u003e`\n- An alias target called `\u003cnamespace\u003e::\u003cproject\u003e::\u003cname\u003e`\n\nIf `NAMESPACE` is not declared, calling this function will result in the\nfollowing:\n\n- A target called `\u003cproject\u003e_\u003cname\u003e`\n- An alias target called `\u003cproject\u003e::\u003cname\u003e`\n\nIn all cases:\n\n- An export file on the library include path called `\u003cname\u003e_export.h`, if the\n  library is not header-only\n- The version of the library corresponds to the project version, if the library\n  is not header-only\n\n#### `noa_library_install`\n\nDeclare installation of opinionated Noa libraries created with `noa_library`.\n\n```cmake\nnoa_library_install([NAMESPACE [namespace]] PROJECT [project] NAME [name])\n```\n\nIf `NAMESPACE` is declared, calling this function will result in the following:\n\n- A `\u003cnamespace\u003e_\u003cproject\u003e_\u003cname\u003e` installation component\n- A `\u003cnamespace\u003e_\u003cproject\u003e_\u003cname\u003e_dev` installation component\n\nIf `NAMESPACE` is not declared, calling this function will result in the\nfollowing:\n\n- A `\u003cproject\u003e_\u003cname\u003e` installation component\n- A `\u003cproject\u003e_\u003cname\u003e_dev` installation component\n\nIn both cases:\n\n- An export file at `LIBDIR/cmake/\u003cproject\u003e`\n\n#### `noa_target_clang_format`\n\nSetup [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) using an\nopinionated configuration file based on the [LLVM coding\nstandards](https://llvm.org/docs/CodingStandards.html).\n\n```cmake\nnoa_target_clang_format(SOURCES [globs...] [REQUIRED])\n```\n\nIf the `REQUIRED` option is set and ClangFormat is not found, configuration\nwill abort.\n\nAfter running this function, you will have two targets at your disposal:\n\n- `clang_format`: Run the formatter on the files declared in the `SOURCES`\n  option and modify them in place\n- `clang_format_test`: Run the formatter on the files declared in the `SOURCES`\n  option in dry-mode, reporting if there is any deviation. This option is meant\n  to be used in a continuous-integration environment\n\nFor example:\n\n```cmake\nnoa_target_clang_format(SOURCES src/*.h src/*.cc REQUIRED)\n```\n\nTo run the targets:\n\n```sh\ncmake --build \u003cdir\u003e [\u003coptions\u003e] --target clang_format\ncmake --build \u003cdir\u003e [\u003coptions\u003e] --target clang_format_test\n```\n\n#### `noa_target_clang_tidy`\n\nSetup [ClangTidy](https://clang.llvm.org/extra/clang-tidy/index.html) using an\nopinionated built-in [configuration\nfile](https://github.com/sourcemeta/noa/blob/main/cmake/noa/targets/clang-tidy.config).\n\n```cmake\nnoa_target_clang_tidy(SOURCES [globs...] [REQUIRED])\n```\n\nIf the `REQUIRED` option is set and ClangTidy is not found, configuration will\nabort.\n\nAfter running this function, you will have a new targets at your disposal:\n\n- `clang_tidy`: Run the analyzer on the files declared in the `SOURCES` option\n\nFor example:\n\n```cmake\nnoa_target_clang_tidy(SOURCES src/*.h src/*.cc REQUIRED)\n```\n\nTo run the targets:\n\n```sh\ncmake --build \u003cdir\u003e [\u003coptions\u003e] --target clang_tidy\n```\n\n#### `noa_target_shellcheck`\n\nSetup [ShellCheck](https://www.shellcheck.net).\n\n```cmake\nnoa_target_shellcheck(SOURCES [globs...] [REQUIRED])\n```\n\nIf the `REQUIRED` option is set and ShellCheck is not found, configuration will\nabort.\n\nAfter running this function, you will have a new targets at your disposal:\n\n- `shellcheck`: Run the linter on the files declared in the `SOURCES` option\n\nFor example:\n\n```cmake\nnoa_target_shellcheck(SOURCES scripts/*.sh REQUIRED)\n```\n\nTo run the targets:\n\n```sh\ncmake --build \u003cdir\u003e [\u003coptions\u003e] --target shellcheck\n```\n\n#### `noa_target_doxygen`\n\nSetup [Doxygen](https://www.doxygen.nl) with a templated configuration file.\n\n```cmake\nnoa_target_doxygen(CONFIG [config] OUTPUT [output])\n```\n\nOn your configuration file, make sure to set `OUTPUT_DIRECTORY` as follows:\n\n```\nOUTPUT_DIRECTORY       = @NOA_TARGET_DOXYGEN_OUTPUT@\n```\n\nAfter running this function, you will have a new target at your disposal:\n\n- `doxygen`: Run Doxygen and store the output in the `OUTPUT` directory\n\nFor example:\n\n```cmake\nnoa_target_doxygen(CONFIG \"${PROJECT_SOURCE_DIR}/Doxyfile.in\"\n  OUTPUT \"${CMAKE_CURRENT_BINARY_DIR}/docs\")\n```\n\nTo run the targets:\n\n```sh\ncmake --build \u003cdir\u003e [\u003coptions\u003e] --target doxygen\n```\n\n#### `noa_add_default_options`\n\nConfigure a target with an opinionated set of strict compiler options. This\nfunction is used by default when making use of `noa_library`.\n\n```cmake\nnoa_add_default_options([visibility] [target])\n```\n\nFor example:\n\n```cmake\nnoa_add_default_options(PUBLIC my_lib)\n````\n\n#### `noa_add_vectorization_diagnostics`\n\nIf possible, configure the given compiler to emit loop vectorization\ndiagnostics during compilation.\n\n```cmake\nnoa_add_vectorization_diagnostics([target])\n```\n\nFor example:\n\n```cmake\nnoa_add_vectorization_diagnostics(my_lib)\n````\n\n#### `noa_sanitizer`\n\nProvides a unified interface for setting up a set of compiler sanitizers\nproject-wide.\n\n```cmake\nnoa_sanitizer(NAME [sanitizer])\n```\n\nSupported sanitizers and their respective compilers are as follows:\n\n| Sanitizer   | Compiler | Description                                                    |\n|-------------|----------|----------------------------------------------------------------|\n| `address`   | LLVM     | Clang [AddressSanitizer][ClangAddressSanitizer]                |\n| `memory`    | LLVM     | Clang [MemorySanitizer][ClangMemorySanitizer]                  |\n| `undefined` | LLVM     | Clang [UndefinedBehaviorSanitizer][UndefinedBehaviorSanitizer] |\n\n[ClangAddressSanitizer]: https://clang.llvm.org/docs/AddressSanitizer.html\n[ClangMemorySanitizer]: https://clang.llvm.org/docs/MemorySanitizer.html\n[UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html\n\nFor example:\n\n```cmake\nnoa_sanitizer(NAME address)\n```\n\n#### `noa_googletest`\n\nInstantiate a C++ executable that links with GoogleTest.\n\n```cmake\nnoa_googletest(\n  [NAMESPACE [namespace]]\n  PROJECT [project]\n  NAME [name]\n  VARIANT [variant]\n  FOLDER [folder]\n  SOURCES [globs...])\n```\n\nCalling this function will result in the following:\n\n- A target called `[\u003cnamespace\u003e_]\u003cproject\u003e_\u003cname\u003e_unit`\n\n#### `noa_googlebenchmark`\n\nInstantiate a C++ executable that links with GoogleBenchmark.\n\n```cmake\nnoa_googlebenchmark(\n  [NAMESPACE [namespace]]\n  PROJECT [project]\n  FOLDER [folder]\n  SOURCES [globs...])\n```\n\nCalling this function will result in the following:\n\n- A target called `[\u003cnamespace\u003e_]\u003cproject\u003e_benchmark`\n\n#### Tips \u0026 Tricks\n\n- To better debug issues raised by the `undefined` sanitizer on LLVM, run with\n  LLDB along with the `-fsanitize-trap=all` compiler option and set the\n  `UBSAN_OPTIONS=print_stacktrace=1` environment variable\n\n### Commands\n\n#### `noa_command_copy_file`\n\nThe built-in [`file`](https://cmake.org/cmake/help/latest/command/file.html)\ncommand can be used to copy a file during the configure phase. Instead, this\ncommand copies a file at the build step to deal with generated files or as an\noptimization.\n\n```cmake\nnoa_command_copy_file(FROM [input] TO [output])\n```\n\nFor example, you can declare a file to be copied at built-time, and then\nreference such output in a target for the copying to actually take place:\n\n```cmake\nnoa_command_copy_file(FROM input.txt TO \"${CMAKE_CURRENT_BINARY_DIR}/output.txt\")\nadd_custom_target(do_copy DEPENDS \"${CMAKE_CURRENT_BINARY_DIR}/output.txt\")\n```\n\nIt is highly recommended to always copy files into the binary directory.\n\n### Variables\n\n#### Programming language\n\n- `NOA_LANGUAGES`: A list of the programming languages declared in the last\n  [`project`](https://cmake.org/cmake/help/latest/command/project.html)\n  invocation\n\n#### Compiler detection\n\n- `NOA_COMPILER_LLVM`: Set to `ON` if using the Clang or AppleClang compilers\n- `NOA_COMPILER_GCC`: Set to `ON` if using the GNU GCC compiler\n- `NOA_COMPILER_MSVC`: Set to `ON` if using the MSVC compiler\n\nFor example:\n\n```cmake\nif(NOA_COMPILER_LLVM)\n  add_compile_options([...])\nendif()\n```\n\n### Options\n\n#### `noa_option_enum`\n\nA shortcut for declaring CMake options that correspond to string enumerations.\n\n```cmake\nnoa_option_enum(NAME [name] DEFAULT [value] DESCRIPTION [description] CHOICES [choices...])\n```\n\nThis function will validate that user provided values (and your own default\nvalue) matches the provided choices. It will also make sure to provide a nice\nselection interface in\n[`cmake-gui(1)`](https://cmake.org/cmake/help/latest/manual/cmake-gui.1.html).\n\nFor example:\n\n```cmake\nnoa_option_enum(\n  NAME MY_OPTION\n  DEFAULT \"foo\"\n  DESCRIPTION \"A test enum\"\n  CHOICES foo bar baz)\n```\n\n### Shims\n\nCMake functionality shimmed to work on older versions:\n\n- [`PROJECT_IS_TOP_LEVEL`](https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsourcemeta-research%2Fnoa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsourcemeta-research%2Fnoa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsourcemeta-research%2Fnoa/lists"}