我正在使用CMake生成一些构建环境:
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=TRUE
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=TRUE
cmake .. -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=TRUE -G "Visual Studio 14 2015 Win64"
第一个和第三个环境成功构建(无论我选择“Debug”还是“Release”),但第二个环境有链接器错误:
MakeFiles/Stub_Time.dir/src/TimeStub.cpp.o: In function `NotSet ConvertJSON<NotSet>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::shared_ptr<IMessageLog>)':
TimeStub.cpp:(.text._Z11ConvertJSONI6NotSetET_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10shared_ptrI11IMessageLogE[_Z11ConvertJSONI6NotSetET_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt10shared_ptrI11IMessageLogE]+0xe4): undefined reference to `void load<cereal::JSONInputArchive>(cereal::JSONInputArchive&, NotSet&)'
../lib/libIO.so: undefined reference to `void save<cereal::JSONOutputArchive>(cereal::JSONOutputArchive&, VehicleBound const&)'
../lib/libIO.so: undefined reference to `void save<cereal::JSONOutputArchive>(cereal::JSONOutputArchive&, Emissions const&)'
collect2: error: ld returned 1 exit status
CMakeFiles/Stub_Time.dir/build.make:111: recipe for target 'bin/Stub_Time' failed
make[2]: *** [bin/Stub_Time] Error 1
CMakeFiles/Makefile2:77: recipe for target 'CMakeFiles/Stub_Time.dir/all' failed
make[1]: *** [CMakeFiles/Stub_Time.dir/all] Error 2
Makefile:94: recipe for target 'all' failed
make: *** [all] Error 2
我尝试调用make VERBOSE=1
,唯一的区别似乎是c++
在成功案例中使用-g
标志进行调用,并且-O3 -DNDEBUG
标志位于不成功的案例。
为什么会这样?
发布模式是否优化了libIO.so
中引用的Stub_Time
中的符号?如果是这样,我怎么能阻止它?如果没有,我该如何调查?
我跑了:
grep -R ifdef | grep DEBUG
在整个项目中,但它提出的所有文件似乎都与上述错误无关(只是与打印版本相关的内容)。
我发现我可以通过将以下内容添加到CMakeLists.txt来修改CMake传递给c++
的标志:
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
这些的不同组合表明-O0
不会发生错误,但-O1
我们使用json序列化库:谷类食品。它寻找类似于下面的功能。通常,您可以在那里调用某些要序列化的字段。有一些奇怪的情况我们想说:“Serialize Nothing”所以我们实现了以下序列化调用:
template <class Archive>
void save(Archive& archive, const NotSet& object)
{
}
template <class Archive>
void load(Archive& archive, NotSet& object)
{
}
我猜测-O1
注意到了一些空虚函数并优化了一些东西。然后其他人试图链接到libIO.so
并发现符号丢失。我能够通过向NotSet
添加一个虚拟字段然后序列化该字段来解决这个问题。
现在它使用-O2
成功构建,但-O3
导致以下内容:
../lib/libIO.so: undefined reference to `void save<cereal::JSONOutputArchive>(cereal::JSONOutputArchive&, Emissions const&)'
../lib/libIO.so: undefined reference to `void save<cereal::JSONOutputArchive>(cereal::JSONOutputArchive&, VehicleBound const&)'
与原始错误类似,但不存在对NotSet
的引用。我已经完成了两次重复导致错误的调用 - 它们看起来与所有其他表现良好的调用相同。
似乎可能与此相关:c++ linker error: undefined references only on optimized build因为麻烦的调用是函数模板。但是,它们的定义位于一个包含在文件中的标题中,该文件被指定为libIO.so的一部分。