0

我正在尝试从我制作的库中创建一个测试可执行文件。让我们将它们命名为 lib1 和 lib2。lib1 与它的测试一起构建得很好。lib2 的构建也没有任何问题。但是,每当我尝试将 lib2 与其测试可执行文件(即使用 lib2 的示例程序)链接时,我都会收到以下错误:

usr/bin/ld: CMakeFiles/Lib2_Test.dir/Lib2_Test.cpp.o: in function `main':
Lib2_Test.cpp:(.text+0xf3): undefined reference to `Lib2::Lib2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, int)'
/usr/bin/ld: Lib2_Test.cpp:(.text+0x3f5): undefined reference to `Lib2::Evaluate(bool&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, float&, cv::Mat&, cv::Mat&, bool)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/Lib2_Test.dir/build.make:130: Lib2_Test] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/Lib2_Test.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

readelf -d我尝试使用和使用命令查看标题ldd,这两个库似乎都有所有必要的引用。但是 lib1 没有任何问题,而 lib2 在链接到使用它的可执行文件时会生成未引用的相关错误。

下面是我为它们制作的 cmakeLists,后来我还包括了readelf.

CMakelist.txt 用于lib1

cmake_minimum_required(VERSION 3.11)
project(Lib1)

set(CMAKE_CXX_STANDARD 17)

find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

add_definitions(-D_LIB1_BUILD_DLL) 

set( CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -fPIC" )

set(CMAKE_INSTALL_PREFIX /home/me/Desktop/LibtorchPort/built_stuff)

include_directories( /home/me/Desktop/LibtorchPort/Dependencies/include ${TORCH_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
LINK_DIRECTORIES(/home/me/libtorch-cxx11-abi-shared-with-deps-1.6.0+cpu/libtorch/lib)

# http://dlib.net/examples/CMakeLists.txt.html
add_subdirectory(/home/me/dlib-19.21 /home/me/dlib-19.21/build)     

set(Lib1_SRC ./lib1.cpp)

add_library(lib1 SHARED  ${Lib1_SRC})

# Link
target_link_libraries(lib1 ${TORCH_LIBRARIES})
target_link_libraries(lib1 ${OpenCV_LIBS})
target_link_libraries(lib1 dlib::dlib)

install(TARGETS lib1 LIBRARY DESTINATION lib)

这是 CMakeList.txt 的lib1_test

cmake_minimum_required(VERSION 3.11)
project(Lib1_Test)
set(CMAKE_CXX_STANDARD 17)

find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

set(CMAKE_INSTALL_PREFIX /home/me/Desktop/LibtorchPort/built_stuff)
include_directories( /home/me/Desktop/LibtorchPort/Dependencies/include ${TORCH_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})
 
# Link
add_executable(lib1_dynamic_test ./Lib1_Test.cpp)
target_link_directories(lib1_dynamic_test PRIVATE /home/me/Desktop/LibtorchPort/Lib1/build)

target_link_libraries(lib1_dynamic_test lib1 )
target_link_libraries(lib1_dynamic_test ${TORCH_LIBRARIES} )
target_link_libraries(lib1_dynamic_test ${OpenCV_LIBS})
install(TARGETS lib1_dynamic_test DESTINATION bin)

这是 CMakeList.txt 的lib2

cmake_minimum_required(VERSION 3.11)
project(Lib2)

set(CMAKE_CXX_STANDARD 17)

find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

add_definitions(-D_LIB2_BUILD_DLL) 

set(CMAKE_INSTALL_PREFIX /home/me/Desktop/LibtorchPort/built_stuff)

include_directories( /home/me/Desktop/LibtorchPort/Dependencies/include ${TORCH_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS})

LINK_DIRECTORIES(/home/me/libtorch-cxx11-abi-shared-with-deps-1.6.0+cpu/libtorch/lib)
LINK_DIRECTORIES(/home/me/Desktop/LibtorchPort/Lib1/build)

set(LIB2_SRC  ./lib2.cpp )

add_library(lib2_dynamic SHARED ${LIB2_SRC} )

target_link_directories(lib2_dynamic PRIVATE /home/me/Desktop/LibtorchPort/Lib1/build)

target_link_libraries(lib2_dynamic  lib1)
target_link_libraries(lib2_dynamic  ${TORCH_LIBRARIES})
target_link_libraries(lib2_dynamic  ${OpenCV_LIBS})

install(TARGETS lib2_dynamic LIBRARY DESTINATION lib)

最后是 CMakeList lib2_test

cmake_minimum_required(VERSION 3.11)
project(Lib2_Test)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_INSTALL_PREFIX /home/me/Desktop/LibtorchPort/built_stuff)

#find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

include_directories( /home/me/Desktop/LibtorchPort/Dependencies/include ${OpenCV_INCLUDE_DIRS})
LINK_DIRECTORIES(/home/me/Desktop/LibtorchPort/Lib1/build)

add_executable(Lib2_Test ./lib2_test.cpp)

target_link_directories(Lib2_Test PRIVATE /home/me/Desktop/LibtorchPort/Lib2/build)
#target_link_directories(Lib2_Test PUBLIC /home/me/Desktop/LibtorchPort/Lib1/build)

#Link
target_link_libraries(Lib2_Test ${OpenCV_LIBS})
target_link_libraries(Lib2_Test lib2_dynamic)
install(TARGETS Lib2_Test DESTINATION bin)

运行readelf -d lib1这是我得到的输出:

Dynamic section at offset 0x908f8 contains 38 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libtorch.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc10.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtorch_cpu.so]
 0x0000000000000001 (NEEDED)             Shared library: [libopencv_highgui.so.3.4]
 0x0000000000000001 (NEEDED)             Shared library: [libopencv_imgproc.so.3.4]
 0x0000000000000001 (NEEDED)             Shared library: [libopencv_core.so.3.4]
 0x0000000000000001 (NEEDED)             Shared library: [libcblas.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [liblapack.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x000000000000000e (SONAME)             Library soname: [libLib1.so]
 0x000000000000001d (RUNPATH)            Library runpath: [/home/me/anaconda3/lib/python3.8/site-packages/torch/lib:/home/me/libtorch-cxx11-abi-shared-with-deps-1.6.0+cpu/libtorch/lib:/usr/local/lib:]
 0x000000000000000c (INIT)               0x1a000
 0x000000000000000d (FINI)               0x57e00
 0x0000000000000019 (INIT_ARRAY)         0x90b28
 0x000000000000001b (INIT_ARRAYSZ)       32 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x90b48
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x328
 0x0000000000000005 (STRTAB)             0x6840
 0x0000000000000006 (SYMTAB)             0x1758
 0x000000000000000a (STRSZ)              56053 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x92000
 0x0000000000000002 (PLTRELSZ)           8112 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x17ff0
 0x0000000000000007 (RELA)               0x14b58
 0x0000000000000008 (RELASZ)             13464 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x149f8
 0x000000006fffffff (VERNEEDNUM)         5
 0x000000006ffffff0 (VERSYM)             0x14336
 0x000000006ffffff9 (RELACOUNT)          6
 0x0000000000000000 (NULL)               0x0

这是输出lib2

Dynamic section at offset 0x37ba0 contains 32 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libLib1.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtorch.so]
 0x0000000000000001 (NEEDED)             Shared library: [libtorch_cpu.so]
 0x0000000000000001 (NEEDED)             Shared library: [libopencv_core.so.3.4]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [libLib2_dynamic.so]
 0x000000000000001d (RUNPATH)            Library runpath: [/home/me/anaconda3/lib/python3.8/site-packages/torch/lib:/home/me/libtorch-cxx11-abi-shared-with-deps-1.6.0+cpu/libtorch/lib:/home/me/Desktop/LibtorchPort/Lib1/build:/usr/local/lib:]
 0x000000000000000c (INIT)               0x1e000
 0x000000000000000d (FINI)               0x2ec10
 0x0000000000000019 (INIT_ARRAY)         0x38108
 0x000000000000001b (INIT_ARRAYSZ)       16 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x38118
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x2f0
 0x0000000000000005 (STRTAB)             0x7d88
 0x0000000000000006 (SYMTAB)             0x1dd0
 0x000000000000000a (STRSZ)              62708 (bytes)
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000003 (PLTGOT)             0x39000
 0x0000000000000002 (PLTRELSZ)           14784 (bytes)
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000017 (JMPREL)             0x19e90
 0x0000000000000007 (RELA)               0x17b38
 0x0000000000000008 (RELASZ)             9048 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffffe (VERNEED)            0x17a78
 0x000000006fffffff (VERNEEDNUM)         3
 0x000000006ffffff0 (VERSYM)             0x1727c
 0x000000006ffffff9 (RELACOUNT)          4
 0x0000000000000000 (NULL)               0x0

然而,lib1构建和链接都很好,虽然lib2这取决于lib1,但在链接到其测试或任何其他库时会出现问题。在这一点上我一无所知,也不知道是什么原因造成的。我错过了什么?

更新 1

这是lib2_test.cpphttps://paste.ee/p/pOgFk 这就是头文件的样子:

#ifndef Lib2_H
#define Lib2_H

/* If we are we on Windows, we want a single define for it.*/
#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__))
#define _WIN32
#endif /* _WIN32 */

#if defined(_WIN32) && defined(_Lib2_BUILD_DLL)
/* We are building Lib2 as a Win32 DLL */
#define LIB2_API __declspec(dllexport)
#elif defined(_WIN32) && defined(Lib2_DLL)
/* We are calling Lib2 as a Win32 DLL */
#define LIB2_API __declspec(dllimport)
#elif defined(__GNUC__) && defined(_Lib2_BUILD_DLL)
/* We are building Lib2 as a shared / dynamic library */
#define LIB2_API __attribute__((visibility("default")))
#else
/* We are building or calling Lib2 as a static library */
#define LIB2_API
#endif

#include <string>
#include <vector>
#include <map>
#include <memory>
#include <opencv2/core.hpp>


enum class ValidationStatus
{
    None = -1,
    UnderValidation = 0,
    Validated = 1,
    Invalidated = 2,
    AnomalyDetected = 3,
    ToomuchAnonalyDetected = 4
};

typedef std::tuple<ValidationStatus, std::string, bool> Lib2Result;

class Lib2Impl;

class LIB2_API Lib2
{
private:
    std::shared_ptr<Lib2Impl> Lib2;

public:
    Lib2(std::string shape_predictor_path = "", std::string eyeNet_path = "", int valid_presence_delay = 5, int fpasPassed = 0);

    std::vector<Lib2Result> Run(std::map<std::string, bool>& validity_result, 
                                       std::vector<std::tuple<std::string, float>>& ids,
                                       std::vector<cv::Mat>& faces, 
                                       cv::Mat& originalImage,
                                       bool show_debug_info=false);

    Lib2Result Evaluate(bool& status, std::string& name, float& theta, cv::Mat& face_image, cv::Mat& originalImage, bool debug_info = true);
    ~Lib2();

};

#endif // !Lib2_H

关于评论,你可以看到调用lib2_test.cpp是好的,它使用相同的签名。

更新 2

我还需要补充一点,该项目在 Windows 中使用 Visual Studio 和 cmake 构建得很好!但是在 Linux(ubuntu 20.04)下,我面临着这些问题。所以这不仅仅是调用不同/错误的方法或使用错误的签名。这段代码应该可以很好地编译和链接,但我在这里做错了,我不确定它是什么。

笔记2

lib1 和 lib2 只是为实际文件名组成的名称(我只是选择 lib1 和 lib2 以使事情更简单并在这里替换了名称,所以如果您发现大小写不同,请不要介意,实际文件是相同的.

4

1 回答 1

3

概括

第三方库(火炬)是使用Pre-cxx11ABI 构建的,而用它构建的库显然无法链接到使用cxx11ABI 的对象!

长解释

经过数小时的调试,在 Windows 中的 Visual Studio 和 CMake 中运行良好的代码,同时在 Linux 中令人头疼,我找到了罪魁祸首!

libtorch 附带两种类型的构建Pre-cxx11cxx11ABI!它使用的Pre-cxx11是 Python 包 (torch1.6cpu) 附带的构建库,并且由于 Anaconda3 在路径中,我也使用它来构建我遇到这个问题的库。

经过这么多小时后,它暴露出来的是未定义方法的奇怪参数,它们是:std::__cxx11::basic_string它应该是简单std::string的。我没想到这两个会有所不同,我想,直到不久之前,g++ 还在使用一个奇怪的命名方案,这让我说,让我们搜索一下,也许我能找到一些东西!瞧!情况就是这样:

如果您收到有关对涉及 std::__cxx11 命名空间或标记 [abi:cxx11] 中的类型的符号的未定义引用的链接器错误,则可能表明您正在尝试将使用不同值编译的目标文件链接在一起 _GLIBCXX_USE_CXX11_ABI宏。当链接到使用旧版本 GCC 编译的第三方库时,通常会发生这种情况。如果第三方库不能用新的 ABI 重建,那么你需要用旧的 ABI 重新编译你的代码。

参考

cxx11为了解决这个问题,我只是在所有库的创建中直接使用了 libtorch ,就这样做了。这与 Pytorch 的官方文档中显示的不同。不要做:

cmake -DCMAKE_PREFIX_PATH="$(python -c 'import torch.utils; print(torch.utils.cmake_prefix_path)')" ..

如果你像我一样期望这些库是用 构建的,那么通过这样做,所有地狱都会崩溃cxx11!因为他们没有!

因此,如果您在 Linux 上,只需获取并使用带有CXX11ABI 的预构建库!并避免 Pytorch 附带的内容!

笔记

如果您正在使用 Pybind11 和 libtorch 构建 Python 扩展,请确保您的 Pytorch 也是使用 构建的GLIBCXX_USE_CXX11_ABI=1,否则您将看到未定义的引用,原因您现在知道了!您可以通过在终端/cmd 中运行以下代码段来简单地检查这一点:

python -c "import torch; print(f'GLIBCXX_USE_CXX11_ABI = {int(torch._C._GLIBCXX_USE_CXX11_ABI)}')"

根据此处提供的信息, conda 包(仅限 cuda 构建)应随GLIBCXX_USE_CXX11_ABI=1. 我使用 pip 和 conda 测试了 1.6cpu,但它们都报告了GLIBCXX_USE_CXX11_ABI = 0。所以请注意这一点。

如果您碰巧需要从源代码构建,您可以按照本指南进行操作。

至于为什么 Pytorch 会这样发货:

我们设置了那个标志,因为我们使用 gcc 4.9.x 构建,它只有旧的 ABI。在 GCC 5.1 中,std::string 的 ABI 已更改,并且使用 gcc >= 5.1 编译的二进制文件与使用 gcc < 5.1 构建的二进制文件(如 pytorch)不兼容 ABI,除非您设置了该标志。 参考

于 2020-09-23T02:48:59.353 回答