Skip to content

docs(rfcs): add RFC0015 for distributing Fortran bindings across rocm-systems and rocm-libraries - #8122

Merged
saadrahim merged 13 commits into
ROCm:mainfrom
amontoison:rocm-fortran
Oct 14, 2026
Merged

saadrahim merged 13 commits into
ROCm:mainfrom
amontoison:rocm-fortran

Conversation

@amontoison

@amontoison amontoison commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

hipfort provides the Fortran bind(C) interfaces to the HIP runtime and the ROCm math
libraries. It lives in its own repository, away from the headers it mirrors, and its
interfaces are partially written by hand, so its coverage is only ever as current as the
last manual update: it drifts behind the C API, and it stalls whenever nobody is
maintaining it.

This RFC proposes fixing that structurally rather than by another catch-up pass:
generate the bindings from the headers, and put them next to those headers, so that a
change to a .h and the change to its .F90 can travel in the same pull request.

There is no tracking issue yet. Following docs/rfcs/README.md, the RFC is itself the
public record and the place to comment; happy to open an issue or a discussion thread
instead if maintainers prefer.

Technical Details

Documentation only. Adds docs/rfcs/RFC0015-Fortran-Bindings-Split.md (status: draft)
and its entry in the RFC index. No build, packaging, or CI behavior changes here.

What the RFC proposes:

  • Co-location. HIP runtime bindings go to rocm-systems, each math library's
    bindings to rocm-libraries next to that project, each in a dedicated fortran/
    directory rather than inside include/.
  • Generation instead of hand-writing. A standalone generator parses the public C
    headers and emits the modules. When a header changes, CI regenerates the affected
    module and suggests the diff on the PR, the way an auto-formatter does.
  • A per-library deliverable. Each library ships its own .F90, .mod,
    lib<lib>_fortran.a, and CMake target in the C library's existing namespace
    (roc::rocblas_fortran, hip::hip_fortran), so find_package(rocblas) yields the C
    library and its Fortran binding together.
  • Module naming. The packaged track drops the hipfort_ prefix and collapses each
    library to one module: use rocblas, use hip.
  • Language standard. F2003 is the floor for the raw type(c_ptr) surface, F2008 is
    needed for the array ergonomics, and F2018 only for the opt-in assumed-rank variants.
  • Transition. Two tracks emitted by one generator: today's hipfort layout stays
    available as source through the 10.x series, the packaged track lands in 10.3. A
    "Migration and compatibility" section states the two mechanical edits a user makes (the
    use rename and the link target), and what the transition does to each population of
    current users.

Appendices cover why a .mod and its archive cannot be shared across compilers or even
across versions of one compiler (the constraint that drives the whole packaging design),
how NVIDIA answers the same problem by owning its compiler, the implementation backlog,
and how the generator is tested.

Test Plan

A documentation-only change, so the checks are the repository's own markdown gates:

pre-commit run --files docs/rfcs/RFC0015-Fortran-Bindings-Split.md docs/rfcs/README.md
pre-commit run --hook-stage manual lychee --files docs/rfcs/RFC0015-Fortran-Bindings-Split.md docs/rfcs/README.md

Test Result

  • All pre-commit hooks pass. mdformat reformatted the tables and normalized
    ordered-list numbering; the content is unchanged and the rendering is identical.
  • The lychee link check passes: the RFC's links and the new index entry resolve.
  • No code, build, or packaging path is touched, so there is nothing to run beyond the
    above.

Submission Checklist

JIRA ID: ROCM-25143

@therock-pr-bot

therock-pr-bot Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass PR does not contain code files — Unit Test auto-passed
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot therock-pr-bot Bot added the Not ready to Review PR has unresolved policy failures — reviews blocked label Sep 10, 2026
@therock-pr-bot

therock-pr-bot Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@amontoison
amontoison marked this pull request as ready for review September 10, 2026 05:24
@amontoison
amontoison requested a review from a team as a code owner September 10, 2026 05:24
@therock-pr-bot therock-pr-bot Bot removed the Not ready to Review PR has unresolved policy failures — reviews blocked label Sep 10, 2026

@saadrahim saadrahim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need stakeholder review across ROCm Core, looks good from product.

amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 21, 2026
rocfft.F90 is generated from the rocFFT public headers by the rocm-fortran
generator and committed next to them, so that a header change and its
binding travel in the same pull request. It is a single self-contained
module, `rocfft`, carrying the interfaces, the enum constants, the opaque
handles and the rocfftCheck status helper. A consumer writes one `use rocfft`.

Implements RFC0014 (ROCm/TheRock#8122) for rocFFT, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: a Fortran binding declares bind(C)
interfaces only, so it compiles against neither the rocFFT headers nor
librocfft, and needs no GPU and no HIP compiler to build. librocfft is a
link-time dependency of a final executable and is carried as the target's
link interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCFFT_BUILD_FORTRAN_* so one library
can be singled out in a monorepo build. FORTRAN_ARRAY_INTERFACES is a
tri-state (none / assumed-shape / assumed-rank, default assumed-shape)
replacing the two booleans USE_FPOINTER_INTERFACES and ASSUMED_RANK: the two
upper tiers cannot legally coexist in one generic, because an assumed-rank
dummy is not distinguishable by rank from the per-rank specifics.
ROCFFT_HAVE_FORTRAN_BINDINGS reports whether they were really built, and the
config package sets rocfft_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, which is the name to
settle on across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, Flang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper, where a
plain basename would not.

The config package lands in lib/cmake/rocfft beside the C package, and a
forwarder in lib/cmake/rocfft-fortran makes find_package(rocfft-fortran)
resolve to the same place.

Tests
-----
test/ carries 19 tests under CTest. Eighteen are runtime tests that allocate
device memory, so they write `use hip` next to `use rocfft` and need the HIP
Fortran binding at compile time; they are skipped with a named message when
it is absent. test_rocfft.F03, the exhaustive symbol test, uses only
iso_c_binding and rocfft, so it is registered outside that guard. That
distinction is load-bearing: ROCm does not currently ship a HIP Fortran
binding, so guarding the whole directory would mean zero tests against a
stock /opt/rocm, including the only one that proves every bind(C) symbol
resolves against librocfft.

Runtime tests are labelled "gpu" and the symbol test "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with gfortran 13.3.0. Against a stock
/opt/rocm the symbol test builds, links and passes on its own. With the HIP
Fortran binding available, 19 of 19 pass; one of those, field_brick_z, prints
SKIPPED and exits 0 because it wants two GPUs, so the honest reading is 17
real GPU tests, 1 self-skip and the symbol test. The documented consumer path
was exercised end to end: install, find_package(rocfft-fortran), link
roc::rocfft_fortran, run on the GPU.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 21, 2026
hipfft.F90 and hipfftw.F90 are generated from the public headers by the
rocm-fortran generator and committed next to them, so that a header change
and its binding travel in the same pull request. Each is a single
self-contained module, `hipfft` and `hipfftw`, carrying the interfaces, the
enum constants, the opaque handles and the status helper. A consumer writes
one `use hipfft`.

Implements RFC0014 (ROCm/TheRock#8122) for hipFFT, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

Two bindings in one directory, because hipFFTW is built by the hipFFT
project rather than one of its own. They are separate modules, separate
targets and separate config packages, but they live next to the headers they
bind rather than in a directory of their own.

The bindings declare bind(C) interfaces only, so they compile against neither
the hipFFT headers nor libhipfft, and need no GPU and no HIP compiler to
build. The C libraries are link-time dependencies of a final executable and
are carried as each target's link interface. The subdirectory guards itself,
returning early when BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is
present, so a C-only site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPFFT_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic,
because an assumed-rank dummy is not distinguishable by rank from the
per-rank specifics. The config packages set hipfft_FORTRAN_FOUND and
hipfftw_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on
across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so each .mod and archive installs
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper, where a
plain basename would not.

Both config packages land in lib/cmake/hipfft beside the C package, and
forwarders in lib/cmake/hipfft-fortran and lib/cmake/hipfftw-fortran make
find_package(hipfft-fortran) and find_package(hipfftw-fortran) resolve to the
same place.

Tests
-----
test/ carries 21 tests under CTest. Nineteen are runtime tests that allocate
device memory, so they write `use hip` next to their own `use`, which makes
the HIP Fortran binding a compile-time dependency; they are skipped with a
named message when it is absent. The two exhaustive symbol tests use only
iso_c_binding and the module under test, so they are registered outside that
guard. That distinction matters: ROCm does not currently ship a HIP Fortran
binding, so guarding the whole directory would mean zero tests against a
stock /opt/rocm, including the only ones that prove every bind(C) symbol
resolves against the installed libraries.

Runtime tests are labelled "gpu" and the symbol tests "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with BOTH compilers, gfortran 13.3.0
and amdflang 23.0.0. Against a stock /opt/rocm the two symbol tests build,
link and pass on their own; with the HIP Fortran binding available, 21 of 21
pass. The documented consumer path was exercised end to end with amdflang:
install, find_package on both packages, link hip::hipfft_fortran and
hip::hipfftw_fortran in one program, run on the GPU. The compiler-mismatch
diagnostic was exercised for real by installing with amdflang and consuming
with gfortran, which is what confirms the CMAKE_Fortran_COMPILER_ID mapping
handles LLVMFlang and that the message renders as prose rather than as a
semicolon-separated list.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 21, 2026
hipsparse.F90 is generated from the hipSPARSE public headers by the
rocm-fortran generator and committed next to them, so that a header change
and its binding travel in the same pull request. It is a single
self-contained module, `hipsparse`, carrying the interfaces, the enum
constants, the opaque handles and the hipsparseCheck status helper. A
consumer writes one `use hipsparse`.

Implements RFC0014 (ROCm/TheRock#8122) for hipSPARSE, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the hipSPARSE
headers nor libhipsparse, and needs no GPU to build. libhipsparse is a
link-time dependency of a final executable and is carried as the target's
link interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected.

Target naming
-------------
hipSPARSE already creates a target called hipsparse_fortran: the hand-written
Fortran layer for its own test clients, under HIPSPARSE_ENABLE_FORTRAN. CMake
target names are global, so the generated binding is built as
hipsparse_fortran_bindings and given EXPORT_NAME hipsparse_fortran. Consumers
therefore still write roc::hipsparse_fortran and link
libhipsparse_fortran.a, exactly as the other libraries, while the two targets
coexist in one build tree. The hand-written layer is untouched: the generated
module is not yet source-compatible with it, so superseding it is a separate
coordinated change.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPSPARSE_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic,
because an assumed-rank dummy is not distinguishable by rank from the
per-rank specifics. HIPSPARSE_HAVE_FORTRAN_BINDINGS reports whether they were
really built, and the config package sets hipsparse_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on
across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

The config package lands in lib/cmake/hipsparse beside the C package, and a
forwarder in lib/cmake/hipsparse-fortran makes find_package(hipsparse-fortran)
resolve to the same place.

Tests
-----
test/ carries 50 tests under CTest. Forty-nine are runtime tests that
allocate device memory around each hipSPARSE call, so they write `use hip`
and need the HIP Fortran binding at compile time; they are skipped with a
named message when it is absent. test_hipsparse.F03, the exhaustive symbol
test, uses only iso_c_binding and hipsparse, so it is registered outside that
guard. That distinction is load-bearing: ROCm does not currently ship a HIP
Fortran binding, so guarding the whole directory would mean zero tests
against a stock /opt/rocm, including the only one that proves every bind(C)
symbol resolves against libhipsparse.

The generated sources are named hipsparse_<op>.f03, so the library name is
stripped when composing the CMake and CTest identifiers: the test is
hipsparse_fortran_dspmv rather than hipsparse_fortran_hipsparse_dspmv. The
source files are untouched.

Runtime tests are labelled "gpu" and the symbol test "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with BOTH compilers, gfortran 13.3.0
and amdflang 23.0.0. A standalone configure is clean under -Wdev. Against a
stock /opt/rocm the symbol test builds, links and passes on its own; with the
HIP Fortran binding available, 50 of 50 pass with each compiler. The
documented consumer path was exercised end to end with amdflang: install,
find_package(hipsparse-fortran), link roc::hipsparse_fortran, run on the GPU.
The compiler-mismatch diagnostic was exercised for real by installing with
amdflang and consuming with gfortran, which is what confirms the
CMAKE_Fortran_COMPILER_ID mapping handles LLVMFlang and that the message
renders as prose rather than as a semicolon-separated list.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 21, 2026
JIRA ID : ROCM-31390

hipblas.F90 is generated from the hipBLAS public headers by the rocm-fortran
generator and committed next to them, so that a header change and its
binding travel in the same pull request. It is a single self-contained
module, `hipblas`, carrying the interfaces, the enum constants, the opaque
handles and the hipblasCheck status helper. A consumer writes one
`use hipblas`.

Implements RFC0014 (ROCm/TheRock#8122) for hipBLAS, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the hipBLAS
headers nor libhipblas, and needs no GPU to build. libhipblas is a link-time
dependency of a final executable and is carried as the target's link
interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected. The hook sits outside the SKIP_LIBRARY guard: that guard
controls whether libhipblas is built here, and the bindings need it linked,
not built.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPBLAS_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic,
because an assumed-rank dummy is not distinguishable by rank from the
per-rank specifics. HIPBLAS_HAVE_FORTRAN_BINDINGS reports whether they were
really built, and the config package sets hipblas_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on
across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
HIPBLAS_FORTRAN_COMPILER_DIR with a suffixed name, so the config package
accepts the recorded directory when it is the derived name OR that name
followed by a separator and anything. A strict equality would reject exactly
the sites that used the documented override. The comparison is done by length
and substring rather than by regex: the derived name comes from the
compiler's basename on the fallback branch, so it is an arbitrary file name,
and interpolating it into a regex would let a compiler called flang(2) either
mismatch silently or abort CMake outright. CMake has no regex-escape.

The config package lands in lib/cmake/hipblas beside the C package, and a
forwarder in lib/cmake/hipblas-fortran makes find_package(hipblas-fortran)
resolve to the same place.

Tests
-----
test/ carries 69 tests under CTest. Sixty-eight are runtime tests that
allocate and copy device memory around each hipBLAS call, so they write
`use hip` and need the HIP Fortran binding at compile time; they are skipped
with a named message when it is absent. test_hipblas.F03, the exhaustive
symbol test, uses only iso_c_binding and hipblas, so it is registered outside
that guard. That distinction is load-bearing: ROCm does not currently ship a
HIP Fortran binding, so guarding the whole directory would mean zero tests
against a stock /opt/rocm, including the only one that proves every bind(C)
symbol resolves against libhipblas.

Runtime tests are labelled "gpu" and the symbol test "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with BOTH compilers, gfortran 13.3.0
and amdflang 23.0.0. A standalone configure is clean under -Wdev. Against a
stock /opt/rocm the symbol test builds, links and passes on its own; with the
HIP Fortran binding available, 69 of 69 pass. The documented consumer path
was exercised end to end with amdflang: install,
find_package(hipblas-fortran), link roc::hipblas_fortran, run on the GPU.

The compiler check was exercised in both directions rather than only the
happy one. Installed under an overridden gfortran-13.3.0 directory, a
gfortran consumer is accepted; an amdflang consumer against that same install
is rejected with a named diagnostic. Installing with amdflang and consuming
with gfortran is what confirms the CMAKE_Fortran_COMPILER_ID mapping handles
LLVMFlang, and that the message renders as prose rather than as a
semicolon-separated list.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 21, 2026
JIRA ID : ROCM-31390

hipblas.F90 is generated from the hipBLAS public headers by the rocm-fortran
generator and committed next to them, so that a header change and its
binding travel in the same pull request. It is a single self-contained
module, `hipblas`, carrying the interfaces, the enum constants, the opaque
handles and the hipblasCheck status helper. A consumer writes one
`use hipblas`.

Implements RFC0014 (ROCm/TheRock#8122) for hipBLAS, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the hipBLAS
headers nor libhipblas, and needs no GPU to build. libhipblas is a link-time
dependency of a final executable and is carried as the target's link
interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected. The hook sits outside the SKIP_LIBRARY guard: that guard
controls whether libhipblas is built here, and the bindings need it linked,
not built.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPBLAS_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic,
because an assumed-rank dummy is not distinguishable by rank from the
per-rank specifics. HIPBLAS_HAVE_FORTRAN_BINDINGS reports whether they were
really built, and the config package sets hipblas_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on
across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
HIPBLAS_FORTRAN_COMPILER_DIR with a suffixed name, so the config package
accepts the recorded directory when it is the derived name OR that name
followed by a separator and anything. A strict equality would reject exactly
the sites that used the documented override. The comparison is done by length
and substring rather than by regex: the derived name comes from the
compiler's basename on the fallback branch, so it is an arbitrary file name,
and interpolating it into a regex would let a compiler called flang(2) either
mismatch silently or abort CMake outright. CMake has no regex-escape.

The config package lands in lib/cmake/hipblas beside the C package, and a
forwarder in lib/cmake/hipblas-fortran makes find_package(hipblas-fortran)
resolve to the same place.

Tests
-----
test/ carries 69 tests under CTest. Sixty-eight are runtime tests that
allocate and copy device memory around each hipBLAS call, so they write
`use hip` and need the HIP Fortran binding at compile time; they are skipped
with a named message when it is absent. test_hipblas.F03, the exhaustive
symbol test, uses only iso_c_binding and hipblas, so it is registered outside
that guard. That distinction is load-bearing: ROCm does not currently ship a
HIP Fortran binding, so guarding the whole directory would mean zero tests
against a stock /opt/rocm, including the only one that proves every bind(C)
symbol resolves against libhipblas.

Runtime tests are labelled "gpu" and the symbol test "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with BOTH compilers, gfortran 13.3.0
and amdflang 23.0.0. A standalone configure is clean under -Wdev. Against a
stock /opt/rocm the symbol test builds, links and passes on its own; with the
HIP Fortran binding available, 69 of 69 pass. The documented consumer path
was exercised end to end with amdflang: install,
find_package(hipblas-fortran), link roc::hipblas_fortran, run on the GPU.

The compiler check was exercised in both directions rather than only the
happy one. Installed under an overridden gfortran-13.3.0 directory, a
gfortran consumer is accepted; an amdflang consumer against that same install
is rejected with a named diagnostic. Installing with amdflang and consuming
with gfortran is what confirms the CMAKE_Fortran_COMPILER_ID mapping handles
LLVMFlang, and that the message renders as prose rather than as a
semicolon-separated list.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 24, 2026
JIRA ID : ROCM-31390

rocrand.F90 is generated from the rocRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocrand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the rocrandCheck status helper. A consumer writes one
`use rocrand`.

Implements RFC0014 (ROCm/TheRock#8122) for rocRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the rocRAND headers
nor librocrand, and needs no GPU to build. librocrand is a link-time dependency
of a final executable and is carried as the target's link interface. The
subdirectory guards itself, returning early when BUILD_FORTRAN_BINDINGS is OFF
or no Fortran compiler is present, so a C-only site is unaffected. The hook sits
outside the USE_SYSTEM_LIB branch: that branch controls whether librocrand is
built here, and the bindings need it linked, not built.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. ROCRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name. It is a bridge
with an end: when the root is switched over, that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
ROCRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. A strict equality would reject exactly the sites that
used the documented override. The comparison is done by length and substring
rather than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Coexistence with the deprecated wrapper
---------------------------------------
rocRAND already ships a hand-written wrapper (library/src/fortran/rocrand_m.f90)
under BUILD_FORTRAN_WRAPPER, itself deprecated in favour of hipfort. It is left
untouched here, and it collides with these bindings in two places.

The target name is the first. Both want rocrand_fortran, which is a hard CMake
error naming neither option, so the clash is reported here instead, with the
flag to turn off. It is not resolved by silently winning: a site that asked for
BUILD_FORTRAN_WRAPPER asked for the wrapper.

The config file name is the second, and it is why this package does not use the
layout the other libraries use. lib/cmake/rocrand/rocrand-fortran-config.cmake
already belongs to the wrapper, and rocrand-config.cmake include()s that name
unconditionally -- it is in /opt/rocm today. Installing there would not shadow a
stale file, it would splice this package into the middle of every
find_package(rocrand) in existence, C++ consumers included, and drop
rocrand_FORTRAN_SRC_DIRS with it. So the real config stands alone in
lib/cmake/rocrand-fortran, which find_package(rocrand-fortran) already searches,
and nothing is written into lib/cmake/rocrand. For the same reason the package
reports rocrand_FORTRAN_BINDINGS_FOUND rather than overloading
rocrand_FORTRAN_FOUND, which the wrapper's config defines with a different
meaning. When the wrapper is retired, both can move to the shared spelling.

Tests
-----
24 tests under CTest, off by default. Twenty-three are runtime tests, one per
(generator, distribution) pair, that allocate and copy device memory around each
rocRAND call, so they write `use hip` and need the HIP Fortran binding at
compile time; they are skipped with a named message when it is absent.

test_rocrand.F03, the exhaustive symbol test, uses only iso_c_binding and
rocrand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against librocrand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 24, 2026
JIRA ID : ROCM-31390

hiprand.F90 is generated from the hipRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hiprand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the hiprandCheck status helper. A consumer writes one
`use hiprand`.

Implements RFC0014 (ROCm/TheRock#8122) for hipRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the hipRAND headers
nor libhiprand, and needs no GPU to build. libhiprand is a link-time dependency
of a final executable and is carried as the target's link interface. The
subdirectory guards itself, returning early when BUILD_FORTRAN_BINDINGS is OFF
or no Fortran compiler is present, so a C-only site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. HIPRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name. It is a bridge
with an end: when the root is switched over, that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
HIPRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. A strict equality would reject exactly the sites that
used the documented override. The comparison is done by length and substring
rather than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Coexistence with the deprecated wrapper
---------------------------------------
hipRAND already ships a hand-written wrapper (library/src/fortran/hiprand_m.f90)
under BUILD_FORTRAN_WRAPPER, itself deprecated in favour of hipfort. It is left
untouched here, and it collides with these bindings in two places.

The target name is the first. Both want hiprand_fortran, which is a hard CMake
error naming neither option, so the clash is reported here instead, with the
flag to turn off. It is not resolved by silently winning: a site that asked for
BUILD_FORTRAN_WRAPPER asked for the wrapper.

The config file name is the second, and it is why this package does not use the
layout the other libraries use. lib/cmake/hiprand/hiprand-fortran-config.cmake
already belongs to the wrapper, and hiprand-config.cmake include()s that name
unconditionally -- it is in /opt/rocm today. Installing there would not shadow a
stale file, it would splice this package into the middle of every
find_package(hiprand) in existence, C++ consumers included, and drop
hiprand_FORTRAN_SRC_DIRS with it. So the real config stands alone in
lib/cmake/hiprand-fortran, which find_package(hiprand-fortran) already searches,
and nothing is written into lib/cmake/hiprand. For the same reason the package
reports hiprand_FORTRAN_BINDINGS_FOUND rather than overloading
hiprand_FORTRAN_FOUND, which the wrapper's config defines with a different
meaning. When the wrapper is retired, both can move to the shared spelling.

Tests
-----
24 tests under CTest, off by default. Twenty-three are runtime tests, one per
(generator, distribution) pair, that allocate and copy device memory around each
hipRAND call, so they write `use hip` and need the HIP Fortran binding at
compile time; they are skipped with a named message when it is absent.

test_hiprand.F03, the exhaustive symbol test, uses only iso_c_binding and
hiprand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against libhiprand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 24, 2026
JIRA ID : ROCM-31390

rocrand.F90 is generated from the rocRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocrand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the rocrandCheck status helper. A consumer writes one
`use rocrand`.

Implements RFC0014 (ROCm/TheRock#8122) for rocRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the rocRAND headers
nor librocrand, and needs no GPU to build. librocrand is a link-time dependency
of a final executable and is carried as the target's link interface. The
subdirectory guards itself, returning early when BUILD_FORTRAN_BINDINGS is OFF
or no Fortran compiler is present, so a C-only site is unaffected. The hook sits
outside the USE_SYSTEM_LIB branch: that branch controls whether librocrand is
built here, and the bindings need it linked, not built.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. ROCRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name. It is a bridge
with an end: when the root is switched over, that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
ROCRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. A strict equality would reject exactly the sites that
used the documented override. The comparison is done by length and substring
rather than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Coexistence with the deprecated wrapper
---------------------------------------
rocRAND already ships a hand-written wrapper (library/src/fortran/rocrand_m.f90)
under BUILD_FORTRAN_WRAPPER, itself deprecated in favour of hipfort. It is left
untouched here, and it collides with these bindings in two places.

The target name is the first. Both want rocrand_fortran, which is a hard CMake
error naming neither option, so the clash is reported here instead, with the
flag to turn off. It is not resolved by silently winning: a site that asked for
BUILD_FORTRAN_WRAPPER asked for the wrapper.

The config file name is the second, and it is why this package does not use the
layout the other libraries use. lib/cmake/rocrand/rocrand-fortran-config.cmake
already belongs to the wrapper, and rocrand-config.cmake include()s that name
unconditionally -- it is in /opt/rocm today. Installing there would not shadow a
stale file, it would splice this package into the middle of every
find_package(rocrand) in existence, C++ consumers included, and drop
rocrand_FORTRAN_SRC_DIRS with it. So the real config stands alone in
lib/cmake/rocrand-fortran, which find_package(rocrand-fortran) already searches,
and nothing is written into lib/cmake/rocrand. For the same reason the package
reports rocrand_FORTRAN_BINDINGS_FOUND rather than overloading
rocrand_FORTRAN_FOUND, which the wrapper's config defines with a different
meaning. When the wrapper is retired, both can move to the shared spelling.

Tests
-----
24 tests under CTest, off by default. Twenty-three are runtime tests, one per
(generator, distribution) pair, that allocate and copy device memory around each
rocRAND call, so they write `use hip` and need the HIP Fortran binding at
compile time; they are skipped with a named message when it is absent.

test_rocrand.F03, the exhaustive symbol test, uses only iso_c_binding and
rocrand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against librocrand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 24, 2026
JIRA ID : ROCM-31390

hiprand.F90 is generated from the hipRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hiprand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the hiprandCheck status helper. A consumer writes one
`use hiprand`.

Implements RFC0014 (ROCm/TheRock#8122) for hipRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: it compiles against neither the hipRAND headers
nor libhiprand, and needs no GPU to build. libhiprand is a link-time dependency
of a final executable and is carried as the target's link interface. The
subdirectory guards itself, returning early when BUILD_FORTRAN_BINDINGS is OFF
or no Fortran compiler is present, so a C-only site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. HIPRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name. It is a bridge
with an end: when the root is switched over, that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
HIPRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. A strict equality would reject exactly the sites that
used the documented override. The comparison is done by length and substring
rather than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Coexistence with the deprecated wrapper
---------------------------------------
hipRAND already ships a hand-written wrapper (library/src/fortran/hiprand_m.f90)
under BUILD_FORTRAN_WRAPPER, itself deprecated in favour of hipfort. It is left
untouched here, and it collides with these bindings in two places.

The target name is the first. Both want hiprand_fortran, which is a hard CMake
error naming neither option, so the clash is reported here instead, with the
flag to turn off. It is not resolved by silently winning: a site that asked for
BUILD_FORTRAN_WRAPPER asked for the wrapper.

The config file name is the second, and it is why this package does not use the
layout the other libraries use. lib/cmake/hiprand/hiprand-fortran-config.cmake
already belongs to the wrapper, and hiprand-config.cmake include()s that name
unconditionally -- it is in /opt/rocm today. Installing there would not shadow a
stale file, it would splice this package into the middle of every
find_package(hiprand) in existence, C++ consumers included, and drop
hiprand_FORTRAN_SRC_DIRS with it. So the real config stands alone in
lib/cmake/hiprand-fortran, which find_package(hiprand-fortran) already searches,
and nothing is written into lib/cmake/hiprand. For the same reason the package
reports hiprand_FORTRAN_BINDINGS_FOUND rather than overloading
hiprand_FORTRAN_FOUND, which the wrapper's config defines with a different
meaning. When the wrapper is retired, both can move to the shared spelling.

Tests
-----
24 tests under CTest, off by default. Twenty-three are runtime tests, one per
(generator, distribution) pair, that allocate and copy device memory around each
hipRAND call, so they write `use hip` and need the HIP Fortran binding at
compile time; they are skipped with a named message when it is absent.

test_hiprand.F03, the exhaustive symbol test, uses only iso_c_binding and
hiprand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against libhiprand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 24, 2026
JIRA ID : ROCM-31390

rocrand.F90 is generated from the rocRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocrand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the rocrandCheck status helper. A consumer writes one
`use rocrand` and links roc::rocrand_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written wrapper
---------------------------------
library/src/fortran (rocrand_m.f90, hip_m.f90), its config template, and the
FRUIT-based suite under test/fortran go with it, along with
BUILD_FORTRAN_WRAPPER and its references in the top-level CMakeLists,
library/CMakeLists.txt, test/CMakeLists.txt, cmake/Summary.cmake,
cmake/Dependencies.cmake and docs/install/build.rst.

That API was deprecated in favour of hipfort in rocRAND 4.0.0 / ROCm 7.0 and has
never been shipped enabled: ROCm builds with BUILD_FORTRAN_WRAPPER=OFF, so in an
installed /opt/rocm rocrand_FORTRAN_FOUND is NOTFOUND, rocrand_FORTRAN_SRC_DIRS
is never set, and rocrand/src/fortran does not exist. No consumer of a ROCm
package can therefore be using it; only a source build that passed the flag.

Removing it also frees two names the generated bindings want. The target
rocrand_fortran was defined by both, which is a hard CMake error. More
importantly lib/cmake/rocrand/rocrand-fortran-config.cmake belonged to the
wrapper, and rocrand-config.cmake include()s that name unconditionally, so the
new package could not have been co-installed beside the C one while the wrapper
stood. With the wrapper gone, rocRAND uses the same layout as the rest of the
series: the real config in lib/cmake/rocrand, a forwarder in
lib/cmake/rocrand-fortran, and rocrand_FORTRAN_FOUND back to its ordinary
meaning.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. ROCRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name.

The bindings hook sits outside the USE_SYSTEM_LIB branch: that branch controls
whether librocrand is built here, and the bindings need it linked, not built.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
ROCRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. The comparison is done by length and substring rather
than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Note that rocm_export_targets' INCLUDE argument is not a substitute for the
OPTIONAL sibling include the config comment describes: it emits a bare,
non-OPTIONAL include(), and emits it before the targets file, so a Fortran
config reached that way would run before roc::rocrand exists. That hook belongs
in rocm-cmake.

Tests
-----
24 tests under CTest, off by default, replacing the FRUIT suite. Twenty-three
are runtime tests, one per (generator, distribution) pair, that allocate and
copy device memory around each rocRAND call, so they write `use hip` and need
the HIP Fortran binding at compile time; they are skipped with a named message
when it is absent.

test_rocrand.F03, the exhaustive symbol test, uses only iso_c_binding and
rocrand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against librocrand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 26, 2026
…ted one

JIRA ID : ROCM-31390

rocblas.F90 is generated from the rocBLAS public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocblas`, carrying the interfaces, the enum constants, the opaque handles and
the rocblasCheck status helper. A consumer writes one `use rocblas` and links
roc::rocblas_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocBLAS, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written binding
---------------------------------
library/include/rocblas_module.f90 is removed, along with the rocm_install()
rule that shipped it into include/rocblas. It defined TWO modules, rocblas and
rocblas_enums; the generated binding defines only rocblas, with the enum
constants folded in. `use rocblas` is unchanged, but `use rocblas_enums` becomes
`use rocblas`, which is applied here to the clients' shims and samples.
Consumers get a compiled archive and .mod rather than a .f90 source to build
themselves.

clients no longer compiles its own rocblas_fortran object library from that
source; rocblas_fortran_client links the target ../fortran exports. Both carried
the same name, so this also removes a latent duplicate-target clash.
next-cmake, which built its own rocblas-fortran-module from the same file, now
builds the generated source instead.

The add_subdirectory(fortran) hook moves out of the SKIP_LIBRARY guard: that
guard decides whether librocblas is built here, and the bindings need it linked,
not built. With clients now consuming the target rather than building their own,
inheriting the skip would leave BUILD_FORTRAN_CLIENTS with no rocblas_fortran.

Linking against an older rocBLAS
--------------------------------
The archive is built with -ffunction-sections -fdata-sections and exports
--gc-sections to its consumers. The module is generated from THIS tree's
headers, so it wraps API no released ROCm has yet -- the six
rocblas_*gemm_grouped_batched entry points today. A static archive links at
object granularity, so pulling in one wrapper pulls in every undefined C symbol
the object references, and a consumer who never touches the new API would still
fail to link. With section GC the unreferenced wrappers are discarded.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCBLAS_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK. ROCBLAS_HAVE_FORTRAN_BINDINGS reports whether they were built.

The compiler probe is read from ROCM_HAVE_FORTRAN, with ROCM_LIBS_HAVE_FORTRAN
honoured second as the spelling this repository's root publishes today.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the directory
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name,
which survives an MPI wrapper, a versioned binary, an absolute path and the Cray
wrapper. A site installing two versions of one compiler overrides
ROCBLAS_FORTRAN_COMPILER_DIR; the config accepts the derived name or that name
followed by a separator and anything, compared by length and substring rather
than by regex.

This uses the shared layout: the real config is co-installed in lib/cmake/rocblas
beside the C package, with a forwarder in lib/cmake/rocblas-fortran.
rocblas-config.cmake carries no Fortran include, so the recursion hazard that
keeps rocRAND and hipRAND in a directory of their own does not apply here.

The config-version file is installed into BOTH package directories. CMake looks
for it next to the <pkg>-config.cmake it actually resolved, and
find_package(rocblas-fortran 5.8) resolves the forwarder, so a version file only
beside the real config is never consulted and the call fails even though the
version matches. Its version is parsed from this tree's VERSION_STRING rather
than from rocblas_VERSION, which is set by the find_package(rocblas) this
directory does for its link interface and would report whatever rocBLAS happens
to be installed.

Tests
-----
81 tests under CTest, off by default: 80 runtime tests carried over from hipFORT,
which allocate and copy device memory and so need the HIP Fortran binding at
compile time, plus test_rocblas.F03, the exhaustive symbol test, which uses only
iso_c_binding and rocblas and is registered outside that guard behind
BUILD_FORTRAN_EXTENDED_TESTS.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 26, 2026
JIRA ID : ROCM-31390

rocrand.F90 is generated from the rocRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocrand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the rocrandCheck status helper. A consumer writes one
`use rocrand` and links roc::rocrand_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written wrapper
---------------------------------
library/src/fortran (rocrand_m.f90, hip_m.f90), its config template, and the
FRUIT-based suite under test/fortran go with it, along with
BUILD_FORTRAN_WRAPPER and its references in the top-level CMakeLists,
library/CMakeLists.txt, test/CMakeLists.txt, cmake/Summary.cmake,
cmake/Dependencies.cmake and docs/install/build.rst.

That API was deprecated in favour of hipfort in rocRAND 4.0.0 / ROCm 7.0 and has
never been shipped enabled: ROCm builds with BUILD_FORTRAN_WRAPPER=OFF, so in an
installed /opt/rocm rocrand_FORTRAN_FOUND is NOTFOUND, rocrand_FORTRAN_SRC_DIRS
is never set, and rocrand/src/fortran does not exist. No consumer of a ROCm
package can therefore be using it; only a source build that passed the flag.

Removing it also frees two names the generated bindings want. The target
rocrand_fortran was defined by both, which is a hard CMake error. More
importantly lib/cmake/rocrand/rocrand-fortran-config.cmake belonged to the
wrapper, and rocrand-config.cmake include()s that name unconditionally, so the
new package could not have been co-installed beside the C one while the wrapper
stood. With the wrapper gone, rocRAND uses the same layout as the rest of the
series: the real config in lib/cmake/rocrand, a forwarder in
lib/cmake/rocrand-fortran, and rocrand_FORTRAN_FOUND back to its ordinary
meaning.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. ROCRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name.

The bindings hook sits outside the USE_SYSTEM_LIB branch: that branch controls
whether librocrand is built here, and the bindings need it linked, not built.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
ROCRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. The comparison is done by length and substring rather
than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Note that rocm_export_targets' INCLUDE argument is not a substitute for the
OPTIONAL sibling include the config comment describes: it emits a bare,
non-OPTIONAL include(), and emits it before the targets file, so a Fortran
config reached that way would run before roc::rocrand exists. That hook belongs
in rocm-cmake.

Tests
-----
24 tests under CTest, off by default, replacing the FRUIT suite. Twenty-three
are runtime tests, one per (generator, distribution) pair, that allocate and
copy device memory around each rocRAND call, so they write `use hip` and need
the HIP Fortran binding at compile time; they are skipped with a named message
when it is absent.

test_rocrand.F03, the exhaustive symbol test, uses only iso_c_binding and
rocrand, so it is registered outside that guard, behind
BUILD_FORTRAN_EXTENDED_TESTS. That distinction is load bearing: ROCm does not
currently ship a HIP Fortran binding, so guarding the whole directory would mean
zero tests against a stock /opt/rocm, including the only one that proves every
bind(C) symbol resolves against librocrand.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 27, 2026
…rated one

JIRA ID : ROCM-31390

hipsparse.F90 is generated from the hipSPARSE public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hipsparse`, carrying the interfaces, the enum constants, the opaque handles and
the hipsparseCheck status helper. A consumer writes one `use hipsparse` and
links roc::hipsparse_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for hipSPARSE, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written module
--------------------------------
library/src/hipsparse.f90 and hipsparse_enums.f90 are removed, along with the
hipsparse_fortran OBJECT target in library/CMakeLists.txt that compiled them.
That target carried the SAME NAME as the one this directory creates, so with
-DHIPSPARSE_ENABLE_CLIENT=ON the two collided outright:

    CMake Error at fortran/CMakeLists.txt (add_library):
      add_library cannot create target "hipsparse_fortran" because another
      target with the same name already exists

CI never saw it because HIPSPARSE_ENABLE_FORTRAN is declared inside
if(HIPSPARSE_ENABLE_CLIENT), which defaults OFF. The Fortran samples now link
roc::hipsparse_fortran, which carries both the .mod directory and the archive,
and HIPSPARSE_ENABLE_FORTRAN is turned off with a message when the bindings were
not built, so -DHIPSPARSE_ENABLE_CLIENT=ON still works without a Fortran
compiler.

Host and device pointer mode
----------------------------
The generated binding follows hipFORT and binds a `const T*` scalar as a
by-reference `real(c_double) :: alpha`. The removed module bound the same
argument as `type(c_ptr), value`, so every sample passes `c_loc(alpha)`. Both
are ABI-correct, but only the second can express
HIPSPARSE_POINTER_MODE_DEVICE, where the library reads alpha from device
memory: a type(c_ptr) cannot be passed where a real is expected.
example_fortran_spmv.f90 does exactly that, passing a hipMalloc'd d_alpha to
hipsparseDbsrmv.

So 25 generics gained a second specific taking those scalars as
type(c_ptr),value and forwarding through c_f_pointer, which only records the
address and never dereferences it on the host. Six zeroPivot routines were plain
functions rather than generics and became generics to carry both; their own
documentation states that `position` can be in host OR device memory. No sample
and no test was modified: all 32 samples and all 50 tests build and pass against
the binding as committed.

This is a local fix in a GENERATED file, kept narrow deliberately. The ~700
other scalar arguments in hipSPARSE, and the same arguments in rocBLAS,
hipBLAS, rocSPARSE and rocSOLVER, still cannot express device pointer mode. The
durable fix belongs in the generator and will have to re-emit these variants.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPSPARSE_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape). HIPSPARSE_HAVE_FORTRAN_BINDINGS reports whether the
bindings were really built. The compiler probe reads ROCM_HAVE_FORTRAN, with
ROCM_LIBS_HAVE_FORTRAN honoured second.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the directory
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name.
The config picks the consumer's own compiler when its .mod is installed, so a
prefix holding several compilers' artifacts resolves without an override, and
repoints the imported target accordingly.

The real config is co-installed in lib/cmake/hipsparse beside the C package,
with a forwarder in lib/cmake/hipsparse-fortran. The config-version file goes
into both directories, because CMake looks for it next to the config it actually
resolved and the versioned spelling resolves the forwarder. Its version is
parsed from this tree's project(hipsparse VERSION ...) rather than from
hipsparse_VERSION, which the find_package(hipsparse) this directory does for its
link interface would set to the installed version.

The generated hipsparse.F90 installs to share/hipsparse/fortran, so a user on a
compiler with no shipped .mod can rebuild the binding without cloning a monorepo
to get one file.

Tests
-----
50 tests under CTest, off by default: 49 runtime tests carried over from hipFORT,
which allocate and copy device memory and so need the HIP Fortran binding at
compile time, plus test_hipsparse.F03, the exhaustive symbol test, which uses
only iso_c_binding and hipsparse and is registered outside that guard behind
BUILD_FORTRAN_EXTENDED_TESTS.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 27, 2026
rocfft.F90 is generated from the rocFFT public headers by the rocm-fortran
generator and committed next to them, so that a header change and its
binding travel in the same pull request. It is a single self-contained
module, `rocfft`, carrying the interfaces, the enum constants, the opaque
handles and the rocfftCheck status helper. A consumer writes one `use rocfft`.

Implements RFC0014 (ROCm/TheRock#8122) for rocFFT, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: a Fortran binding declares bind(C)
interfaces only, so it compiles against neither the rocFFT headers nor
librocfft, and needs no GPU and no HIP compiler to build. librocfft is a
link-time dependency of a final executable and is carried as the target's
link interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCFFT_BUILD_FORTRAN_* so one library
can be singled out in a monorepo build. FORTRAN_ARRAY_INTERFACES is a
tri-state (none / assumed-shape / assumed-rank, default assumed-shape)
replacing the two booleans USE_FPOINTER_INTERFACES and ASSUMED_RANK: the two
upper tiers cannot legally coexist in one generic, because an assumed-rank
dummy is not distinguishable by rank from the per-rank specifics.
ROCFFT_HAVE_FORTRAN_BINDINGS reports whether they were really built, and the
config package sets rocfft_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, which is the name to
settle on across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, Flang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper, where a
plain basename would not.

The generated source is installed too, as share/rocfft/fortran/rocfft.F90, so
that a user on a compiler ROCm ships no .mod for can rebuild the binding
without cloning a monorepo to get one file, and cannot end up with source
generated from a different ROCm than the librocfft they link. It goes under
share/ rather than include/ deliberately: everything under include/fortran/
is partitioned by compiler and the config enumerates that directory to report
which compilers are installed, so a compiler-independent source file there
would be listed as though it were one.

The config package lands in lib/cmake/rocfft beside the C package, and a
forwarder in lib/cmake/rocfft-fortran makes find_package(rocfft-fortran)
resolve to the same place. A version file is installed into BOTH directories,
and it has to be: CMake looks for the version file next to the config it
actually resolved, so find_package(rocfft-fortran 1.0) resolves the forwarder
and would never see a version file kept only beside the real config. The
number is parsed from this tree's projects/rocfft/CMakeLists.txt, never from
rocfft_VERSION, which in a standalone build reports whatever rocFFT happens
to be installed. rocFFT composes VERSION_STRING from ROCFFT_VERSION_MAJOR /
_MINOR / _PATCH rather than spelling a literal, so the three components are
read and recomposed; when that fails, no version file is installed and a
STATUS message says so, because a file claiming the wrong number is worse
than none.

The recorded compiler directory is only a DEFAULT. A prefix can hold
artifacts for several compilers at once, while the config package is written
once and names whichever install ran last, so the config prefers the
consumer's own compiler when its .mod is present under the prefix, falls back
to the recorded directory otherwise, and fails naming what IS available. When
the resolved directory differs from the recorded one it repoints
INTERFACE_INCLUDE_DIRECTORIES and every IMPORTED_LOCATION_<CFG>, without
which find_package would succeed while linking the wrong archive.

The archive is compiled with -ffunction-sections -fdata-sections and exports
--gc-sections to consumers. A static archive links at object granularity and
this module is one object, so one wrapper otherwise pulls in every undefined C
symbol the object references: the first rocFFT entry point added after a
release would break the link for consumers who never call it. Both are guarded
on the compilers known to accept the spelling.

Tests
-----
test/ carries 19 tests under CTest. Eighteen are runtime tests that allocate
device memory, so they write `use hip` next to `use rocfft` and need the HIP
Fortran binding at compile time; they are skipped with a named message when
it is absent. test_rocfft.F03, the exhaustive symbol test, uses only
iso_c_binding and rocfft, so it is registered outside that guard. That
distinction is load-bearing: ROCm does not currently ship a HIP Fortran
binding, so guarding the whole directory would mean zero tests against a
stock /opt/rocm, including the only one that proves every bind(C) symbol
resolves against librocfft.

Runtime tests are labelled "gpu" and the symbol test "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with gfortran 13.3.0. Standalone
configure is clean under -Wdev, the version resolves to 1.0.41 and the
version file installs into both cmake directories. Against a stock /opt/rocm
the symbol test builds, links and passes on its own. With the HIP Fortran
binding available, 19 of 19 pass; one of those, field_brick_z, prints SKIPPED
and exits 0 because it wants two GPUs, so the honest reading is 17 real GPU
tests, 1 self-skip and the symbol test. The documented consumer path was
exercised end to end: install, find_package(rocfft-fortran 1.0), link
roc::rocfft_fortran, run on the GPU. The per-compiler fallback was exercised
by hand too: with the recorded directory pointing at a compiler whose .mod is
not installed, the consumer's own compiler is picked and the imported target
repointed at it, and with no usable directory at all find_package fails
naming what is installed.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 27, 2026
hipfft.F90 and hipfftw.F90 are generated from the public headers by the
rocm-fortran generator and committed next to them, so that a header change
and its binding travel in the same pull request. Each is a single
self-contained module, `hipfft` and `hipfftw`, carrying the interfaces, the
enum constants, the opaque handles and the status helper. A consumer writes
one `use hipfft`.

Implements RFC0014 (ROCm/TheRock#8122) for hipFFT, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

Two bindings in one directory, because hipFFTW is built by the hipFFT
project rather than one of its own. They are separate modules, separate
targets and separate config packages, but they live next to the headers they
bind rather than in a directory of their own.

The bindings declare bind(C) interfaces only, so they compile against neither
the hipFFT headers nor libhipfft, and need no GPU and no HIP compiler to
build. The C libraries are link-time dependencies of a final executable and
are carried as each target's link interface. The subdirectory guards itself,
returning early when BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is
present, so a C-only site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPFFT_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic,
because an assumed-rank dummy is not distinguishable by rank from the
per-rank specifics. The config packages set hipfft_FORTRAN_FOUND and
hipfftw_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on
across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so each .mod and archive installs
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper, where a
plain basename would not.

Both config packages land in lib/cmake/hipfft beside the C package, and
forwarders in lib/cmake/hipfft-fortran and lib/cmake/hipfftw-fortran make
find_package(hipfft-fortran) and find_package(hipfftw-fortran) resolve to the
same place. Each package gets a config-version file, stamped with hipFFT's
version (hipFFTW has none of its own) parsed from the HIPFFT_VERSION_* components
in this tree rather than from hipfft_VERSION, which reports whatever hipFFT is
INSTALLED. Both files install into BOTH of their package directories, because
CMake looks for the version file next to the config it actually resolved and the
versioned spelling resolves the forwarder. When the version cannot be read, no
version file is installed and a STATUS message says so: a file claiming the wrong
number is worse than none.

The recorded compiler directory is only a DEFAULT. A prefix can hold artifacts
for several compilers while the config is written once, so each config prefers
the consumer's own compiler when its .mod is installed under the prefix --
hipfft.mod for one package, hipfftw.mod for the other, since either half is
switchable on its own -- falls back to the recorded directory, and otherwise
names what IS available. When the resolved directory differs from the recorded
one, INTERFACE_INCLUDE_DIRECTORIES and every IMPORTED_LOCATION_<CFG> are
repointed, or find_package would succeed while linking the wrong archive.

Both generated sources also install to share/hipfft/fortran, so that a user on a
compiler ROCm ships no .mod for can rebuild without cloning a monorepo. Under
share/ and not include/, because everything under include/fortran/ is partitioned
by compiler and the configs glob that directory to report which compilers are
present.

Both archives are built with -ffunction-sections -fdata-sections and export
--gc-sections to consumers, guarded on the compilers that accept the spelling. A
static archive links at object granularity and each of these is one object, so
without section GC one wrapper pulls in every undefined C symbol the whole module
references, and a consumer fails to link over API their installed .so lacks.

Tests
-----
test/ carries 21 tests under CTest. Nineteen are runtime tests that allocate
device memory, so they write `use hip` next to their own `use`, which makes
the HIP Fortran binding a compile-time dependency; they are skipped with a
named message when it is absent. The two exhaustive symbol tests use only
iso_c_binding and the module under test, so they are registered outside that
guard. That distinction matters: ROCm does not currently ship a HIP Fortran
binding, so guarding the whole directory would mean zero tests against a
stock /opt/rocm, including the only ones that prove every bind(C) symbol
resolves against the installed libraries.

Runtime tests are labelled "gpu" and the symbol tests "symbols", so
ctest -LE gpu stays meaningful on a machine without one.

Verified against ROCm 10.0 on gfx1101 with BOTH compilers, gfortran 13.3.0
and amdflang 23.0.0. Against a stock /opt/rocm the two symbol tests build,
link and pass on their own; with the HIP Fortran binding available, 21 of 21
pass. The documented consumer path was exercised end to end with amdflang:
install, find_package on both packages, link hip::hipfft_fortran and
hip::hipfftw_fortran in one program, run on the GPU. The compiler-mismatch
diagnostic was exercised for real by installing with amdflang and consuming
with gfortran, which is what confirms the CMAKE_Fortran_COMPILER_ID mapping
handles LLVMFlang and that the message renders as prose rather than as a
semicolon-separated list.

The per-compiler selection was verified the same way: both bindings installed
into one prefix twice, with gfortran and then amdflang, so that the configs
record amdflang while the gfortran artifacts are still present. A gfortran
consumer then still resolves both packages, compiles against
include/fortran/gfortran and links lib/fortran/gfortran, which is the repointing
working. Removing only gfortran's hipfftw.mod makes hipfftw-fortran fail with the
named message while hipfft-fortran still resolves, which is the per-module glob
working. find_package(hipfft-fortran 1.0) and find_package(hipfftw-fortran 1.0)
both resolve through their forwarders and report 1.0.27; 2.0 is refused.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
…rated one

JIRA ID : ROCM-31390

hipsparse.F90 is generated from the hipSPARSE public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hipsparse`, carrying the interfaces, the enum constants, the opaque handles and
the hipsparseCheck status helper. A consumer writes one `use hipsparse` and
links roc::hipsparse_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for hipSPARSE, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written module
--------------------------------
library/src/hipsparse.f90 and hipsparse_enums.f90 are removed, along with the
hipsparse_fortran OBJECT target in library/CMakeLists.txt that compiled them.
That target carried the SAME NAME as the one this directory creates, so with
-DHIPSPARSE_ENABLE_CLIENT=ON the two collided outright:

    CMake Error at fortran/CMakeLists.txt (add_library):
      add_library cannot create target "hipsparse_fortran" because another
      target with the same name already exists

CI never saw it because HIPSPARSE_ENABLE_FORTRAN is declared inside
if(HIPSPARSE_ENABLE_CLIENT), which defaults OFF. The Fortran samples now link
roc::hipsparse_fortran, which carries both the .mod directory and the archive,
and HIPSPARSE_ENABLE_FORTRAN is turned off with a message when the bindings were
not built, so -DHIPSPARSE_ENABLE_CLIENT=ON still works without a Fortran
compiler.

Host and device pointer mode
----------------------------
The generated binding follows hipFORT and binds a `const T*` scalar as a
by-reference `real(c_double) :: alpha`. The removed module bound the same
argument as `type(c_ptr), value`, so every sample passes `c_loc(alpha)`. Both
are ABI-correct, but only the second can express
HIPSPARSE_POINTER_MODE_DEVICE, where the library reads alpha from device
memory: a type(c_ptr) cannot be passed where a real is expected.
example_fortran_spmv.f90 does exactly that, passing a hipMalloc'd d_alpha to
hipsparseDbsrmv.

So 25 generics gained a second specific taking those scalars as
type(c_ptr),value and forwarding through c_f_pointer, which only records the
address and never dereferences it on the host. Six zeroPivot routines were plain
functions rather than generics and became generics to carry both; their own
documentation states that `position` can be in host OR device memory. No sample
and no test was modified: all 32 samples and all 49 tests build and pass against
the binding as committed.

This is a local fix in a GENERATED file, kept narrow deliberately. The ~700
other scalar arguments in hipSPARSE, and the same arguments in rocBLAS,
hipBLAS, rocSPARSE and rocSOLVER, still cannot express device pointer mode. The
durable fix belongs in the generator and will have to re-emit these variants.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPSPARSE_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape). HIPSPARSE_HAVE_FORTRAN_BINDINGS reports whether the
bindings were really built. The compiler probe reads ROCM_HAVE_FORTRAN, with
ROCM_LIBS_HAVE_FORTRAN honoured second.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the directory
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name.
The config picks the consumer's own compiler when its .mod is installed, so a
prefix holding several compilers' artifacts resolves without an override, and
repoints the imported target accordingly.

The real config is co-installed in lib/cmake/hipsparse beside the C package,
with a forwarder in lib/cmake/hipsparse-fortran. The config-version file goes
into both directories, because CMake looks for it next to the config it actually
resolved and the versioned spelling resolves the forwarder. Its version is
parsed from this tree's project(hipsparse VERSION ...) rather than from
hipsparse_VERSION, which the find_package(hipsparse) this directory does for its
link interface would set to the installed version.

The generated hipsparse.F90 installs to share/hipsparse/fortran, so a user on a
compiler with no shipped .mod can rebuild the binding without cloning a monorepo
to get one file.

Tests
-----
49 tests under CTest, off by default: the runtime tests carried over from
hipFORT, which allocate and copy device memory and so need the HIP Fortran
binding at compile time, and are skipped with a named message when it is
absent. They are labelled gpu, so ctest -LE gpu stays meaningful on a machine
without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
…ted one

JIRA ID : ROCM-31390

hipblas.F90 is generated from the hipBLAS public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hipblas`, carrying the interfaces, the enum constants, the opaque handles and
the hipblasCheck status helper. A consumer writes one `use hipblas` and links
roc::hipblas_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for hipBLAS, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923, and mirroring rocBLAS.

Removing the hand-written binding
---------------------------------
library/src/hipblas_module.f90 is removed, along with the rocm_install() rule
that shipped it into include/hipblas. It defined TWO modules, hipblas and
hipblas_enums; the generated binding defines only hipblas, with the hipBLAS enum
constants folded in. `use hipblas` is unchanged, `use hipblas_enums` becomes
`use hipblas`, applied here across 1197 sites in the clients.

clients no longer compiles its own hipblas_fortran object library from that
source; hipblas_fortran_client links the target ../fortran exports. Both carried
the same name, so this also removes a latent duplicate-target clash. The
BUILD_WITH_SOLVER split is preserved. Because hipBLAS's consumers absorb
$<TARGET_OBJECTS:hipblas_fortran_client> rather than linking it, and that
carries neither the archive nor the .mod include directory, the Fortran samples
and rocblas-bench now link hipblas_fortran_client explicitly.

The hipDataType enumerators, and why a stub ships temporarily
-------------------------------------------------------------
hipblas_enums also re-exported HIP's hipDataType enumerators. The generated
module does not: a hipDataType belongs to HIP, and the generated interfaces type
those arguments as plain integer(c_int). That is correct, but it leaves the
client shims -- which declare their datatype arguments as
integer(kind(HIP_R_16F)) -- with no source for the name. 57 scopes across
clients/include/hipblas_fortran_blas{,_64}.f90 are affected, and they now say
`use hip`.

ROCm ships no HIP Fortran binding yet, so fortran/hip_datatypes_stub.F90
provides one, carrying only the sixteen enumerators those scopes reference, with
values copied verbatim from the HIP binding. It is compiled into
hipblas_fortran_client and is NOT installed, exported or packaged, so no second
hip.mod can reach an installed prefix and collide with the real binding.

It is meant to be deleted. When ROCm/rocm-systems#11923 lands: drop the stub
from the source list and from fortran/, then find_package(hip-fortran) and link
hip::hip_fortran. The `use hip` lines do not change -- they start resolving to
the real module, which declares the same enumerators with the same values, so
the swap is observably a no-op.

Note that a hipBLAS USER calling hipblasGemmEx needs those values too, and the
stub does not help them since it is not installed. Until the HIP binding ships
they need `use hip` from a HIP binding of their own. hipSPARSE has the same gap.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable through HIPBLAS_BUILD_FORTRAN_*. FORTRAN_ARRAY_INTERFACES is a
tri-state (none / assumed-shape / assumed-rank, default assumed-shape).

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The shared layout
is used: the real config in lib/cmake/hipblas beside the C package, a forwarder
in lib/cmake/hipblas-fortran.

The config-version file is installed into BOTH package directories, because
CMake looks for it next to the <pkg>-config.cmake it actually resolved and
find_package(hipblas-fortran 3.8) resolves the forwarder. Its version is parsed
from this tree's VERSION_STRING rather than from hipblas_VERSION, which the
find_package(hipblas) this directory does for its link interface would set to
the installed version.

Section GC (-ffunction-sections, --gc-sections) is carried over from rocBLAS.
hipBLAS needs none of it today -- every symbol the module references is present
in the installed libhipblas -- because this binding currently lags the headers
rather than running ahead of them. It is kept so the next regeneration that
picks up a new entry point does not reintroduce undefined references in
downstream builds.

Tests
-----
69 tests under CTest, off by default: 68 runtime tests from hipFORT plus
test_hipblas.F03, the exhaustive symbol test, registered outside the
hip::hip_fortran guard behind BUILD_FORTRAN_EXTENDED_TESTS.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
JIRA ID : ROCM-31390

hiprand.F90 is generated from the hipRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`hiprand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the hiprandCheck status helper. A consumer writes one
`use hiprand` and links hip::hiprand_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for hipRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written wrapper
---------------------------------
library/src/fortran (hiprand_m.f90, hip_m.f90), its config template, and the
FRUIT-based suite under test/fortran go with it, along with
BUILD_FORTRAN_WRAPPER and its references in the top-level CMakeLists,
library/CMakeLists.txt, test/CMakeLists.txt, cmake/Summary.cmake,
cmake/Dependencies.cmake, docs/install/build.rst and testing.md.

That API was deprecated in favour of hipfort in hipRAND 3.0.0 / ROCm 7.0 and has
never been shipped enabled: ROCm builds with BUILD_FORTRAN_WRAPPER=OFF, so in an
installed /opt/rocm hiprand_FORTRAN_FOUND is NOTFOUND, hiprand_FORTRAN_SRC_DIRS
is never set, and hiprand/src/fortran does not exist. No consumer of a ROCm
package can therefore be using it; only a source build that passed the flag.

Removing it frees the target name hiprand_fortran, which both defined and which
is a hard CMake error.

Why the config package still stands alone
-----------------------------------------
It does NOT free lib/cmake/hiprand/hiprand-fortran-config.cmake, and that is the
one place rocRAND and hipRAND diverge from the rest of the series.

Removing the wrapper frees that name in this source tree, but not in prefixes
that are already installed. Every ROCm shipped so far has a hiprand-config.cmake
whose line 94 is a bare, unguarded include() of a sibling by that exact name.
Installing this package's config there hands that include a file that calls
find_dependency(hiprand), which re-enters hiprand-config.cmake, which includes
the Fortran config again -- unbounded recursion until CMake gives up. That is
precisely the documented standalone path: build the binding yourself and install
it into an existing /opt/rocm, which is what anyone whose compiler is not the
shipped amdflang has to do.

So the package installs only into lib/cmake/hiprand-fortran, where
find_package(hiprand-fortran) resolves it directly and no forwarder is needed.
When rocm-cmake grows an OPTIONAL end-of-config hook and no supported ROCm still
carries the old unguarded include, this can join the shared layout.

A config-version file is installed alongside, so find_package(hiprand-fortran
3.4) resolves. Its version is parsed from this tree's own VERSION_STRING, not
from hiprand_VERSION: that variable is set by the find_package(hiprand) this
directory does for its link interface, so it would report whatever hipRAND
happens to be installed rather than the headers the bindings were generated
from. When the version cannot be determined, no file is written at all, because
a version file claiming the wrong number is worse than none.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through HIPRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK. HIPRAND_HAVE_FORTRAN_BINDINGS reports whether they were built.

BUILD_FORTRAN_BINDINGS is declared at the top level as well as in fortran/,
because print_configuration_summary() runs before add_subdirectory(fortran) and
would otherwise report an empty value.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the name derived
from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name, which
survives an MPI wrapper, a versioned binary, an absolute path and the Cray
wrapper. A site installing two versions of one compiler overrides
HIPRAND_FORTRAN_COMPILER_DIR; the config accepts the derived name or that name
followed by a separator and anything, compared by length and substring rather
than by regex, since the derived name can be an arbitrary file name.

Tests
-----
23 tests under CTest, off by default, replacing the FRUIT suite. One per
(generator, distribution) pair, each allocating and copying device memory
around its hipRAND call, so they write `use hip` and need the HIP Fortran
binding at compile time; they are skipped with a named message when it is
absent.

They are labelled gpu, so ctest -LE gpu stays meaningful on a machine without
one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
…ted one

JIRA ID : ROCM-31390

rocblas.F90 is generated from the rocBLAS public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocblas`, carrying the interfaces, the enum constants, the opaque handles and
the rocblasCheck status helper. A consumer writes one `use rocblas` and links
roc::rocblas_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocBLAS, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written binding
---------------------------------
library/include/rocblas_module.f90 is removed, along with the rocm_install()
rule that shipped it into include/rocblas. It defined TWO modules, rocblas and
rocblas_enums; the generated binding defines only rocblas, with the enum
constants folded in. `use rocblas` is unchanged, but `use rocblas_enums` becomes
`use rocblas`, which is applied here to the clients' shims and samples.
Consumers get a compiled archive and .mod rather than a .f90 source to build
themselves.

clients no longer compiles its own rocblas_fortran object library from that
source; rocblas_fortran_client links the target ../fortran exports. Both carried
the same name, so this also removes a latent duplicate-target clash.
next-cmake, which built its own rocblas-fortran-module from the same file, now
builds the generated source instead.

The add_subdirectory(fortran) hook moves out of the SKIP_LIBRARY guard: that
guard decides whether librocblas is built here, and the bindings need it linked,
not built. With clients now consuming the target rather than building their own,
inheriting the skip would leave BUILD_FORTRAN_CLIENTS with no rocblas_fortran.

Linking against an older rocBLAS
--------------------------------
The archive is built with -ffunction-sections -fdata-sections and exports
--gc-sections to its consumers. The module is generated from THIS tree's
headers, so it wraps API no released ROCm has yet -- the six
rocblas_*gemm_grouped_batched entry points today. A static archive links at
object granularity, so pulling in one wrapper pulls in every undefined C symbol
the object references, and a consumer who never touches the new API would still
fail to link. With section GC the unreferenced wrappers are discarded.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCBLAS_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK. ROCBLAS_HAVE_FORTRAN_BINDINGS reports whether they were built.

The compiler probe is read from ROCM_HAVE_FORTRAN, with ROCM_LIBS_HAVE_FORTRAN
honoured second as the spelling this repository's root publishes today.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the directory
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name,
which survives an MPI wrapper, a versioned binary, an absolute path and the Cray
wrapper. A site installing two versions of one compiler overrides
ROCBLAS_FORTRAN_COMPILER_DIR; the config accepts the derived name or that name
followed by a separator and anything, compared by length and substring rather
than by regex.

This uses the shared layout: the real config is co-installed in lib/cmake/rocblas
beside the C package, with a forwarder in lib/cmake/rocblas-fortran.
rocblas-config.cmake carries no Fortran include, so the recursion hazard that
keeps rocRAND and hipRAND in a directory of their own does not apply here.

The config-version file is installed into BOTH package directories. CMake looks
for it next to the <pkg>-config.cmake it actually resolved, and
find_package(rocblas-fortran 5.8) resolves the forwarder, so a version file only
beside the real config is never consulted and the call fails even though the
version matches. Its version is parsed from this tree's VERSION_STRING rather
than from rocblas_VERSION, which is set by the find_package(rocblas) this
directory does for its link interface and would report whatever rocBLAS happens
to be installed.

Tests
-----
80 tests under CTest, off by default: the runtime tests carried over from
hipFORT, which allocate and copy device memory and so need the HIP Fortran
binding at compile time, and are skipped with a named message when it is
absent. They are labelled gpu, so ctest -LE gpu stays meaningful on a machine
without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
JIRA ID : ROCM-31390

rocrand.F90 is generated from the rocRAND public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocrand`, carrying the interfaces, the enum constants, the derived types, the
opaque handles and the rocrandCheck status helper. A consumer writes one
`use rocrand` and links roc::rocrand_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocRAND, following the shape already
reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written wrapper
---------------------------------
library/src/fortran (rocrand_m.f90, hip_m.f90), its config template, and the
FRUIT-based suite under test/fortran go with it, along with
BUILD_FORTRAN_WRAPPER and its references in the top-level CMakeLists,
library/CMakeLists.txt, test/CMakeLists.txt, cmake/Summary.cmake,
cmake/Dependencies.cmake and docs/install/build.rst.

That API was deprecated in favour of hipfort in rocRAND 4.0.0 / ROCm 7.0 and has
never been shipped enabled: ROCm builds with BUILD_FORTRAN_WRAPPER=OFF, so in an
installed /opt/rocm rocrand_FORTRAN_FOUND is NOTFOUND, rocrand_FORTRAN_SRC_DIRS
is never set, and rocrand/src/fortran does not exist. No consumer of a ROCm
package can therefore be using it; only a source build that passed the flag.

Removing it also frees two names the generated bindings want. The target
rocrand_fortran was defined by both, which is a hard CMake error. More
importantly lib/cmake/rocrand/rocrand-fortran-config.cmake belonged to the
wrapper, and rocrand-config.cmake include()s that name unconditionally, so the
new package could not have been co-installed beside the C one while the wrapper
stood. With the wrapper gone, rocRAND uses the same layout as the rest of the
series: the real config in lib/cmake/rocrand, a forwarder in
lib/cmake/rocrand-fortran, and rocrand_FORTRAN_FOUND back to its ordinary
meaning.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCRAND_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK: the two upper tiers cannot legally coexist in one generic, because
an assumed-rank dummy is not distinguishable by rank from the per-rank
specifics. ROCRAND_HAVE_FORTRAN_BINDINGS reports whether they were really built.

The compiler probe is read from ROCM_HAVE_FORTRAN, the name to settle on across
both monorepos. This repository's root publishes ROCM_LIBS_HAVE_FORTRAN today,
so that spelling is honoured second, never over the new name.

The bindings hook sits outside the USE_SYSTEM_LIB branch: that branch controls
whether librocrand is built here, and the bindings need it linked, not built.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, LLVMFlang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper.

A site installing two versions of one compiler side by side overrides
ROCRAND_FORTRAN_COMPILER_DIR with a suffixed name, so the config package accepts
the recorded directory when it is the derived name OR that name followed by a
separator and anything. The comparison is done by length and substring rather
than by regex: the derived name comes from the compiler's basename on the
fallback branch, so it is an arbitrary file name, and interpolating it into a
regex would let a compiler called flang(2) either mismatch silently or abort
CMake outright.

Note that rocm_export_targets' INCLUDE argument is not a substitute for the
OPTIONAL sibling include the config comment describes: it emits a bare,
non-OPTIONAL include(), and emits it before the targets file, so a Fortran
config reached that way would run before roc::rocrand exists. That hook belongs
in rocm-cmake.

Tests
-----
23 tests under CTest, off by default, replacing the FRUIT suite. One per
(generator, distribution) pair, each allocating and copying device memory
around its rocRAND call, so they write `use hip` and need the HIP Fortran
binding at compile time; they are skipped with a named message when it is
absent.

They are labelled gpu, so ctest -LE gpu stays meaningful on a machine without
one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
…rated one

JIRA ID : ROCM-31390

rocsparse.F90 is generated from the rocSPARSE public headers by the rocm-fortran
generator and committed next to them, so that a header change and its binding
travel in the same pull request. It is a single self-contained module,
`rocsparse`, carrying the interfaces, the enum constants, the opaque handles and
the rocsparseCheck status helper. A consumer writes one `use rocsparse` and
links roc::rocsparse_fortran.

Implements RFC0014 (ROCm/TheRock#8122) for rocSPARSE, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

Removing the hand-written binding
---------------------------------
library/src/rocsparse.f90 and library/src/rocsparse_enums.f90 are removed, along
with the rocm_install(FILES ...) rule that shipped them into include/rocsparse.
Unlike rocRAND's wrapper, this one WAS shipped and built by default, so the
removal is user visible: the module keeps the name `rocsparse`, but the separate
`rocsparse_enums` module is gone -- its constants are part of `rocsparse` --
and consumers get a compiled archive and .mod rather than .f90 sources to build
themselves.

clients no longer compiles its own rocsparse_fortran object library from those
sources; it consumes the one ../fortran exports. Both carried the same target
name, so this also removes a latent duplicate-target clash. All fourteen
existing Fortran samples compile unmodified against the generated module.

The add_subdirectory(fortran) hook moves out of the BUILD_CLIENTS_ONLY branch.
That is a bug fix, not tidying: clients now require the rocsparse_fortran target
and BUILD_FORTRAN_CLIENTS defaults to ON, so -DBUILD_CLIENTS_ONLY=ON skipped the
directory and then stopped in clients with "the rocsparse_fortran target is
missing".

Linking against an older rocSPARSE
----------------------------------
The archive is built with -ffunction-sections -fdata-sections and exports
--gc-sections to its consumers. This is not a size optimisation: the module is
generated from THIS tree's headers, so it wraps API no released ROCm has yet
(rocsparse_dnvec_descr_create_scalar, rocsparse_ell_set_strided_batch,
rocsparse_spmat_scale today). A static archive links at object granularity, so
pulling in one wrapper pulls in every undefined C symbol the object references.
Without section GC a consumer who never touches the new API still fails to link,
with 25 undefined references to functions they have never heard of; with it, the
unreferenced wrappers are discarded and the link succeeds.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCSPARSE_BUILD_FORTRAN_*.
FORTRAN_ARRAY_INTERFACES is a tri-state (none / assumed-shape / assumed-rank,
default assumed-shape) replacing the two booleans USE_FPOINTER_INTERFACES and
ASSUMED_RANK. ROCSPARSE_HAVE_FORTRAN_BINDINGS reports whether they were built.

The compiler probe is read from ROCM_HAVE_FORTRAN, with ROCM_LIBS_HAVE_FORTRAN
honoured second as the spelling this repository's root publishes today.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>, the directory
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name,
which survives an MPI wrapper, a versioned binary, an absolute path and the Cray
wrapper. A site installing two versions of one compiler overrides
ROCSPARSE_FORTRAN_COMPILER_DIR; the config accepts the derived name or that name
followed by a separator and anything, compared by length and substring rather
than by regex, since the derived name can be an arbitrary file name.

This uses the SHARED layout: the real config is co-installed in
lib/cmake/rocsparse beside the C package, with a forwarder in
lib/cmake/rocsparse-fortran. rocRAND and hipRAND cannot do this because their
shipped <lib>-config.cmake carries a bare unguarded include() of a sibling
<lib>-fortran-config.cmake and a file there would recurse; rocsparse-config.cmake
has no such include, checked against an installed ROCm.

A config-version file is installed alongside, its version parsed from this tree's
VERSION_STRING rather than from rocsparse_VERSION -- that variable is set by the
find_package(rocsparse) this directory does for its link interface, so it would
report whatever rocSPARSE happens to be installed.

Tests
-----
58 tests under CTest, off by default: 57 runtime tests carried over from hipFORT,
which allocate and copy device memory and so need the HIP Fortran binding at
compile time, plus test_rocsparse.F03, the exhaustive symbol test, which uses
only iso_c_binding and rocsparse and is registered outside that guard behind
BUILD_FORTRAN_EXTENDED_TESTS.

The csrgeam and csrgemm tests, all four precisions of each, are listed but
commented out because they segfault, with the analysis recorded next to them.
The cause is in the tests: both families select what they compute from whether
alpha and beta are NULL POINTERS rather than from their values, and these tests
pass beta = 0.0_c_double, a valid pointer, while passing c_null_ptr for descr_D
and every D array, so rocSPARSE looks for a D term that is not there. The
binding can express the NULL -- it carries a _dptr specific taking
type(c_ptr),value :: alpha,beta -- so fixing them is a follow-up, not a change
to the binding.

Runtime tests are labelled gpu and the symbol test symbols, so ctest -LE gpu
stays meaningful on a machine without one.
amontoison added a commit to amontoison/rocm-libraries that referenced this pull request Sep 28, 2026
rocfft.F90 is generated from the rocFFT public headers by the rocm-fortran
generator and committed next to them, so that a header change and its
binding travel in the same pull request. It is a single self-contained
module, `rocfft`, carrying the interfaces, the enum constants, the opaque
handles and the rocfftCheck status helper. A consumer writes one `use rocfft`.

Implements RFC0014 (ROCm/TheRock#8122) for rocFFT, following the shape
already reviewed for HIP in ROCm/rocm-systems#11923.

The directory is self-contained: a Fortran binding declares bind(C)
interfaces only, so it compiles against neither the rocFFT headers nor
librocfft, and needs no GPU and no HIP compiler to build. librocfft is a
link-time dependency of a final executable and is carried as the target's
link interface. The subdirectory guards itself, returning early when
BUILD_FORTRAN_BINDINGS is OFF or no Fortran compiler is present, so a C-only
site is unaffected.

Build options
-------------
BUILD_FORTRAN_BINDINGS (ON, guarded) and BUILD_FORTRAN_TESTS (OFF, guarded),
both overridable per library through ROCFFT_BUILD_FORTRAN_* so one library
can be singled out in a monorepo build. FORTRAN_ARRAY_INTERFACES is a
tri-state (none / assumed-shape / assumed-rank, default assumed-shape)
replacing the two booleans USE_FPOINTER_INTERFACES and ASSUMED_RANK: the two
upper tiers cannot legally coexist in one generic, because an assumed-rank
dummy is not distinguishable by rank from the per-rank specifics.
ROCFFT_HAVE_FORTRAN_BINDINGS reports whether they were really built, and the
config package sets rocfft_FORTRAN_FOUND.

The compiler probe is read from ROCM_HAVE_FORTRAN, which is the name to
settle on across both monorepos. This repository's root publishes
ROCM_LIBS_HAVE_FORTRAN today, so that spelling is honoured second, never over
the new name. It is a bridge with an end: when the root is switched over,
that branch is dead code and goes.

Install layout
--------------
A .mod is not portable across compilers, so the .mod and the archive install
under include/fortran/<compiler> and lib/fortran/<compiler>. The directory is
derived from CMAKE_Fortran_COMPILER_ID and mapped back to the executable name
(GNU to gfortran, Flang to amdflang, Cray to ftn), which survives an MPI
wrapper, a versioned binary, an absolute path and the Cray wrapper, where a
plain basename would not.

The generated source is installed too, as share/rocfft/fortran/rocfft.F90, so
that a user on a compiler ROCm ships no .mod for can rebuild the binding
without cloning a monorepo to get one file, and cannot end up with source
generated from a different ROCm than the librocfft they link. It goes under
share/ rather than include/ deliberately: everything under include/fortran/
is partitioned by compiler and the config enumerates that directory to report
which compilers are installed, so a compiler-independent source file there
would be listed as though it were one.

The config package lands in lib/cmake/rocfft beside the C package, and a
forwarder in lib/cmake/rocfft-fortran makes find_package(rocfft-fortran)
resolve to the same place. A version file is installed into BOTH directories,
and it has to be: CMake looks for the version file next to the config it
actually resolved, so find_package(rocfft-fortran 1.0) resolves the forwarder
and would never see a version file kept only beside the real config. The
number is parsed from this tree's projects/rocfft/CMakeLists.txt, never from
rocfft_VERSION, which in a standalone build reports whatever rocFFT happens
to be installed. rocFFT composes VERSION_STRING from ROCFFT_VERSION_MAJOR /
_MINOR / _PATCH rather than spelling a literal, so the three components are
read and recomposed; when that fails, no version file is installed and a
STATUS message says so, because a file claiming the wrong number is worse
than none.

The recorded compiler directory is only a DEFAULT. A prefix can hold
artifacts for several compilers at once, while the config package is written
once and names whichever install ran last, so the config prefers the
consumer's own compiler when its .mod is present under the prefix, falls back
to the recorded directory otherwise, and fails naming what IS available. When
the resolved directory differs from the recorded one it repoints
INTERFACE_INCLUDE_DIRECTORIES and every IMPORTED_LOCATION_<CFG>, without
which find_package would succeed while linking the wrong archive.

The archive is compiled with -ffunction-sections -fdata-sections and exports
--gc-sections to consumers. A static archive links at object granularity and
this module is one object, so one wrapper otherwise pulls in every undefined C
symbol the object references: the first rocFFT entry point added after a
release would break the link for consumers who never call it. Both are guarded
on the compilers known to accept the spelling.

Tests
-----
test/ carries 18 tests under CTest. All are runtime tests that allocate
device memory, so they write `use hip` next to `use rocfft` and need the HIP
Fortran binding at compile time; they are skipped with a named message when
it is absent.

They are labelled "gpu", so ctest -LE gpu stays meaningful on a machine
without one.

Verified against ROCm 10.0 on gfx1101 with gfortran 13.3.0. Standalone
configure is clean under -Wdev, the version resolves to 1.0.41 and the
version file installs into both cmake directories. With the HIP Fortran
binding available, 18 of 18 pass; one of those, field_brick_z, prints SKIPPED
and exits 0 because it wants two GPUs, so the honest reading is 17 real GPU
tests and 1 self-skip. The documented consumer path was
exercised end to end: install, find_package(rocfft-fortran 1.0), link
roc::rocfft_fortran, run on the GPU. The per-compiler fallback was exercised
by hand too: with the recorded directory pointing at a compiler whose .mod is
not installed, the consumer's own compiler is picked and the imported target
repointed at it, and with no usable directory at all find_package fails
naming what is installed.

@saadrahim saadrahim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved as a draft RFC

Comment thread docs/rfcs/README.md Resolved
amontoison and others added 13 commits October 13, 2026 11:19
…cm-libraries

hipfort lives in a separate repository and its interfaces are partially
hand-written, so its coverage is only ever as current as the last manual
update. This RFC co-locates generated bindings with the C headers they
mirror: the HIP runtime bindings in rocm-systems, each math library's
bindings in rocm-libraries, each under a dedicated fortran/ directory,
kept in sync by a CI gate that suggests the regenerated diff on the PR
that changes a header.

It also fixes the packaged deliverable (per-library .mod, archive, and
CMake target under the C library's own namespace), the module naming
(no hipfort_ prefix, one module per library), the Fortran standard
tiers, and the two-track transition from today's hipfort.
A user on a compiler other than the one ROCm ships bindings for builds
the binding themselves, and today that means cloning a monorepo to get
the source. Installing it alongside the binding removes that step, and
removes a failure mode with it: source fetched separately can come from
a different ROCm than the installed .so, which surfaces as an undefined
symbol at link time or as an interface that silently differs from the
one the caller meant. Installed source matches the installed library by
construction.

It goes under share/<lib>/fortran/, not include/.

The .mod is compiler-specific and the .F90 is not, and everything under
include/fortran/ is partitioned by compiler. A source file placed there
is a level error with a concrete symptom: a config that enumerates
include/fortran/* to report the installed compilers lists the .F90 as
though it were one, and invites the user to select it.

share/ also leaves room if the Fortran side ever ships more than the
module, and keeps a Fortran source out of the development-headers
namespace that tooling walks.

This breaks with where the hand-written modules lived
(include/rocsparse/rocsparse.f90, include/hipblas/hipblas_module.f90).
Those were headers by convention that a user compiled into their own
build; the generated module is a source artifact of the library, and the
filenames change in the move anyway, so there is no drop-in path to
preserve.
Renumbered from RFC0014, which main now uses for the code coverage RFC;
0015 to 0018 are claimed by open RFC pull requests.

- roctx is no longer deferred: it ships with rocprofiler-sdk as
  roc::roctx_fortran (rocm-systems#12700)
- discovery goes through the <lib>-fortran package; find_package(<lib>)
  alone needs the rocm-cmake OPTIONAL hook, now in the backlog
- BUILD_FORTRAN_BINDINGS defaults to ${UNIX}; document the per-library
  overrides, FORTRAN_ARRAY_INTERFACES (replacing USE_ASSUMED_RANK),
  BUILD_FORTRAN_CLIENTS, the standalone fortran/ build, and the
  per-compiler directory and its override
- the shared CMake helper is not there yet: say so, and move it to the
  backlog with the ROCM_HAVE_FORTRAN / ROCM_LIBS_HAVE_FORTRAN split
- correct which hand-written modules were ever installed (three, not four)
- the hip* libraries default the bindings off on their CUDA backend
- hipfort is maintained beside the packaged bindings through 10.x and
  removed at 11.0; a binding holds for a major ROCm series
- add the population that builds one code on several ROCm versions,
  some older than 10.2
- list the call-site changes for users of a library's own module,
  including handle creation by reference, which still compiles
- link the migration guides (ROCm/hipfort#548) and list the 12
  implementation pull requests
- set CMAKE_Fortran_COMPILER to the amdflang TheRock builds in the
  generated subproject toolchain, so every binding (and rocSOLVER
  against rocBLAS) uses the compiler that ships
- install share/<lib>/fortran in the dev component; drop hipSOLVER's
  libhipsolver_fortran.so and EXPORT_FORTRAN_BINDINGS
- tests, dependency order and the flang runtime need nothing new
As asked in review: if the need for an F77-callable path arises, it is
prioritized separately, in its own RFC.
- add a summary of the decisions at the top
- P2: each library builds its own binding and TheRock packages them;
  drop the separate job that collected every fortran/ directory
- the CI hook is not implemented yet: it needs the generator repository
  to be public, which this RFC now settles
- add the size of the generated files as an open question, as raised
  in review
- drop fortran/examples/, which no project has, and describe the tests
  as each library's fortran/test/ rather than the hipfort suite
Co-authored-by: Saad Rahim (AMD) <44449863+saadrahim@users.noreply.github.com>
Rename the file to match the RFC0015 entry in the index.
10.2 is too close to its snap date to land the packaging. The bring-current
stage now covers 10.2 as well.
- curated metadata stays with the generator until it is public; the
  co-location PRs commit the generated .F90, its build, and its tests
- tests: coverage is uneven during the migration (rocBLAS and hipBLAS
  are exercised through clients/ for now, rocRAND/hipRAND tests are
  not installed yet)
- state what exists on develop and what the PRs add: ROCmFortran.cmake
  comes with the HIP binding, rocRAND/hipRAND's -fortran config is
  include()d by the C config today, hipBLAS has no libhipblas_fortran.so
- handles are type(c_ptr) in every generated module
- ASan and coverage: the projects build the bindings, TheRock turns them off
- rocSOLVER/hipSOLVER/hipBLAS keep gfortran for clients linking a host
  LAPACK; say what forcing amdflang implies
- hipSOLVER: roc::hipsolver_fortran moves to find_package(hipsolver-fortran)
- guard placement, client gating, cmake/toolchains/, hipFFTW packages,
  hipsparse_enums.f90, rocsparse_error, CODEOWNERS in rocm-systems,
  share/hip in the lib component
… list

- build on TheRock#3928 (FORTRAN_OPTIONAL / FORTRAN_REQUIRED, per-subproject
  CMAKE_Fortran_COMPILER) instead of describing a second mechanism
- ASAN/coverage: TheRock will pass BUILD_FORTRAN_BINDINGS=OFF; today it
  compiles Fortran uninstrumented
- TheRock's host LAPACK is OpenBLAS with C_LAPACK=ON, so amdflang is safe
  for the clients too
- hipSOLVER's .so goes away once rocm-libraries#12581 lands
- flang is built on Linux only; the gfortran pick is CMake 3.31's
- per-project CMake minimums range from 3.13 to 3.25.2
- hipfort_handles never existed; _types exists only for rocRAND and hipFFTW
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants