https://github.com/sourcemeta-research/noa
A set of re-usable utilities for Sourcemeta projects
https://github.com/sourcemeta-research/noa
build-system cmake cpp
Last synced: 4 months ago
JSON representation
A set of re-usable utilities for Sourcemeta projects
- Host: GitHub
- URL: https://github.com/sourcemeta-research/noa
- Owner: sourcemeta-research
- License: other
- Created: 2023-07-27T16:47:53.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-01-27T17:12:09.000Z (over 1 year ago)
- Last Synced: 2025-08-08T11:54:02.134Z (10 months ago)
- Topics: build-system, cmake, cpp
- Language: CMake
- Homepage: http://noa.sourcemeta.com/
- Size: 948 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.markdown
- License: LICENSE
Awesome Lists containing this project
README
Noa
===
A set of re-usable and opinionated utilities for
[Sourcemeta](https://www.sourcemeta.com) projects.
Installation
------------
We recommend using [`vendorpull`](https://github.com/sourcemeta/vendorpull) to
include Noa in your `vendor` directory.
### Live at head
Like projects such as [`GoogleTest`](https://github.com/google/googletest), Noa
follows the [Abseil Live at
Head](https://abseil.io/about/philosophy#upgrade-support) philosophy. We
recommend always following the latest commit in the `main` branch.
CMake
-----
To load the CMake utilities, include `cmake/noa.cmake` as part of your project.
### Defaults
Noa will automatically set sane defaults for your project. You can check the
list of applied defaults
[here](https://github.com/sourcemeta/noa/blob/main/cmake/noa/defaults.cmake).
**Note that these are only defaults. You can always override them after
including Noa.**
### Functions
#### `noa_executable`
Instantiate a C++ executable with an opinionated target name and default options.
```cmake
noa_library(
[NAMESPACE [namespace]]
PROJECT [project]
NAME [name]
VARIANT [variant]
FOLDER [folder]
SOURCES [globs...]
[OUTPUT [output-variable]])
```
Calling this function will result in the following:
- A target called `[_]_`
If `OUTPUT` is declared, such variable will contain the target name created by
this function.
#### `noa_library`
Instantiate a C++ library with an opinionated structure and configuration.
```cmake
noa_library(
[NAMESPACE [namespace]]
PROJECT [project]
NAME [name]
VARIANT [variant]
FOLDER [folder]
[PRIVATE_HEADERS [headers...]]
[SOURCES [globs...]])
```
If `NAMESPACE` is declared, the files in `PRIVATE_HEADERS` are resolved
relatively to `include///_`. Otherwise, they are
resolved relatively to `include//_`.
If `NAMESPACE` is declared, the expected structure is as follows:
```
include/
/
/
.h
_.h
.cc
.h
```
If `NAMESPACE` is not declared, the expected structure is as follows:
```
include/
/
.h
_.h
.cc
.h
```
If `VARIANT` is declared, it allows for creating sub-libraries or variants
of a main library. The expected structure changes as follows:
```
/
include/
/
/
.h
_.h
/
.cc
.h
```
If `NAMESPACE` is declared, calling this function will result in the following:
- A target called `__`
- An alias target called `::::`
If `NAMESPACE` is not declared, calling this function will result in the
following:
- A target called `_`
- An alias target called `::`
In all cases:
- An export file on the library include path called `_export.h`, if the
library is not header-only
- The version of the library corresponds to the project version, if the library
is not header-only
#### `noa_library_install`
Declare installation of opinionated Noa libraries created with `noa_library`.
```cmake
noa_library_install([NAMESPACE [namespace]] PROJECT [project] NAME [name])
```
If `NAMESPACE` is declared, calling this function will result in the following:
- A `__` installation component
- A `___dev` installation component
If `NAMESPACE` is not declared, calling this function will result in the
following:
- A `_` installation component
- A `__dev` installation component
In both cases:
- An export file at `LIBDIR/cmake/`
#### `noa_target_clang_format`
Setup [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) using an
opinionated configuration file based on the [LLVM coding
standards](https://llvm.org/docs/CodingStandards.html).
```cmake
noa_target_clang_format(SOURCES [globs...] [REQUIRED])
```
If the `REQUIRED` option is set and ClangFormat is not found, configuration
will abort.
After running this function, you will have two targets at your disposal:
- `clang_format`: Run the formatter on the files declared in the `SOURCES`
option and modify them in place
- `clang_format_test`: Run the formatter on the files declared in the `SOURCES`
option in dry-mode, reporting if there is any deviation. This option is meant
to be used in a continuous-integration environment
For example:
```cmake
noa_target_clang_format(SOURCES src/*.h src/*.cc REQUIRED)
```
To run the targets:
```sh
cmake --build [] --target clang_format
cmake --build [] --target clang_format_test
```
#### `noa_target_clang_tidy`
Setup [ClangTidy](https://clang.llvm.org/extra/clang-tidy/index.html) using an
opinionated built-in [configuration
file](https://github.com/sourcemeta/noa/blob/main/cmake/noa/targets/clang-tidy.config).
```cmake
noa_target_clang_tidy(SOURCES [globs...] [REQUIRED])
```
If the `REQUIRED` option is set and ClangTidy is not found, configuration will
abort.
After running this function, you will have a new targets at your disposal:
- `clang_tidy`: Run the analyzer on the files declared in the `SOURCES` option
For example:
```cmake
noa_target_clang_tidy(SOURCES src/*.h src/*.cc REQUIRED)
```
To run the targets:
```sh
cmake --build [] --target clang_tidy
```
#### `noa_target_shellcheck`
Setup [ShellCheck](https://www.shellcheck.net).
```cmake
noa_target_shellcheck(SOURCES [globs...] [REQUIRED])
```
If the `REQUIRED` option is set and ShellCheck is not found, configuration will
abort.
After running this function, you will have a new targets at your disposal:
- `shellcheck`: Run the linter on the files declared in the `SOURCES` option
For example:
```cmake
noa_target_shellcheck(SOURCES scripts/*.sh REQUIRED)
```
To run the targets:
```sh
cmake --build [] --target shellcheck
```
#### `noa_target_doxygen`
Setup [Doxygen](https://www.doxygen.nl) with a templated configuration file.
```cmake
noa_target_doxygen(CONFIG [config] OUTPUT [output])
```
On your configuration file, make sure to set `OUTPUT_DIRECTORY` as follows:
```
OUTPUT_DIRECTORY = @NOA_TARGET_DOXYGEN_OUTPUT@
```
After running this function, you will have a new target at your disposal:
- `doxygen`: Run Doxygen and store the output in the `OUTPUT` directory
For example:
```cmake
noa_target_doxygen(CONFIG "${PROJECT_SOURCE_DIR}/Doxyfile.in"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/docs")
```
To run the targets:
```sh
cmake --build [] --target doxygen
```
#### `noa_add_default_options`
Configure a target with an opinionated set of strict compiler options. This
function is used by default when making use of `noa_library`.
```cmake
noa_add_default_options([visibility] [target])
```
For example:
```cmake
noa_add_default_options(PUBLIC my_lib)
````
#### `noa_add_vectorization_diagnostics`
If possible, configure the given compiler to emit loop vectorization
diagnostics during compilation.
```cmake
noa_add_vectorization_diagnostics([target])
```
For example:
```cmake
noa_add_vectorization_diagnostics(my_lib)
````
#### `noa_sanitizer`
Provides a unified interface for setting up a set of compiler sanitizers
project-wide.
```cmake
noa_sanitizer(NAME [sanitizer])
```
Supported sanitizers and their respective compilers are as follows:
| Sanitizer | Compiler | Description |
|-------------|----------|----------------------------------------------------------------|
| `address` | LLVM | Clang [AddressSanitizer][ClangAddressSanitizer] |
| `memory` | LLVM | Clang [MemorySanitizer][ClangMemorySanitizer] |
| `undefined` | LLVM | Clang [UndefinedBehaviorSanitizer][UndefinedBehaviorSanitizer] |
[ClangAddressSanitizer]: https://clang.llvm.org/docs/AddressSanitizer.html
[ClangMemorySanitizer]: https://clang.llvm.org/docs/MemorySanitizer.html
[UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
For example:
```cmake
noa_sanitizer(NAME address)
```
#### `noa_googletest`
Instantiate a C++ executable that links with GoogleTest.
```cmake
noa_googletest(
[NAMESPACE [namespace]]
PROJECT [project]
NAME [name]
VARIANT [variant]
FOLDER [folder]
SOURCES [globs...])
```
Calling this function will result in the following:
- A target called `[_]__unit`
#### `noa_googlebenchmark`
Instantiate a C++ executable that links with GoogleBenchmark.
```cmake
noa_googlebenchmark(
[NAMESPACE [namespace]]
PROJECT [project]
FOLDER [folder]
SOURCES [globs...])
```
Calling this function will result in the following:
- A target called `[_]_benchmark`
#### Tips & Tricks
- To better debug issues raised by the `undefined` sanitizer on LLVM, run with
LLDB along with the `-fsanitize-trap=all` compiler option and set the
`UBSAN_OPTIONS=print_stacktrace=1` environment variable
### Commands
#### `noa_command_copy_file`
The built-in [`file`](https://cmake.org/cmake/help/latest/command/file.html)
command can be used to copy a file during the configure phase. Instead, this
command copies a file at the build step to deal with generated files or as an
optimization.
```cmake
noa_command_copy_file(FROM [input] TO [output])
```
For example, you can declare a file to be copied at built-time, and then
reference such output in a target for the copying to actually take place:
```cmake
noa_command_copy_file(FROM input.txt TO "${CMAKE_CURRENT_BINARY_DIR}/output.txt")
add_custom_target(do_copy DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/output.txt")
```
It is highly recommended to always copy files into the binary directory.
### Variables
#### Programming language
- `NOA_LANGUAGES`: A list of the programming languages declared in the last
[`project`](https://cmake.org/cmake/help/latest/command/project.html)
invocation
#### Compiler detection
- `NOA_COMPILER_LLVM`: Set to `ON` if using the Clang or AppleClang compilers
- `NOA_COMPILER_GCC`: Set to `ON` if using the GNU GCC compiler
- `NOA_COMPILER_MSVC`: Set to `ON` if using the MSVC compiler
For example:
```cmake
if(NOA_COMPILER_LLVM)
add_compile_options([...])
endif()
```
### Options
#### `noa_option_enum`
A shortcut for declaring CMake options that correspond to string enumerations.
```cmake
noa_option_enum(NAME [name] DEFAULT [value] DESCRIPTION [description] CHOICES [choices...])
```
This function will validate that user provided values (and your own default
value) matches the provided choices. It will also make sure to provide a nice
selection interface in
[`cmake-gui(1)`](https://cmake.org/cmake/help/latest/manual/cmake-gui.1.html).
For example:
```cmake
noa_option_enum(
NAME MY_OPTION
DEFAULT "foo"
DESCRIPTION "A test enum"
CHOICES foo bar baz)
```
### Shims
CMake functionality shimmed to work on older versions:
- [`PROJECT_IS_TOP_LEVEL`](https://cmake.org/cmake/help/latest/variable/PROJECT_IS_TOP_LEVEL.html)