# [`cmake-common`][]

A [CMake][]\>=3.14 [C++][] common project helper.

[CMake][] has many useful features but requires verbose per-project
configuration to enable them. This helper allows you to just place your files
where everyone expects them to be anyway, install the tools you want to use,
and things like downloading dependencies, linting, building, testing,
sanitizing, packaging (build artifacts, assets, documentation), and installing
will automatically be enabled.

[`cmake-common`]: https://git.rcrnstn.net/rcrnstn/cmake-common
[CMake]: https://cmake.org
[C++]: https://en.wikipedia.org/wiki/C++

## Usage

This work is licensed in such a way that you may use it however you please,
including relicensing, without attribution. As such, the encouraged way to use
this work is to simply copy the required files or content into your project,
optionally(!) mentioning where it came from in the readme or other
documentation. See [License][].

Copy the file [`common.cmake`][] into your project and [`include`][] it from
(e.g.) the main [`CMakeLists.txt`][]. This will define a `common` function that
takes a number of arguments to configure the project.

[License]: #license
[`include`]: https://cmake.org/cmake/help/v3.14/command/include.html
[`common.cmake`]: common.cmake
[`CMakeLists.txt`]: https://cmake.org/cmake/help/v3.14/manual/cmake-language.7.html#directories

### Overview

```cmake
## CMake
cmake_minimum_required(VERSION 3.14)
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Debug)
endif()

## Project
project(project-name
    VERSION 1.0.0
    LANGUAGES CXX
)

## Main target
add_library(${PROJECT_NAME})

## Common
include(common.cmake)
common(
    CXX_STANDARD 11
    DISABLE_INCLUDE_WHAT_YOU_USE
    PACKAGES
        Package
    EXTERNAL
        external_project
    FETCHCONTENT
        "https://example.com/user/online_project GIT_TAG v1.2.3"
    DEPENDENCIES_PUBLIC
        Package::Package
    DEPENDENCIES_PRIVATE
        external_project
    DEPENDENCIES_TESTS
        online_project
    DEFINITIONS
        PROJECT_FEATURE
)
```

### Main target

If there are files in the `src` and/or `include` directories, they are added as
sources to a single "main" target, which is assumed to already be declared with
the name `${`[`PROJECT_NAME`][]`}` (which is automatically set by CMake when
calling [`project`][]). The "main" target may be of any type, such as [normal
executable][], [normal library][], [interface library][], or [custom target][]
(the latter probably with the `ALL` specifier, so that it is added to the
default build target so that it will be run every time).

[`PUBLIC`][] dependencies are taken from `DEPENDENCIES_PUBLIC` and
[`PRIVATE`][] dependencies are taken from `DEPENDENCIES_PRIVATE`, see
[Dependencies][].

For [top level project][]s, `*Config.cmake` and `*ConfigVersion.cmake` files
that can be used by [`find_package`][] to find this project are
[`install`][]ed, see [Packaging][].

[`PROJECT_NAME`]: https://cmake.org/cmake/help/v3.14/variable/PROJECT_NAME.html
[`project`]: https://cmake.org/cmake/help/v3.14/command/project.html
[normal executable]: https://cmake.org/cmake/help/v3.14/command/add_executable.html#normal-executables
[normal library]: https://cmake.org/cmake/help/v3.14/command/add_library.html#normal-libraries
[interface library]: https://cmake.org/cmake/help/v3.14/command/add_library.html#interface-libraries
[custom target]: https://cmake.org/cmake/help/v3.14/command/add_custom_target.html
[`PUBLIC`]: https://cmake.org/cmake/help/v3.14/manual/cmake-buildsystem.7.html#target-usage-requirements
[`PRIVATE`]: https://cmake.org/cmake/help/v3.14/manual/cmake-buildsystem.7.html#target-usage-requirements
[Dependencies]: #dependencies
[top level project]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_PROJECT_NAME.html
[`find_package`]: https://cmake.org/cmake/help/v3.14/command/find_package.html
[`install`]: https://cmake.org/cmake/help/v3.14/command/install.html
[Packaging]: #packaging

### Test targets

For [top level project][]s, every file directly under the `tests` directory is
individually added as a source to a separate executable "test" target, which is
automatically declared with the name `${PROJECT_NAME}-test-${TEST_NAME}` and
passed to [`add_test`][]. All files in the `tests/common` directory are also
added as sources to all "test" targets.

