diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6af691b..ebce5d1 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -115,7 +115,7 @@ jobs: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} publish-native: - name: Publish native source archive + name: Publish native CMake package needs: check-version runs-on: ubuntu-latest permissions: @@ -126,21 +126,21 @@ jobs: - uses: actions/checkout@v7 with: ref: ${{ github.event.release.tag_name }} - - name: Create native archive + - name: Set up development toolchains + uses: jdx/mise-action@v4 + - name: Create native CMake package env: TAG: ${{ github.event.release.tag_name }} run: | version="${TAG#v}" - archive="ptfkit-native-${version}.tar.gz" + package="ptfkit-native-${version}" + archive="${package}.tar.gz" + staging="${RUNNER_TEMP}/${package}" + cmake -S targets/ptfkit-native -B targets/ptfkit-native/build-release \ + -GNinja -DBUILD_TESTING=OFF -DPTFKIT_BUILD_CPP_MODULES=ON + cmake --install targets/ptfkit-native/build-release --prefix "$staging" tar --sort=name --mtime="UTC 1970-01-01" --owner=0 --group=0 --numeric-owner \ - --transform="s,^targets/ptfkit-native,ptfkit-native-${version}," \ - -czf "$archive" \ - targets/ptfkit-native/CMakeLists.txt \ - targets/ptfkit-native/LICENSE \ - targets/ptfkit-native/README.md \ - targets/ptfkit-native/cmake \ - targets/ptfkit-native/cpp \ - targets/ptfkit-native/include + -C "$RUNNER_TEMP" -czf "$archive" "$package" sha256sum "$archive" > "$archive.sha256" echo "archive=$archive" >> "$GITHUB_ENV" - name: Attest native archive provenance diff --git a/README.md b/README.md index 653ba7d..b50f109 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ for the scientific and structural contract represented by the YAML files. | [Python](./targets/ptfkit-py/) | Scalar and NumPy array inputs backed by native ufuncs; distributed on [PyPI](https://pypi.org/project/ptfkit/) | [Python API](https://agrodt.github.io/ptfkit/reference/python/) | | [Rust](./targets/ptfkit-rs/) | Scalar functions grouped by source publication; distributed on [crates.io](https://crates.io/crates/ptfkit) | [Rust API](https://docs.rs/ptfkit/) | | [C](./targets/ptfkit-native/) | Header-only C11 functions provided as a CMake package and [versioned release archive](https://github.com/AgroDT/ptfkit/releases) | [C API](https://agrodt.github.io/ptfkit/reference/c/) | -| [C++](./targets/ptfkit-native/) | Optional C++20 modules provided by the native CMake package and [versioned release archive](https://github.com/AgroDT/ptfkit/releases) | [C++ API](https://agrodt.github.io/ptfkit/reference/cpp/) | +| [C++](./targets/ptfkit-native/) | Optional C++23 modules provided by the native CMake package and [versioned release archive](https://github.com/AgroDT/ptfkit/releases) | [C++ API](https://agrodt.github.io/ptfkit/reference/cpp/) | Installation and usage instructions are maintained in each target's linked README. diff --git a/codegen/src/targets/reference/cpp.rs b/codegen/src/targets/reference/cpp.rs index 53f1b6b..4b3021f 100644 --- a/codegen/src/targets/reference/cpp.rs +++ b/codegen/src/targets/reference/cpp.rs @@ -51,7 +51,7 @@ fn render_index( writer.line("title: C++ API reference"); }); writer.write( - "# C++ API reference\n\nptfkit's C++ API is organized around C++20 modules.\n\n## Modules\n\n- [`ptfkit`](modules/ptfkit.md) — Re-exports every ptfkit source module.\n", + "# C++ API reference\n\nptfkit's C++ API is organized around C++23 modules.\n\n## Modules\n\n- [`ptfkit`](modules/ptfkit.md) — Re-exports every ptfkit source module.\n", ); for (slug, functions) in sources { writer.line(format_args!( diff --git a/docs/src/contributing/development.md b/docs/src/contributing/development.md index 0afcb73..8a8382c 100644 --- a/docs/src/contributing/development.md +++ b/docs/src/contributing/development.md @@ -10,7 +10,7 @@ package builds and documentation builds do not depend on running codegen first. - `specs/functions/` contains one YAML specification per source publication. - `specs/schema/` defines the specification format. - `codegen/` contains validation and generation code. -- `targets/ptfkit-native/` contains the C11 headers and C++20 modules. +- `targets/ptfkit-native/` contains the C11 headers and C++23 modules. - `targets/ptfkit-py/` contains the Python package and its native extension. - `targets/ptfkit-rs/` contains the Rust crate. - `docs/mkdocs.yml` configures the documentation site. @@ -27,7 +27,7 @@ the [PTF source specification guide](../ptf-catalog/index.md). Install [Mise](https://mise.jdx.dev/getting-started/) and activate it in your shell. `mise.toml` is the source of truth for the pinned Rust, uv, CMake, Ninja, Clang, Ruff, ty, and prek toolchains; `mise.lock` records their resolved -downloads and checksums. The native target requires the C11/C++20 compiler +downloads and checksums. The native target requires the C11/C++23 compiler provided by Clang. From the repository root, trust the repository configuration and install the diff --git a/docs/src/index.md b/docs/src/index.md index 46365c6..9984d4a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -37,7 +37,7 @@ ptfkit exposes generated implementations for several programming languages: | Python | Scalar and NumPy array inputs backed by native ufuncs | [Python target](targets/python.md) · [Python API](reference/python/index.md) | | Rust | Scalar functions grouped by source publication | [Rust target](targets/rust.md) · [docs.rs](https://docs.rs/ptfkit/) | | C | Header-only C11 functions | [C and C++ target](targets/native.md) · [C API](reference/c/index.md) | -| C++ | Optional C++20 modules | [C and C++ target](targets/native.md) · [C++ API](reference/cpp/index.md) | +| C++ | Optional C++23 modules | [C and C++ target](targets/native.md) · [C++ API](reference/cpp/index.md) | Packages are distributed through [PyPI](https://pypi.org/project/ptfkit/) and [crates.io](https://crates.io/crates/ptfkit); C and C++ releases are available diff --git a/docs/src/reference/cpp/index.md b/docs/src/reference/cpp/index.md index 13a70c7..0d24c39 100644 --- a/docs/src/reference/cpp/index.md +++ b/docs/src/reference/cpp/index.md @@ -6,7 +6,7 @@ title: C++ API reference # C++ API reference -ptfkit's C++ API is organized around C++20 modules. +ptfkit's C++ API is organized around C++23 modules. ## Modules diff --git a/targets/ptfkit-native/CMakeLists.txt b/targets/ptfkit-native/CMakeLists.txt index 0b9950e..6f5d3bc 100644 --- a/targets/ptfkit-native/CMakeLists.txt +++ b/targets/ptfkit-native/CMakeLists.txt @@ -15,7 +15,7 @@ target_compile_definitions(ptfkit_c INTERFACE PTFKIT_VERSION=\"${PROJECT_VERSION}\" ) if(UNIX) - target_link_libraries(ptfkit_c INTERFACE m) + target_link_libraries(ptfkit_c INTERFACE $) endif() target_include_directories(ptfkit_c INTERFACE $ @@ -24,7 +24,7 @@ target_include_directories(ptfkit_c INTERFACE cmake_dependent_option( PTFKIT_BUILD_CPP_MODULES - "Build the C++20 module interface target" + "Provide the C++23 module interface target" ON "CMAKE_VERSION VERSION_GREATER_EQUAL 3.28" OFF @@ -33,7 +33,6 @@ cmake_dependent_option( if(PTFKIT_BUILD_CPP_MODULES) enable_language(CXX) add_subdirectory(cpp) - set(INSTALL_EXPORT_ARGS CXX_MODULES_DIRECTORY cxx-modules) endif() install(TARGETS ptfkit_c EXPORT ptfkitTargets) @@ -49,7 +48,6 @@ install( EXPORT ptfkitTargets NAMESPACE ptfkit:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ptfkit - ${INSTALL_EXPORT_ARGS} ) configure_package_config_file( cmake/ptfkitConfig.cmake.in @@ -60,6 +58,7 @@ write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/ptfkitConfigVersion.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion + ARCH_INDEPENDENT ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ptfkitConfig.cmake diff --git a/targets/ptfkit-native/README.md b/targets/ptfkit-native/README.md index 4592633..86c868a 100644 --- a/targets/ptfkit-native/README.md +++ b/targets/ptfkit-native/README.md @@ -3,23 +3,24 @@ The native ptfkit distribution provides: - header-only C11 functions through the `ptfkit::c` CMake target; -- optional C++20 modules through the `ptfkit::cpp` CMake target. +- optional C++23 modules through the `ptfkit::cpp` CMake target. ## Install from a release archive -Versioned native source archives are attached to each +Versioned native CMake packages are attached to each [GitHub Release](https://github.com/AgroDT/ptfkit/releases). For a release `vX.Y.Z`, download `ptfkit-native-X.Y.Z.tar.gz`, extract the -archive, and build it with CMake. A matching `.sha256` file is provided for -optional checksum verification. +archive, and add its root directory to `CMAKE_PREFIX_PATH`. The package is +ready for `find_package` and does not need a separate build or install step. A +matching `.sha256` file is provided for optional checksum verification. The archives are generated by the release workflow and carry GitHub build-provenance attestations. -## Build and install +## Build and install from source CMake 3.21 or newer is required for the C package. C++ modules require CMake -3.28 or newer and a compiler with C++20 module support. +3.28 or newer and a compiler with C++23 module support. ```shell cmake -S . -B build -GNinja -DBUILD_TESTING=OFF @@ -29,7 +30,9 @@ cmake --install build --prefix /path/to/prefix The C++ module target is enabled by default when the active CMake version supports it. It can be controlled explicitly with -`-DPTFKIT_BUILD_CPP_MODULES=ON` or `OFF`. +`-DPTFKIT_BUILD_CPP_MODULES=ON` or `OFF`. The C and C++ targets are +independent: `ptfkit::c` is C11-only, while `ptfkit::cpp` provides only C++ +modules. ## CMake package @@ -40,7 +43,17 @@ add_executable(example example.c) target_link_libraries(example PRIVATE ptfkit::c) ``` -For C++ modules, link against `ptfkit::cpp` instead. +For C++ modules, scan the importing target and link against `ptfkit::cpp`. +The installed package provides both targets, so consumers use the same +`find_package` call. + +```cmake +find_package(ptfkit CONFIG REQUIRED) + +add_executable(example example.cpp) +set_target_properties(example PROPERTIES CXX_SCAN_FOR_MODULES ON) +target_link_libraries(example PRIVATE ptfkit::cpp) +``` ## C usage diff --git a/targets/ptfkit-native/cmake/ptfkitConfig.cmake.in b/targets/ptfkit-native/cmake/ptfkitConfig.cmake.in index ea4904c..2e6d5f3 100644 --- a/targets/ptfkit-native/cmake/ptfkitConfig.cmake.in +++ b/targets/ptfkit-native/cmake/ptfkitConfig.cmake.in @@ -1,3 +1,18 @@ @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/ptfkitTargets.cmake") +set(ptfkit_c_FOUND TRUE) +get_target_property(_ptfkit_c_libraries ptfkit::c INTERFACE_LINK_LIBRARIES) +if(UNIX AND NOT "m" IN_LIST _ptfkit_c_libraries) + set_property(TARGET ptfkit::c APPEND PROPERTY INTERFACE_LINK_LIBRARIES m) +endif() +unset(_ptfkit_c_libraries) + +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28) + include("${CMAKE_CURRENT_LIST_DIR}/ptfkitCppModules.cmake" OPTIONAL) +endif() +if(TARGET ptfkit::cpp) + set(ptfkit_cpp_FOUND TRUE) +endif() + +check_required_components(ptfkit) diff --git a/targets/ptfkit-native/cmake/ptfkitCppModules.cmake.in b/targets/ptfkit-native/cmake/ptfkitCppModules.cmake.in new file mode 100644 index 0000000..8e6f0a2 --- /dev/null +++ b/targets/ptfkit-native/cmake/ptfkitCppModules.cmake.in @@ -0,0 +1,15 @@ +if(NOT TARGET ptfkit::cpp) + add_library(ptfkit::cpp INTERFACE IMPORTED) + target_compile_features(ptfkit::cpp INTERFACE cxx_std_23) + target_compile_definitions(ptfkit::cpp INTERFACE + PTFKIT_VERSION="@PROJECT_VERSION@" + ) + target_compile_options(ptfkit::cpp INTERFACE + $<$:-fmodules-ts> + ) + target_sources(ptfkit::cpp INTERFACE + FILE_SET CXX_MODULES + BASE_DIRS "${PACKAGE_PREFIX_DIR}/@PTFKIT_CPP_MODULE_INSTALL_DIR@" + FILES @PTFKIT_CPP_MODULE_PACKAGE_FILES@ + ) +endif() diff --git a/targets/ptfkit-native/cpp/CMakeLists.txt b/targets/ptfkit-native/cpp/CMakeLists.txt index 0ff1e71..be62cd4 100644 --- a/targets/ptfkit-native/cpp/CMakeLists.txt +++ b/targets/ptfkit-native/cpp/CMakeLists.txt @@ -1,23 +1,38 @@ -add_library(ptfkit_cpp) -add_library(ptfkit::cpp ALIAS ptfkit_cpp) -set_target_properties(ptfkit_cpp PROPERTIES - EXPORT_NAME cpp CXX_SCAN_FOR_MODULES ON -) -target_compile_features(ptfkit_cpp PUBLIC cxx_std_23) -target_compile_definitions(ptfkit_cpp PUBLIC +file(GLOB_RECURSE PTFKIT_CPP_MODULES CONFIGURE_DEPENDS *.cppm) + +add_library(ptfkit::cpp INTERFACE IMPORTED GLOBAL) +target_compile_features(ptfkit::cpp INTERFACE cxx_std_23) +target_compile_definitions(ptfkit::cpp INTERFACE PTFKIT_VERSION=\"${PROJECT_VERSION}\" ) -target_compile_options(ptfkit_cpp PUBLIC +target_compile_options(ptfkit::cpp INTERFACE $<$:-fmodules-ts> ) -target_link_libraries(ptfkit_cpp PRIVATE ptfkit::c) -file(GLOB_RECURSE PTFKIT_CPP_MODULES CONFIGURE_DEPENDS *.cppm) -target_sources(ptfkit_cpp PUBLIC +target_sources(ptfkit::cpp INTERFACE FILE_SET CXX_MODULES + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} FILES ${PTFKIT_CPP_MODULES} ) + +set(PTFKIT_CPP_MODULE_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/ptfkit/modules) +install( + FILES ${PTFKIT_CPP_MODULES} + DESTINATION ${PTFKIT_CPP_MODULE_INSTALL_DIR} +) + +set(PTFKIT_CPP_MODULE_PACKAGE_FILES) +foreach(module IN LISTS PTFKIT_CPP_MODULES) + get_filename_component(module_name ${module} NAME) + list(APPEND PTFKIT_CPP_MODULE_PACKAGE_FILES + "\${PACKAGE_PREFIX_DIR}/${PTFKIT_CPP_MODULE_INSTALL_DIR}/${module_name}" + ) +endforeach() +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ptfkitCppModules.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/ptfkitCppModules.cmake + @ONLY +) install( - TARGETS ptfkit_cpp - EXPORT ptfkitTargets - FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_LIBDIR}/ptfkit/modules + FILES ${CMAKE_CURRENT_BINARY_DIR}/ptfkitCppModules.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ptfkit ) diff --git a/targets/ptfkit-native/tests/CMakeLists.txt b/targets/ptfkit-native/tests/CMakeLists.txt index a40de52..a161c57 100644 --- a/targets/ptfkit-native/tests/CMakeLists.txt +++ b/targets/ptfkit-native/tests/CMakeLists.txt @@ -13,10 +13,9 @@ function(ptfkit_add_native_tests case) if(arg_DEFINITIONS) target_compile_definitions(${target} PRIVATE ${arg_DEFINITIONS}) endif() - set_target_properties(${target} PROPERTIES - CXX_STANDARD 23 - ${arg_PROPERTIES} - ) + if(arg_PROPERTIES) + set_target_properties(${target} PROPERTIES ${arg_PROPERTIES}) + endif() add_test(NAME ${target} COMMAND ${target}) endforeach() endfunction() @@ -25,13 +24,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(c) -include(CheckLanguage) -check_language(CXX) -if(CMAKE_CXX_COMPILER) - enable_language(CXX) - add_subdirectory(cpp_fallback) -endif() - if(PTFKIT_BUILD_CPP_MODULES) add_subdirectory(cpp) endif() diff --git a/targets/ptfkit-native/tests/cpp_fallback/CMakeLists.txt b/targets/ptfkit-native/tests/cpp_fallback/CMakeLists.txt deleted file mode 100644 index d4679f8..0000000 --- a/targets/ptfkit-native/tests/cpp_fallback/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -file(GLOB sources CONFIGURE_DEPENDS ../c/*.c) - -set_source_files_properties( - ${sources} - PROPERTIES LANGUAGE CXX -) - -ptfkit_add_native_tests(cpp_fallback - SOURCES ${sources} - LIBRARIES ptfkit::c m -)