From e1c527f54ca218368df69c9c6ad851b7d71f5b0f Mon Sep 17 00:00:00 2001 From: grdanny Date: Mon, 13 Apr 2026 15:47:28 -0700 Subject: [PATCH 1/9] updating version numbers --- CMakeLists.txt | 2 +- meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0318b9..9c5184e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.10) -project(pystring LANGUAGES CXX VERSION 1.1.4) +project(pystring LANGUAGES CXX VERSION 1.2.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/meson.build b/meson.build index 5dab5b8..a4ff6be 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'pystring', 'cpp', - version: '1.1.4', + version: '1.2.0', license: 'BSD-3-Clause', license_files: 'LICENSE', meson_version: '>=1.3', From ea59fd53c2d03ef34185ec3a52829baf7e9ea9c7 Mon Sep 17 00:00:00 2001 From: grdanny Date: Mon, 13 Apr 2026 16:17:10 -0700 Subject: [PATCH 2/9] no need for meson options now that we are building both compiled and header only together and providing them as options --- meson_options.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 meson_options.txt diff --git a/meson_options.txt b/meson_options.txt deleted file mode 100644 index 77be15e..0000000 --- a/meson_options.txt +++ /dev/null @@ -1 +0,0 @@ -option('header_only', type: 'boolean', value: false, description: 'Build as header-only library') From 069e93350d82082ca4274f57f252ec209831bd61 Mon Sep 17 00:00:00 2001 From: grdanny Date: Mon, 13 Apr 2026 16:18:52 -0700 Subject: [PATCH 3/9] no need for header only ci tasks, each ci task now builds and tests two different targets, regular pystring and pystring_header_only --- .github/workflows/ci.yml | 54 +--------------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 130df83..6e6c7d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - build: [1, 2, 3, 4, 5, 6] + build: [1, 2, 3, 4] include: # ------------------------------------------------------------------- # CLANG, Release @@ -75,36 +75,6 @@ jobs: compiler-desc: gcc os: ubuntu-latest - - # ------------------------------------------------------------------- - # CLANG, Release header only - # ------------------------------------------------------------------- - - build: 5 - build-type: Release - build-shared: 'ON' - header-only: 'ON' - cxx-standard: 17 - cxx-compiler: clang++ - cxx-flags: '' - cc-compiler: clang - compiler-desc: clang - os: ubuntu-latest - - # ------------------------------------------------------------------- - # gcc, Release header only - # ------------------------------------------------------------------- - - build: 6 - build-type: Release - build-shared: 'ON' - header-only: 'ON' - cxx-standard: 17 - cxx-compiler: g++ - cxx-flags: '' - cc-compiler: gcc - compiler-desc: gcc - os: ubuntu-latest - - env: CXX: ${{ matrix.cxx-compiler }} CC: ${{ matrix.cc-compiler }} @@ -124,7 +94,6 @@ jobs: -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \ -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ - -DPYSTRING_HEADER_ONLY=${{ matrix.header-only }} working-directory: _build - name: Build run: | @@ -165,16 +134,6 @@ jobs: cxx-flags: '' os: macos-latest - - # Release header only - - build: 3 - build-type: Release - build-shared: 'ON' - header-only: 'ON' - cxx-standard: 17 - cxx-flags: '' - os: macos-latest - steps: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -192,7 +151,6 @@ jobs: -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \ -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ - -DPYSTRING_HEADER_ONLY=${{ matrix.header-only }} working-directory: _build - name: Build run: | @@ -232,15 +190,6 @@ jobs: cxx-flags: '' os: windows-latest - # Release header only - - build: 3 - build-type: Release - build-shared: 'ON' - header-only: 'ON' - cxx-standard: 17 - cxx-flags: '' - os: windows-latest - steps: - name: Checkout @@ -261,7 +210,6 @@ jobs: -DCMAKE_CXX_FLAGS=${{ matrix.cxx-flags }} \ -DCMAKE_VERBOSE_MAKEFILE:BOOL='OFF' \ -DBUILD_SHARED_LIBS=${{ matrix.build-shared }} \ - -DPYSTRING_HEADER_ONLY=${{ matrix.header-only }} shell: bash working-directory: _build - name: Build From 0c58743bdaf73467b8821cc8fadc76ff2bcb3dbc Mon Sep 17 00:00:00 2001 From: grdanny Date: Mon, 13 Apr 2026 16:19:28 -0700 Subject: [PATCH 4/9] no need for header only ci tasks, each ci task now builds and tests two different targets, regular pystring and pystring_header_only --- .github/workflows/meson.yml | 40 +++++++------------------------------ 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/.github/workflows/meson.yml b/.github/workflows/meson.yml index e020145..bca9437 100644 --- a/.github/workflows/meson.yml +++ b/.github/workflows/meson.yml @@ -7,16 +7,13 @@ on: jobs: meson-build-and-tests: runs-on: ${{ matrix.platform }} - name: ${{ matrix.platform }}, ${{ matrix.mode.name }} ${{ matrix.flavor }} ${{ matrix.library_mode }} + name: ${{ matrix.platform }}, ${{ matrix.mode.name }} ${{ matrix.flavor }} strategy: fail-fast: false matrix: flavor: - debug - release - library_mode: - - compiled - - header-only mode: - name: default extra_envs: {} @@ -64,29 +61,6 @@ jobs: - macos-latest exclude: - # Only test header-only with a subset of configurations to reduce CI time - # Test header-only only with default compiler in release mode - - library_mode: header-only - flavor: debug - - library_mode: header-only - mode: - name: gcc - - library_mode: header-only - mode: - name: clang - - library_mode: header-only - mode: - name: sanitize - - library_mode: header-only - mode: - name: sanitize+asanonly - - library_mode: header-only - mode: - name: clang+sanitize - - library_mode: header-only - mode: - name: clang-cl+sanitize - # clang-cl only makes sense on windows. - platform: ubuntu-22.04 mode: @@ -151,21 +125,21 @@ jobs: if: ${{ matrix.platform == 'windows-2022' }} env: ${{ matrix.mode.extra_envs }} run: | - meson setup build-${{ matrix.flavor }}-${{ matrix.library_mode }} --buildtype=${{ matrix.flavor }} -Ddefault_library=static -Dheader_only=${{ matrix.library_mode == 'header-only' && 'true' || 'false' }} ${{ matrix.mode.args }} --vsenv + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} -Ddefault_library=static ${{ matrix.mode.args }} --vsenv - name: Configuring if: ${{ matrix.platform != 'windows-2022' }} env: ${{ matrix.mode.extra_envs }} run: | - meson setup build-${{ matrix.flavor }}-${{ matrix.library_mode }} --buildtype=${{ matrix.flavor }} -Dheader_only=${{ matrix.library_mode == 'header-only' && 'true' || 'false' }} ${{ matrix.mode.args }} + meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} - name: Building run: | - meson compile -C build-${{ matrix.flavor }}-${{ matrix.library_mode }} + meson compile -C build-${{ matrix.flavor }} - name: Running tests env: ${{ matrix.mode.extra_envs }} run: | - meson test -C build-${{ matrix.flavor }}-${{ matrix.library_mode }} --timeout-multiplier 0 + meson test -C build-${{ matrix.flavor }} --timeout-multiplier 0 - uses: actions/upload-artifact@v4 if: failure() with: - name: ${{ matrix.platform }}-${{ matrix.mode.name }}-${{ matrix.flavor }}-${{ matrix.library_mode }}-logs - path: build-${{ matrix.flavor }}-${{ matrix.library_mode }}/meson-logs \ No newline at end of file + name: ${{ matrix.platform }}-${{ matrix.mode.name }}-${{ matrix.flavor }}-logs + path: build-${{ matrix.flavor }}/meson-logs From ab5c25a0f01fb5875f252649d8f8ddf343583525 Mon Sep 17 00:00:00 2001 From: grdanny Date: Tue, 14 Apr 2026 11:07:07 -0700 Subject: [PATCH 5/9] updated meson and cmake build systems to have two available targets for the user to pick from compiled and header only --- CMakeLists.txt | 127 +++++++++++++++++++++++------------- meson.build | 86 ++++++++++++------------ test_header_only_define.cpp | 5 ++ 3 files changed, 130 insertions(+), 88 deletions(-) create mode 100644 test_header_only_define.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c5184e..be8c306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) option (BUILD_SHARED_LIBS "Build shared libraries (set to OFF to build static libs)" ON) -option(PYSTRING_HEADER_ONLY "Build as header-only library" OFF) # If the user hasn't configured cmake with an explicit # -DCMAKE_INSTALL_PREFIX=..., then set it to safely install into ./dist, to @@ -19,52 +18,86 @@ endif() message (STATUS "Installation path will be ${CMAKE_INSTALL_PREFIX}") include(GNUInstallDirs) -if(PYSTRING_HEADER_ONLY) - message(STATUS "Building pystring as header-only library") - add_library(pystring INTERFACE) - - target_compile_definitions(pystring INTERFACE PYSTRING_HEADER_ONLY) - - target_include_directories(pystring INTERFACE - $ - $ - ) - - # Install both headers for header-only mode - install(FILES pystring.h pystring_impl.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} - ) -else() - message(STATUS "Building pystring as compiled library") - - add_library(pystring - pystring.cpp - pystring.h - ) - - set_target_properties(pystring PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - ) - - install(TARGETS pystring - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - ARCHIVE DESTINATION lib - ) - - install (FILES pystring.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} - COMPONENT developer - ) - -endif() - -# Test executable - -add_executable (pystring_test test.cpp) -TARGET_LINK_LIBRARIES (pystring_test pystring) +# --- Compiled library target: pystring::pystring --- +add_library(pystring + pystring.cpp + pystring.h +) + +set_target_properties(pystring PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +target_include_directories(pystring PUBLIC + $ + $ +) + +install(TARGETS pystring + EXPORT pystringTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + + +# --- Header-only target: pystring::pystring_header_only --- +add_library(pystring_header_only INTERFACE) + +target_compile_definitions(pystring_header_only INTERFACE PYSTRING_HEADER_ONLY) + +target_include_directories(pystring_header_only INTERFACE + $ + $ +) + +install(TARGETS pystring_header_only + EXPORT pystringTargets +) + +install(FILES pystring.h pystring_impl.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} +) + +# --- Export & package config --- +install(EXPORT pystringTargets + FILE pystringTargets.cmake + NAMESPACE pystring:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pystring +) + +include(CMakePackageConfigHelpers) + +configure_package_config_file( + cmake/pystringConfig.cmake.in + pystringConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pystring +) + +write_basic_package_version_file( + pystringConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/pystringConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/pystringConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pystring +) + +# --- Tests --- +add_executable(pystring_test test.cpp) +target_link_libraries(pystring_test pystring) + +add_executable(pystring_test_header_only test.cpp) +target_link_libraries(pystring_test_header_only pystring_header_only) + +# Compile-time check that PYSTRING_HEADER_ONLY propagates correctly +add_executable(pystring_test_header_only_define test_header_only_define.cpp) +target_link_libraries(pystring_test_header_only_define pystring_header_only) enable_testing() add_test(NAME PyStringTest COMMAND pystring_test) - +add_test(NAME PyStringTestHeaderOnly COMMAND pystring_test_header_only) diff --git a/meson.build b/meson.build index a4ff6be..a083d08 100644 --- a/meson.build +++ b/meson.build @@ -8,58 +8,44 @@ project( default_options: ['cpp_std=c++17,c++11', 'warning_level=3'], ) -# Option to build as header-only library -header_only = get_option('header_only') - inc = include_directories('.') hdrs = files('pystring.h') -if header_only - # Header-only mode: create a header-only dependency - message('Building pystring as header-only library') - - pystring_dep = declare_dependency( - include_directories: inc, - compile_args: ['-DPYSTRING_HEADER_ONLY'], - ) - - # Install headers for header-only mode - install_headers(hdrs, files('pystring_impl.h'), subdir: 'pystring') - -else - # Compiled mode: build as normal library - message('Building pystring as compiled library') +# --- Compiled library target --- +pystring_lib = library( + 'pystring', + files('pystring.cpp'), + implicit_include_directories: false, + include_directories: inc, + version: meson.project_version(), + install: true, +) - srcs = files('pystring.cpp') +pystring_dep = declare_dependency( + link_with: pystring_lib, + include_directories: inc, +) - pystring_lib = library( - 'pystring', - srcs, - implicit_include_directories: false, - include_directories: inc, - version: meson.project_version(), - install: true, - ) +install_headers(hdrs, subdir: 'pystring') - pystring_dep = declare_dependency( - link_with: pystring_lib, - include_directories: inc, - ) +pkgconfig = import('pkgconfig') +pkgconfig.generate( + pystring_lib, + description: 'C++ functions matching the interface and behavior of python string methods with std::string', +) - # Install headers for compiled mode - install_headers(hdrs, subdir: 'pystring') +# --- Header-only target --- +pystring_header_only_dep = declare_dependency( + include_directories: inc, + compile_args: ['-DPYSTRING_HEADER_ONLY'], +) - # Generate pkg-config file - pkgconfig = import('pkgconfig') - pkgconfig.generate( - pystring_lib, - description: 'C++ functions matching the interface and behavior of python string methods with std::string', - ) -endif +install_headers(hdrs, files('pystring_impl.h'), subdir: 'pystring') +# --- Override default dependency --- meson.override_dependency('pystring', pystring_dep) -# Build and run tests +# --- Tests --- test( 'PyStringTest', executable( @@ -69,3 +55,21 @@ test( build_by_default: false, ), ) + +test( + 'PyStringTestHeaderOnly', + executable( + 'pystring_test_header_only', + 'test.cpp', + dependencies: pystring_header_only_dep, + build_by_default: false, + ), +) + +# Compile-time check that PYSTRING_HEADER_ONLY propagates correctly +executable( + 'pystring_test_header_only_define', + 'test_header_only_define.cpp', + dependencies: pystring_header_only_dep, + build_by_default: true, +) \ No newline at end of file diff --git a/test_header_only_define.cpp b/test_header_only_define.cpp new file mode 100644 index 0000000..27c8acf --- /dev/null +++ b/test_header_only_define.cpp @@ -0,0 +1,5 @@ +// test_header_only_mode.cpp +#ifndef PYSTRING_HEADER_ONLY +#error "PYSTRING_HEADER_ONLY must be defined when using the header-only target" +#endif +int main() { return 0; } \ No newline at end of file From 827564d6307d2949cb4f26bea7c1da69718bb135 Mon Sep 17 00:00:00 2001 From: grdanny Date: Tue, 14 Apr 2026 11:18:43 -0700 Subject: [PATCH 6/9] adding cmake configuration file --- cmake/pystringConfig.cmake.in | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 cmake/pystringConfig.cmake.in diff --git a/cmake/pystringConfig.cmake.in b/cmake/pystringConfig.cmake.in new file mode 100644 index 0000000..be89175 --- /dev/null +++ b/cmake/pystringConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/pystringTargets.cmake") + +check_required_components(pystring pystring_header_only) +EOF + From 4cf2ec08a812dd7a794b699f65d3d2e18a1152e0 Mon Sep 17 00:00:00 2001 From: grdanny Date: Tue, 14 Apr 2026 11:21:15 -0700 Subject: [PATCH 7/9] removing empty ci target --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e6c7d9..ed7e9ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: runs-on: macos-latest strategy: matrix: - build: [1, 2, 3] + build: [1, 2] include: # Release From 7e6d7a8267ac10dee2ab39260a556bf17034ecde Mon Sep 17 00:00:00 2001 From: grdanny Date: Tue, 14 Apr 2026 12:52:28 -0700 Subject: [PATCH 8/9] adding bit in pystringConfig to prevent double definition error --- cmake/pystringConfig.cmake.in | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/pystringConfig.cmake.in b/cmake/pystringConfig.cmake.in index be89175..c5fd1f5 100644 --- a/cmake/pystringConfig.cmake.in +++ b/cmake/pystringConfig.cmake.in @@ -1,7 +1,8 @@ @PACKAGE_INIT@ -include("${CMAKE_CURRENT_LIST_DIR}/pystringTargets.cmake") - -check_required_components(pystring pystring_header_only) -EOF +# Prevent double-definition errors +if(NOT TARGET pystring::pystring AND NOT TARGET pystring::pystring_header_only) + include("${CMAKE_CURRENT_LIST_DIR}/pystringTargets.cmake") +endif() +check_required_components(pystring) \ No newline at end of file From 3568181761ac909d04dfaf5b4477f08e15c66010 Mon Sep 17 00:00:00 2001 From: grdanny Date: Tue, 14 Apr 2026 12:54:23 -0700 Subject: [PATCH 9/9] adding newline in file end for consistency --- cmake/pystringConfig.cmake.in | 2 +- meson.build | 2 +- test_header_only_define.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/pystringConfig.cmake.in b/cmake/pystringConfig.cmake.in index c5fd1f5..b62792d 100644 --- a/cmake/pystringConfig.cmake.in +++ b/cmake/pystringConfig.cmake.in @@ -5,4 +5,4 @@ if(NOT TARGET pystring::pystring AND NOT TARGET pystring::pystring_header_only) include("${CMAKE_CURRENT_LIST_DIR}/pystringTargets.cmake") endif() -check_required_components(pystring) \ No newline at end of file +check_required_components(pystring) diff --git a/meson.build b/meson.build index a083d08..d0da73d 100644 --- a/meson.build +++ b/meson.build @@ -72,4 +72,4 @@ executable( 'test_header_only_define.cpp', dependencies: pystring_header_only_dep, build_by_default: true, -) \ No newline at end of file +) diff --git a/test_header_only_define.cpp b/test_header_only_define.cpp index 27c8acf..5a364ce 100644 --- a/test_header_only_define.cpp +++ b/test_header_only_define.cpp @@ -2,4 +2,4 @@ #ifndef PYSTRING_HEADER_ONLY #error "PYSTRING_HEADER_ONLY must be defined when using the header-only target" #endif -int main() { return 0; } \ No newline at end of file +int main() { return 0; }