C++ 模块中的向量导致无用的错误文件数据 GCC 输出

Vector in C++ module causes useless Bad file data GCC output

TL;DR: GCC 11.2.0 (image f7ea55625e09) + C++20 + <vector>'s std::vector<anything> 导致无用的输出。如何获得我可以使用的东西?

编译适用于:

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.

对于 fatal(门),我只找到了这些参考资料(1, 2),从中我的情况看起来一切正常。


我已经使用新的 C++ 模块(C++20、GCC 11.2)尝试了各种简单的事情,这让我想知道我是否只是遇到编译器错误/缺少实现或没有得到非常简单的东西。

这是一个带有 vector<string> 的简单 C++ 代码,它使用基本标志编译得很好,并输出预期的内容:

# 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

在这里,我将矢量创建移动到一个新函数中,编译正常,工作正常。除了系统 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;
    }
}

在这里我将函数移动到单独的模块文件中的单独的导出函数。

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;
}

编译得很好,但是当添加到 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++ -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                                                                             

这似乎不是简单容器的问题,也不是单独 <vector>import 声明的问题:

// 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;
}

我试过(但没有实际效果):

看起来问题是由 <vector> header 引起的。任何想法我怎样才能撬开 GCC 给我一些比“naaah,做不到”更好的东西?至少我可以使用 -S (3k+ 行)生成程序集或使用 hexdump / objdump 来生成 gcm.cache/mymodule.gcm 并查看二进制文件,但我不确定要做什么寻找因为无用的输出。

编辑: 看起来像是架构问题?

编辑 2: 所以我在 this article 的帮助下重写了一点以使其与 Clang 12 (b978a93) 兼容,但事实并非如此1:1 有点像屠杀(string_view 注意),但也许我没有看到更广泛的图景或缺少某些东西。

我认为我不应该包括 <string_view>,因为那应该是自动包括的。否则,即使我编写了我的模块,我也可以从实现中每隔 #include 开始 copy-pasting,直到剩下 none,这样我就可以确保文件顺序(然后又是什么模块的点)。

// 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

所以这个问题似乎是 GCC 特有的,并且很可能是一个由架构切换判断的错误(hardcoding/wrong GCC 中的代码分支?)。也许值得在 >11.2.0.

之后重访

我正在使用 C++20 模块 (gcc 11.2.0) 编写共享库,并且对于 std::vector 自定义类型有相同的“错误文件数据”错误。就我而言,正如 已经提到的,大多数容器都会出现此错误:地图、列表等

根据您的参考,我找到了 this issue,现在有了一个临时解决方案,只需要在模块中添加这一行。

namespace std _GLIBCXX_VISIBILITY(default){}

这在我的库中与其他容器一起工作。我一直在使用编译器选项寻找合适的解决方案,但没有成功。

文件/命令

// 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。我不能评论,所以张贴为答案,希望它能提出来。