CMake (C / C++)¶
find_package(llvm-dsdl) provides dsdlc_generate(), which queries dsdlc for the exact input and output lists at configure time and produces a static library to link. Four lines of build file, and adding a definition needs no edit to any of them.
| Language | C |
| Build system | CMake |
| Idiom | B -- your project owns the manifest |
| Regeneration | Configure-time query (--list-outputs) |
Notes¶
Requires llvm-dsdl to have been installed, not merely built -- the package config and the function ship in the bin install component.
Editing a definition regenerates; adding or removing one re-runs configure first, so the file list stays honest. Removing one also deletes its generated header, because the function hands dsdlc a --prune-manifest -- a type you deleted stops existing instead of lingering on the include path.
One call is the simple case. A project with more than one namespace needs several, and they must not overlap: two calls defaulting to SUPPORT as-needed into one output directory both emit the runtime header, which Ninja refuses to build. Split with SUPPORT only / SUPPORT never, OMIT_DEPENDENCIES, and a BUILTIN call owning the shared standard types. dsdlc_generate() checks for overlap itself and fails at configure time naming both claimants.
The obj variant. -l obj runs the C backend and then compiles it, handing back the headers, the objects, and a .a. Reach for it when the generated code should be built once -- for a target triple that is not this host, or by a party who ships the archive rather than the schema. The archive is self-contained and the headers are published beside it in the same layout the c backend uses, so one call gives a complete interface. dsdlc_generate(LANGUAGE obj) hands back a target that carries both.
Prerequisites¶
| Tool | Why |
|---|---|
cmake |
configures and drives the build |
cc |
compiles the generated C and the round-trip program |
Commands¶
Run these from the recipe directory, with dsdl/ and src/ copied alongside it. This is the exact sequence CI runs.
# configure
cmake -S . -B build "-DCMAKE_PREFIX_PATH=$LLVM_DSDL_PREFIX"
# build
cmake --build build
# round-trip
./build/roundtrip
# round-trip (prebuilt archive)
./build/roundtrip_prebuilt
The types this builds¶
The whole lanyard namespace -- twenty-four definitions, browsable from the showroom overview, where each one is paired with its wire-layout facts and a declaration excerpt in every language.
The build files¶
CMakeLists.txt¶
cmake_minimum_required(VERSION 3.20)
project(lanyard_c_cmake C)
# find_package brings in the imported target llvm-dsdl::dsdlc and the dsdlc_generate() function.
# Point CMAKE_PREFIX_PATH at wherever llvm-dsdl was installed, or let it be found on the default
# search path if it went to /usr or /usr/local.
find_package(llvm-dsdl REQUIRED)
# One call. It asks dsdlc at configure time what the run would read and what it would produce, hands
# CMake the exact lists, and -- for the C and C++ backends -- builds a static library out of the
# generated sources with the output directory already on its interface include path.
#
# So there is no glob to keep in step, no stamp file, no hand-maintained list of generated files, and
# adding a definition to dsdl/lanyard/ is picked up on the next build with nothing edited here.
dsdlc_generate(lanyard
LANGUAGE c
NAMESPACE "${CMAKE_CURRENT_SOURCE_DIR}/dsdl/lanyard")
add_executable(roundtrip src/c/roundtrip.c)
target_link_libraries(roundtrip PRIVATE lanyard)
# --------------------------------------------------------------------------------------------------
# The obj backend: the same types as a prebuilt archive rather than as sources.
#
# `-l obj` runs the C backend and then compiles it, handing back the headers, the objects, and a
# `.a`. That is what you want when the generated code should be built once -- for a target triple
# that is not this host, or by a party who ships the archive rather than the schema.
#
# One call, like the source build above: the headers are declared outputs published beside the
# archive, so linking the target brings its include path with it.
dsdlc_generate(lanyard_prebuilt
LANGUAGE obj
NAMESPACE "${CMAKE_CURRENT_SOURCE_DIR}/dsdl/lanyard"
# Required for obj. It selects the codegen strategy, not the wire format -- DSDL is little-endian
# on every target either way. Add --target-triple here to build the archive for a different one,
# after which it only links into a build using that same toolchain.
OPTIONS --target-endianness little)
add_executable(roundtrip_prebuilt src/c/roundtrip.c)
target_link_libraries(roundtrip_prebuilt PRIVATE lanyard_prebuilt)