【发布时间】:2021-10-25 13:44:09
【问题描述】:
我是 CMake 的新手,还试图了解链接的工作原理,或者是什么导致 libtorch 和 OpenNMTTokenizer.so 不能一起工作。前者是一个带有 CMake 配置的包,后者是一个共享库。
如果我删除其中任何一个,二进制文件可以正常工作,但它们不能链接到同一个项目中。可能OpenNMTTokenizer.so 缺少标题,但我不确定如何正确添加它们。
这是错误信息:
/usr/bin/ld: CMakeFiles/example_shared.dir/src/app.cpp.o: in function `main':
app.cpp:(.text+0x292): undefined reference to `onmt::Tokenizer::joiner_marker'
/usr/bin/ld: app.cpp:(.text+0x2a7): undefined reference to `onmt::Tokenizer::Tokenizer(onmt::Tokenizer::Mode, int, std::string const&, std::string const&, std::string const&, int)'
collect2: error: ld returned 1 exit status
程序是一个简单的hello world,只是为了隔离问题:
.
│
├── CMakeLists.txt
│
├── src
│ └── app.cpp
├── include
│ └── app.h.in
│ └── app.h
├── build
#
#. Project meta
#
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
project(hello_world)
configure_file(include/app.h.in include/app.h)
#
# Add libraries
#
# 1. Torch
find_package(Torch REQUIRED PATHS /usr/local/libtorch)
# Required flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
if (Torch_FOUND)
list(APPEND LINK_LIBRARIES "${TORCH_LIBRARIES}")
else()
message(FATAL_ERROR "Cannot find libtorch")
endif()
# 2. OpenNMTTokenizer
find_library(OpenNMTTokenizer lib/libOpenNMTTokenizer.so)
if (OpenNMTTokenizer)
add_library(OpenNMTTokenizer SHARED IMPORTED lib/libOpenNMTTokenizer.so)
set_target_properties(OpenNMTTokenizer
PROPERTIES
IMPORTED_LOCATION /usr/local/lib/libOpenNMTTokenizer.so
LINKER_LANGUAGE CXX)
list(APPEND LINK_LIBRARIES OpenNMTTokenizer "${OpenNMTTokenizer_LIBRARIES}")
else()
message(FATAL_ERROR "Cannot find OpenNMTTokenizer")
endif()
#
# Add the executable
#
add_executable("${PROJECT_NAME}" src/app.cpp)
set_property(TARGET "${PROJECT_NAME}" PROPERTY CXX_STANDARD 14)
target_link_libraries("${PROJECT_NAME}" "${LINK_LIBRARIES}")
target_include_directories("${PROJECT_NAME}" PUBLIC
"${CMAKE_SOURCE_DIR}/include"
"${TORCH_INCLUDE_DIRS}")
set_target_properties("${PROJECT_NAME}"
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/../lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/../lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/../bin"
)
这是来源src/app.cpp
#include "app.h"
#include <iostream>
#include <vector>
#include <torch/torch.h>
#include <torch/script.h>
#include <onmt/Tokenizer.h>
using namespace onmt;
int main(){
torch::Tensor tensor = torch::eye(3);
std::cout << tensor << std::endl;
// It doesn't work if torch is linked
Tokenizer tokenizer(Tokenizer::Mode::Conservative, Tokenizer::Flags::JoinerAnnotate);
return 0;
}
完成构建输出
/usr/local/bin/cmake -S/home/inez/Projects/cmake_hello_world -B/home/inez/Projects/cmake_hello_world/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/local/bin/cmake -E cmake_progress_start /home/inez/Projects/cmake_hello_world/build/CMakeFiles /home/inez/Projects/cmake_hello_world/build//CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/inez/Projects/cmake_hello_world/build'
make -f CMakeFiles/hello_world.dir/build.make CMakeFiles/hello_world.dir/depend
make[2]: Entering directory '/home/inez/Projects/cmake_hello_world/build'
cd /home/inez/Projects/cmake_hello_world/build && /usr/local/bin/cmake -E cmake_depends "Unix Makefiles" /home/inez/Projects/cmake_hello_world /home/inez/Projects/cmake_hello_world /home/inez/Projects/cmake_hello_world/build /home/inez/Projects/cmake_hello_world/build /home/inez/Projects/cmake_hello_world/build/CMakeFiles/hello_world.dir/DependInfo.cmake --color=
Dependencies file "CMakeFiles/hello_world.dir/src/app.cpp.o.d" is newer than depends file "/home/inez/Projects/cmake_hello_world/build/CMakeFiles/hello_world.dir/compiler_depend.internal".
Consolidate compiler generated dependencies of target hello_world
make[2]: Leaving directory '/home/inez/Projects/cmake_hello_world/build'
make -f CMakeFiles/hello_world.dir/build.make CMakeFiles/hello_world.dir/build
make[2]: Entering directory '/home/inez/Projects/cmake_hello_world/build'
[ 50%] Linking CXX executable ../bin/hello_world
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/hello_world.dir/link.txt --verbose=1
/usr/bin/c++ -D_GLIBCXX_USE_CXX11_ABI=0 -rdynamic CMakeFiles/hello_world.dir/src/app.cpp.o -o ../bin/hello_world -Wl,-rpath,/usr/local/libtorch/lib:/usr/local/cuda-11.2/lib64/stubs:/usr/local/cuda-11.2/lib64:/usr/local/lib /usr/local/libtorch/lib/libtorch.so /usr/local/libtorch/lib/libc10.so /usr/local/libtorch/lib/libkineto.a /usr/local/cuda-11.2/lib64/stubs/libcuda.so /usr/local/cuda-11.2/lib64/libnvrtc.so -lnvToolsExt /usr/local/cuda-11.2/lib64/libcudart.so /usr/local/libtorch/lib/libc10_cuda.so /usr/local/lib/libOpenNMTTokenizer.so -Wl,--no-as-needed,"/usr/local/libtorch/lib/libtorch_cuda.so" -Wl,--as-needed -Wl,--no-as-needed,"/usr/local/libtorch/lib/libtorch_cuda_cpp.so" -Wl,--as-needed -Wl,--no-as-needed,"/usr/local/libtorch/lib/libtorch_cpu.so" -Wl,--as-needed -lpthread /usr/local/libtorch/lib/libc10_cuda.so /usr/local/libtorch/lib/libc10.so /usr/local/cuda-11.2/lib64/libcufft.so /usr/local/cuda-11.2/lib64/libcurand.so /usr/local/cuda-11.2/lib64/libcublas.so /usr/local/cuda-11.2/lib64/libcudnn.so -Wl,--no-as-needed,"/usr/local/libtorch/lib/libtorch_cuda_cu.so" -Wl,--as-needed -Wl,--no-as-needed,"/usr/local/libtorch/lib/libtorch.so" -Wl,--as-needed -lnvToolsExt /usr/local/cuda-11.2/lib64/libcudart.so
/usr/bin/ld: CMakeFiles/hello_world.dir/src/app.cpp.o: in function `main':
app.cpp:(.text+0x292): undefined reference to `onmt::Tokenizer::joiner_marker'
/usr/bin/ld: app.cpp:(.text+0x2a7): undefined reference to `onmt::Tokenizer::Tokenizer(onmt::Tokenizer::Mode, int, std::string const&, std::string const&, std::string const&, int)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/hello_world.dir/build.make:114: ../bin/hello_world] Error 1
make[2]: Leaving directory '/home/inez/Projects/cmake_hello_world/build'
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/hello_world.dir/all] Error 2
make[1]: Leaving directory '/home/inez/Projects/cmake_hello_world/build'
make: *** [Makefile:91: all] Error 2
Torch 有一个 TorchConfig.make
# Finds the Torch library
#
# This will define the following variables:
#
# TORCH_FOUND -- True if the system has the Torch library
# TORCH_INCLUDE_DIRS -- The include directories for torch
# TORCH_LIBRARIES -- Libraries to link against
# TORCH_CXX_FLAGS -- Additional (required) compiler flags
来自LINK_LIBRARIES的链接库
LINK_LIBRARIES=torchtorch_library/usr/local/libtorch/lib/libc10.so/usr/local/libtorch/lib/libkineto.a/usr/local/cuda-11.2/lib64/stubs/libcuda.so/usr/local/cuda-11.2/lib64/libnvrtc.so/usr/lib/x86_64-linux-gnu/libnvToolsExt.so/usr/local/cuda-11.2/lib64/libcudart.so/usr/local/libtorch/lib/libc10_cuda.soOpenNMTTokenizer
请看下面的答案
这些库链接到不同的标准库。正如 @botje 所建议的,_GLIBCXX_USE_CXX11_ABI 的值不匹配。
我用这一行重新编译了OpenNMTTokenizer,然后主项目编译没有错误:
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)
来自 libstdc++
如果您收到有关未定义符号引用的链接器错误,这些符号涉及 std::__cxx11 命名空间或标签 [abi:cxx11] 中的类型,则可能表明您正在尝试将使用不同值编译的目标文件链接在一起_GLIBCXX_USE_CXX11_ABI 宏。
这通常发生在链接到第三方库时 使用旧版本的 GCC 编译。如果第三方库 无法使用新的 ABI 重建,那么您将需要重新编译 旧 ABI 的代码。
【问题讨论】:
-
如果你运行
make VERBOSE=1,你能显示构建输出吗?这将告诉我们是否正在链接 opennmt 库。 -
另外,
LINK_LIBRARIES变量的最终内容是什么? -
不知道怎么调试,不过应该有
OpenNMTTokenizer,和预定义的TORCH_LIBRARIES -
请用
message( LINK_LIBRARIES is ${LINK_LIBRARIES})之类的东西检查内容 -
请不要在您的问题中添加“解决方案”部分,而是添加一个答案(您可以回答自己的问题并接受答案,我们鼓励这样做)。
标签: c++ cmake linker shared-libraries