作者:流云清动_438 | 来源:互联网 | 2022-12-24 21:34
我的团队最近从2015英特尔编译器(并行工作室)升级到2018年版本,我们遇到了一个链接器问题,每个人都在撕扯他们的头发.
我有以下类(为了简洁而适度编辑)来处理子进程的包装和相关的文件描述符以便与它们交谈:
class SubprocWrapper
{
public:
static const int PASSTHRU_FD = 0;
static const int MAKE_PIPE = -1;
typedef std::map EnvMapType;
static EnvMapType getMyEnv();
SubprocWrapper(
int stdin_fd_req,
int stdout_fd_req,
int stderr_fd_req,
const std::string & execPath,
const std::vector & args,
const std::set & dont_close_fds,
const EnvMapType * env = 0);
};
然后我用以下代码调用它:
std::string runCmd = "/run/some/file.bin";
std::vector args(2);
args[0] = "-c";
args[1] = runCmd;
SubprocWrapper::EnvMapType env_vars = SubprocWrapper::getMyEnv();
SubprocWrapper subproc(
SubprocWrapper::PASSTHRU_FD,
SubprocWrapper::PASSTHRU_FD,
SubprocWrapper::PASSTHRU_FD,
std::string("/bin/sh"),
args,
std::set(), //dont_close_fds = null means "close all fds"
&env_vars
);
在2015年和2018年的英特尔编译器上,上面的代码编译得很好.
但是,在2018年的英特尔编译器中,上面的代码无法链接,而在2015年的英特尔编译器中,它链接得很好.
错误似乎是链接器无法找到构造函数符号,因为我得到以下错误:
SourceFile.o: in function SourceFile.hh:: undefined reference to
`SubprocWrapper::SubprocWrapper(int, int, int, std::string const&,
std::vector > const&,
std::set, std::allocator > const&,
std::map,
std::allocator > > const*)'
请注意,SubprocWrapper类正在编译为.a文件,并静态链接到调用它的代码中.在生成的.a文件上执行nm似乎确认SubprocWrapper构造函数的符号存在,但代码仅链接在2015下,即使原始.a是使用2018编译的.我们已确认正在传入正确的.a文件在链接器行(我们的构建过程没有改变),我们尝试在链接顺序中移动.a无济于事.
在我链接的.a文件上执行nm会显示与构造函数关联的以下签名(lib.a和SourceFile.o之间不同):
lib.a:
0000000000001020 T _ZN4beau5posix14SubprocWrapperC1EiiiRKSsRKSt6vectorISsSaISsEERKSt3setIiSt4lessIiESaIiEEPKSt3mapISsSsSA_ISsESaISt4pairIS2_SsEEE
0000000000000084 r _ZN4beau5posix14SubprocWrapperC1EiiiRKSsRKSt6vectorISsSaISsEERKSt3setIiSt4lessIiESaIiEEPKSt3mapISsSsSA_ISsESaISt4pairIS2_SsEEE$$LSDA
0000000000001010 T _ZN4beau5posix14SubprocWrapperC2EiiiRKSsRKSt6vectorISsSaISsEERKSt3setIiSt4lessIiESaIiEEPKSt3mapISsSsSA_ISsESaISt4pairIS2_SsEEE
SourceFile.o:
U _ZN4beau5posix14SubprocWrapperC1EiiiRKSsRKSt6vectorISsSaISsEERKSt3setIiSt4lessIiESaIiEEPKSt3mapISsSsSA_ISsESaISt4pairIKSsSsEEE
请注意,构造函数的两个受损名称不匹配!
我假设代码符合标准,因为它编译得很好,它只是无法链接.代码在大约7年左右没有改变,所有以前版本的英特尔编译器都使用它很好.
为什么此代码在英特尔2015而非2018下工作?
Operating system: RHEL 7.4
GCC version: 4.8.5
libstdc++ version: 4.8.5
Intel compiler versions:
2015.3.187 (Works!)
2018.1.163 (Fails to link!)
编辑:
这个问题似乎是某种竞争条件.当使用非常大的作业批处理(make -j30)进行编译时,我们在Intel 2015编译器上也注意到了它.问题突然出现,经过进一步检查,我们发现其中一个.o文件是使用符号的KS版本而不是IS2版本编译的.在交换了几个咒骂之后,我们删除了有问题的.o文件并再次编译没有作业批处理(只是make),并且令我们惊讶地发现,编译器这次为该函数生成了一个不同的符号(IS2版本) ).这似乎非常奇怪,因为无论作业批号如何,编译器都应始终生成相同的符号.不幸的是,这种行为不容易重复,因为我们做了一个make clean,并且再次运行了一个高工作批号,却发现它在那个时候工作了.