Skip to content

Commit 78e7d1f

Browse files
authored
Add CMake integration (#68)
Add first-class CMake integration Add UsePRIK.cmake and PRIKConfig.cmake for building PRIK extensions inside existing CMake projects, with structural configure-time planning and incremental build-time generation. Support CMake targets, native sources, link dependencies, compiler and wrapper flags, linker-language selection, depfiles, and stable generated source graphs. Package the CMake modules for direct discovery, find_package(PRIK), scikit-build-core's cmake.module entry point, and the cmake-dir and install-dir CLI helpers. Add integration tests, installed-wheel discovery tests, runnable CMake examples, and user documentation for the supported discovery and build workflows.
1 parent 5394553 commit 78e7d1f

43 files changed

Lines changed: 4921 additions & 91 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/merge-validation.yml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,19 @@ jobs:
281281
ln -sf "$(command -v "$PRIK_GFORTRAN_BINARY")" "$compiler_dir/gfortran"
282282
echo "$compiler_dir" >> "$GITHUB_PATH"
283283
"$compiler_dir/gfortran" --version
284+
- name: Verify CMake build tooling
285+
shell: bash
286+
run: |
287+
if ! command -v cmake >/dev/null 2>&1; then
288+
echo "cmake is missing, so the CMake integration tests would deselect themselves" >&2
289+
exit 1
290+
fi
291+
cmake --version
292+
if command -v ninja >/dev/null 2>&1; then
293+
ninja --version
294+
else
295+
echo "::warning::ninja is missing; CMake tests fall back to the Makefile generator"
296+
fi
284297
- name: Run tests
285298
if: ${{ !matrix.coverage }}
286299
shell: bash
@@ -401,6 +414,19 @@ jobs:
401414
gfortran --version
402415
command -v gcc
403416
gcc --version
417+
- name: Verify CMake build tooling
418+
shell: bash
419+
run: |
420+
if ! command -v cmake >/dev/null 2>&1; then
421+
echo "cmake is missing, so the CMake integration tests would deselect themselves" >&2
422+
exit 1
423+
fi
424+
cmake --version
425+
if command -v ninja >/dev/null 2>&1; then
426+
ninja --version
427+
else
428+
echo "::warning::ninja is missing; CMake tests fall back to the Makefile generator"
429+
fi
404430
- name: Show repository-owned lane plan
405431
run: |
406432
python tools/run_fortran_toolchain_lane.py \

‎.github/workflows/publish-to-pypi.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ jobs:
6262
"$RUNNER_TEMP/prik-release-check/bin/prik" --version
6363
"$RUNNER_TEMP/prik-release-check/bin/python" -c \
6464
'import importlib.metadata as m, prik; assert prik.__version__ == m.version("prik")'
65+
"$RUNNER_TEMP/prik-release-check/bin/python" -c \
66+
'from prik.cmake import cmake_module_dir; assert (cmake_module_dir() / "UsePRIK.cmake").is_file()'
6567
"$RUNNER_TEMP/prik-release-check/bin/prik" --help
6668
"$RUNNER_TEMP/prik-release-check/bin/python" -m prik --help
6769
- name: Upload distributions

‎.github/workflows/tests.yml‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ jobs:
4545
ln -sf "$(command -v "$PRIK_GFORTRAN_BINARY")" "$compiler_dir/gfortran"
4646
echo "$compiler_dir" >> "$GITHUB_PATH"
4747
"$compiler_dir/gfortran" --version
48+
- name: Verify CMake build tooling
49+
shell: bash
50+
run: |
51+
if ! command -v cmake >/dev/null 2>&1; then
52+
echo "cmake is missing, so the CMake integration tests would deselect themselves" >&2
53+
exit 1
54+
fi
55+
cmake --version
56+
if command -v ninja >/dev/null 2>&1; then
57+
ninja --version
58+
else
59+
echo "::warning::ninja is missing; CMake tests fall back to the Makefile generator"
60+
fi
4861
- name: Run tests
4962
shell: bash
5063
env:
@@ -122,6 +135,19 @@ jobs:
122135
gfortran --version
123136
command -v gcc
124137
gcc --version
138+
- name: Verify CMake build tooling
139+
shell: bash
140+
run: |
141+
if ! command -v cmake >/dev/null 2>&1; then
142+
echo "cmake is missing, so the CMake integration tests would deselect themselves" >&2
143+
exit 1
144+
fi
145+
cmake --version
146+
if command -v ninja >/dev/null 2>&1; then
147+
ninja --version
148+
else
149+
echo "::warning::ninja is missing; CMake tests fall back to the Makefile generator"
150+
fi
125151
- name: Show repository-owned lane plan
126152
run: |
127153
python tools/run_fortran_toolchain_lane.py \

‎CHANGELOG.md‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,75 @@ release tags add a leading `v` to the package version.
77

88
## Unreleased
99

10+
- Added CMake integration through the packaged `UsePRIK.cmake` helper and a
11+
`prik generate --cmake` standalone-project mode. CMake generates PRIK wrapper
12+
sources as build outputs and owns native compilation, linking, external
13+
targets, and incremental rebuilds while preserving per-source flags,
14+
compiler-required ABI options, preprocessing dependencies, and linker
15+
language from PRIK's completed build plan.
16+
17+
- CMake contract modules now distinguish semantic `NATIVE_LANGUAGE` from the
18+
final `LINKER_LANGUAGE`, keep native compilation flags target-local, and
19+
report a clear error when CMake's C language is not enabled.
20+
21+
- CMake dependency targets now propagate their native compile usage
22+
requirements, and standalone `--cmake --lto` initializes IPO for native and
23+
generated targets.
24+
25+
- CMake configuration no longer runs PRIK's semantic pipeline. It asks for a
26+
structural plan -- deterministic generated filenames, the link driver, and
27+
compiler-profile ABI flags -- and the full pipeline then runs once at build
28+
time. Configuring a 300-procedure module's plan drops from about 2.5s to
29+
0.4s, and the structural query no longer grows with source size.
30+
31+
- Generated CMake targets have a fixed source list. The optional collision
32+
adapter and Fortran bridge units are always written, holding a
33+
symbol-free placeholder when unused, so a semantic edit changes file
34+
contents instead of the build graph and never forces a CMake reconfigure.
35+
Transitive semantic inputs now reach CMake through a generated dependency
36+
file, which raises the CMake floor for the packaged helper to 3.21.
37+
38+
- `prik generate --cmake` keeps each native link input in its own CMake
39+
category: prebuilt objects, archives, and shared libraries stay filesystem
40+
paths in `LINK_LIBRARIES` instead of becoming ambiguous relative tokens,
41+
while library names and linker arguments keep their meaning and order.
42+
43+
- CMake native object targets receive `LINK_LIBRARIES` with the caller's link
44+
syntax unchanged, so `debug`/`optimized` keywords and generator-expression
45+
entries keep selecting usage requirements per configuration instead of being
46+
flattened or dropped.
47+
48+
- CMake mode rejects a `.C` source suffix, which CMake compiles as C++ while
49+
PRIK plans the source as C, and reports a clear error when a module
50+
contributes native Fortran sources without CMake's Fortran language enabled.
51+
52+
- `prik_add_module()` accepts `LIBRARY_DIRS`, mapping it to
53+
`target_link_directories()` and the extension's `BUILD_RPATH`.
54+
`generate --cmake` translates `--native-library-dir` into `LIBRARY_DIRS`, so
55+
a shared native library outside the system search path is found both at link
56+
time and on import without `LD_LIBRARY_PATH`.
57+
58+
- `prik-build.json` schema 5 records generated/native compilation-unit ABI
59+
flags and explicit native linker-language requirements.
60+
61+
- PRIK's CMake modules are packaged inside the `prik` distribution and
62+
discovered automatically. scikit-build-core builds pick the directory up
63+
through a `cmake.module` entry point, so `include(UsePRIK)` needs no lookup,
64+
and a packaged `PRIKConfig.cmake` makes `find_package(PRIK CONFIG REQUIRED)`
65+
load the same helper. `prik cmake-dir` prints the packaged module directory
66+
and `prik install-dir` the prefix PRIK's data files are installed under, for
67+
`-DPRIK_DIR=` and `-DCMAKE_PREFIX_PATH=`. `cmake_module_dir()` and the
68+
`share/prik/cmake` installation are unchanged.
69+
70+
- The Ubuntu and macOS unit-test jobs now fail when CMake is missing instead of
71+
letting the CMake integration tests deselect themselves, and report a missing
72+
Ninja as a warning because those tests then use the Makefile generator.
73+
74+
- Added the runnable `examples/cmake/` project, which builds one Fortran module
75+
through every CMake discovery route -- scikit-build-core's entry point,
76+
`CMAKE_MODULE_PATH`, `PRIK_DIR`, and an installation prefix -- with a script
77+
that runs each route and calls the built extension.
78+
1079
- Array handles support allocatable and pointer arguments, results, module
1180
variables, derived fields, optional arguments, and matching ordinary-array
1281
parameters. Numeric and character arrays accept supported forward and

‎MANIFEST.in‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
include CHANGELOG.md
22
include CITATION.cff
33
include .artifacts/.gitignore
4+
recursive-include prik/cmake_modules *.cmake

‎docs/developer/packages/pipeline.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ prik/pipeline/
8686

8787
`build.py` is the orchestration hub. Its public records describe inputs and
8888
results without executing a build: `NativeCompilationUnit`,
89+
`GeneratedCompilationUnit`,
8990
`NativePrebuiltArtifact`, `NativeLinkItem`, `NativeBuildPlan`, and
9091
`WrapperBuildResult`. Its three public entrypoints are source-first builds,
9192
contract-first builds, and replay of a saved contract-build manifest.
@@ -114,6 +115,18 @@ source collections stay distinct, a source-free `.pyi` build states its native
114115
language instead of deriving it from a compiler or ABI decorator, and prebuilt
115116
objects, archives, and libraries stay ordered `NativeLinkItem` records.
116117

118+
Build integrations consume the completed result rather than compiler command
119+
logs. Native and generated compilation units retain their own requested flags,
120+
required ABI flags, and include directories; the result also records every
121+
semantic/preprocessing dependency and the final linker language. This is the
122+
lossless boundary used by `UsePRIK.cmake` for regeneration, linker-driver
123+
selection, and target-local compilation. CMake places native units in a
124+
private per-module object target so source properties cannot leak between
125+
PRIK extension targets; generated sources remain on the Python extension
126+
target. CMake dependency targets stay attached to the extension for linking
127+
and are also attached to that object target when present, so their usage
128+
requirements reach native compilation.
129+
117130
`WrapperBuildResult` and saved `.pyi` manifests report each generated native
118131
group's kind, language, member keys, and source paths, so zero-source,
119132
adapter-only, support-only, and mixed output stay factual across direct builds,

0 commit comments

Comments
 (0)