Skip to content

NVHPC/PGI builds generate no header dependencies (get_dependency_gen_args not implemented) #16160

Description

@stoiver

Describe the bug

PGICompiler (used by NvidiaHPC_CCompiler, NvidiaHPC_FortranCompiler, PGICCompiler, …)
does not implement get_dependency_gen_args(), so it inherits the base class stub:

# mesonbuild/compilers/compilers.py
def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
    return []

Meson still emits deps = gcc and a depfile into the ninja rule, and sets DEPFILE
on every build statement — but the compile line never receives -MD/-MF, so no depfile
is ever written. Ninja waits for a file that never appears and records zero
dependencies for every object
. A changed header therefore never triggers a rebuild.

This is the same defect as #11969 (CUDA), fixed by #12665, in a different compiler class.

This is not just a stale-build annoyance. Incremental builds silently produce binaries
whose translation units disagree about struct layout. In our project a struct member in
a shared header shifted, only some objects were rebuilt, and two members aliased: the
program printed a nonsense value and hung, with no compile error, no warning and no
crash. It took a long time to attribute to the build system rather than to our own code.

To Reproduce

Any meson project built with CC=nvc:

$ meson setup build && ninja -C build
$ ninja -C build -t deps | grep -cE '^\S+\.o: #deps [1-9]'
0                                  # no object has any recorded dependency
$ find build -name '*.d' | wc -l
0                                  # no depfile was ever produced
$ touch some_header_used_everywhere.h
$ ninja -C build -n | grep -c 'Compiling'
0                                  # nothing rebuilds

The generated rule declares depfile support that the command line never satisfies:

rule c_COMPILER
 command = .../compilers/bin/nvc $ARGS -o $out -c $in
 deps = gcc
 depfile = $DEPFILE_UNQUOTED

Expected behavior

Touching a header rebuilds the objects that include it, as with GCC and Clang.

Fix

nvc supports the GCC-style flags, so this is the same shape of fix as #12665.

Important: -MQ must not be used. nvc accepts -MQ but ignores its argument and
writes the literal string mttarget as the depfile target, which ninja then silently
discards — reintroducing the original bug in a form that looks fixed. Verified on
nvc 26.3:

$ nvc -MD -MQ 'ZZZ_unique_target' -MF q.d -c a.c -o q.o && head -1 q.d
mttarget : a.c \

$ nvc -MD -MT 'ZZZ_unique_target' -MF t.d -c a.c -o q.o && head -1 t.d
ZZZ_unique_target : a.c \

$ nvc -MD -MT 'sub/dir/a.c.o' -MF t.d -c a.c -o q.o && head -1 t.d
sub/dir/a.c.o : a.c \

So PGICompiler needs ['-MD', '-MT', outtarget, '-MF', outfile].

Because -MT does not Make-escape the target, this also needs the escaping that #12665
added for CUDA. That escaping is currently gated on langname == 'cuda' /
compiler.get_language() == 'cuda' in ninjabackend.py. Rather than add a second
special case, the attached patch introduces a compiler predicate:

def needs_escaped_depfile_target(self) -> bool:
    """Whether the depfile target must be Make-escaped by the backend."""
    return False

returning True for CUDA and PGI, and switches both ninjabackend.py gates to it. The
ninja variable CUDA_ESCAPED_TARGET is renamed ESCAPED_DEPFILE_TARGET since it is no
longer CUDA-specific. No behaviour change for CUDA.

Diffstat:

 mesonbuild/backend/ninjabackend.py | 15 +++++++++------
 mesonbuild/compilers/compilers.py  |  8 ++++++++
 mesonbuild/compilers/cuda.py       |  5 +++++
 mesonbuild/compilers/mixins/pgi.py | 10 ++++++++++
 4 files changed, 32 insertions(+), 6 deletions(-)

Verification

With the patch applied, on a real NVHPC project (~34 objects, C + Cython-generated C,
-mp=gpu):

$ grep -A2 '^rule c_COMPILER' build/build.ninja
 command = .../nvc $ARGS -MD -MT $ESCAPED_DEPFILE_TARGET -MF $DEPFILE -o $out -c $in

$ ninja -C build -t deps | grep -cE '^\S+\.o: #deps [1-9]'
34                                 # was 0
$ ninja -C build -t deps | grep -c 'sw_domain.h'
13
$ touch src/sw_domain.h && ninja -C build -n | grep -c 'Compiling C object'
13                                 # was 0

The 13 rebuilt objects are exactly those including that header, across both extension
modules. The project's test suites pass unchanged with the patch applied.

Note for anyone checking this: the fixed build leaves no *.d files on disk — ninja
folds each depfile into .ninja_deps and deletes it. Check ninja -t deps, not the
filesystem.

Open questions for maintainers

  1. Version gating. Add support for dumping dependent headers in nvcc #12665 gated CUDA on >= 10.2. I have only nvc 26.3 available and
    do not know the earliest NVHPC/PGI release supporting -MD/-MT. If gating is wanted,
    someone with older toolchains should pick the bound.
  2. Classic PGI vs NVHPC. PGICompiler backs both PGICCompiler (pgcc) and
    NvidiaHPC_*. I verified NVHPC only. If legacy pgcc differs, the override may belong
    on the NVHPC classes rather than the shared mixin.
  3. Fortran. The mixin is shared with the Fortran compilers, which I have not tested.

system parameters

  • Is this a cross build or just a plain native build (for the same computer)? — native
  • what operating system — Linux (Ubuntu, kernel 7.0.0)
  • what Python version are you using — 3.14.5
  • what meson --version — 1.11.1 (bug also present on master at time of writing)
  • what ninja --version if it's a Ninja build — 1.13.2
  • compiler — NVIDIA HPC SDK nvc 26.3-0, x86-64, -tp znver5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions