https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126786
Bug ID: 126786
Summary: [libstdc++] Module fallback installs empty interface
files but the manifest lists them
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: libstdc++
Assignee: unassigned at gcc dot gnu.org
Reporter: hello at bjornpagen dot com
Target Milestone: ---
Definitions
A module interface file contains a module declaration.
The module manifest is libstdc++.modules.json. The manifest tells tools where
GCC installed each module interface file.
The fallback lets the libstdc++ build continue after module compilation fails.
Description
The libstdc++ build generates std.cc and std.compat.cc. The build compiles
these files as module interfaces.
The fallback starts when module compilation fails. The fallback replaces the
interface file with an empty translation unit.
The Makefile uses this command:
echo > $<.tmp && mv $<.tmp $<
The build then compiles the empty file. This action lets the libstdc++ build
continue.
The Makefile also installs the same source files:
toolexeclib_DATA = libstdc++.modules.json
includebitsdir = $(gxx_include_dir)/bits
includebits_DATA = std.cc std.compat.cc
The installation includes the empty files. The installation also includes the
module manifest.
The manifest still lists std.cc and std.compat.cc as module interface files.
Consumer tools read the manifest and try to compile the empty files.
This commit added the fallback:
https://gcc.gnu.org/g:9d02b118ee10506f90c7cf0e439108f48d370fc1
Observed result
A Homebrew GCC 16.1.0 installation on Apple Silicon contained these file sizes:
1 .../include/c++/16/bits/std.cc
1 .../include/c++/16/bits/std.compat.cc
331 .../libstdc++.modules.json
The manifest contained these entries:
{
"logical-name": "std",
"source-path": "../../../include/c++/16/bits/std.cc",
"is-std-library": true
},
{
"logical-name": "std.compat",
"source-path": "../../../include/c++/16/bits/std.compat.cc",
"is-std-library": true
}
CMake read the manifest. CMake then rejected both files:
CMake Error: Output .../std.cc.o is of type `CXX_MODULES`
but does not provide a module interface unit or partition
CMake Error: Output .../std.compat.cc.o is of type `CXX_MODULES`
but does not provide a module interface unit or partition
The Homebrew report contains the complete downstream reproducer:
https://github.com/Homebrew/homebrew-core/issues/289142
The GCC Darwin branch has a second report of the same installed-file problem:
https://github.com/iains/gcc-16-branch/issues/5
Trigger in the observed build
The observed Darwin build could not compile std.cc. A macOS SDK header used the
undefined type rsize_t.
The build produced this output:
error: 'rsize_t' has not been declared
Cannot compile std module
Module initialization function will be missing
PR126782 tracks that separate compiler and SDK problem:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126782
This report does not depend on the rsize_t problem. Any module compilation
failure can start the fallback.
The fallback can then create an inconsistent installation on any target.
Steps to reproduce
1. Build GCC 16 on a configuration that cannot compile std.cc.
2. Let the fallback complete the libstdc++ build.
3. Install the completed GCC build.
4. Find the module manifest.
Use this command:
g++ -print-file-name=libstdc++.modules.json
5. Check the files that the manifest lists.
Use commands similar to these commands:
wc -c \
<install-prefix>/include/c++/16/bits/std.cc \
<install-prefix>/include/c++/16/bits/std.compat.cc \
"$(g++ -print-file-name=libstdc++.modules.json)"
6. Configure a CMake project that uses CMAKE_CXX_MODULE_STD.
7. Compile a source file that contains import std;.
Actual result
The fallback lets the libstdc++ build complete.
GCC installs one-byte std.cc and std.compat.cc files. GCC also installs a
manifest that lists those files as module interfaces.
Consumer tools trust the manifest. The consumer tools fail because the files
contain no module declarations.
Expected result
GCC must not list an unavailable module interface in the installed manifest.
The fallback can continue to provide an empty object file. The fallback must
not replace an interface file that GCC will install.
The manifest and the installed interface files must describe the same module
availability.
Possible design
The fallback can compile a separate empty source file. The fallback does not
need to replace std.cc or std.compat.cc.
The build can record the result of each module compilation. The manifest
generator can use those results.
The manifest must omit a module when the build cannot provide its interface.
The libstdc++ maintainers can decide whether GCC should still install the
original source file.
The build can also print a clear summary. The summary can state which
standard-library modules are unavailable.
Related reports
PR124268 added the module initialization objects and the fallback.
PR119266 reports incorrect paths in libstdc++.modules.json. PR119266 does not
report empty interface files.
PR125460 reports another condition that can prevent module interface
compilation.
PR126782 reports the Darwin rsize_t failure that started the observed fallback.
Homebrew issue:
https://github.com/Homebrew/homebrew-core/issues/289142
GCC Darwin branch issue:
https://github.com/iains/gcc-16-branch/issues/5
Patch status
This report does not include a patch.
The report first asks the libstdc++ maintainers to select the required fallback
and installation behavior.