This file is the canonical record of user-visible PRIK changes. Add changes to
Unreleased as they land, then move them into a versioned section during
release preparation. Versions use Semantic Versioning;
release tags add a leading v to the package version.
This release updates documentation, examples, and repository tooling. The prik
library code is unchanged from 0.5.1.
- Improve the Reference BLAS example guide
- Improve the LAPACK example guide
- Improve the MINPACK example guide
- Compare the MINPACK example's eight SciPy-exposed solvers with SciPy
- Improve the FFTPACK example guide
- Improve the BSPLINE-FORTRAN example guide
- Improve the Open MPI
mpi_f08tutorial - Improve the PRIMA example guide
- The README and the documentation homepage now open with a short terminal demo.
- The repository root holds fewer files. Contributor notes moved to
.github/CONTRIBUTING.md, the pre-push hook totools/githooks/(activate it withgit config core.hooksPath tools/githooks), and the documentation theme totools/mkdocs-theme/. Local builds writeprik.egg-info/to the ignored repository root;.artifacts/still holds the documentation site and distributions. Subprocess coverage uses the startup hook that ships with coverage, soCOVERAGE_PROCESS_STARTworks as before.
- Fortran derived-type scalar fields now expose live, writable rank-zero NumPy
views instead of copied scalars or strings. Generated contracts use
T[()]andString[n][()]; an edited contract can still request a copied value with plainTorString[n]. Scalarallocatableandpointerfields also return a current view orNone, and are omitted from default constructor keywords. - Mutable Fortran module scalars now expose live rank-zero NumPy views instead
of copied scalar values. Scalar
allocatableandpointermodule variables return a current view orNone; read them again after native storage changes. - Generated Fortran derived-type classes now use capitalized names such as
Point_Tforpoint_t; other Fortran names remain lowercase. Generated C names preserve source case, soFooandfooremain distinct. Update Python imports and calls that relied on the old generated spellings. - The
Stridedcontract marker and dimension-step forms have been removed. UseT[::]for a strided axis andT[:]for a contiguous one.
TYPE(*)dummies accept supported NumPy scalar and array storage through the dummy's address or descriptor ABI, including directBIND(C)calls. Contracts useAnyNative, shape subscripts, andReadOnlyfor scalar inputs that may use immutable NumPy values. Callers retain buffers used by nonblocking native operations until completion.- UCS-4
character(kind=selected_char_kind('ISO_10646'))usesUStringand NumPyU<n>storage.selected_char_kind('ASCII')and'DEFAULT'useString; numeric character kinds are classified with the selected compiler. - Source commands accept repeated
--module-source-dirpaths, andbuild_fortran_extensionacceptsmodule_source_dirs. PRIK finds used module and submodule sources under those directories, including transitive dependencies, and reports missing or ambiguous definitions. Native libraries and prebuilt module directories remain explicit build inputs. --export-symbolsandbuild_fortran_extension(export_symbols=...)select module-qualified public Fortran procedures, generics, and variables, including public facade re-exports. Required signature declarations remain available; the generated contract's__all__records the Python surface. C source selection likewise records its Python surface in__all__.- Source builds and
generate --pyinow agree on Fortran project resolution, selected exports, names, and generated contracts. A contract build treats its edited__all__as authoritative, including withheld dependencies and package sub-namespaces; relative sibling imports let a module leaf be built directly. - Cross-module derived types, variables, procedures, callback interfaces, and
generic interfaces now resolve through public
useand re-export routes. A facade may expose a module variable as another live route to the same native storage, and merged generics retain specifics from every accessible contributor. A type used by another module's procedure keeps one native identity and can be constructed or returned through that module. - Optional Fortran callbacks can be omitted or passed
None. Optional arguments inside callback interfaces preservePRESENT(), and assumed-shape callback array arguments are supported. Writable scalar callback dummies reach Python as rank-zero storage so writes reach the native caller. - Supported optional arguments retain Fortran absence through forwarded native
calls, including combinations that previously expanded into many generated
call paths. Optional assumed-rank arrays retain their actual rank when
present and may be omitted or passed
None. - Numeric, logical, and fixed-character reference dummies accept matching
rank-zero NumPy storage as well as scalar values; a
VALUEdummy orImmutableargument receives a copy. - Contracts can rename classes, variables, constants, and callables while
retaining their native targets through
@bindorSourceName. Generated contracts preserve those targets, relative imports, overload links, pure specification functions, and Python publication when read back for a build.
- Array extents defined by a pure specification function are checked before a
native call, preventing out-of-bounds reads and writes when a caller supplies
the wrong shape. Generated contracts also retain
@pureand the callable names used in those extent expressions. - Fortran
useresolution now distinguishes bare,only, renamed, repeated, intrinsic, and non-intrinsic forms. Accessibility is honored through each re-export route; ambiguous routes fail instead of selecting a declaration by import order. Separate module procedures and generic specifics resolve in the modules that declare them. - Generated contracts now use consistent Python names for imports,
annotations,
__all__, and built extensions. This fixes replay of renamed types, private callback prototypes, re-exported declarations, merged generics, keyword-like names, and collisions between variables and procedures. An edited__all__matches Python spelling exactly. - Character declarations and constants preserve their stated kind, length, quotes, and contents, including entity-specific lengths and kind-prefixed literals. Generated Fortran continuation no longer splits a character literal, and preprocessed parse diagnostics report source locations.
- Optional
intent(inout)scalar omission returnsNonefor that output. A pointer-derived argument reports inaccessible fields before wrapper planning, and unsupported output ordering reports a policy diagnostic. - Generated wrappers correctly share derived-type helpers across namespaces, allow same-spelled types in different modules, and import bundled support for alias-only modules.
- The PRIMA example builds one static
libprimafarchive, generates a selected contract for five derivative-free solvers, and checks numerical results and callbacks on the real-library portability matrix. - The Open MPI
mpi_f08tutorial generates a restricted contract, builds a wrapper against a matching Open MPI installation, and runs a two-rank mpi4py-style example. CI tests Open MPI 4.1 and 5.0 on Linux and macOS against mpi4py built from the same installation and uploads matched-installation benchmark results. - Generated derived-object calls and module attribute lookup are faster in the documented Open MPI measurements. The tutorial reports operation-specific comparisons with mpi4py and the measured environment.
-
Added CMake integration through the packaged
UsePRIK.cmakehelper and aprik generate --cmakestandalone-project mode. CMake generates PRIK wrapper sources as build outputs and owns native compilation, linking, external targets, and incremental rebuilds while preserving per-source flags, compiler-required ABI options, preprocessing dependencies, and linker language from PRIK's completed build plan. -
CMake contract modules now distinguish semantic
NATIVE_LANGUAGEfrom the finalLINKER_LANGUAGE, keep native compilation flags target-local, and report a clear error when CMake's C language is not enabled. -
CMake dependency targets now propagate their native compile usage requirements, and standalone
--cmake --ltoinitializes IPO for native and generated targets. -
CMake configuration no longer runs PRIK's semantic pipeline. It asks for a structural plan -- deterministic generated filenames, the link driver, and compiler-profile ABI flags -- and the full pipeline then runs once at build time. Configuring a 300-procedure module's plan drops from about 2.5s to 0.4s, and the structural query no longer grows with source size.
-
Generated CMake targets have a fixed source list. The optional collision adapter and Fortran bridge units are always written, holding a symbol-free placeholder when unused, so a semantic edit changes file contents instead of the build graph and never forces a CMake reconfigure. Transitive semantic inputs now reach CMake through a generated dependency file, which raises the CMake floor for the packaged helper to 3.21.
-
prik generate --cmakekeeps each native link input in its own CMake category: prebuilt objects, archives, and shared libraries stay filesystem paths inLINK_LIBRARIESinstead of becoming ambiguous relative tokens, while library names and linker arguments keep their meaning and order. -
CMake native object targets receive
LINK_LIBRARIESwith the caller's link syntax unchanged, sodebug/optimizedkeywords and generator-expression entries keep selecting usage requirements per configuration instead of being flattened or dropped. -
CMake mode rejects a
.Csource suffix, which CMake compiles as C++ while PRIK plans the source as C, and reports a clear error when a module contributes native Fortran sources without CMake's Fortran language enabled. -
prik_add_module()acceptsLIBRARY_DIRS, mapping it totarget_link_directories()and the extension'sBUILD_RPATH.generate --cmaketranslates--native-library-dirintoLIBRARY_DIRS, so a shared native library outside the system search path is found both at link time and on import withoutLD_LIBRARY_PATH. -
prik-build.jsonschema 5 records generated/native compilation-unit ABI flags and explicit native linker-language requirements. -
PRIK's CMake modules are packaged inside the
prikdistribution and discovered automatically. scikit-build-core builds pick the directory up through acmake.moduleentry point, soinclude(UsePRIK)needs no lookup, and a packagedPRIKConfig.cmakemakesfind_package(PRIK CONFIG REQUIRED)load the same helper.prik cmake-dirprints the packaged module directory andprik install-dirthe prefix PRIK's data files are installed under, for-DPRIK_DIR=and-DCMAKE_PREFIX_PATH=.cmake_module_dir()and theshare/prik/cmakeinstallation are unchanged. -
The Ubuntu and macOS unit-test jobs now fail when CMake is missing instead of letting the CMake integration tests deselect themselves, and report a missing Ninja as a warning because those tests then use the Makefile generator.
-
Added the runnable
examples/cmake/project, which builds one Fortran module through every CMake discovery route -- scikit-build-core's entry points,CMAKE_MODULE_PATH,PRIK_DIR, and an installation prefix -- with a script that runs each route and calls the built extension. -
PRIK also publishes scikit-build-core's
cmake.rootentry point, which setsPRIK_ROOT, so a project listing PRIK andscikit-build-core>=0.11in[build-system] requiresresolvesfind_package(PRIK CONFIG REQUIRED)with noPRIK_DIR,CMAKE_PREFIX_PATH, orCMAKE_MODULE_PATH.include(UsePRIK)keeps working through the existingcmake.moduleentry point. -
A configure-time structural query that fails because PRIK or one of its dependencies cannot be imported now names the selected
Python_EXECUTABLEand how to check it, while keeping the underlying error. Other generation failures are reported unchanged. -
Added
prik doctor cmake, which reports the imported package, the distribution metadata answering for it,cmake-dir,install-dir, both CMake entry points, and any duplicate installation orPYTHONPATHentry that could answer instead. -
Array handles support allocatable and pointer arguments, results, module variables, derived fields, optional arguments, and matching ordinary-array parameters. Numeric and character arrays accept supported forward and reversed Fortran sections without copying.
-
Character array handles support caller-created and returned storage. Deferred-length allocation and resizing use
element_length=.... -
Wider Fortran logical arrays use the matching-width NumPy integer dtype;
logical(c_bool)arrays usenumpy.bool_. Handle storage also supportslongdouble,clongdouble, anduintpwhere the target exposes them. -
Improved generated-wrapper build time and contiguous-array call overhead.
-
Breaking (native ABI): native array handles use
prik.native_array_backend.v2. Rebuild extensions that exchange handles.
- Republishes 0.4.2. That tag carried the previous package version, so the built distribution was rejected as an existing release and never reached PyPI. The contents are unchanged.
-
The
jupyterextra now accepts IPython 7.0 and newer instead of requiring 8.0. The cell magics use only long-stable IPython APIs, and the higher floor madepip install prik[jupyter]upgrade the IPython that hosted notebook environments ship, which forced a runtime restart for no benefit. Theqaextra installsprik[jupyter]rather than repeating that requirement, so the supported IPython range is stated once. -
Added a runnable
examples/notebooks/quickstart.ipynband its guided tutorial, covering a Fortran cell, a C cell, and reshaping the generated API by editing its semantic contract in the same session. The home page, Getting Started, the tutorial, and the README offer it as a Colab run or a direct download, so the documented workflow can be tried before installing anything. -
Generated contracts now represent a one-level primitive C pointer as runtime-rank
T[...]NumPy storage instead of choosing a scalar temporary. It accepts ranks 0 through 15 with any strides, so a Fortran-ordered array or a strided slice reaches the native call unchanged, and it can be narrowed to contiguous, rank-zero, fixed-rank, or scalar-address storage in an edited contract.Arg(i).sizesupplies the total element count to a native parameter, alongside the existingArg(i).shape[d]andArg(i).strides[d]layout projections; an axis projection against storage that has no such axis now raisesTypeErrorinstead of reading past the actual's shape. -
Getting Started now offers complete Fortran and C paths for toolchain verification, building the same first function, and the edit-review-build-test loop. Fortran modules now begin in their task-focused User Guide page instead of a separate mandatory beginner step.
-
Added a dedicated C section to the User Guide for scalar functions, pointer contracts, arrays and strings, outputs and errors, and native symbols and dependencies. The C Support page now serves as a concise capability and boundary map with the same wrapper-area, boundary, and source-entry structure as Fortran Support. User Guide navigation presents separate Fortran and C paths followed by their shared build workflows.
-
An array argument now requires the NumPy storage of the C element type its source declares, rather than the canonical storage of the same width. A target's
int64_tmay belongorlong long, and NumPy independently givesNPY_INT64to whichever of the two is 64 bits, so those two choices could disagree: along long *buffer asked fornumpy.longlongon one target andnumpy.int64on another. One C source now keeps one accepted dtype everywhere. -
A scalar argument whose native parameter is a 64-bit C integer now accepts either NumPy spelling of that width and converts it, so
np.int64andnp.longlongare both valid for along longorlongparameter whichever one the target callsint64_t. Array arguments are unchanged: an element buffer cannot be converted, so it still requires the exact native dtype. -
A cell magic that reads a dash-prefixed flag value as another option now names the equals form and, for the flag groups, the quoted-group form.
-
Added optional
%%fortran,%%c, and%%pyiIPython/Jupyter cell magics. Native-source cells compile directly or, with--pyi, persist their exact source and insert editable per-module or direct-declaration contract cells. Executing the generated%%pyicell recovers the source language from its digest, builds against that cached source, and publishes declared Fortran modules or standalone declarations directly in the notebook namespace. Exact cells reuse a persistent SHA-256 build cache unless--forceis selected, and PRIK does not expose an internal package entry. Wrapped functions follow the published notebook path (maths.squareor standalonesquare) instead of exposing the private cache extension name; ordinary file builds retain their user-selected package root, such asgeometry.maths.square. Existing notebook build artifacts are rebuilt once so cached extensions cannot retain the old private function identity. Multi-module--pyicells are presented sequentially in terminal IPython, whose next-input prompt can hold only one editable contract, while Jupyter frontends continue to receive every generated module cell immediately. All cells in one generated contract bundle retain the source cell's effective compiler and build flags; changing that configuration requires regenerating the bundle and is rejected before compiler execution. Independently authored%%pyicells can instead name one or more existing implementation files with--native-fortran-sourcesor--native-c-sources; each cell builds and publishes only its own contract module, and native file-content changes invalidate its persistent cache. -
A one-character
@native_callliteral is now buildable:String[1]("N")declares the character a native parameter receives instead of leaving it a visible Python argument. It crosses the boundary as an interoperablechar, so the same completed decision reaches a bridged Fortrancharacter(len=1)dummy and a directbind(C)entrypoint. Policy completion requires exactly one byte-representable character; invalid values and longer fixed-length literals are rejected before planning. -
A
@native_callcomputed projection can now state the integer type it is materialized as:Int32(Arg(0).shape[0])beside the existingInt32(1)literal form. Shape, stride and length producers previously always crossed the boundary asSizeT, which is the right identity for a Csize_tparameter but not for a default FortranINTEGER, so those parameters had to stay visible in the Python signature. Fixed-width signed and unsigned integer contract types andSizeTare accepted; unresolvedIntandUIntare rejected before planning. The explicit conversion is not range-checked. -
Renamed the exact C scalar mechanism from "cast" to "identity" throughout the semantic IR and policy, matching the documented
Exact C Scalar Identitiesvocabulary and freeing "cast" for the conversion above. The public contract helpers (CInt,CLongLong, and the rest) are unchanged. The semantic-IR JSON record emitted byprik semantics --jsonrenames itsnative_castprojection key tonative_c_identityand gains avalue_castkey. -
Added a Pythonic BLAS tutorial and runnable example that reshape
DDOT,DNRM2,DGEMVandDGEMMintodot,norm,matvecandmatmul, plusDenseMatrix. An edited.pyicontract owns the exact native mapping, extents, leading dimensions, transposition modes, array validation, fixed numeric values and result allocation. Matrix operations consume Fortran-contiguous storage directly, whileDenseMatrixconverts its matrix once at construction. The example reuses the existing Reference BLAS sources in a four-file contract, Python API, build and test workflow. The.pyireference now states the native identity of shape and stride projections and the declared-character-literal form. -
Reduced clean-build time for large projects under optimizing compiler flags. Generated bindings now bind each ordinary array argument through one shared
prik_bind_arrayhelper instead of emitting the whole validate, extract, and native-handle sequence at every array argument of every wrapper. A wrapper carries one call and a small table of required extents in place of the sequence, so the compiler optimizes the binding logic once rather than once per argument per wrapper. Building the 155-source reference BLAS with-O3 -march=nativeemits about a third less binding code and compiles it about 1.4x faster. -
A binding is always one generated C file. Large procedure-only projects were previously split across
<module>_wrapper_001.cand siblings so those units could compile concurrently; every project now generates only<module>_wrapper.c. Splitting raised total compiler work — each unit re-parsedPython.hand the NumPy headers — and paid off only where cores were idle, which a project's own sources rarely leave. Removing it lowers total build work and leaves one file to read when inspecting generated output.
- Fixed README links and the logo for PyPI rendering. Documentation links now open the published website, maintained-library links open their complete website guides, and repository files use absolute GitHub URLs.
-
Reorganized the Reference overview by task and linked every published user reference, including the editable
.pyiformat and generated build files. The Reference sidebar now follows the same grouped structure, with.pyiFormat followed by the clearly named Editing Contracts guide, and the build-file reference clearly distinguishes source and semantic-contract generation while showing the structures of both the replay manifest and Makefile. The user Reference now presents.pyiFormat as a top-down guide to the distinct Fortran package and C single-file layouts, namespace exports, declarations, C- and Fortran-specific forms, decorators, native-call entries, types, storage, and metadata, while leaving the internal Semantic IR model to the developer Semantics Stage guide. -
Added C-focused FAQ answers for first builds, pointer contracts, supported arrays and strings, a runnable existing-library or large-header workflow with task-specific follow-up links, and fail-closed unsupported APIs.
-
Linked the Language Support overview directly to an expanded At A Glance comparison, separated the detailed Fortran, C, and shared sections, gave each supported and unsupported C capability family its own evidence row, removed the ambiguous implementation-route column and empty planned-work placeholder, replaced vague lane terminology with explicit C wrapper wording, and made Fortran Support a complete guide-linked wrapper overview while retaining its concise source-format and public-entrypoint reference. The duplicated monolithic Fortran Wrapper Reference and the three redundant generated Fortran API pages were removed; their unique public rules now live in Fortran Support, the topic-specific User Guide, and
.pyiFormat. The README and website homepage now describe C as a focused wrapper subset and name its currently supported primitive, one-level-pointer, NumPy-array, and string surface without changing PRIK's Fortran-and-C positioning. -
Grouped the maintained library projects under
examples/fortran/andexamples/c/, with the same Fortran and C grouping in the published example navigation. Commands, CI jobs, source-linked documentation, and package imports now use the language-specific paths. General documentation names both direct-C projects, while the homepage defers their technical details to the example guides. The gallery summarizes the hosted compiler and architecture matrix, and every project guide records its own tested platforms. -
Added a maintained TA-Lib v0.7.1 example with a checked-in semantic contract for all 322 double and float-input indicators plus initialization and shutdown. Its reviewed inventory accounts for all 522 public functions, its edited contract projects TA-Lib's output range metadata, and its fail-closed differential harness sends the same request through a direct native reference and the PRIK wrapper for every numerical entrypoint. The guide explains the common indicator signature, semantic
.pyimapping, and provenance and limits of those live reference results. Maintained-example pages now distinguish the five Fortran source examples from libm and TA-Lib, whose wrappers consume public C declarations and link compiled libraries. -
Multi-source Fortran builds compile in dependency order instead of the order you listed. PRIK records which parsed file provides each module and submodule, resolves the
usedependencies between them, and groups the objects into batches that only depend on earlier batches, so naming a consumer before its provider no longer fails the build. Batches within a level can compile concurrently;--jobs Nbounds that. When a compiled source was never parsed — an extra--native-fortran-sourcesfile, for example — or the dependencies cannot be ordered, the build falls back to the order you supplied. Discovering sources you did not name, prebuilt module search paths, and external libraries remains the caller's responsibility. The reference and feature matrix previously described this as unsupported. -
Every Python fence in
docs/is now checked, not only those on the README, Getting Started, and User Guide pages. Each is parsed, and one importing fromprik.contractsis loaded as a semantic.pyicontract, so a reference-page snippet can no longer drift into a contract that does not load. Two markers support this:prik-doc-test-outputnow also tells the audit that a fence holds captured output rather than source, and the newprik-doc-contract: invalidmarks a negative example and asserts that loading it fails.docs/developer/workflows/documentation.mddocuments the marker set. A function selected byprik-doc-sourceis checked together with its decorators, so semantic-call mappings cannot drift outside the verified excerpt. -
The copied LAPACK example now mirrors Reference LAPACK's default source selection: XBLAS-only routines are excluded, the two required
INSTALL/workspace helpers are bundled, and a failed native build now stops without a secondary missing-source diagnostic. This makes the maintained 127-routine example build consistently on Linux and both hosted macOS architectures.
-
Removed the redundant user recipe section and the unpublished deferred C parser page. Their maintained workflows and evidence now point directly to Getting Started, the User Guide, Language Support, and the active API, CLI, parser, and preprocessing references.
-
Semantic class contracts now use class-level
@native_abi("c")for Fortranbind(C)derived types as well as callable entrypoints. The redundant@native_typedecorator has been removed, and the behavior-neutral Fortransequenceattribute is no longer serialized into semantic.pyior carried into wrapper planning. Native teardown operations use one language-neutral@destroydeclaration per operation and remain lifecycle metadata rather than public Python methods. The generated class reference also clarifies constructor replacement, complete method overload sets, object destruction, and when native resource ownership needs custom teardown. -
Fortran feature tests now keep permanent native inputs, reviewed generated contracts, edited contracts, and routing cases in one consistent fixture layout. The exhaustive primitive-array evidence now belongs to the arrays feature, and the documented array journey is checked through both source and generated-
.pyibuilds. -
Report commands now share one output rule:
--jsonselects the format and--outselects the destination, and neither changes the other. Without--jsonevery report command prints a human-readable report; with--jsonit emits the complete record.--out PATHwrites whichever format was selected, and bare--outwrites one file beside each input source, using.jsonfor the record and.txtfor the report.This changes three commands:
parse --out PATHpreviously wrote JSON regardless of--json; it now writes the human-readable report unless--jsonis given. Useparse --json --out PATHto keep the previous output.semanticsgains--jsonand--print-limit, and now prints a human-readable summary by default instead of the complete JSON record. Usesemantics --jsonto keep the previous standard-output behavior. The summary reports each module's functions with their semantic signatures and every argument's semantic dtype, rank, ownership, and mutability.probereplaces--format {json,markdown}with--json. The Markdown mapping table is now the default standard-output rendering, and the Markdown output itself is unchanged.
-
probenow selects its report from--exprrather than from the output format. Without--exprit measures the standard datatype mapping table, so the bare command reports that table instead of an empty measurement; with--exprit measures the named expressions, which now render in both formats. The JSON mapping report adds the structuredtarget_factmeasurement,recipe, andsource_textalongside the displayed text. The mapping report now rejects-I,-D,-U, and--stdinstead of accepting options its fixed inventory cannot use. -
prik.pipeline.type_mapping_reportnow exposesc_type_mapping_report()andfortran_type_mapping_report()returning measured records, plustype_mapping_markdown()andexpression_probe_markdown()renderers, replacingc_type_mapping_markdown()andfortran_type_mapping_markdown(). -
Documentation: added a source-backed Fortran support reference, clarified the C direct-wrapper boundary, aligned root CLI help with Fortran, supported C, and semantic-
.pyiinputs, and refreshed the user and contributor documentation navigation.
-
Fortran-led semantic
.pyibuilds now select the C compiler paired with the chosen Fortran driver when no C override is supplied, and record that resolved driver for manifest replay instead of forcing the systemcc. -
Coercive integer callback results now raise
OverflowErrorwhen a Python integer falls outside the declared native width instead of narrowing or wrapping it silently. -
UInt64andSizeTscalar results now use the same target-specific NumPy scalar identities accepted by their arguments, so a generated result can be passed back into the same direct-C API on LP64 targets. -
Manifest replay now validates the recorded semantic
.pyiimport graph before generating files or invoking a compiler. -
Mixed-language builds now use the Fortran driver's matching C compiler when no C override is supplied, use that same driver for C probing and compilation, and reject an explicitly supplied C/Fortran family mismatch.
-
Native link-item language requirements now survive result serialization and manifest replay for named libraries and linker arguments as well as path artifacts, preserving link-driver selection.
-
Generated bindings now allocate writable string-replacement buffers only after all inputs validate, release every live buffer on later setup or conversion failure, free replacements before other fallible output conversions, and release unpublished native results if string write-back conversion fails.
-
Binding-owned array-coercion temporaries now clear their local owner when released, so later native-status error cleanup cannot release them twice.
-
Failed Python conversion of one native result now releases every later unpublished string, array, descriptor, or derived-result owner instead of leaking storage returned by the same native call.
-
Source builds now fail before native compilation if their promised semantic contract package cannot be rendered, and report the written
.pyifiles inWrapperBuildResult.generated_files. -
Direct-C preflight now rejects every intrinsic unsupported-policy diagnostic before target ABI probing; only diagnostics that require compiler-probed primitive facts are deferred.
-
Direct-C array policy now rejects explicitly non-C layouts instead of silently replacing the authored semantic contract with C-order validation.
-
Semantic
.pyidecorators used on declaration kinds where their meaning cannot be represented are now rejected instead of silently discarded. -
Abstract derived-type identity is now module-qualified during semantic conversion. A concrete type with the same local name in another module no longer inherits abstract-dummy policy, while imported abstract types are recognized regardless of project source order.
-
Source-free C contracts now carry compiler-probed
Int,UInt, andSizeTstorage through primitive arrays and projected outputs while preserving exact standard C spellings such asint *in generated prototypes. Target- generatedint[]contracts therefore stay in the documented direct-C lane without requiring a manualInt32[:]rewrite. -
Verbose wrapper builds now print each compiler command before it starts, so failed invocations remain directly replayable.
-
semanticsandgenerate --pyinow reject non-source inputs instead of emitting an empty report. -
Ordinary array arguments now preserve their non-array type check before accessing NumPy storage. Native-handle-capable branches still avoid repeating that check after selecting their NumPy fast path.
-
Common scalar and string conversions in C bindings with several Python outputs now share one linear reference-cleanup path instead of repeating every earlier
Py_DECREFat each failure site. Large wrappers retain the same result ownership and diagnostics while generating smaller C control-flow graphs. -
Ordinary NumPy-array arguments no longer repeat
PyArray_Checkinside the validation helper after the generated fast-path branch has already performed that check. Dtype, rank, layout, byte-order, alignment, and mutability validation remain unchanged. -
Built-in release compiler profiles no longer force loop unrolling in generated wrappers and native sources. Release builds retain
-O3, and callers can still request vendor unrolling flags explicitly; optimized large-wrapper builds therefore avoid the hidden compilation cost by default. -
Real Libraries Portability now exposes the matching GNU C driver beside its selected GNU Fortran driver. Generated C bindings therefore use GCC on macOS, including its
ISO_Fortran_binding.hsearch path, instead of accidentally resolving Apple's unrelatedgcc-named Clang driver. -
The copied BLAS and LAPACK examples now give GNU Fortran a positional archive input when creating a macOS dynamic library. Apple
ldstill receives the targeted-force_loadoption, while the compiler driver no longer aborts with "no input files" on either hosted macOS architecture. -
The Linux x86-64 BLAS and LAPACK full-surface CI audits now run in the same shell steps as their example builds, so they reuse the temporary extensions instead of losing their exported import paths at a GitHub Actions step boundary.
-
The portable libm tests now read and call
long doubleroutines through the public dtype selected by the target-generated contract. Apple ARM64 usesnumpy.float64, while targets with wider Clong doublestorage usenumpy.longdouble. -
An exact native C scalar passed by address and projected back to Python now converts its native call-local into the public contract storage type before constructing the NumPy result. This removes an incompatible-pointer handoff such as
long long *to anint64_tresult helper. -
Compiler-preprocessed C prototypes with an unnamed builtin parameter, such as Apple
<math.h>'slong rinttol(double), are no longer mistaken for unsupported K&R definitions. -
Compiler-preprocessed C headers that provide fallback
_FloatNtypedefs now parse successfully. This keeps private glibc compatibility declarations from blocking an allowlisted public API when Clang preprocesses<math.h>. -
An exact native C type around a NumPy-backed
Arg(...)now requires its matching NumPy C storage type. For example,CLongLong(Arg(0))acceptsnumpy.longlongand rejects a distinctnumpy.int64buffer instead of passing that buffer tolong long *through an incompatible pointer. The rule covers all supported exact C types with matching NumPy storage; scalar value arguments keep their existing conversion behavior. -
A C translation unit's module variables, enum or macro constants, and aggregate type declarations no longer reach wrapper planning. They previously generated a Fortran adapter module for a C input and failed with a raw compiler error after writing files; they now fail closed before planning with
C_DIRECT_NATIVE_GLOBAL_STATE,C_DIRECT_ENUM_CONSTANT,C_DIRECT_MACRO_CONSTANT, orC_DIRECT_AGGREGATE_TYPEand leave no output. -
A C declaration the parser cannot model — for example one carrying an unsupported calling-convention attribute — is no longer dropped from a wrapper build's public API. It raises
C_DIRECT_UNMODELED_DECLARATIONinstead of silently publishing a smaller or reinterpreted API. -
T[:] | NoneandT[()] | Nonein a C semantic contract no longer build a silently non-nullable wrapper. Nullable C pointers are outside the initial C lane, so the contract now fails withC_DIRECT_NULLABLE_POINTER. -
A route-neutral
@native_callreorder in a C contract no longer converts one argument's Python value using another argument's declared type. -
An edited array contract can now derive its native extent from the buffer, as
@native_call([Arg(0).shape[0], Arg(0)]). A binding-owned extent, length, or presence producer is no longer mistaken for the argument's own transport slot, which had also lowered the promoted buffer as a by-value scalar. -
Fortran
bind(C)procedures that pass strings, derived objects, or callbacks through their direct entrypoint build again. The new exact C declaration plan is now built only for C-source operations. -
The generated docstring for a call-local scalar address argument no longer claims that native code updates the supplied storage in place. That update lands in a call-local copy and is not visible in Python.
-
A
generate --makefilebuild invoked with relative paths now produces a Makefile that runs on a clean tree. The link rule demanded each user object twice, once under a relative spelling that no rule produced, somakestopped with "No rule to make target". This affected Fortran and C builds alike. -
C contracts can now pass strings.
Stringhands a Cconst char *the Python object's own NUL-terminated buffer, andString[...][()]hands achar *a rank-zero NumPy bytes buffer untouched, so native writes are visible in place. A declared capacity such asString[32][()]additionally checks the caller's itemsize. PRIK takes no position on whether the callee reads to a terminator or takes a separate length: the contract states which form the C code expects.@raises(message=...)works too when the projected message declares a capacity, such asReturns["message", String[64]]: the binding owns that buffer and passes it aschar *, instead of the bridged route's owned-allocationchar **. Arrays of strings, pointer results, and owned buffers stay fail-closed. -
@raises(message=...)can now name a visible argument instead of a projected hidden output, in both the C and Fortran lanes. The caller then supplies writable storage — a rank-zero NumPy bytes array forString[n][()]orString[...][()]— so no capacity has to be declared, and the buffer survives the raise for inspection. A visibleStringis accepted too, but it borrows the Python object's own buffer and lowers toconst char *: the contract states a read-only input, so native code that writes through it is violating the declaration it was handed. That is the C API author's call to make; prefer NumPy storage for any message the native code fills. Only the hidden form still requires a fixed width, because there the binding allocates the buffer and the size the native code assumes is not in the signature. -
Hidden(name, T)declares a native output the Python signature never shows. It is planned, passed, and released exactly like a returned output — the bridge sees no difference — and only the binding skips building a Python value from it. This makes@raisesstatus and message one instance of a general mechanism rather than a special case, and it works in both the C and Fortran lanes. -
@raisestargets are now declared withHidden(name, T)inside@native_callinstead of occupying a slot in the return annotation. A status or message is produced by the native call but consumed into the exception, so listing it as a returned value described a Python signature that never existed:-> tuple[Returns["root", Float64], Returns["status", Int32]]returned a bareFloat64. Contracts now say what they mean, and the emitted.pyinormalizes the old spelling to the new one. -
Rank-zero character storage may now leave its width assumed in the Fortran lane too:
String[...][()]takes the width from the caller's NumPy array instead of the contract, matching what the C lane already accepted. The same now holds for character arrays, whereString[...][:]takes every element's width from the array's itemsize. A declared width still validates the caller's itemsize; an assumed one accepts whatever the array carries. -
Rank-zero character storage now always reports its width beside the address, so a declared and an assumed width generate the same adapter shape instead of baking a literal into the generated Fortran. A raw string address keeps the declared width, because a bare caller-supplied address has no Python object whose size could be measured.
-
A
@raisesmessage is now read within the capacity its storage declares instead of by scanning for a terminator. Fortran blank-pads fixed-length character storage and never writes a NUL, so the previous scan reported the padding as part of the exception text — acharacter(len=64)message raised'negative'followed by 56 spaces. When the native code did terminate, the bytes are still taken exactly as written. -
A
@privatedeclaration in a C semantic contract is no longer refused as an unsupported C operation. Being unexported is a shared contract feature, not a C-lane limit, so the documented@overloadpattern — private concrete candidates behind one public Python name — now works for C. -
A C wrapper build now works when the C compiler is named
cc.ccis the documented default for the C lane, but its vendor was read from the executable's filename, which names no vendor. That happened to work wherecclinks to a vendor-named binary and failed everywhere it does not, such as macOS. The driver's own--versionbanner now settles the vendor when the name cannot. -
The BLAS and LAPACK examples now expect the character selectors that the conservative
intent(inout)default returns. Their assertions still encoded the olderintent(in)assumption forcharacterdummies, so the example suites failed against the behavior the same release documents. Positional reads of a returned scalar tuple moved with the selectors; five LAPACK assertions that had kept passing on a coincidentally equal value now index the dummy they name. -
The semantic contract a C build saves beside its extension now describes only the wrapped file's own API. Preprocessed system-header declarations stay inspection facts instead of filling the contract with private entries that the next build could not accept.
-
A C parameter or result written through a typedef now declares the exact builtin type the compiler probe resolved it to. The generated binding writes its own prototype, so a typedef name defined only by the wrapped source's headers previously reached the compiler undeclared and failed the build after files were written.
-
Added a portable libm example that regenerates its target-specific semantic
.pyifrom a reviewed 60-function ISO C99math.hselection before every build and validates every exported routine with a named numerical test. The contract records exact native scalar casts without changing its NumPy-facing signatures, and its dtype assertions follow the activelongandlong doubleABIs. A dedicated Real Libraries Portability workflow, reused by the pull-request gate, runs all maintained examples on Linux x86-64, Linux Arm64, macOS Intel, and macOS Arm64; libm additionally runs with GCC and Clang on each platform, and Linux x86-64 retains the deep BLAS and LAPACK audits. -
--positional-onlyexposes every wrapper whose arguments are all required as positional-only, renaming themarg0..argNin the signature, docstring, and argument diagnostics. A native declaration's parameter names then stay out of the Python API, which matters for a system header that spells them__xor omits them entirely. A function with an optional argument keeps its keywords, and a module with overload sets is rejected because overload dispatch selects a candidate by keyword. -
--ltoadds-fltoto generated and native compilation and to the extension link. A collision adapter is emitted with hidden visibility, so link-time optimization can inline the forwarder and drop its definition rather than exporting it from the extension. -
Target-specific C contracts now preserve exact scalar call identities with sparse expressions such as
CLongLong(Arg(0))and typed native-result projections. Public annotations remain ordinary NumPy types; policy completes the conversion before planning and the binding reuses its exact native scalar storage and direct-result path. Native C scalar names are rejected outside@native_call. -
--collision-adapter NAMEand--collision-adapter-allnow isolate genuine C identifier collisions only. The separate translation unit includes noPython.h, reconstructs the completed exact native declaration, and emits a hidden pure forwarder defined once per native symbol even when several Python callables name it. Only a C-source function is eligible: an explicitly named symbol that is unknown or ineligible fails before wrapper planning, while--collision-adapter-allpasses over Fortranbind(C)entrypoints instead of failing the build. Saved build manifests retain the selected adapter mode when replayed. -
Added a published C support guide with executable source and semantic-contract workflows, CLI and Python build APIs, supported primitive and NumPy-pointer contracts, compiler preprocessing, and the direct lane's fail-closed limits. Published the linked language-support, CLI, Python API, diagnostic, reference, and examples landing pages after aligning their commands and public links with the implemented surface.
-
Added the initial direct-only C wrapper lane.
build_c_extension, explicitnative_c_sources, and C-native semantic.pyicontracts compile, link, import, and call supported target-probed primitive C symbols directly. The lane covers arithmetic scalar values,void, completed scalar-reference and primitive NumPy-pointer contracts, and fails closed before planning for callbacks, aggregates, variadics, pointer results, multi-level or nullable pointers, ownership-sensitive forms, and other unsupported C ABI features. C wrapper builds preprocess their sources with the selected C compiler, so an ordinary#define,#ifdef, or macro-defined declaration is read the same way the C inspection routes read it, and only the wrapped translation unit's own declarations become public API. -
Every build now writes its semantic
.pyicontract beside the extension, in acontracts/package inside the build directory (__prik__/contracts/by default). Reshaping the generated Python API no longer needs a separategenerate --pyirun: the contract describing the API a build just produced is always there, and rebuilding from it works directly. It lives in its own directory so its__init__.pyicannot make the build directory look like a Python package. -
Generic constructors declared as
interface <typename>are now wrapped from Fortran source. Such an interface is that type's constructor, so its specifics become the accepted signatures of one overloaded__init__rather than a module-level generic, and a call matching none of them is refused instead of guessed at. A specific that isprivatein its module is reached through the public type name, which resolves to the same procedure. Because the interface supplies every accepted signature, it replaces the keyword-field constructor, and the generated contract states only the signatures the class accepts. The three sources of a constructor are now: no user constructor keeps the keyword-field__init__, aninterface <typename>supplies the overload set, and an edited.pyideclares exactly what it says. A constructor candidate carries no@bind, because the class name already states the generic that reaches it — the same reason an unrenamed method omits it — and@privateis refused on__init__, since a constructor is published or absent and the accessibility of the specific it selects is that procedure's own fact. -
Added the BSPLINE-FORTRAN example under
examples/fortran/bspline. It wraps the upstream sources unmodified and validates both public interfaces from Python: the object-oriented classes over an abstract base with deferred bindings and generic constructors, and the procedural interpolation routines. Numerical checks use analytic values andscipy.interpolateas independent oracles. It is the first example project written in modern Fortran rather than FORTRAN 77. -
BSPLINE-FORTRAN now follows the maintained real-library example workflow: its checked-in build instructions are verified with the documentation suite, its full procedural and derived-type surface is exercised in the native library CI job, and its inventory fails closed if generated exports or named numerical tests drift. The example now calls all one- through six-dimensional procedural setup and evaluation routines and constructs every concrete spline class against an independent affine interpolation result.
-
Abstract Fortran derived types are now wrapped. A
type, abstract ::declaration becomes a Python class with no constructor — instantiating it raisesTypeErrornaming the concrete extensions to use instead — while its extensions remain ordinary Python subclasses that inherit its implemented bindings. A deferred binding (procedure(iface), deferred ::) is declared on the base and resolved by the object's own type: the generated adapter converts the address to the caller's concrete type and lets Fortran select the override, so no Python-side dispatch is involved. An abstract type publishes no component accessors of its own, because each extension already generates one for every component it inherits, and it is excluded from the polymorphic cases a caller can supply, since no object can have it as a dynamic type. In semantic.pyicontracts the class carries@abstractand each deferred binding carries@abstractmethod, both re-exported fromprik.contracts; a deferred binding never carries@bind, because it has no native symbol.
- Reorganized the C and Fortran test suites around a strict ownership rule:
language features remain under
<feature>/<stage>, while shared parsing, preprocessing, CLI, semantic-representation, contract, build, and policy evidence live underinfrastructure/. Focused commands and documentation now use the corresponding infrastructure owners.
-
A
bind(C)character dummy that is a pointer now declares deferred length, as the Fortran standard requires. GNU Fortran 13 and newer reject the declared-length spelling earlier releases emitted, so wrapping acharacter(len=N), pointermodule array failed to compile there. Pointer assignment takes the length from its target, so the associated width is unchanged. The matching allocatable descriptor consumer travels as an assumed-length assumed-shape dummy, whose descriptor still carries the element length. -
A generic interface whose specifics project an
intent(out)argument into a result now reloads from its generated contract. The declaration states the public signature, so an output the projection turned into a result is not one of the arguments it accepts; comparing the declaration against the specific's native argument list rejected every such generic — the common shape in numerical Fortran — with "Overload declaration 'x' is incompatible with specific procedure 'y'". The same comparison now drives a type-bound generic's receiver search. Generated contracts for BSPLINE-FORTRAN'sdb1ink,db1val, andinitializeload again. -
A module whose only procedures are
bind(C)now installs the bundled native support its derived-type accessors need. Compiled wrapper builds for such a module previously failed to link withundefined symbol: prik_float64_to_numpy, because native support was requested only for module variables, for ordinary procedure arguments and results, and for array components — and abind(C)procedure supplies none of those. Every published component converts through those helpers, so a type with any component now requests them. -
A derived type's
privateandpublicstatements are now honored. The statement beforecontainssets the default accessibility of components and the statement after it sets the default for type-bound procedures; a declaration that states its own accessibility still keeps it. The statement aftercontainspreviously failed to parse at all, and the one before it parsed but was discarded — so a type with private components reached the Fortran compiler as generated accessors that read them, failing with "Component 'x' is a PRIVATE component of 'y'". Private components and bindings now simply stay off the generated Python class. Parsed derived types additionally recordcomponent_visibilityandbinding_visibility, and each type-bound binding records thevisibilityit resolves to, so the parser's serialized form states the accessibility it read. -
A
type, public ::declaration is no longer hidden by a module-levelprivatedefault. The type's own declared accessibility is the most specific statement about it, so it wins over the module default and over the module's accessibility lists. Previously such a type — and every one of its methods — was dropped from the extension silently, with the build still reporting success. -
A deferred type-bound binding (
procedure(iface), deferred :: name) now parses instead of failing as a syntax error, so whether it can be wrapped is a policy decision rather than a parser limit. Abstract types and deferred bindings are wrapped as described above; this entry records only the parsing change that made that possible. -
A named
blockconstruct (main: block ... end block main) is recognized as the start of a procedure's execution part. A construct name prefix is now stripped before a statement is classified, so nameddo,if,select,associate, andblockconstructs are all read as executable rather than as an unknown declaration. -
The compiler type probe no longer emits a program it cannot compile. The probe is a standalone program that cannot
usea module from the project being analyzed, because that module has not been compiled yet; an expression naming a kind parameter declared elsewhere in the project —storage_size(1_ip, kind=ip), for example — is now left for the requirement report instead of being compiled into the probe. Previously one such expression failed the whole probe and with it the entire build.
-
Added the C-only
--export-symbols FILEallowlist for source builds,semantics, andgenerate --pyi, with resolved-name parity throughbuild_c_extension(export_symbols=...). It promotes exactly the named reachable functions even from private system headers, excludes every unlisted declaration, and fails closed for malformed, repeated, missing, non-function, or ambiguous selections. This lets maintained examples parse platform headers without publishing their implementation-specific surface. -
The libm portability audit now reuses the Linux x86-64 and macOS Arm64 CI jobs and adds one focused Linux Arm64 job. All three regenerate from the target
math.hand run the complete 60-function suite without repeating the heavyweight Fortran real-library matrix. -
The libm example now stops immediately when contract generation or wrapper compilation fails, instead of exporting a broken build environment to a later test command.
-
Added
--assume-intent-in-scalars, which treats a primitive scalar dummy that declares nointentasintent(in)instead of applying the conservativeintent(inout)default. Fortran permits an undeclared dummy to be written, so prik returns its post-call value; for sources that predate theintentattribute this fills the Python return with unmodified controls, and reference BLASddotreturns(value, n, incx, incy)rather than the value alone. With the option, that call returns32.0. The choice is made once in semantic conversion, where an absentintentis interpreted, so the build andgenerate --pyidescribe the same Python surface. It is deliberately narrow: it covers the primitive and character scalars whose replacement is otherwise returned, a declaredintentalways wins, and arrays, derived-type objects, and allocatable or pointer scalars are unaffected. It is an assertion about the source rather than a fact derived from it — prik does not inspect the procedure body, so a procedure that does write such a dummy loses that value, exactly as removing the result from the generated contract by hand would. The option appears in the first--helpscreen because it changes the default Python surface, and every command that produces semantic IR accepts it — the build,generate --pyi, andsemantics.--build-manifestrejects it along with the other saved wrapper settings, and a.pyiwrapper build rejects it because a contract already states its own results.
-
A scalar
characterdummy that declares nointentnow uses the same conservativeintent(inout)default as every other scalar, so the value the native procedure left behind is returned. It was silently assumedintent(in), which meant a procedure that wrote to such a dummy lost that write with no diagnostic, while anintegerdummy on the same call had its write returned. The exception was undocumented and untested; the strings guide already stated the uniform rule this change makes true. Wrapping fixed-form sources, whereintentcannot be declared, therefore returns(result, text)where it previously returnedresult—--assume-intent-in-scalarsrestores the shorter surface and now covers character scalars along with primitive ones. Anallocatableorpointercharacter scalar with nointentlikewise now matches its numeric counterpart and returns a nullable snapshot; the option does not reach either one, because a snapshot is not a replacement value the caller supplied. -
Generated wrapper source is now readable. Each generated Fortran adapter and each CPython binding function carries a short leading comment naming what it is for — the native procedure an adapter wraps and the C symbol it exports, the Python callable a binding serves and the entrypoint it calls, and what a module accessor reads or writes — and an adapter additionally summarizes the conversions it performs. Generated Fortran modules also separate their procedures with a blank line instead of running them together. Comment prose is wrapped well inside the free-form 132-column limit, and each backend describes only its own plan facet, so the binding never names a Fortran symbol and the bridge never names a Python one.
- Declared-length
charactermodule arrays (character(len=4), allocatable :: arr(:), and thepointerequivalent) no longer fail in the Fortran compiler. The generated descriptor-consumer interface and descriptor ABI parameter both spelledcharacter(len=:)regardless of what the array declared, and an allocatable or pointer dummy accepts a deferred-length actual only when it declares one itself. Both now spell the declared width. A deferred-lengthcharacter(len=:), allocatablemodule array still fails to compile under GNU Fortran 11.4 with an internal compiler error, which is a compiler defect rather than a wrapper contract.
-
Every
charactermodule-variable form is now wrapped. Declared-length scalars are readable and writable as ordinarystrproperties, matching how numeric module variables already behave; a character value has no by-value C ABI, so the accessors copy through the same fixed-width buffer a character field already used, and assignment requires exactly the declared byte width rather than truncating or padding.allocatableandpointerscalars read as a detachedstr, orNonewhen unallocated or unassociated, through the same nullable snapshot a descriptor numeric scalar uses, carrying the width the descriptor holds at the time of the read.characterparameterarrays are copied once at import into a read-only fixed-width bytes array, the way numeric parameter arrays already were. Character module arrays report their own element width through their generated accessor rather than having it restated by the binding, so an assumed-length (character(len=*)) parameter array works too and takes the dtype width its initializer implied. An assumed-length scalar still keeps its rejecting setter, having no storage width to write into. -
Fixed-shape
charactermodule arrays with thetargetattribute now expose the same live fixed-width bytes view numeric module arrays already did, at any rank. The live-view lane rejected them only because it required a primitive numeric element type; a character element differs only in carrying its Fortran element length as the dtype width. Native writes appear in the view, and Python writes reach the storage Fortran reads.targetis required here exactly as it already was for numeric module arrays. -
Pointer array handles now expose
deallocate()without aPointerPolicyannotation, matching what allocatable handles already offered. Release stays manual and caller-driven — prik never frees a native target on its own, on garbage collection or otherwise — so this is the same responsibility a Fortran caller takes when writingdeallocatefor the same pointer. Previously a wrapped procedure that returned freshly allocated pointer storage leaked with no way to reclaim it from Python.allocateandresizestill requirePointerPolicy, because they establish a new target rather than releasing the one the handle already names. -
Added wrapper support for
allocatableandpointerscalarcharactervalues in every direction:intent(in),intent(out), andintent(inout)arguments, and function results, at both deferred (len=:) and declared (len=n) length. Policy now completes the adapter-local storage each dummy needs — its attribute, its length, and who releases it — instead of always building a plain fixed-length temporary. The C ABI is unchanged: a scalar character argument still crosses as a byte buffer and a length whatever the dummy declares. Previously most of these forms either stopped at a policy diagnostic or reached the Fortran compiler and failed there with "Actual argument for 'x' must be ALLOCATABLE"; declared-length allocatable and pointer forms additionally failed plan validation. -
Added a character-length subscription to semantic
.pyicontracts. The first subscription afterStringis always the length —String[...]assumed,String[8]orString[n]explicit,String[:]deferred — and an array adds its shape as a second subscription. Deferred-length scalars therefore have a contract spelling for the first time, so those procedures rebuild from their generated contract; the one-subscription array spellings the printer used to emit (String[::], andString[n]for an extent) are replaced byString[...][::]andString[...][n], which the parser had rejected or read as a scalar length. -
Added wrapper support for mutable scalar character descriptor arguments (
allocatableorpointer,intent(inout)). The dummy stays astrargument and additionally returns the value the native procedure left behind, orNonewhen it leaves the dummy unallocated or unassociated. Policy completes two decisions for the one dummy — a call-local character-buffer input and a nullable descriptor result — so the adapter copies back the local the native procedure may have replaced rather than the caller's buffer. A pointer dummy additionally records who releases the target the adapter allocated: the adapter frees it only while the dummy still identifies it, so storage the native procedure deallocated or replaced is left alone. The dummy spells asAllocatable(Arg(i))orPointer(Arg(i))withString[:]orString[n]in a semantic.pyicontract, so these procedures also rebuild from their generated contract. -
Added wrapper support for
allocatablescalarcharacterfunction results. The adapter moves the result out through an allocatable dummy rather than assigning it, which makes allocation a testable fact, so an unallocated result becomesNone. Other allocatable scalar function results remain blocked, because they have no such completed move. -
Added
@native_abi("c")to semantic.pyicontracts so Fortranbind(C)procedures retain their ABI and optional link label through generated and source-free contract workflows. -
Added selective direct routing for policy-proved Fortran
bind(C)procedures, including direct/mixed compiled feature fixtures and support-only generated Fortran artifacts where independent helpers remain necessary. -
Added a separate direct-entrypoint PRIK/f2py runtime and clean-build benchmark cohort with untimed correctness, generated-source membership, and linked direct-symbol preflight, plus an ordinary-Fortran PRIK control.
- Made nested semantic classes use the same complete planning and backend-symbol allocation path as top-level classes.
- Published the maintained-run direct-entrypoint runtime, adapter-control, and clean-build results separately from the normal-interface benchmark cohort.
- Made direct-entrypoint benchmark preflight identify binding and native objects by their inspected symbol relationships across f2py build backends.
- Reduced exact numeric-scalar call overhead by using typed NumPy scalar payload access and result allocation while preserving strict dtype checking and exact NumPy result types.
- Separated wrapper plans into strict binding, shared native-entrypoint, and Fortran-adapter facets, with planner-owned generated support procedure entrypoints for accessors, lifecycles, descriptors, and callbacks, without changing generated wrappers.
- Build manifest schema 4 records physical generated sources and separate adapter/support membership, including zero-generated-native builds.
- Reorganized contributor documentation around a concise architecture guide and one canonical page per production package, with local structures, important objects, runnable examples, expected outputs, test owners, change routes, and invariants.
- Consolidated contributor workflows and removed nonessential concept and design drafts, TODO-only pages, duplicate architecture maps, and completed migration ledgers.
- Added the persistent Zenodo all-versions DOI badge and citation links to the README and About page.
- Included the repository's machine-readable
CITATION.cffmetadata in source distributions.
- Marked the contributor Architecture and Codebase Map as reviewed for publication; the renamed map now focuses on package and cross-stage module ownership.
- Clarified the Feature-to-Code Map as the capability-to-owner and evidence index, linking reviewed user documentation and retaining only planned contributor-documentation paths before their review.
- Revised the Feature-to-Code Map with reviewed package-guide links, stage-ordered change routes, narrower focused evidence, and separate array, callback, and error routes.
- Condensed the contributor Testing Strategy around test ownership, stage evidence, stable contracts, end-to-end evidence, fixture placement, and verification scope.
- Clarified contributor workflows for changing PRIK, local verification, pull request checks, and documentation maintenance.
- Linked the Contributing workflow to the Feature-to-Code Map and Testing Strategy, explained its pre-push hook setup, and normalized its editable checkout test commands.
- Clarified that pull-request validation requires the performance benchmark and identified its workflow implementation.
- Renamed the Package Guides section to Architecture Components and grouped its build stages separately from its supporting components, distinguishing cross-build pipeline orchestration from sequential stages.
- Ordered the Developer Documentation sidebar by the architecture reading path, with build stages before supporting components.
- Made every expandable documentation-sidebar section label open its first published page, including through nested sections, while the adjacent + control only expands or collapses it.
- Made documentation tables wrap readable cell content instead of hiding later columns behind unnecessary horizontal scrolling.
- Added accessible two-, three-, and four-view example tabs to the User Guide; Getting Started remains linear and example results stay visible.
- Reviewed the Pipeline Component guide around the source-build handoff, independent contract and inspection workflows, and build-result ownership.
- Reviewed the Preprocessing Stage guide around its Fortran source route, compiler-derived target probes, module navigation, and executable examples.
- Reviewed the Parsing Stage guide around its Fortran and semantic-
.pyialgorithms, source-level navigation, executable examples, and ownership boundaries. - Reviewed the Semantics Stage guide around its shared IR, frontend-conversion algorithms, raw contract facts, executable examples, and policy boundary.
- Reviewed the Policy Stage guide around ordered policy completion, immutable interoperability decisions, module algorithms, executable examples, and the planning boundary.
- Reviewed the Planning Stage guide around deterministic policy projection, editable plan ownership, module algorithms, executable examples, and the generator freeze boundary.
- Reviewed the Code Generation Stage guide around its generator handoff, backend lowering algorithms, plan-only decisions, executable examples, and focused evidence.
- Reviewed the Printing Stage guide around representation-specific traversal,
safe source formatting, isolated
.pyiemission, executable examples, and focused evidence. - Reviewed the Compiler Stage guide around coherent toolchain selection, explicit command construction, conditional native-support installation, executable examples, and focused evidence.
- Added focused C Binding and Fortran Bridge lowering guides with executable manually constructed plans and printed backend-source examples.
- Moved binding and bridge algorithms and rendered-source demonstrations out of the Code Generation overview and into their focused lowering guides.
- Explained each reviewed package-guide execution example in terms of its in-memory setup and the stage boundary established by its output.
- Added Pipeline Component and source-level navigation for contract loading,
wrapper generation, build-manifest replay, and
build.pyorchestration. - Removed empty package-marker entries from the Pipeline Component and Compiler Stage guides.
- Added a brief Developer Documentation overview that routes readers to Architecture, then Architecture Components, and linked it from the website home page.
- Replaced the contributor architecture's text-only build path with a rendered diagram of its two input routes and shared pipeline.
- Made the architecture build-path diagram keyboard-accessible and linked each route and stage to its reviewed component guide.
- Added accessible explanations for
.pyi, f2py.pyf, ABI, semantic IR, array order, and the GIL throughout User Documentation and on the Home page, plus per-stage detail panels to the architecture diagram. - Changed the site-wide repository control into a “★ Star on GitHub” call to action while preserving its repository destination.
- Published concise Contracts, Naming, Runtime, and Utilities component guides, restored their architecture links, corrected the diagram fallback, and clarified the NumPy result type in the architecture example.
- Made numeric scalar results consistently preserve their exact NumPy types;
Boolean scalar results remain Python
boolvalues. - Corrected user documentation to distinguish numeric and Boolean scalar boundaries, and aligned the Getting Started route with normal package installation rather than a repository checkout.
- Reduced documentation tests to enforce publication, link integrity, executable examples, and public-reference contracts without freezing prose, headings, page inventories, private names, or source-tree layout.
- Reclassified implementation-structure and codegen-complexity checks as contributor recommendations, while retaining hard behavioral, safety, ABI, publication, and architectural-boundary contracts.
- Moved contributor package-guide execution checks into the documentation suite, using each guide's displayed result instead of a duplicate exact- output inventory.
- Reduced the root
prikAPI to its version and normal-user build entrypoints; parser, semantic, probe, runtime, and planning tools now use their owning package import paths. - Moved stage-record freezing from
prik.stage_valuestoprik.utilities.stage_values; the root module path was removed. - Made
prikan import-only package boundary by removing its direct-script demonstration; command and stage-value examples remain available from their owning modules. - Expanded the contributor architecture and package guides with concrete stage handoffs, runnable example results, focused test purposes, and change routes.
- Moved generated documentation and distribution output under the hidden
.artifacts/directory in local commands and CI workflows. - Consolidated developer and maintainer material under one Contributor Documentation tree and removed the separate maintainer documentation lane.
- Moved the bundled header-only binding runtime from the package root into
prik.runtime.native_support; generated builds continue to receive it under their internalbinding_support/include directory. - Deferred the contributor architecture sections for the immature C input parser and C-to-IR path while retaining the generated CPython C binding backend documentation required by Fortran wrappers.
- Reorganized compiler and pre-parse infrastructure into
prik.compilerandprik.preprocessing, including C/Fortran preprocessing and target probes; the formerprik.compiling,prik.probes, parser-local C preprocessor, and pipeline-local preprocessing import paths were removed. - Replaced the public semantic-to-NumPy helper API with stage-owned semantic, contract-runtime, and code-generation datatype catalogues.
- Separated post-IR policy and wrapper planning into
prik.policyandprik.planning; code generation now renders plan-driven docstrings, and the former maintainer import paths were removed. - Added a top-level language-printer package for C, Fortran, and semantic
.pyioutput, and madepipeline.wrapper.WrapperGeneratorthe single plan-to-rendered-wrapper orchestration boundary. - Documented the completed ownership vocabulary, lifetime-policy philosophy, pointer-policy boundary, and maintainer change routes in one maintained architecture reference.
- Moved exact overload selection from generated Python predicate chains to generated C dispatchers with planned candidate IDs and direct switch-based calls to the selected existing wrapper.
- Stopped standalone Fortran parser discovery from descending into inaccessible procedure-internal subprograms; procedure-local callback interfaces remain classified and discoverable.
- Made directory project parsing read and parse each discovered Fortran file once before dependency ordering and project assembly.
- Corrected README licensing wording to refer to bundled native-support files
rather than the removed package-root
binding_support/path. - Unified source-level compile-time resolution across project and CLI parsing so imported and host-associated kind facts also reach derived-type fields.
- Added machine-readable citation metadata through the repository-root
CITATION.cfffile. - Added an About page and public development disclosure covering PRIK's motivation, design principles, stewardship, and use of AI-assisted tools.
- Removed the stale
0.1.xqualifier from the README and website alpha-status wording after the0.2.0release.
- Added maintained FFTPACK and MINPACK examples built from the upstream fortran-lang projects. Their build scripts, user guides, and numerical tests cover all 31 FFTPACK and 22 MINPACK public procedures.
- Added Python-owned, read-only NumPy snapshots for supported public Fortran
parameter arrays, including MINPACK's
dpmparconstants. - Added declaration-expression support for richer arithmetic, comparisons, conditionals, array inquiries, and local, imported, or standalone specification functions, including native-dependent result extents.
- Added exact NumPy Boolean-array conversion for compiler-measured 8-, 16-, 32-, and 64-bit Fortran logical kinds, with canonical writeback.
- Added
WrapperBuildResult.import_module()to load a generated extension explicitly without changingsys.path.
- Moved documentation and maintainer-tool tests to
tests/docs/andtests/tools/, removed the generictests/shared/bucket, and mirrored internal tests by production package with narrower support helpers; removed recursive layout-policing tests that froze maintainer organization, retaining exceptional release safety undertests/workflows/. The maintainer-tool and workflow-safety suites, blocking static analysis, and focused documentation smoke checks now also run through the repository's tracked pre-push hook, together with one compiled scalar-wrapper smoke test, for earlier local feedback while remaining enforced by GitHub Actions. - Simplified the documented DGESV validation and the LAPACK test suite to use explicit NumPy Fortran-order copies, with documented numerical-test helper conventions.
- Aligned the documented MINPACK
hybrd1callback example with its runnable test, made it verify callback invocation, and made its test problems self-contained; FFTPACK workspace initializer tests now validate a paired transform against NumPy or SciPy. - Renamed the developer-facing wrapper generation package from
prik.wrapper_codegentoprik.codegen; the old import path was removed. - Expanded public interface resolution so implemented unnamed interfaces and public generics can be wrapped without exposing private implementation procedures.
- Expanded the Real Libraries CI lane to build and test BLAS, LAPACK, FFTPACK, and MINPACK, with cached native BLAS and LAPACK builds where available.
- Made performance comparisons faster and less order-sensitive with balanced A/B/B/A runtime measurements, merged samples, smaller worker budgets, and four measured clean builds after warm-up.
- Refreshed the README and website around the canonical PRIK — Python Runtime Interop Kit identity, with a concise FAQ, a fair PRIK-versus-f2py guide, clearer array guidance, and searchable real-library examples, including a four-library capability and validation summary, a concise statement of current limitations, and a derived-type inheritance walkthrough.
- Hardened preprocessing, compiler-derived type probes, semantic policy completion, and multi-source build reporting so unsupported contracts fail earlier with clearer diagnostics.
- Preserved authoritative public interface signatures when linked legacy
implementations use different internal storage declarations, including
FFTPACK's
zfftfcomplex-array interface. - Corrected SciPy reference inputs for the LAPACK
dstemranddstebztests and strengthened BLAS and LAPACK routine validation with independent mathematical expectations.
- Update README and CONTRIBUTING
- Change the Description section and add more tags
- First public release under the PRIK name.
- Build importable Python extensions from supported Fortran sources.
- Generate, inspect, edit, and rebuild from semantic
.pyicontracts. - Expose the
prikconsole command and the equivalentpython -m prikmodule command. - Report the installed release through
prik --versionandprik.__version__. - Added a complete runnable Reference BLAS correctness example covering all 155 discovered routines through PRIK, independent mathematical expectations, and f2py differential comparisons.
- Moved the repository's authoritative Reference BLAS sources to
examples/fortran/blas/native/for shared use by the example, integration tests, LAPACK CI build, and build comparison tooling. - Added a complete Reference LAPACK build and correctness project. It wraps all 2,062 implementation sources once and explicitly validates the reviewed 127 SciPy 1.18.0 double-precision real routines against independent mathematical invariants and f2py comparisons in the dedicated CI lane.
- Moved the repository's authoritative Reference LAPACK implementation sources
to
examples/fortran/lapack/native/and updated full-library integration and CI to consume that single source owner alongsideexamples/fortran/blas/native/. - Fixed dependency-safe Python argument conversion ordering for wrappers whose array extents depend on later native scalar arguments, including padded BLAS leading dimensions.