callonce is a single header: src/memoized_invoke.hh. There is nothing to compile — the library is one #include away once the file is on your include path. This page covers four ways to get it there, from "copy one file" to a full CMake package.

Prerequisites

  • A C++20 compiler with <atomic> wait/notify_all support: GCC ≥ 11, Clang ≥ 14, MSVC ≥ 19.29. No compiler-specific extensions are used.
  • CMake ≥ 3.20 — only if you build the tests or the examples.
  • GoogleTest — only for the unit test suite, and only in a standalone build.

There are no runtime dependencies. The header pulls in <atomic>, <functional>, <optional>, <tuple>, <type_traits> and <utility> from the standard library and nothing else.

Mode 1 — Copy the header

cp src/memoized_invoke.hh third_party/include/
#include <memoized_invoke.hh>
using namespace fedem::utility;

That is the whole integration. The single-header form is the intended path for most projects — the file is under 700 lines including the licence and the Doxygen comments.

Mode 2 — Embedded (add_subdirectory)

Drop the extracted directory into your tree (under libs/external/callonce/ or as a git submodule) and add:

add_subdirectory(libs/external/callonce)

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE callonce::callonce)

callonce::callonce is an INTERFACE target — linking it just puts src/ on your include path and requests cxx_std_20. In embedded mode callonce detects it is not the top-level project (CMAKE_CURRENT_SOURCE_DIR != CMAKE_SOURCE_DIR) and turns its tests, examples and docs target off automatically. The host build type is left untouched.

Mode 3 — Standalone install

cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local
cmake --build build
sudo cmake --install build

This installs the header to <prefix>/include/ and a callonce-config.cmake package file to <prefix>/lib/cmake/callonce/. From a consumer:

find_package(callonce CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE callonce::callonce)

A standalone build also enables the GoogleTest unit suites (TESTING=ON) and the examples/ programs with their ctest smoke tests (EXAMPLE=ON):

ctest --test-dir build --output-on-failure

Mode 4 — Conan

A recipe ships as conanfile.py (a header-library package — no binaries, so one package id for every configuration). In your consumer's conanfile.txt:

[requires]
callonce/1.0.0

[generators]
CMakeDeps
CMakeToolchain
find_package(callonce CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE callonce::callonce)

The recipe's version is read from the single project(... VERSION ...) line in CMakeLists.txt, so it always matches the release.

Verifying the install

This program should compile, link and exit 0:

#include <memoized_invoke.hh>

int main()
{
    int calls = 0;
    fedem::utility::memoized_invoke once( [&calls]{ return ++calls; } );
    return once() == 1 && once() == 1 ? 0 : 1;   // ran once, cached
}
g++ -std=c++20 smoke.cpp -Isrc -o smoke && ./smoke && echo OK

If that runs, callonce is available and you can move on to the Getting Started guide.

Building the API docs

With Doxygen (and, for the graphs, Graphviz dot) installed, the docs CMake target writes the HTML tree — the same one published at /api — to build/docs/html/:

cmake -B build
cmake --build build --target docs
xdg-open build/docs/html/index.html