Issue
TL;DR: rel="nofollow noreferrer">GCC 11.2.0 (image f7ea55625e09
) + C++20 + <vector>
's std::vector<anything>
cause useless output. How to get out something I can work with?
Compilation works in:
- module cache
- single file
- separate module file
In module imported at main.cpp:4:1: import mymodule; mymodule: error: failed to read compiled module: Bad file data eh??????? mymodule: note: compiled module file is 'gcm.cache/mymodule.gcm' exists, 124 912 Bytes mymodule: fatal error: returning to the gate for a mechanical issue ???????? compilation terminated.
For the fatal
(gate) I found only these references (1, 2), from which everything looks okay for my case.
I've tried various simple things with the new C++ modules (C++20, GCC 11.2) and it makes me wonder whether I'm just encountering a compiler bug / missing implementation or not getting something very simple.
Here is a simple C++ code with vector<string>
, it compiles just fine with basic flags and outputs what's expected:
# create module cache for system headers
for item in iostream string vector
do
g++ -fmodules-ts -std=c++20 -x c++-system-header $item
done
g++ -Wall -Wextra -Wpedantic -std=c++20 -fmodules-ts main.cpp
// main.cpp
import <iostream>;
import <string>;
import <vector>;
int main() {
std::vector<std::string> vec = std::vector<std::string>{};
vec.push_back("Hello");
vec.push_back("world");
for (auto& item : vec) {
std::cout << item << std::endl;
}
}
$ ./a.out
Hello
world
Here I move the vector creation into a new function, compiles fine, works fine. Still no separate module except for the system headers.
// main.cpp
import <iostream>;
import <string>;
import <vector>;
std::vector<std::string> create() {
std::vector<std::string> vec = std::vector<std::string>{};
vec.push_back("Hello");
vec.push_back("world");
return vec;
}
int main() {
std::vector<std::string> vec = create();
for (auto& item : vec) {
std::cout << item << std::endl;
}
}
And here I move the function to a separate, exported function in a separate module file.
g++ -Wall -Wextra -Wpedantic -std=c++20 -fmodules-ts -c mymodule.cpp
// mymodule.cpp
export module mymodule;
import <string>;
import <vector>;
export std::vector<std::string> create() {
std::vector<std::string> vec = std::vector<std::string>{};
vec.push_back("Hello");
vec.push_back("world");
return vec;
}
which compiles just fine, but when adding to the main.cpp
,
import <iostream>;
import <string>;
import <vector>;
import mymodule;
int main() {
std::vector<std::string> vec = create();
for (auto& item : vec) {
std::cout << item << std::endl;
}
}
I get only this:
g++ -Wall -Wextra -Wpedantic -std=c++20 -fmodules-ts mymodule.cpp main.cpp
In module imported at main.cpp:4:1: import mymodule; mymodule: error: failed to read compiled module: Bad file data eh??????? mymodule: note: compiled module file is 'gcm.cache/mymodule.gcm' exists, 124 912 Bytes mymodule: fatal error: returning to the gate for a mechanical issue ???????? compilation terminated.
# file gcm.cache/mymodule.gcm
ELF 32-bit LSB no file type, no machine, version 1 (SYSV)
# file gcm.cache/usr/local/include/c++/11.2.0/iostream.gcm
ELF 32-bit LSB no file type, no machine, version 1 (SYSV)
# file a.out
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, not stripped
And it doesn't seem to be a problem with simple containers nor with the import
declarations of the <vector>
alone:
// mymodule.cpp
export module mymodule;
import <string>;
import <vector>;
export std::string create() {
return "world";
}
// main.cpp
import <iostream>;
import <string>;
import <vector>;
import mymodule;
int main() {
std::string vec = create();
std::cout << vec << std::endl;
}
And I've tried playing with (and with no real effect):
.cpp
vs.mpp
extensions, though it shouldn't matter- clearing the cache before each compilation (ref)
global module fragment (7)
placement i.e.module; [stuff]; export module mymodule;
- compiling separately (
-c mymodule.cpp
+-c main.cpp
) to link manually (fails the same way onmain.cpp
) - (re)moving
export
from the function - not calling the function, just importing (
import mymodule;
to trigger compilation) - switching from
std::vector<std::string>
tostd::vector<int>
to see whether the template's argument list causes the problem - switching from
std::vector<std::string>
tostd::pair<int, int>
and then tostd::pair<std::string, std::string>
(with<utility>
header module cache) to see whether just<vector>
is broken for me
And it looks like <vector>
header is causing the problem. Any ideas how can I pry open GCC to give me something better than "naaah, can't do"? At the least I can generate assembly with -S
(3k+ lines) or use hexdump
/ objdump
for gcm.cache/mymodule.gcm
and look at the binary, but I'm not sure what to look for because of the useless output.
Edit: It looks like a problem with the architectures perhaps?
- using
-m64
does nothing for the module cache, remains 32bit - using
-m32
(apk install -y g++-multilib
on 64bit) returns the same output
Edit 2: So I rewrote it a bit to make it compatible with Clang 12 (b978a93
) with a help of this article but it's not 1:1 and is rather kind of butchering (string_view
note), but maybe I'm not seeing the broader picture or something is missing.
I don't think I should be including <string_view>
though as that should have been included automatically. Otherwise even if I write my module, I can just start copy-pasting every #include
from the implementation until there's none left so I can ensure the file order (then again what'd be the module's point).
// mymodule.cpp
module;
// no proper "import" available yet, so switching to the old includes
#include <string>
#include <vector>
#include <iostream>
export module mymodule;
export std::vector<std::string> create() {
std::vector<std::string> vec = std::vector<std::string>{};
vec.push_back("Hello");
vec.push_back("world");
return vec;
}
// need to wrap printing for a string_view for some reason
export void printme(std::string &item) {
std::cout << item << std::endl;
}
// main.cpp
// includes needed for "auto" and usage of those types
// and were needed also for print(create()) call
// so something seems broken over here
#include <vector>
#include <string>
import mymodule;
int main() {
auto vec = create();
for (std::string item : vec) {
// string_view:142:2: note: declaration of
// 'basic_string_view<_CharT, _Traits>' does not match
// std::cout << item << std::endl;
printme(item);
}
}
clang++ -std=c++20 -c mymodule.cpp -Xclang -emit-module-interface -fimplicit-modules -fimplicit-module-maps -o mymodule.pcm
clang++ -std=c++20 -fprebuilt-module-path=. -fimplicit-modules -fimplicit-module-maps mymodule.cpp main.cpp
So the issue seems to be GCC specific and most likely is a bug judging by the architecture switching (hardcoding/wrong code branch in GCC?). Maybe worth revisiting after >11.2.0
.
Solution
I'm writing a shared library using C++20 modules (gcc 11.2.0) and have the same "Bad file data" error for std::vector
with custom type. In my case, as already mentioned by @balázs-Árva this error occurs for most containers: maps, lists, etc.
Following your references I found this issue and now have a temporary solution with just this line in module.
namespace std _GLIBCXX_VISIBILITY(default){}
This works in my library with other containers. I've looked for a proper solution using compiler options but haven't any success.
Files / commands
// mymodule.cpp
export module mymodule;
import <string>;
import <vector>;
namespace std _GLIBCXX_VISIBILITY(default){}
export std::vector<std::string> create() {
std::vector<std::string> vec = std::vector<std::string>{};
vec.push_back("Hello");
vec.push_back("world");
return vec;
}
// main.cpp
import <iostream>;
import <string>;
import <vector>;
import mymodule;
int main() {
std::vector<std::string> vec = create();
for (auto& item : vec) {
std::cout << item << std::endl;
}
}
g++ -fmodules-ts -std=c++20 -x c++-system-header iostream
g++ -fmodules-ts -std=c++20 -x c++-system-header string
g++ -fmodules-ts -std=c++20 -x c++-system-header vector
g++ -fmodules-ts -std=c++20 mymodule.cpp main.cpp
$ ./a.out
Hello
world
P.S. I can't comment, so posted it as answer, hope it will bring up them.
Answered By - Serg Answer Checked By - Candace Johnson (WPSolving Volunteer)