From ed6c1b05bfa53ec2e30a1f10dc723ec95c477306 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:49:33 -0500 Subject: [PATCH 1/6] refactor: move xo::facet::typeseq to xo-reflectutil/ prep for adding xo-arena/ --- CMakeLists.txt | 2 +- xo-facet/CMakeLists.txt | 4 + xo-facet/cmake/xo_facetConfig.cmake.in | 4 +- xo-facet/include/xo/facet/typeseq.hpp | 80 ++--------------- xo-reflectutil/CMakeLists.txt | 2 +- .../cmake/xo_reflectutilConfig.cmake.in | 7 +- .../include/xo/reflectutil/typeseq.hpp | 88 +++++++++++++++++++ 7 files changed, 103 insertions(+), 84 deletions(-) create mode 100644 xo-reflectutil/include/xo/reflectutil/typeseq.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bef04e3b..7232c203 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,13 +77,13 @@ set(DOX_EXCLUDE_PATTERNS [=[ add_subdirectory(xo-cmake) add_subdirectory(xo-facet) # sep iface,data add_subdirectory(xo-indentlog) +add_subdirectory(xo-reflectutil) # header-only reflect support add_subdirectory(xo-allocutil) add_subdirectory(xo-refcnt) add_subdirectory(xo-subsys) add_subdirectory(xo-randomgen) add_subdirectory(xo-flatstring) add_subdirectory(xo-pyutil) -add_subdirectory(xo-reflectutil) add_subdirectory(xo-reflect) add_subdirectory(xo-pyreflect) add_subdirectory(xo-ratio) diff --git a/xo-facet/CMakeLists.txt b/xo-facet/CMakeLists.txt index e1804f25..ad8a4cb4 100644 --- a/xo-facet/CMakeLists.txt +++ b/xo-facet/CMakeLists.txt @@ -25,6 +25,10 @@ add_subdirectory(utest) set(SELF_LIB xo_facet) xo_add_headeronly_library(${SELF_LIB}) + +# note: dependencies here must coordinate with cmake/xo_facetConfig.cmake.in +xo_headeronly_dependency(${SELF_LIB} xo_reflectutil) + xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) diff --git a/xo-facet/cmake/xo_facetConfig.cmake.in b/xo-facet/cmake/xo_facetConfig.cmake.in index c25a5c24..88709824 100644 --- a/xo-facet/cmake/xo_facetConfig.cmake.in +++ b/xo-facet/cmake/xo_facetConfig.cmake.in @@ -1,7 +1,7 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) -#find_dependency(indentlog) -#find_dependency(xo_flatstring) +# note: dependencies here must coordinate with xo-facet/CMakeLists.txt +find_dependency(xo_reflectutil) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/xo-facet/include/xo/facet/typeseq.hpp b/xo-facet/include/xo/facet/typeseq.hpp index ab85821c..23b84a92 100644 --- a/xo-facet/include/xo/facet/typeseq.hpp +++ b/xo-facet/include/xo/facet/typeseq.hpp @@ -1,87 +1,19 @@ /** @file typeseq.hpp + * + * @brief Re-export typeseq from xo-arena for backwards compatibility * * @author Roland Conybeare, Dec 2025 **/ #pragma once -#include -#include +#include namespace xo { namespace facet { - /** - * Tag here so we can preserve header-only implementation - * and still have static variable - */ - template - struct typeseq_impl { - explicit typeseq_impl(int32_t s) : seqno_{s} {} - - /** Can't have this be constexpr. - * We need ids in shared libraries to be generated - * at load time to avoid false positives - * - * Return unique id number for each type. - * Numbers are sequentially allocated, so can use - * as vector indices - * - * Conversely note that built-in typeinfo may - * return false negatives across library boundaries - * when using clang. - **/ - template - static typeseq_impl id() { - static bool armed = true; - static int32_t id = 0; - - if (armed) { - armed = false; - id = ++s_next_id; - } - - return typeseq_impl(id); - - } - - /** 'anonymous' sentinel type. - * Niche uses for this, e.g. untyped allocator - **/ - static typeseq_impl anon() { - return typeseq_impl(-1); - } - - int32_t seqno() const { return seqno_; } - - private: - static int32_t s_next_id; - - int32_t seqno_; - }; - - template - int32_t typeseq_impl::s_next_id = 0; - - template - inline bool - operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { - return lhs.seqno() == rhs.seqno(); - } - - template - inline bool - operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { - return lhs.seqno() != rhs.seqno(); - } - - template - inline std::ostream & - operator<<(std::ostream & s, const typeseq_impl & x) { - s << x.seqno(); - return s; - } - - using typeseq = typeseq_impl<>; + // Re-export from xo::arena namespace + using xo::reflect::typeseq_impl; + using xo::reflect::typeseq; } } /*namespace xo*/ diff --git a/xo-reflectutil/CMakeLists.txt b/xo-reflectutil/CMakeLists.txt index a231f5dc..4f3f6dee 100644 --- a/xo-reflectutil/CMakeLists.txt +++ b/xo-reflectutil/CMakeLists.txt @@ -39,7 +39,7 @@ xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets # ---------------------------------------------------------------- # dependencies -xo_headeronly_dependency(${SELF_LIB} xo_flatstring) +#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) #xo_headeronly_dependency(${SELF_LIB} randomgen) # etc.. diff --git a/xo-reflectutil/cmake/xo_reflectutilConfig.cmake.in b/xo-reflectutil/cmake/xo_reflectutilConfig.cmake.in index b7a5a0a2..26df0fc7 100644 --- a/xo-reflectutil/cmake/xo_reflectutilConfig.cmake.in +++ b/xo-reflectutil/cmake/xo_reflectutilConfig.cmake.in @@ -6,12 +6,7 @@ include(CMakeFindDependencyMacro) # must coordinate with xo_dependency() calls # in xo-reactor/src/reactor/CMakeLists.txt # -find_dependency(xo_flatstring) -#find_dependency(subsys) -#find_dependency(Eigen3) -#find_dependency(webutil) -#find_dependency(printjson) -#find_dependency(callback) +#find_dependency(xo_flatstring) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") diff --git a/xo-reflectutil/include/xo/reflectutil/typeseq.hpp b/xo-reflectutil/include/xo/reflectutil/typeseq.hpp new file mode 100644 index 00000000..dd0b869a --- /dev/null +++ b/xo-reflectutil/include/xo/reflectutil/typeseq.hpp @@ -0,0 +1,88 @@ +/** @file typeseq.hpp + * + * @author Roland Conybeare, Dec 2025 + **/ + +#pragma once + +#include +#include + +namespace xo { + namespace reflect { + /** + * Tag here so we can preserve header-only implementation + * and still have static variable + */ + template + struct typeseq_impl { + explicit typeseq_impl(int32_t s) : seqno_{s} {} + + /** Can't have this be constexpr. + * We need ids in shared libraries to be generated + * at load time to avoid false positives + * + * Return unique id number for each type. + * Numbers are sequentially allocated, so can use + * as vector indices + * + * Conversely note that built-in typeinfo may + * return false negatives across library boundaries + * when using clang. + **/ + template + static typeseq_impl id() { + static bool armed = true; + static int32_t id = 0; + + if (armed) { + armed = false; + id = ++s_next_id; + } + + return typeseq_impl(id); + + } + + /** 'anonymous' sentinel type. + * Niche uses for this, e.g. untyped allocator + **/ + static typeseq_impl anon() { + return typeseq_impl(-1); + } + + int32_t seqno() const { return seqno_; } + + private: + static int32_t s_next_id; + + int32_t seqno_; + }; + + template + int32_t typeseq_impl::s_next_id = 0; + + template + inline bool + operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() == rhs.seqno(); + } + + template + inline bool + operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() != rhs.seqno(); + } + + template + inline std::ostream & + operator<<(std::ostream & s, const typeseq_impl & x) { + s << x.seqno(); + return s; + } + + using typeseq = typeseq_impl<>; + } /*namespace reflect*/ +} /*namespace xo*/ + +/* end typeseq.hpp */ From 88ac4b0ceb1eb231599c8c2c0cbcd9480191b586 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:53:41 -0500 Subject: [PATCH 2/6] build: delay xo-facet order --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7232c203..3127d7ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,9 +75,9 @@ set(DOX_EXCLUDE_PATTERNS [=[ # in reverse topological order i.e. dependencies first add_subdirectory(xo-cmake) -add_subdirectory(xo-facet) # sep iface,data add_subdirectory(xo-indentlog) add_subdirectory(xo-reflectutil) # header-only reflect support +add_subdirectory(xo-facet) # sep iface,data add_subdirectory(xo-allocutil) add_subdirectory(xo-refcnt) add_subdirectory(xo-subsys) From 5bd216ce5dedcffc37e0cb31c02dc48a67d8786a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:54:33 -0500 Subject: [PATCH 3/6] xo-imgui: fix apple-only carveout --- xo-imgui/src/imgui/VulkanApp.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xo-imgui/src/imgui/VulkanApp.cpp b/xo-imgui/src/imgui/VulkanApp.cpp index dba09930..7e1e236a 100644 --- a/xo-imgui/src/imgui/VulkanApp.cpp +++ b/xo-imgui/src/imgui/VulkanApp.cpp @@ -90,8 +90,6 @@ VulkanApp::create_instance() #ifdef __APPLE__ // Add portability extension for MoltenVK (macOS) extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); -#else - static_assert(false, "expecting apple build"); #endif createInfo.enabledExtensionCount = extensions.size(); @@ -101,8 +99,6 @@ VulkanApp::create_instance() #ifdef __APPLE__ // CRITICAL: Enable portability enumeration flag for MoltenVK createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; -#else - static_assert(false, "expecting apple build"); #endif int result = vkCreateInstance(&createInfo, nullptr, &(this->instance_)); From 247d5d0b101eab13aee04d74798df7156f4e36fe Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 21:54:58 -0500 Subject: [PATCH 4/6] + xo-arena (empty) --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3127d7ae..51cf7907 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ set(DOX_EXCLUDE_PATTERNS [=[ add_subdirectory(xo-cmake) add_subdirectory(xo-indentlog) add_subdirectory(xo-reflectutil) # header-only reflect support +add_subdirectory(xo-arena) # arena allocator (DArena) add_subdirectory(xo-facet) # sep iface,data add_subdirectory(xo-allocutil) add_subdirectory(xo-refcnt) From 827de87a22de64d94a05237df3f05506e7da1872 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 22:15:33 -0500 Subject: [PATCH 5/6] xo-arena: empty scaffold (builds, but empty!) [WIP] --- xo-arena/CMakeLists.txt | 41 ++++++ xo-arena/cmake/xo-bootstrap-macros.cmake | 33 +++++ xo-arena/cmake/xo_arenaConfig.cmake.in | 12 ++ xo-arena/include/xo/arena/.gitkeep | 0 xo-cmake/bin/scaffold-headeronly | 167 +++++++++++++++++++++++ 5 files changed, 253 insertions(+) create mode 100644 xo-arena/CMakeLists.txt create mode 100644 xo-arena/cmake/xo-bootstrap-macros.cmake create mode 100644 xo-arena/cmake/xo_arenaConfig.cmake.in create mode 100644 xo-arena/include/xo/arena/.gitkeep create mode 100755 xo-cmake/bin/scaffold-headeronly diff --git a/xo-arena/CMakeLists.txt b/xo-arena/CMakeLists.txt new file mode 100644 index 00000000..70e8d6d9 --- /dev/null +++ b/xo-arena/CMakeLists.txt @@ -0,0 +1,41 @@ +# xo-arena/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_arena VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# header-only library + +set(SELF_LIB xo_arena) +xo_add_headeronly_library(${SELF_LIB}) +xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets) +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# input dependencies +# +# NOTE: dependency set here must be kept consistent with +# xo-arena/cmake/xo_arenaConfig.cmake.in + +#xo_headeronly_dependency(${SELF_LIB} xo_flatstring) + +# end CMakeLists.txt diff --git a/xo-arena/cmake/xo-bootstrap-macros.cmake b/xo-arena/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..2cf387e5 --- /dev/null +++ b/xo-arena/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,33 @@ +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + message(FATAL "could not find xo-cmake-config executable") +endif() + +if (NOT XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/xo-arena/cmake/xo_arenaConfig.cmake.in b/xo-arena/cmake/xo_arenaConfig.cmake.in new file mode 100644 index 00000000..b5c3cd5c --- /dev/null +++ b/xo-arena/cmake/xo_arenaConfig.cmake.in @@ -0,0 +1,12 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# note: changes to find_dependency() calls here +# must coordinate with xo_dependency() calls +# in CMakeLists.txt +# +#find_dependency(xo_flatstring) + +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/xo-arena/include/xo/arena/.gitkeep b/xo-arena/include/xo/arena/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/xo-cmake/bin/scaffold-headeronly b/xo-cmake/bin/scaffold-headeronly new file mode 100755 index 00000000..636dad47 --- /dev/null +++ b/xo-cmake/bin/scaffold-headeronly @@ -0,0 +1,167 @@ +#!/usr/bin/env bash +# +# scaffold-headeronly.sh - Create a new xo header-only subdirectory +# +# Usage: scaffold-headeronly.sh +# where is the short name (e.g., "arena" creates "xo-arena") +# + +set -euo pipefail + +usage() { + echo "Usage: $0 " + echo " Creates xo-/ with header-only library scaffolding" + echo "" + echo "Example: $0 arena" + echo " Creates xo-arena/CMakeLists.txt" + echo " xo-arena/cmake/xo-bootstrap-macros.cmake" + echo " xo-arena/cmake/xo_arenaConfig.cmake.in" + echo " xo-arena/include/xo/arena/" + exit 1 +} + +if [[ $# -ne 1 ]]; then + usage +fi + +NAME="$1" + +# Validate name: alphanumeric and underscores only +if [[ ! "$NAME" =~ ^[a-zA-Z][a-zA-Z0-9_]*$ ]]; then + echo "Error: name must start with letter and contain only alphanumeric/underscores" + exit 1 +fi + +# Derive names +DIR_NAME="xo-${NAME}" +LIB_NAME="xo_${NAME}" +PROJECT_NAME="xo_${NAME}" + +# Get script directory to find umbrella root +XO_UMBRELLA_ROOT=$(git rev-parse --show-toplevel) + +TARGET_DIR="${XO_UMBRELLA_ROOT}/${DIR_NAME}" + +if [[ -d "$TARGET_DIR" ]]; then + echo "Error: ${TARGET_DIR} already exists" + exit 1 +fi + +echo "Creating ${DIR_NAME} in ${XO_UMBRELLA_ROOT}..." + +# Create directories +mkdir -p "${TARGET_DIR}/cmake" +mkdir -p "${TARGET_DIR}/include/xo/${NAME}" + +# Create CMakeLists.txt +cat > "${TARGET_DIR}/CMakeLists.txt" << EOF +# ${DIR_NAME}/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(${PROJECT_NAME} VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(\${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# header-only library + +set(SELF_LIB ${LIB_NAME}) +xo_add_headeronly_library(\${SELF_LIB}) +xo_install_library4(\${SELF_LIB} \${PROJECT_NAME}Targets) +xo_export_cmake_config(\${PROJECT_NAME} \${PROJECT_VERSION} \${PROJECT_NAME}Targets) + +# ---------------------------------------------------------------- +# input dependencies +# +# NOTE: dependency set here must be kept consistent with +# ${DIR_NAME}/cmake/${LIB_NAME}Config.cmake.in + +#xo_headeronly_dependency(\${SELF_LIB} xo_flatstring) + +# end CMakeLists.txt +EOF + +# Create cmake/xo-bootstrap-macros.cmake +cat > "${TARGET_DIR}/cmake/xo-bootstrap-macros.cmake" << EOF +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=\$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if (("\${CMAKE_MODULE_PATH}" STREQUAL "") OR ("\${CMAKE_MODULE_PATH}" STREQUAL "prefix")) + message(FATAL "could not find xo-cmake-config executable") +endif() + +if (NOT XO_SUBMODULE_BUILD) + if (("\${CMAKE_MODULE_PATH}" STREQUAL "") OR ("\${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND \${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=\${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() +EOF + +# Create cmake/xo_${NAME}Config.cmake.in +cat > "${TARGET_DIR}/cmake/${LIB_NAME}Config.cmake.in" << EOF +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) + +# note: changes to find_dependency() calls here +# must coordinate with xo_dependency() calls +# in CMakeLists.txt +# +#find_dependency(xo_flatstring) + +include("\${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") +EOF + +# Create placeholder .gitkeep in include dir +touch "${TARGET_DIR}/include/xo/${NAME}/.gitkeep" + +echo "" +echo "Created ${DIR_NAME}/ with:" +echo " ${DIR_NAME}/CMakeLists.txt" +echo " ${DIR_NAME}/cmake/xo-bootstrap-macros.cmake" +echo " ${DIR_NAME}/cmake/${LIB_NAME}Config.cmake.in" +echo " ${DIR_NAME}/include/xo/${NAME}/" +echo "" +echo "Next steps:" +echo " 1. Add header files to ${DIR_NAME}/include/xo/${NAME}/" +echo " 2. Add ${DIR_NAME} to umbrella CMakeLists.txt" +echo " 3. Uncomment dependencies as needed in CMakeLists.txt and Config.cmake.in" From b378ac5c17b04ba21ef75c5ff32fd11f85fd0d41 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 5 Jan 2026 22:25:23 -0500 Subject: [PATCH 6/6] xo-cmake: scaffold-headeronly works for shared libs also --- xo-cmake/bin/scaffold-headeronly | 137 ++++++++++++++++++++++++++++--- 1 file changed, 126 insertions(+), 11 deletions(-) diff --git a/xo-cmake/bin/scaffold-headeronly b/xo-cmake/bin/scaffold-headeronly index 636dad47..b4455677 100755 --- a/xo-cmake/bin/scaffold-headeronly +++ b/xo-cmake/bin/scaffold-headeronly @@ -1,25 +1,63 @@ #!/usr/bin/env bash # -# scaffold-headeronly.sh - Create a new xo header-only subdirectory +# scaffold-headeronly - Create a new xo library subdirectory # -# Usage: scaffold-headeronly.sh +# Usage: scaffold-headeronly [--mode=headeronly|shared] # where is the short name (e.g., "arena" creates "xo-arena") # set -euo pipefail usage() { - echo "Usage: $0 " - echo " Creates xo-/ with header-only library scaffolding" + echo "Usage: $0 [--mode=headeronly|shared] " + echo " Creates xo-/ with library scaffolding" + echo "" + echo "Options:" + echo " --mode=headeronly Create header-only library (default)" + echo " --mode=shared Create shared library with src/ directory" echo "" echo "Example: $0 arena" echo " Creates xo-arena/CMakeLists.txt" echo " xo-arena/cmake/xo-bootstrap-macros.cmake" echo " xo-arena/cmake/xo_arenaConfig.cmake.in" echo " xo-arena/include/xo/arena/" + echo "" + echo "Example: $0 --mode=shared mylib" + echo " Creates xo-mylib/CMakeLists.txt" + echo " xo-mylib/cmake/xo-bootstrap-macros.cmake" + echo " xo-mylib/cmake/xo_mylibConfig.cmake.in" + echo " xo-mylib/include/xo/mylib/" + echo " xo-mylib/src/CMakeLists.txt" exit 1 } +# Default mode +MODE="headeronly" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --mode=*) + MODE="${1#--mode=}" + if [[ "$MODE" != "headeronly" && "$MODE" != "shared" ]]; then + echo "Error: --mode must be 'headeronly' or 'shared'" + exit 1 + fi + shift + ;; + --help|-h) + usage + ;; + -*) + echo "Error: unknown option $1" + usage + ;; + *) + break + ;; + esac +done + if [[ $# -ne 1 ]]; then usage fi @@ -47,14 +85,19 @@ if [[ -d "$TARGET_DIR" ]]; then exit 1 fi -echo "Creating ${DIR_NAME} in ${XO_UMBRELLA_ROOT}..." +echo "Creating ${DIR_NAME} (${MODE}) in ${XO_UMBRELLA_ROOT}..." # Create directories mkdir -p "${TARGET_DIR}/cmake" mkdir -p "${TARGET_DIR}/include/xo/${NAME}" -# Create CMakeLists.txt -cat > "${TARGET_DIR}/CMakeLists.txt" << EOF +if [[ "$MODE" == "shared" ]]; then + mkdir -p "${TARGET_DIR}/src" +fi + +# Create CMakeLists.txt (different content based on mode) +if [[ "$MODE" == "headeronly" ]]; then + cat > "${TARGET_DIR}/CMakeLists.txt" << EOF # ${DIR_NAME}/CMakeLists.txt cmake_minimum_required(VERSION 3.10) @@ -97,6 +140,42 @@ xo_export_cmake_config(\${PROJECT_NAME} \${PROJECT_VERSION} \${PROJECT_NAME}Targ # end CMakeLists.txt EOF +else + # Shared library mode + cat > "${TARGET_DIR}/CMakeLists.txt" << EOF +# ${DIR_NAME}/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(${PROJECT_NAME} VERSION 1.0) +enable_language(CXX) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings + +# one-time project-specific c++ flags. usually empty +set(PROJECT_CXX_FLAGS "") +add_definitions(\${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- +# output targets + +add_subdirectory(src) +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# cmake export + +xo_export_cmake_config(\${PROJECT_NAME} \${PROJECT_VERSION} \${PROJECT_NAME}Targets) + +# end CMakeLists.txt +EOF +fi # Create cmake/xo-bootstrap-macros.cmake cat > "${TARGET_DIR}/cmake/xo-bootstrap-macros.cmake" << EOF @@ -151,17 +230,53 @@ include("\${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") check_required_components("@PROJECT_NAME@") EOF +# Create src/CMakeLists.txt for shared library mode +if [[ "$MODE" == "shared" ]]; then + cat > "${TARGET_DIR}/src/CMakeLists.txt" << EOF +# ${DIR_NAME}/src/CMakeLists.txt + +set(SELF_LIB ${LIB_NAME}) +set(SELF_SRCS + # Add source files here, e.g.: + # ${NAME}.cpp +) + +xo_add_shared_library4(\${SELF_LIB} \${PROJECT_NAME}Targets \${PROJECT_VERSION} 1 \${SELF_SRCS}) +xo_install_include_tree3(include/xo/${NAME}) + +# ---------------------------------------------------------------- +# input dependencies +# +# NOTE: dependency set here must be kept consistent with +# ${DIR_NAME}/cmake/${LIB_NAME}Config.cmake.in + +#xo_dependency(\${SELF_LIB} xo_indentlog) + +# end src/CMakeLists.txt +EOF +fi + # Create placeholder .gitkeep in include dir touch "${TARGET_DIR}/include/xo/${NAME}/.gitkeep" echo "" -echo "Created ${DIR_NAME}/ with:" +echo "Created ${DIR_NAME}/ (${MODE}) with:" echo " ${DIR_NAME}/CMakeLists.txt" echo " ${DIR_NAME}/cmake/xo-bootstrap-macros.cmake" echo " ${DIR_NAME}/cmake/${LIB_NAME}Config.cmake.in" echo " ${DIR_NAME}/include/xo/${NAME}/" +if [[ "$MODE" == "shared" ]]; then + echo " ${DIR_NAME}/src/CMakeLists.txt" +fi echo "" echo "Next steps:" -echo " 1. Add header files to ${DIR_NAME}/include/xo/${NAME}/" -echo " 2. Add ${DIR_NAME} to umbrella CMakeLists.txt" -echo " 3. Uncomment dependencies as needed in CMakeLists.txt and Config.cmake.in" +if [[ "$MODE" == "headeronly" ]]; then + echo " 1. Add header files to ${DIR_NAME}/include/xo/${NAME}/" + echo " 2. Add ${DIR_NAME} to umbrella CMakeLists.txt" + echo " 3. Uncomment dependencies as needed in CMakeLists.txt and Config.cmake.in" +else + echo " 1. Add header files to ${DIR_NAME}/include/xo/${NAME}/" + echo " 2. Add source files to ${DIR_NAME}/src/ and update src/CMakeLists.txt SELF_SRCS" + echo " 3. Add ${DIR_NAME} to umbrella CMakeLists.txt" + echo " 4. Uncomment dependencies as needed in src/CMakeLists.txt and Config.cmake.in" +fi