A set of re-usable and opinionated utilities for Sourcemeta projects.
We recommend using vendorpull
to
include Noa in your vendor
directory.
Like projects such as GoogleTest
, Noa
follows the Abseil Live at
Head philosophy. We
recommend always following the latest commit in the main
branch.
To make use of Noa in a CMake project (after installing it into your project
using vendorpull
), add the following statements after the first call to
project
:
include(vendor/noa/cmake/noa.cmake)
Noa will automatically set sane defaults for your project. You can check the list of applied defaults here. Note that these are only defaults. You can always override them after including Noa.
Instantiate a C++ library with an opinionated structure and configuration.
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/<namespace>/<name>/<name>_
. Otherwise, they are
resolved relatively to include/<name>/<name>_
.
If NAMESPACE
is declared, the expected structure is as follows:
include/
<namespace>/
<project>/
<name>.h
<name>_<private_header>.h
<sources...>.cc
<sources...>.h
If NAMESPACE
is not declared, the expected structure is as follows:
include/
<project>/
<name>.h
<name>_<private_header>.h
<sources...>.cc
<sources...>.h
If VARIANT
is declared, it allows for creating sub-libraries or variants
of a main library. The expected structure changes as follows:
<name>/
include/
<namespace>/
<project>/
<name>.h
<name>_<private_header>.h
<variant>/
<sources...>.cc
<sources...>.h
If NAMESPACE
is declared, calling this function will result in the following:
- A target called
<namespace>_<project>_<name>
- An alias target called
<namespace>::<project>::<name>
If NAMESPACE
is not declared, calling this function will result in the
following:
- A target called
<project>_<name>
- An alias target called
<project>::<name>
In all cases:
- An export file on the library include path called
<name>_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
Declare installation of opinionated Noa libraries created with noa_library
.
noa_library_install([NAMESPACE [namespace]] PROJECT [project] NAME [name])
If NAMESPACE
is declared, calling this function will result in the following:
- A
<namespace>_<project>_<name>
installation component - A
<namespace>_<project>_<name>_dev
installation component
If NAMESPACE
is not declared, calling this function will result in the
following:
- A
<project>_<name>
installation component - A
<project>_<name>_dev
installation component
In both cases:
- An export file at
LIBDIR/cmake/<project>
Setup ClangFormat using an opinionated configuration file based on the LLVM coding standards.
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 theSOURCES
option and modify them in placeclang_format_test
: Run the formatter on the files declared in theSOURCES
option in dry-mode, reporting if there is any deviation. This option is meant to be used in a continuous-integration environment
For example:
noa_target_clang_format(SOURCES src/*.h src/*.cc REQUIRED)
To run the targets:
cmake --build <dir> [<options>] --target clang_format
cmake --build <dir> [<options>] --target clang_format_test
Setup ClangTidy using an opinionated built-in configuration file.
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 theSOURCES
option
For example:
noa_target_clang_tidy(SOURCES src/*.h src/*.cc REQUIRED)
To run the targets:
cmake --build <dir> [<options>] --target clang_tidy
Setup ShellCheck.
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 theSOURCES
option
For example:
noa_target_shellcheck(SOURCES scripts/*.sh REQUIRED)
To run the targets:
cmake --build <dir> [<options>] --target shellcheck
Setup Doxygen with a templated configuration file.
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 theOUTPUT
directory
For example:
noa_target_doxygen(CONFIG "${PROJECT_SOURCE_DIR}/Doxyfile.in"
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/docs")
To run the targets:
cmake --build <dir> [<options>] --target doxygen
Configure a target with an opinionated set of strict compiler options. This
function is used by default when making use of noa_library
.
noa_add_default_options([visibility] [target])
For example:
noa_add_default_options(PUBLIC my_lib)
If possible, configure the given compiler to emit loop vectorization diagnostics during compilation.
noa_add_vectorization_diagnostics([target])
For example:
noa_add_vectorization_diagnostics(my_lib)
Provides a unified interface for setting up a set of compiler sanitizers project-wide.
noa_sanitizer(NAME [sanitizer])
Supported sanitizers and their respective compilers are as follows:
Sanitizer | Compiler | Description |
---|---|---|
address |
LLVM | Clang AddressSanitizer |
memory |
LLVM | Clang MemorySanitizer |
undefined |
LLVM | Clang UndefinedBehaviorSanitizer |
For example:
noa_sanitizer(NAME address)
- To better debug issues raised by the
undefined
sanitizer on LLVM, run with LLDB along with the-fsanitize-trap=all
compiler option and set theUBSAN_OPTIONS=print_stacktrace=1
environment variable
The built-in file
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.
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:
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.
NOA_LANGUAGES
: A list of the programming languages declared in the lastproject
invocation
NOA_COMPILER_LLVM
: Set toON
if using the Clang or AppleClang compilersNOA_COMPILER_GCC
: Set toON
if using the GNU GCC compilerNOA_COMPILER_MSVC
: Set toON
if using the MSVC compiler
For example:
if(NOA_COMPILER_LLVM)
add_compile_options([...])
endif()
A shortcut for declaring CMake options that correspond to string enumerations.
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)
.
For example:
noa_option_enum(
NAME MY_OPTION
DEFAULT "foo"
DESCRIPTION "A test enum"
CHOICES foo bar baz)
CMake functionality shimmed to work on older versions: