-
Notifications
You must be signed in to change notification settings - Fork 0
ExternalProject Superbuild
Use CMake ExternalProject when Protocyte and the consuming application must have separate configure, cache, build, and install boundaries.
This is an isolation-oriented alternative to the recommended FetchContent workflow.
ExternalProject_Add() performs its configure and build steps after the parent superbuild has configured. A Protocyte prefix produced by an external project therefore cannot satisfy find_package(protocyte) in the parent configure.
Use this dependency chain:
superbuild
|-- protocyte_external
| |-- configures Protocyte independently
| `-- installs a private CMake prefix
`-- application_external
|-- depends on protocyte_external
|-- configures after the prefix exists
`-- uses find_package(protocyte CONFIG REQUIRED)
Do not call find_package(protocyte) from the superbuild itself.
protocyte-superbuild/
|-- CMakeLists.txt
`-- application/
|-- CMakeLists.txt
|-- main.cpp
`-- proto/
`-- reading.proto
The application sources can be copied from Getting Started. Only the CMake integration changes.
Create the top-level CMakeLists.txt:
cmake_minimum_required(VERSION 3.24)
project(protocyte_superbuild LANGUAGES NONE)
include(ExternalProject)
set(
PROTOCYTE_PRIVATE_PREFIX
"${CMAKE_BINARY_DIR}/protocyte-prefix"
)
set(superbuild_config_args)
if(NOT CMAKE_CONFIGURATION_TYPES AND CMAKE_BUILD_TYPE)
list(
APPEND superbuild_config_args
"-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
)
endif()
ExternalProject_Add(
protocyte_external
PREFIX "${CMAKE_BINARY_DIR}/protocyte"
GIT_REPOSITORY https://github.com/anthonyprintup/protocyte.git
GIT_TAG 9bae6fe8bf78a47a6356dc1fdc1e0ab8baa97d14
UPDATE_DISCONNECTED TRUE
INSTALL_DIR "${PROTOCYTE_PRIVATE_PREFIX}"
CMAKE_ARGS
${superbuild_config_args}
"-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>"
"-DPROTOCYTE_INSTALL:BOOL=ON"
)
ExternalProject_Add(
application_external
PREFIX "${CMAKE_BINARY_DIR}/application-prefix"
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/application"
BINARY_DIR "${CMAKE_BINARY_DIR}/application"
DEPENDS protocyte_external
BUILD_ALWAYS TRUE
CMAKE_ARGS
${superbuild_config_args}
"-DCMAKE_PREFIX_PATH:PATH=${PROTOCYTE_PRIVATE_PREFIX}"
"-DPROTOCYTE_FETCH_PROTOBUF:BOOL=ON"
INSTALL_COMMAND ""
)The Protocyte project installs into a build-private prefix. The application receives that prefix through its own CMAKE_PREFIX_PATH; it does not inherit Protocyte targets or cache entries from the superbuild.
BUILD_ALWAYS TRUE lets the application's own build system recheck source
dependencies on every superbuild invocation. Without it, ExternalProject's
completed build stamp could hide edits made under the local application
source tree.
The full commit SHA is intentional. Pin a reviewed immutable commit until releases exist, then prefer an immutable release tag.
Create application/CMakeLists.txt:
cmake_minimum_required(VERSION 3.24)
project(protocyte_external_application LANGUAGES CXX)
find_package(protocyte CONFIG REQUIRED)
protocyte_add_proto_library(
TARGET application_proto
ALIAS application::proto
PROTO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/proto"
DISCOVER
HOSTED_ALLOCATOR
)
add_executable(protocyte_external_application main.cpp)
target_link_libraries(
protocyte_external_application
PRIVATE application::proto
)
target_compile_features(
protocyte_external_application
PRIVATE cxx_std_20
)
enable_testing()
add_test(
NAME protocyte_external_project_round_trip
COMMAND protocyte_external_application
)The installed package defaults PROTOCYTE_FETCH_PROTOBUF to OFF. The superbuild explicitly passes ON to the application so a native build can fetch a pinned protobuf fallback when the compiler or import tree is absent.
For a controlled or offline build, leave that option off and pass explicit tool paths instead.
cmake -S . -B build
cmake --build build --config Release --target application_external
ctest --test-dir build\application -C Release --output-on-failurecmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --target application_external
ctest --test-dir build/application --output-on-failureBuilding application_external first builds and installs protocyte_external, then configures and builds the application.
The installed prefix is located at:
build/protocyte-prefix/
The application build tree is located at:
build/application/
A successful test ends with:
100% tests passed, 0 tests failed out of 1
External projects have independent CMake caches. A Python3_EXECUTABLE value in the superbuild is not inherited automatically.
Add it to the application external project's CMAKE_ARGS:
ExternalProject_Add(
application_external
# ...
CMAKE_ARGS
${superbuild_config_args}
"-DCMAKE_PREFIX_PATH:PATH=${PROTOCYTE_PRIVATE_PREFIX}"
"-DPROTOCYTE_FETCH_PROTOBUF:BOOL=ON"
"-DPython3_EXECUTABLE:FILEPATH=/path/to/python3.12"
INSTALL_COMMAND ""
)The application configure uses Python to provision the generator from the installed Protocyte prefix.
A fully offline superbuild must control both stages:
- provide an existing Protocyte source checkout to the install stage;
- provide the application stage with a compatible plugin, host
protoc, and protobuf import tree.
Replace the Git download fields in protocyte_external with:
SOURCE_DIR "/path/to/protocyte"
DOWNLOAD_COMMAND ""
UPDATE_COMMAND ""Pass the tool paths to application_external:
CMAKE_ARGS
${superbuild_config_args}
"-DCMAKE_PREFIX_PATH:PATH=${PROTOCYTE_PRIVATE_PREFIX}"
"-DPROTOCYTE_FETCH_PROTOBUF:BOOL=OFF"
"-DPROTOCYTE_PLUGIN_EXECUTABLE:FILEPATH=/path/to/protoc-gen-protocyte"
"-DProtobuf_PROTOC_EXECUTABLE:FILEPATH=/path/to/protoc"
"-DPROTOCYTE_PROTOBUF_IMPORT_DIR:PATH=/path/to/protobuf/src"If the superbuild already made Protocyte available, obtain the plugin path from the public API rather than duplicating provisioning or reading an internal global property:
protocyte_get_host_tools(PLUGIN_EXECUTABLE_VAR protocyte_plugin)
ExternalProject_Add(
application_external
# ...
CMAKE_ARGS
"-DPROTOCYTE_PLUGIN_EXECUTABLE:FILEPATH=${protocyte_plugin}"
)The child validates the supplied plugin against its own Protocyte package version. Because a managed plugin normally lives under the parent build tree, the child shares that build tree's lifetime.
The checked example also accepts
-DPROTOCYTE_SOURCE_DIR=/path/to/protocyte. That cache variable replaces the
Git download with the supplied source tree and is how repository tests exercise
the current checkout. Explicit plugin, protoc, protobuf import, and Python
variables supplied to the superbuild are forwarded to the dependent
application configure.
PROTOCYTE_PROTOBUF_IMPORT_DIR must contain google/protobuf/descriptor.proto.
Treat the two external projects separately:
- the Protocyte install contains architecture-independent CMake files, Python sources, protobuf options, and C++ headers;
- the application external project owns the target toolchain and generated C++ build;
- code generation still requires a concrete
protocthat runs on the build host.
Pass the target toolchain file only to application_external unless the Protocyte install stage has an independent reason to use it:
"-DCMAKE_TOOLCHAIN_FILE:FILEPATH=/path/to/target-toolchain.cmake"Also pass a host-runnable Protobuf_PROTOC_EXECUTABLE. Protocyte does not build a host compiler with the target toolchain or invoke one through CROSSCOMPILING_EMULATOR.
Change the pinned GIT_TAG, reconfigure the superbuild, and rebuild application_external.
Because UPDATE_DISCONNECTED is enabled, repeated builds do not contact the remote merely to check for updates. Changing the declared revision still gives CMake an explicit reason to update the external source.
Protocyte is pre-1.0. Regenerate and retest all checked outputs when changing the pin.
Compared with FetchContent, this design provides:
- separate CMake caches;
- an explicit install boundary;
- no Protocyte targets in the superbuild;
- easier reuse of one private prefix across dependent external consumers.
It also introduces:
- two configure phases;
- a longer first build;
- explicit forwarding for toolchains, Python, and other cache settings;
- more complicated IDE integration.
Use FetchContent unless one of these isolation properties is required.
The repository's tested version of this layout lives under:
Repository · Releases · Issues · Apache License 2.0
Canonical source: docs/wiki/