A ([`PRIVATE`][]) dependency on the "main" target is declared and further
([`PRIVATE`][]) dependencies are taken from `DEPENDENCIES_TESTS`, see
[Dependencies][].

CMake can be run with the standard `-D`[`BUILD_TESTING`][]`=OFF` to disable
testing.

See [Testing][].

[`add_test`]: https://cmake.org/cmake/help/v3.14/command/add_test.html
[`BUILD_TESTING`]: https://cmake.org/cmake/help/v3.14/module/CTest.html
[Testing]: #testing

### Assets

If there are files in the `assets` directory, a target named
`${PROJECT_NAME}-assets` that runs by default and [symlink][]s them to
`${`[`CMAKE_BINARY_DIR`][]`}/assets` is automatically declared.

If the path does not include `/tests/`, the asset is [`install`][]ed into
`${`[`CMAKE_INSTALL_DATADIR`][]`}/${CMAKE_PROJECT_NAME}/assets` (note that
`CMAKE_PROJECT_NAME` is the name of the [top level project][]), see
[Packaging][].

[symlink]: https://en.wikipedia.org/wiki/Symbolic_link
[`CMAKE_BINARY_DIR`]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_BINARY_DIR.html
[`CMAKE_INSTALL_DATADIR`]: https://cmake.org/cmake/help/v3.14/module/GNUInstallDirs.html

### Documentation

For [top level project][]s, documentation from the `doc` directory and
repository root is automatically [`install`][]ed, see [Packaging][].

### Man pages

For [top level project][]s, [man page][]s from the `man` directory is
automatically [`install`][]ed, see [Packaging][].

[man page]: https://en.wikipedia.org/wiki/Man_page

### Dependencies

Dependencies on other targets are declared with `DEPENDENCIES_PUBLIC`,
`DEPENDENCIES_PRIVATE`, and `DEPENDENCIES_TESTS`, see [Main target][] and [Test
targets][].

Three mechanisms to make these dependencies available are provided, given as
arguments to the `common` function:

-   `PACKAGES`: Packages passed to [`find_package`][]`(...)` in order to find
    system packages.
-   `EXTERNAL`: Subdirectories of `external` that is passed to
    [`add_subdirectory`][].
-   `FETCHCONTENT`: [Git][] [URL][]s passed to [`FetchContent_Declare`][]'s
    `GIT_REPOSITORY`. If a specific [Git tag][] is wanted, specify it in the
    same (quoted) argument, delimited with `GIT_TAG`, see [Usage][].
    (`GIT_SHALLOW` and `GIT_PROGRESS` are always set to `TRUE`).
    [`FetchContent_MakeAvailable`][] is automatically called in order to
    download and make targets available during the CMake configure step.

If more involved steps are required to make targets available, perform them
manually before calling the `common` function.

[Main target]: #main-target
[Test targets]: #test-targets
[`add_subdirectory`]: https://cmake.org/cmake/help/v3.14/command/add_subdirectory.html
[Git]: https://git-scm.com
[URL]: https://en.wikipedia.org/wiki/URL
[`FetchContent_Declare`]: https://cmake.org/cmake/help/v3.14/module/FetchContent.html#command:fetchcontent_declare
[`FetchContent_MakeAvailable`]: https://cmake.org/cmake/help/v3.14/module/FetchContent.html#command:fetchcontent_makeavailable
[Git tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging
[Usage]: #usage

### Preprocessor definitions

[Preprocessor definitions][] can be specified with the `DEFINITIONS` argument
to the `common` function. Both `NAME` and `NAME=EXPANSION` forms are supported.

[preprocessor definitions]: https://en.cppreference.com/w/cpp/preprocessor/replace#.23define_directives

### Language version

For [top level project][]s, the `CXX_STANDARD` argument to the `common`
function sets the [`CXX_STANDARD`][] property applied to configured targets
([`CXX_STANDARD_REQUIRED`][] is always set to `ON`, [`CXX_EXTENSIONS`][] is
always set to `OFF`).

[`CXX_STANDARD`]: https://cmake.org/cmake/help/v3.14/prop_tgt/CXX_STANDARD.html
[`CXX_STANDARD_REQUIRED`]: https://cmake.org/cmake/help/v3.14/prop_tgt/CXX_STANDARD_REQUIRED.html
[`CXX_EXTENSIONS`]: https://cmake.org/cmake/help/v3.14/prop_tgt/CXX_EXTENSIONS.html

### Build options

For [top level project][]s, aggressive warnings are enabled and treated as
errors.

For projects compiled with [GCC][] or [Clang][], [`-Wshadow`][] is enabled by
default, but can be disabled by passing `DISABLE_WSHADOW` to the `common`
function.

For projects compiled with [MSVC][], [`/Zc:__cplusplus`][] is enabled.

If supported, [interprocedural optimization][] (also known as link-time
optimization) is enabled.

For projects compiled with the `Debug` [build type][] with [GCC][] or
[Clang][], [address sanitizer][] ([wiki][address sanitizer wiki]), [leak
sanitizer][] ([wiki][leak sanitizer wiki]), and [undefined behavior
sanitizer][] are linked into all targets. The sanitizers can be disabled by
passing `DISABLE_SANITIZERS` to the `common` function. Suppression files that
match the [glob][]s `*.asan.supp`, `*.lsan.supp`, and `*.ubsan.supp`
respectively in the repository root are automatically used.

[GCC]: https://gcc.gnu.org
[Clang]: https://clang.llvm.org
[`-Wshadow=`]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wshadow
[MSVC]: https://visualstudio.microsoft.com/vs/
[`/Zc:__cplusplus`]: https://learn.microsoft.com/en-us/cpp/build/reference/zc-cplusplus
[interprocedural optimization]: https://en.wikipedia.org/wiki/Interprocedural_optimization
[build type]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_BUILD_TYPE.html
[address sanitizer]: https://clang.llvm.org/docs/AddressSanitizer.html
[address sanitizer wiki]: https://github.com/google/sanitizers/wiki/AddressSanitizer
[leak sanitizer]: https://clang.llvm.org/docs/LeakSanitizer.html
[leak sanitizer wiki]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
[undefined behavior sanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
[glob]: https://en.wikipedia.org/wiki/Glob_(programming)

### Tools

For [top level project][]s compiled with the `Debug` [build type][],
[Cppcheck][], [Clang-Tidy][], and [Include What You Use][] are automatically
configured if present on the system. The tools can be disabled by passing the
`DISABLE_CPPCHECK`, `DISABLE_CLANG_TIDY`, and/or `DISABLE_INCLUDE_WHAT_YOU_USE`
options, respectively, to the `common` function. CppCheck suppressions list
files that match the [glob][] `.cppcheck.supp`, a Clang-Tidy configuration file
named `.clang-tidy`, and Include What You Use [mapping files][] that match the
[glob][] `*.iwyu.imp`, in the repository root, are automatically used.

[Cppcheck]: https://cppcheck.sourceforge.io
[Clang-Tidy]: https://clang.llvm.org/extra/clang-tidy
[Include What You Use]: https://include-what-you-use.org
[mapping files]: https://github.com/include-what-you-use/include-what-you-use/blob/0.20/docs/IWYUMappings.md

### Testing

For [top level project][]s, [CTest][] is automatically configured and can be
run with [`ctest`][], see the [`BUILDING.md`][] auxiliary file.

[CTest]: https://cmake.org/cmake/help/v3.14/module/CTest.html
[`ctest`]: https://cmake.org/cmake/help/v3.14/manual/ctest.1.html
[`BUILDING.md`]: BUILDING.md

### Packaging

For [top level project][]s, [CPack][] is automatically configured and can be
run with [`cpack`][], see the [`BUILDING.md`][] auxiliary file.

[CPack]: https://cmake.org/cmake/help/v3.14/module/Pack.html
[`cpack`]: ttps://cmake.org/cmake/help/v3.14/manual/cpack.1.html

## Auxiliary files

This repository includes some files besides [`common.cmake`][] that may be of
use:

-   [`BUILDING.md`][]: Instructions to build a project that uses
    [`cmake-common`][].

-   [`.gitignore`][]: A configuration file for [Git][] that makes it ignore the
    created `_build` directory created when following the instructions in
    [`BUILDING.md`][].

-   [`.cppcheck.supp`][]: A suppressions list for [CppCheck][] with a set of
    suppressed warnings.

-   [`.clang-tidy`][]: A configuration file for [Clang-Tidy][] with a set of
    enabled and disabled warnings.

[`.gitignore`]: .gitignore
[`.cppcheck.supp`]: .cppcheck.supp
[`.clang-tidy`]: .clang-tidy

## License

Licensed under the [BSD 0-Clause License][] unless otherwise noted, see the
[`LICENSE`][] file.

[BSD 0-Clause License]: https://choosealicense.com/licenses/0bsd/
[`LICENSE`]: LICENSE
