use parquet brings the whole library into scope and is the right answer for most programs. It is
also the largest: a project that imports it compiles 66 of this library's Fortran files.
Every layer underneath is importable on its own, and several of them cost a great deal less. This page says what each entry module gives you, what it costs, and — the part that is easy to get wrong — what "costs less" does and does not mean.
No import makes the package Arrow-free. link is a package-level key in fpm.toml, and fpm
cannot prune a C++ translation unit, so a project that depends on parquet-fortran compiles
src/parquet_wrapper.cpp and links -larrow -larrow_compute -lparquet whichever module it
imports — including use parquet_temporal. If Arrow's development headers are not installed, the
build fails at arrow/api.h regardless of what you wrote in your use statement.
What the tiers below labelled Arrow-free do guarantee is narrower and is about the Fortran
graph: no module fpm compiles for that import names parquet_bindings, so none of your Fortran
code path crosses the C++ boundary. That is what keeps those modules fast to compile, independently
testable, and free of the reader/writer machinery — and it is enforced, not merely intended.
tools/check_source_conventions.py carries one check per Arrow-free tier and fails the build if
that tier's graph — submodules included — ever reaches parquet_bindings, and
tools/check_argsort_standalone.sh proves it the other way round, compiling the argsort tier with
a bare compiler and no Arrow on the system at all. A check per tier rather than one for the group
is deliberate: several of these modules sit in each other's graphs, so a single check would go on
passing for a tier that had stopped being reachable from it.
If you need a genuinely Arrow-free package, this is not it, and no use statement will make it
one.
Sizes are the number of this library's Fortran source files fpm compiles for a project whose only
import is that module, measured with tools/check_module_footprints.sh and recorded in
tools/module_footprints.txt. src/parquet_wrapper.cpp is excluded from the count, being present
in every one of them.
| Import | Files | Fortran graph reaches Arrow? | What it gives you |
|---|---|---|---|
parquet_version |
2 | no | parquet_get_version: which parquet-fortran this is |
parquet_temporal |
1 | no | parquet_date, parquet_time, parquet_timestamp and their unit constants |
parquet_strings |
2 | no | parquet_string_column / parquet_string: packed, null-aware string storage |
parquet_random |
3 | no | counter-based random numbers and the four distributions |
parquet_argsort |
4 | no | pf_argsort over the six intrinsic types, plus pf_sort_threads |
parquet_sampling |
8 | no | permutations, subsets, resampling and weighted draws |
parquet_columns |
10 | no | parquet_column: a typed, null-aware column container |
parquet_sorting |
21 | no | the whole sorting API, every element type, including pf_sort_keys |
parquet_settings |
3 | yes | the process-global knobs, and parquet_get_arrow_version |
parquet_io |
44 | yes | reading and writing Parquet files, and nothing else |
parquet_tables |
62 | yes | the parquet_table container |
parquet |
66 | yes | everything above, through one use |
Four rows deserve a note.
parquet_version is the only route to parquet_get_version, apart from use parquet. No other
entry module re-exports it, deliberately: a version string is fixed at compile time and nothing in
the library reads it, so making every tier carry it would grow every tier's graph for a name none of
them needs. A program built on one of the Arrow-free modules that wants to report its library
version writes a second use parquet_version line — two files, no C++ boundary. The Arrow and
Parquet C++ versions are a different question with a different answer: parquet_get_arrow_version,
in parquet_settings (and so in parquet_io, parquet_tables and parquet), because reading them
means calling into the C++ half.
parquet_tables costs all but four files of parquet, so importing it instead of the facade
buys little beyond a narrower namespace. The table layer sits on the reader, the column container
and the sorting engine, which between them are almost the whole library; the four it leaves behind
are the two facades themselves, parquet_sampling and parquet_version.
parquet_io is the one real saving on the Arrow side, at 44 files against 66: it drops the
entire table layer, the sampling module, parquet_version and the outer facade. Reach for it when
your program opens files, moves columns in and out, and never builds a parquet_table.
It does not drop parquet_random, and the three files it keeps that belong to none of the
reader/writer machinery are that generator's: parquet_open_reader(..., sample_fraction=) picks its
rows with this library's own generator, so the reader genuinely depends on it. The three are a
closed set — parquet_random and the two leaves it reads, parquet_expkey and parquet_ziggurat,
which import nothing but iso_fortran_env — so the graph cannot grow further through them.
parquet_settings is the cheapest import that reaches Arrow, at three files, and that is the
point of listing it: what naming it costs you is not compile time, it is the C++ boundary. Those
three are the knob state, this module, and parquet_bindings — which it imports because it is the
module that mirrors verbosity, message_stream and the four performance knobs across to the C++
half. Everything below explains why the Arrow-free tiers cannot import it, and re-export the knobs
they read instead.
fpm prunes at module granularity, and a submodule is never pruned separately from the module it
belongs to. So each row above is a union of whole modules, not of the procedures you actually
call. parquet_sorting costs 21 files whether you use one specific or all of them, because its
seven submodules come as a set.
That is also why the argsort tier exists at all. parquet_sampling needs exactly one sorting
specific — pf_argsort over a real64 array, for pf_weighted_permutation — and taking it from
parquet_sorting cost the whole 21-file graph, Arrow included. Splitting the intrinsic-type
pf_argsort and its engine into parquet_argsort took use parquet_sampling from 24 files to 8
and off the C++ boundary entirely.
The practical consequence for your own code: one added use line can multiply what a consumer
compiles. If you contribute to this library, tools/check_module_footprints.sh is what notices.
A process-global setting is normally reached through parquet_settings — but that module owns the
C++ boundary, so importing it would pull the Arrow stack into an otherwise Arrow-free build. Each
entry module therefore re-exports, getter and setter both, every knob its own code reads, so a
program that imports one module for one capability can configure that capability without importing
anything else.
| Import | Settings it re-exports |
|---|---|
parquet_version |
verbosity and message_stream — it can print, see below |
parquet_temporal |
none — it reads none |
parquet_random |
none — it reads none; the thread rule lives in parquet_sampling |
parquet_columns |
none — it reads none |
parquet_strings |
string_threads, plus verbosity and message_stream |
parquet_sampling |
random_threads, random_parallel_min_elements |
parquet_argsort |
sort_threads, sort_radix_path, sort_counting_path, sort_counting_bucket_limit, plus verbosity and message_stream |
parquet_sorting |
the same six as parquet_argsort |
parquet_settings, and so parquet_io, parquet_tables, parquet |
all of them |
The output pair (verbosity, message_stream) appears wherever a module can print something: a
user who imports parquet_argsort alone must still be able to silence its thread-clamp warning.
parquet_version is in that table for exactly that reason, and it is the one row where the rule is
easy to miss: parquet_get_version prints a remark on a development build, so a program whose only
import is use parquet_version has to be able to quiet it. Two files, still no C++ boundary.
parquet_get_version itself is deliberately outside this rule and is re-exported by none of
these modules — it is not a setting, nothing in the library reads it, and it has its own entry
module. See the note under The entry modules.
parquet_settings remains available and is what use parquet gives you; naming it directly is
only a problem for a build that is deliberately staying clear of Arrow. See
Settings for what every knob does, and note in particular that six of them reach
the C++ half when a reader or writer is opened rather than when you set them — which is exactly
what makes this per-module re-export possible.
use parquet. One import, everything reachable, no decisions.parquet_table: use parquet_io.parquet_sorting, parquet_argsort, parquet_sampling,
parquet_random, parquet_columns, parquet_strings, parquet_temporal. Remember the caveat at
the top: your package still links Arrow.use parquet_version, alongside whatever else you
import. parquet_get_version is there and, apart from use parquet, nowhere else.use parquet_core. It is internal, undocumented and may change in any release;
parquet_io is its supported face.A narrow import is an ordinary program — there is nothing to configure and no facade to go through.
This one compiles four of this library's Fortran files and reaches no reader, no writer and no
parquet_table:
program narrow_import
use parquet_argsort
use iso_fortran_env, only: int32
implicit none
integer(int32) :: v(5) = [30, 10, 50, 20, 40]
integer(int32), allocatable :: perm(:)
call pf_argsort(v, perm)
print *, perm ! 2 4 1 5 3
end program narrow_import
Swap parquet_argsort for any other row of the table and the shape is the same.
Every module in the table above is public API and is covered by the library's versioning promise. A
module advertised as an entry point makes its own surface a promise separate from use parquet, and
parquet_columns is the sharpest case: a change to parquet_column's bindings is a public API
change even when nothing reachable through use parquet moves.
parquet_core, parquet_bindings, parquet_settings_base, parquet_expkey, parquet_ziggurat,
parquet_sorting_oracle and every *_engine/*_kernel submodule are not covered. They are
accessible because Fortran has no package scope, not because they are meant to be imported.
One module is importable and promised but deliberately absent from the table: parquet_maml_base,
which holds the MAML schemas bundled with this library and the shared parquet_maml_file type. It is
left out because you would reach for it for what it holds rather than for what it costs to compile
— and because most of its public names are this library's own embedded fixtures rather than API,
which is why use parquet imports three types from it with an only: list instead of re-exporting
it whole. See Embedding your own MAML schemas.
The table above is the authority on what costs what. It is the list
tools/check_module_footprints.sh measures and the list this promise covers; anywhere else in the
repository that appears to enumerate entry modules is describing it, not defining it. A module added
to that table needs a section in tools/module_footprints.txt and, if its Fortran graph is meant to
stay clear of Arrow, its own check in tools/check_source_conventions.py — both of which fail
loudly when they are missing, which is how the list stays one list.