Skip to content

pkg-config: Fix Install Directories, Add C++17 & MPI Flags - #1942

Open
ax3l wants to merge 3 commits into
openPMD:devfrom
ax3l:topic-pkgconfig-installdirs
Open

ax3l wants to merge 3 commits into
openPMD:devfrom
ax3l:topic-pkgconfig-installdirs

Conversation

@ax3l

@ax3l ax3l commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

The generated openPMD.pc did not follow the actual install layout and lacked the public usage requirements of openPMD.

Install directories

  • use openPMD_INSTALL_{BIN,LIB,INCLUDE}DIR, keep absolute dirs (e.g., Nix) as they are
  • substitute prefix at install time: honors cmake --install --prefix (also relative) and DESTDIR
  • exec_prefix=${prefix} (was ${prefix}/bin), add bindir
  • derive openPMD_INSTALL_CMAKEDIR and the default openPMD_INSTALL_PYTHONDIR from openPMD_INSTALL_LIBDIR

Public usage requirements

  • MPI builds: MPI include dirs, definitions and compile options in Cflags; MPI link flags and libraries in Libs (public headers include mpi.h and call MPI functions)
  • new variable cxxstd with the C++ standard flag: pkg-config --variable=cxxstd openPMD (e.g., -std=c++17)
  • escape paths and arguments (spaces, #, quotes)
Details: behavior changes, design, testing, known limitations

Behavior changes (changelog):

  • pkg-config --variable=exec_prefix openPMD now returns the prefix (GNU/pkg-config convention); use the new bindir for the CLI tools.
  • New cxxstd variable. The flag is intentionally not in Cflags: it would override newer standards requested by consumers, e.g., CMake's pkg_check_modules(IMPORTED_TARGET) puts it after the target's own -std=c++20, and it breaks C sources.

Bugs fixed (reproduced before the change):

  • -DopenPMD_INSTALL_LIBDIR=lib64 -DopenPMD_INSTALL_INCLUDEDIR=include/openpmd installed there, but the .pc pointed to lib and include.
  • Absolute CMAKE_INSTALL_LIBDIR produced libdir=${prefix}//abs/lib.
  • On Windows, GNUInstallDirs is not included, so CMAKE_INSTALL_LIBDIR is typically empty and libdir=${prefix}/ resulted (code inspection, not tested on Windows). Same for the default Python install dir (/site-packages).
  • With openPMD_INSTALL_LIBDIR set, the CMake package config still went to ${CMAKE_INSTALL_LIBDIR}/cmake/openPMD.
  • MPI builds: compiling against the .pc flags alone failed with mpi.h: No such file or directory.

Design:

  • The prefix placeholder is replaced via string(REPLACE) in install(CODE) rather than a second configure_file, so dependency paths are not rescanned for @VAR@. The install code sets cmake_policy(VERSION 3.22), since install scripts run with policies unset (CMP0053 would expand @VAR@).
  • Absolute prefix instead of a relocatable ${pcfiledir}-relative one: the latter breaks when only the .pc file is symlinked elsewhere. Package managers (conda, Spack) rewrite absolute prefixes when relocating.
  • Paths are backslash-escaped rather than quoted: pkg-config's define-prefix escapes the guessed prefix itself, which breaks inside quotes.
  • MPI flags come from the FindMPI result variables: the MPI::MPI_<lang> target properties contain generator expressions ($<HOST_LINK:SHELL:...>, $<COMPILE_LANG_AND_ID:...>). Shared MPI libraries are written as -L<dir> -l<name>, since FindPkgConfig places plain paths before the object files, which fails to link with --as-needed. The MPICH_SKIP_MPICXX/OMPI_SKIP_MPICXX/_MPICC_H defines are only for building openPMD itself and are filtered, as for CMake consumers.
  • The MSVC PUBLIC options (/bigobj, /Zc:__cplusplus) are not added: public headers do not use __cplusplus.

Tested (Linux, real build + install; pkgconf 1.8.1 and pkg-config 0.29.2, each with and without define-prefix; pkgconf --validate ok):

  • Layouts: default dirs, --prefix <other>, relative --prefix from another directory, trailing slash, prefix with a space and #, DESTDIR, lib64 + custom includedir, absolute lib/include dirs, unchanged re-install is Up-to-date. A consumer compiled, linked and ran using only the .pc flags.
  • MPI (MPICH), shared and static: a consumer calling MPI and openPMD::Series(..., MPI_COMM_WORLD) compiled with plain g++ (not mpicxx), -std=c++14 followed by cxxstd, linked and ran on 2 ranks. Controls fail as expected: previous flags (mpi.h not found), -std=c++14 without cxxstd.
  • CMake pkg_check_modules(IMPORTED_TARGET) consumer with CXX_STANDARD 20 and -Wl,--as-needed: compiles as C++20 only, links and runs on 2 ranks; control with plain MPI library paths fails with undefined reference to symbol 'MPI_Init'.
  • openPMD_MPI_LINK_C=ON and --static: no duplicate MPI flags. Unit tests for the escape/link helpers (including -framework X kept as is).

Known limitations, not addressed here:

  • If openPMD-api is built with an MPI compiler wrapper as C++ compiler (mpicxx, Cray CC), FindMPI reports no MPI flags; consumers need the same wrapper (documented).
  • --define-prefix (default in e.g. conda-forge's pkg-config) guesses the prefix as two levels above the .pc file, which is wrong for multiarch libdirs such as lib/x86_64-linux-gnu. This affects every package (verified with Debian's zlib.pc).
  • MPI link flags can contain -Wl,-rpath,<MPI prefix>/lib, as with mpicxx and CMake's MPI::MPI_CXX: another libopenPMD in that prefix can shadow the intended one. Seen in testing with a conda env shipping openPMD-api 0.17.1 (also via conda's LDFLAGS).
  • With special characters in the prefix, --variable=prefix/libdir/... show the escaping backslashes (as with define-prefix). ${ and $$ in paths are not escaped. pkgconf 1.8.1 does not re-escape spaces on output for arguments other than -I/-L.
  • Pre-existing in static builds: Libs.private does not list the libraries of imported targets (e.g., ADIOS2, HDF5) themselves, and FindHDF5's debug/optimized keywords can leak into it.

🤖 Generated with Claude Code

ax3l and others added 2 commits September 14, 2026 21:24
The generated `openPMD.pc` ignored `openPMD_INSTALL_*DIR` and the
actual install prefix. Now it follows the real install layout:

- use `openPMD_INSTALL_{BIN,LIB,INCLUDE}DIR`, keep absolute dirs
- substitute `prefix` at install time (`cmake --install --prefix`)
- `exec_prefix=${prefix}` (was `${prefix}/bin`), add `bindir`
- derive `openPMD_INSTALL_CMAKEDIR` and the default
  `openPMD_INSTALL_PYTHONDIR` from `openPMD_INSTALL_LIBDIR`

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`openPMD` requires C++17 and links MPI publicly (public headers include
`mpi.h` and call MPI functions), but `openPMD.pc` provided neither.

- `Cflags`: add the C++17 flag and the MPI compile options, definitions
  and include directories
- `Libs`: add the MPI link flags and libraries
- escape arguments in `Libs`/`Cflags` and quote the directory
  variables, so paths with spaces (e.g., MS-MPI) work
- docs: mention the flags and the `-std` flag order

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ax3l ax3l changed the title CMake: Fix pkg-config Install Directories pkg-config: Fix Install Directories, Add C++17 & MPI Flags Sep 15, 2026
Review fixes for the generated `openPMD.pc`:

- C++ standard flag: move from `Cflags` to the new `cxxstd` variable,
  since it overrode newer standards of consumers (e.g., CMake's
  `pkg_check_modules(IMPORTED_TARGET)`) and broke C sources
- escape the install prefix and directories instead of quoting them,
  which broke prefixes with spaces under pkg-config's define-prefix
- absolute `prefix` for a relative `cmake --install --prefix`
- MPI libraries as `-L`/`-l`: CMake's FindPkgConfig places plain paths
  before the object files, which fails to link with `--as-needed`
- do not escape multi-argument link items, e.g., `-framework X`
- drop openPMD's own MPI C++ binding skip defines from `Cflags`
- no duplicate MPI flags with `--static` or `openPMD_MPI_LINK_C`
- docs: `cxxstd` variable, builds with MPI compiler wrappers

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant