如果调试版本没有,发布版本为什么会出现链接器错误?

时间:2017-02-21 00:32:52

标签: c++ cmake g++

我正在使用CMake生成一些构建环境:

  1. cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=TRUE

  2. cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=TRUE

  3. cmake .. -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE -DBUILD_SHARED_LIBS=TRUE -G "Visual Studio 14 2015 Win64"
  4. 第一个和第三个环境成功构建(无论我选择“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
    

    在整个项目中,但它提出的所有文件似乎都与上述错误无关(只是与打印版本相关的内容)。

    编辑2:

    我发现我可以通过将以下内容添加到CMakeLists.txt来修改CMake传递给c++的标志:

    set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") 
    

    这些的不同组合表明-O0不会发生错误,但-O1

    会发生错误

    编辑3

    我们使用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的一部分。

0 个答案:

没有答案