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.
noa_library
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:
<namespace>_<project>_<name>
<namespace>::<project>::<name>
If NAMESPACE
is not declared, calling this function will result in the
following:
<project>_<name>
<project>::<name>
In all cases:
<name>_export.h
, if the
library is not header-onlynoa_library_install
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:
<namespace>_<project>_<name>
installation component<namespace>_<project>_<name>_dev
installation componentIf NAMESPACE
is not declared, calling this function will result in the
following:
<project>_<name>
installation component<project>_<name>_dev
installation componentIn both cases:
LIBDIR/cmake/<project>
noa_target_clang_format
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 the SOURCES
option and modify them in placeclang_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 environmentFor 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
noa_target_clang_tidy
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 the SOURCES
optionFor example:
noa_target_clang_tidy(SOURCES src/*.h src/*.cc REQUIRED)
To run the targets:
cmake --build <dir> [<options>] --target clang_tidy
noa_target_shellcheck
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 the SOURCES
optionFor example:
noa_target_shellcheck(SOURCES scripts/*.sh REQUIRED)
To run the targets:
cmake --build <dir> [<options>] --target shellcheck
noa_target_doxygen
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 the OUTPUT
directoryFor 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
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
.
noa_add_default_options([visibility] [target])
For example:
noa_add_default_options(PUBLIC my_lib)
noa_add_vectorization_diagnostics
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)
noa_sanitizer
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)
undefined
sanitizer on LLVM, run with
LLDB along with the -fsanitize-trap=all
compiler option and set the
UBSAN_OPTIONS=print_stacktrace=1
environment variablenoa_command_copy_file
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 last
project
invocationNOA_COMPILER_LLVM
: Set to ON
if using the Clang or AppleClang compilersNOA_COMPILER_GCC
: Set to ON
if using the GNU GCC compilerNOA_COMPILER_MSVC
: Set to ON
if using the MSVC compilerFor example:
if(NOA_COMPILER_LLVM)
add_compile_options([...])
endif()
noa_option_enum
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: