noa

Noa

A set of re-usable and opinionated utilities for Sourcemeta projects.

Installation

We recommend using vendorpull to include Noa in your vendor directory.

Live at head

Like projects such as GoogleTest, Noa follows the Abseil Live at Head philosophy. We recommend always following the latest commit in the main branch.

CMake

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)

Defaults

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.

Functions

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:

If NAMESPACE is not declared, calling this function will result in the following:

In all cases:

noa_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:

If NAMESPACE is not declared, calling this function will result in the following:

In both cases:

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:

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

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:

For 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:

For 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:

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

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)

Tips & Tricks

Commands

noa_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.

Variables

Programming language

Compiler detection

For example:

if(NOA_COMPILER_LLVM)
  add_compile_options([...])
endif()

Options

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)

Shims

CMake functionality shimmed to work on older versions: