CMake helpers

Consume apiary from CMake via find_package(Apiary) (installed) or add_subdirectory (vendored). Both provide:

  • apiary::apiary — the codegen executable.

  • apiary::annotations — an INTERFACE target carrying the APIARY_* macro header; link it instead of hardcoding the include path.

…plus the helper functions below (lifted from their in-source documentation).

apiary_detect_toolchain

Probe ``CMAKE_CXX_COMPILER`` (or a conda clang++) for the include paths
libtooling needs and cache them as:
  APIARY_RESOURCE_DIR        - clang -resource-dir (builtin headers)
  APIARY_EXTRA_ISYSTEM       - active conda env's include dir (third-party)
  APIARY_CXX_INCLUDE_DIRS    - the compiler's C++ stdlib search dirs

Without these even ``#include <string>`` fails when the build compiler is
gcc (libstdc++) rather than the clang that backs the apiary binary.

apiary_collect_usage_requirements

Recursively collect BUILD_INTERFACE include directories AND
INTERFACE_COMPILE_DEFINITIONS reachable from <target> via
INTERFACE_LINK_LIBRARIES. CMake has no built-in for this; the walk is
reliable since usage requirements are set explicitly via
target_link_libraries / target_include_directories.

  apiary_collect_usage_requirements(<target> INCLUDES_OUT <v> DEFINES_OUT <v>)

Genex-wrapped entries are unwrapped for BUILD_INTERFACE and dropped
otherwise (config-conditional values can't be evaluated at configure time).

apiary_add_bindings

Emit the codegen custom command(s) that run apiary on one set of headers.

  apiary_add_bindings(
      HEADERS         <abs header...>      # parsed by apiary (positional)
      SOURCE_INCLUDES <relative name...>   # --source-include each
      REGISTER_FUNCTION <name>             # --register-function (binding TU)
      MODULE          <name>               # --module (docs json; default "module")
      DEPENDS_TARGETS <target...>          # usage requirements -> -I / -D
      OUTPUT_DIR      <dir>                # where generated files land
      OUTPUT_NAME     <stem>               # base filename for outputs
      CXX_STANDARD    <n>                  # default 17
      MAX_DEFS_PER_TU <n>                  # split binding into shard TUs of ~n .def's
      EXTRA_FLAGS     <flag...>            # extra -I/-D/... after --
      EXTRA_DEPENDS   <file...>            # extra DEPENDS (e.g. Defines.hpp)
      BINDING                              # emit the pybind TU (+ stub)
      DOCS_JSON                            # emit the docs-json
      OUT_BINDING <v>  OUT_STUB <v>  OUT_DOCS_JSON <v>
  )

MAX_DEFS_PER_TU > 0 splits the generated binding into several smaller TUs
(``<name>_pybind.shard<k>.cpp``) so a heavily instantiated module doesn't
compile as one TU large enough to exhaust memory. The shard count is
discovered at configure time by running ``apiary --plan`` (so the OUT_BINDING
list and the custom-command OUTPUTs are exact). This needs the apiary binary
to already exist at configure time — true under find_package(Apiary); in
add_subdirectory mode the tool isn't built yet, so sharding is skipped (with
a status message) and a single TU is emitted.

Computes flags = APIARY_SYSTEM_FLAGS + usage-requirements(DEPENDS_TARGETS) +
EXTRA_FLAGS + -std, and sets the requested OUT_* variables in the caller's
scope. Requires apiary_detect_toolchain() to have run.

apiary_aggregate_extension

Assemble per-module bindings into one Python extension.

  apiary_aggregate_extension(
      NAME <target>                # pybind11 module target to create
      MAIN <main.cpp>              # consumer's PYBIND11_MODULE source
      BINDINGS <generated tu...>   # per-module binding TUs (from apiary_add_bindings)
      MODULES <name...>            # modules to register
      REGISTER_PREFIX <p>          # default apiary_register_
      MODULES_HEADER <path>        # generated header declaring <prefix>all()
      MODULES_INCLUDE_DIR <dir>    # added to the target so MAIN finds the header
      # optional .pyi aggregation:
      STUBS <pyi...>  STUBS_TARGET <name>  FRAG_DIR <d>  PKG_DIR <d>
      PY_HELPERS_DIR <d>  PY_HELPER_DEPENDS <file...>
      # optional consumer-provided overlay for runtime-patched members the
      # codegen can't see (content + target-class regex are the caller's):
      STUB_OVERLAY <file.pyi>  STUB_OVERLAY_CLASS_REGEX <regex>
      # optional docs render (built on demand, not part of ALL):
      DOCS_JSON <json...>  DOCS_TARGET <name>  DOCS_OUTDIR <d>
  )

Generates the register header, creates the pybind11 module (the consumer
configures output name / linkage / packaging afterward), and — when the
optional groups are given — wires the stub-aggregation (ALL) and docs-render
(on-demand) targets using Apiary's bundled scripts (APIARY_SCRIPTS_DIR).