clawdforge/clients/cpp/CMakeLists.txt
Kayos bae34a7701 clients/cpp: initial C++ SDK for clawdforge
Modern C++20 SDK targeting CMake 3.20+. Library is RAII / move-only,
backed by a libcurl easy handle per Client. Public surface is throwing;
exception hierarchy under clawdforge::Error covers AuthError, APIError
(carries status_code + body), TransportError, and ProtocolError.

Dependencies: libcurl + nlohmann/json (FetchContent or find_package).
Tests use cpp-httplib's in-process server + doctest. 12 test cases /
70 assertions cover healthz, run with JSON / text / 502 / files,
multipart upload, full token CRUD, transport failure, URL normalization,
and bad-input rejection. Clean under -Wall -Wextra -Wpedantic -Werror,
ASan + UBSan clean (no leaks, no UB).

upload_file streams via curl_mime_filedata — no in-memory buffering.

Install path produces clawdforge::clawdforge target consumable via
target_link_libraries; FetchContent path mirrors the existing Rust /
Go SDK ergonomics. MIT licensed.
2026-04-28 23:02:51 -07:00

204 lines
6.3 KiB
CMake

# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.20)
project(clawdforge
VERSION 0.1.0
DESCRIPTION "C++ SDK for the clawdforge HTTP API"
LANGUAGES CXX
)
# ---- options ----------------------------------------------------------------
option(CLAWDFORGE_BUILD_TESTS "Build unit tests" ON)
option(CLAWDFORGE_BUILD_EXAMPLES "Build examples" ON)
option(CLAWDFORGE_WARNINGS_AS_ERRORS "Treat warnings as errors" ON)
# When consumed via add_subdirectory, default the extras off unless the user
# explicitly opts in. Top-level builds (the SDK's own CI / dev loop) keep them
# on so we exercise them.
if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(CLAWDFORGE_BUILD_TESTS OFF)
set(CLAWDFORGE_BUILD_EXAMPLES OFF)
endif()
# ---- standard / flags -------------------------------------------------------
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE)
endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
include(FetchContent)
# ---- dependencies -----------------------------------------------------------
# nlohmann/json — try find_package first, fall back to FetchContent.
find_package(nlohmann_json 3.10 QUIET)
if(NOT nlohmann_json_FOUND)
message(STATUS "clawdforge: nlohmann_json not installed, fetching v3.11.3")
FetchContent_Declare(nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3
GIT_SHALLOW TRUE
)
set(JSON_BuildTests OFF CACHE INTERNAL "")
set(JSON_Install ON CACHE INTERNAL "")
FetchContent_MakeAvailable(nlohmann_json)
endif()
# libcurl — system-installed.
find_package(CURL REQUIRED)
# ---- library target ---------------------------------------------------------
add_library(clawdforge)
add_library(clawdforge::clawdforge ALIAS clawdforge)
target_sources(clawdforge
PRIVATE
src/client.cpp
src/http.cpp
)
target_include_directories(clawdforge
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(clawdforge
PUBLIC
nlohmann_json::nlohmann_json
PRIVATE
CURL::libcurl
)
target_compile_features(clawdforge PUBLIC cxx_std_20)
set_target_properties(clawdforge PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
POSITION_INDEPENDENT_CODE ON
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
EXPORT_NAME clawdforge
)
# Warnings -- private so consumers don't inherit our flags.
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(clawdforge PRIVATE
-Wall -Wextra -Wpedantic
-Wshadow -Wconversion -Wsign-conversion
-Wnon-virtual-dtor -Wold-style-cast
)
if(CLAWDFORGE_WARNINGS_AS_ERRORS)
target_compile_options(clawdforge PRIVATE -Werror)
endif()
elseif(MSVC)
target_compile_options(clawdforge PRIVATE /W4 /permissive-)
if(CLAWDFORGE_WARNINGS_AS_ERRORS)
target_compile_options(clawdforge PRIVATE /WX)
endif()
endif()
# ---- install ----------------------------------------------------------------
install(DIRECTORY include/clawdforge
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.hpp"
)
install(TARGETS clawdforge
EXPORT clawdforge-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(EXPORT clawdforge-targets
FILE clawdforge-targets.cmake
NAMESPACE clawdforge::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/clawdforge
)
configure_package_config_file(
cmake/clawdforge-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/clawdforge-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/clawdforge
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/clawdforge-config-version.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/clawdforge-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/clawdforge-config-version.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/clawdforge
)
# ---- examples ---------------------------------------------------------------
if(CLAWDFORGE_BUILD_EXAMPLES)
add_executable(clawdforge_basic_example examples/basic.cpp)
target_link_libraries(clawdforge_basic_example PRIVATE clawdforge::clawdforge)
endif()
# ---- tests ------------------------------------------------------------------
if(CLAWDFORGE_BUILD_TESTS)
enable_testing()
# cpp-httplib for an in-process mock server. Prefer system / installed copy.
find_package(httplib QUIET CONFIG)
if(NOT httplib_FOUND)
message(STATUS "clawdforge: cpp-httplib not installed, fetching v0.15.3")
FetchContent_Declare(cpp_httplib
GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git
GIT_TAG v0.15.3
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(cpp_httplib)
endif()
# doctest — single-header, fastest to compile of the popular options.
find_package(doctest QUIET CONFIG)
if(NOT doctest_FOUND)
message(STATUS "clawdforge: doctest not installed, fetching v2.4.11")
FetchContent_Declare(doctest
GIT_REPOSITORY https://github.com/doctest/doctest.git
GIT_TAG v2.4.11
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(doctest)
endif()
add_executable(clawdforge_tests tests/test_client.cpp)
target_link_libraries(clawdforge_tests
PRIVATE
clawdforge::clawdforge
httplib::httplib
doctest::doctest
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(clawdforge_tests PRIVATE
-Wall -Wextra
# Designated initializers in C++20 don't need to set every member.
-Wno-missing-field-initializers
# CHECK_THROWS_AS expands to a discarded-value expression; the
# `[[nodiscard]]` on Client methods makes that legitimately noisy.
-Wno-unused-result
)
endif()
add_test(NAME clawdforge_tests COMMAND clawdforge_tests)
endif()