CMake连接错误(collect2:ld返回1个退出状态)

3
下面的项目结构是一个简化的例子。
├── CMakeLists.txt
├── debug
├── CommBase
│   ├── Task.h
│   ├── Task.cpp
│   ├── Thread.h
│   ├── Thread.cpp
│   └── CMakeLists.txt
├── NetWork
│   ├── TSocket.h
│   ├── TSocket.cpp
│   ├── Stream_Channel.h
│   ├── Stream_Channel.cpp
│   └── CMakeLists.txt
├── MessageDispatch
│   ├── Channel_Manager.h
│   ├── Channel_Manager.cpp
│   ├── Message_Facade.h
│   ├── Message_Facade.cpp
│   └── CMakeLists.txt
└── DemoServer
    ├── CMakeLists.txt
    └── main.cpp

./CMakeLists.txt

PROJECT(DDLIB)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

MESSAGE(STATUS "This is PROJECT_BINARY_DIR dir "${PROJECT_BINARY_DIR})
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
ADD_SUBDIRECTORY(CommBase)
ADD_SUBDIRECTORY(NetWork)
ADD_SUBDIRECTORY(DemoServer)

CommBase/CMakeLists.txt

AUX_SOURCE_DIRECTORY(. LIB_SRC_LIST)
ADD_LIBRARY(CommBase SHARED STATIC ${LIB_SRC_LIST})

INCLUDE_DIRECTORIES(../boost)
INSTALL(TARGETS CommBase CommBase
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)

SET( CMAKE_BUILD_TYPE Debug )
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

NetWork/CMakeLists.txt

AUX_SOURCE_DIRECTORY(. LIB_SRC_LIST)
ADD_LIBRARY(NetWork SHARED STATIC ${LIB_SRC_LIST})

INCLUDE_DIRECTORIES(../boost)
INSTALL(TARGETS NetWork NetWork
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
 TARGET_LINK_LIBRARIES(NetWork CommBase)
SET( CMAKE_BUILD_TYPE Debug )
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

MessageDispatch/CMakeLists.txt

AUX_SOURCE_DIRECTORY(. LIB_SRC_LIST)
ADD_LIBRARY(MessageDispatch SHARED STATIC ${LIB_SRC_LIST})

INCLUDE_DIRECTORIES(../boost)
INCLUDE_DIRECTORIES(../CommBase)
INCLUDE_DIRECTORIES(../NetWork)
ADD_DEPENDENCIES(MessageDispatch CommBase NetWork)
LINK_DIRECTORIES(/home/cl/server/ddsvn/debug)
TARGET_LINK_LIBRARIES(MessageDispatch CommBase NetWork)
INSTALL(TARGETS MessageDispatch MessageDispatch
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)

DemoServer/CMakeLists.txt

PROJECT(DDLIB)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
MESSAGE(STATUS "This is PROJECT_BINARY_DIR dir "${PROJECT_BINARY_DIR})
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
AUX_SOURCE_DIRECTORY(. SRC_LIST)
ADD_EXECUTABLE(DemoServer ${SRC_LIST})
INCLUDE_DIRECTORIES(../boost)
INCLUDE_DIRECTORIES(../CommBase)
INCLUDE_DIRECTORIES(../NetWork)
INCLUDE_DIRECTORIES(../MessageDispatch)
ADD_DEPENDENCIES(DemoServer CommBase NetWork MessageDispatch)
LINK_DIRECTORIES(/home/cl/server/ddsvn/debug)
TARGET_LINK_LIBRARIES(DemoServer CommBase NetWork MessageDispatch)

链接 CXX 可执行文件 DemoServer

/usr/bin/cmake -E cmake_link_script CMakeFiles/DemoServer.dir/link.txt --verbose=1
/usr/bin/c++     -fPIC CMakeFiles/DemoServer.dir/stdafx.cpp.o CMakeFiles/DemoServer.dir/DemoServer.cpp.o  -o DemoServer -rdynamic -lCommBase -lNetWork -lMessageDispatch 
/usr/local/lib/libMessageDispatch.a(Message_Facade.cpp.o): In function `Message_Facade::stop()':
/home/cl/server/ddsvn/MessageDispatch/Message_Facade.cpp:80: undefined reference to `Timer_Queue::instance()'
/home/cl/server/ddsvn/MessageDispatch/Message_Facade.cpp:80: undefined reference to `Timer_Queue::stop()'
/usr/local/lib/libMessageDispatch.a(Message_Facade.cpp.o): In function `Message_Facade::wait()':
/home/cl/server/ddsvn/MessageDispatch/Message_Facade.cpp:87: undefined reference to `Task::wait()'
/home/cl/server/ddsvn/MessageDispatch/Message_Facade.cpp:88: undefined reference to `Task::wait()'
/usr/local/lib/libMessageDispatch.a(Acceptor_Manager.cpp.o): In function `Stream_Acceptor':
/home/cl/server/ddsvn/MessageDispatch/../NetWork/Stream_Accecptor.h:40: undefined reference to `vtable for Stream_Acceptor'
/usr/local/lib/libMessageDispatch.a(Channel_Manager.cpp.o): In function `Channel_Manager':
/home/cl/server/ddsvn/MessageDispatch/Channel_Manager.cpp:81: undefined reference to `Channel_Handler::~Channel_Handler()'
/usr/local/lib/libMessageDispatch.a(Channel_Manager.cpp.o): In function `~Channel_Manager':
/home/cl/server/ddsvn/MessageDispatch/Channel_Manager.cpp:86: undefined reference to `Channel_Handler::~Channel_Handler()'
/home/cl/server/ddsvn/MessageDispatch/Channel_Manager.cpp:86: undefined reference to `Channel_Handler::~Channel_Handler()'
/usr/local/lib/libMessageDispatch.a(Channel_Manager.cpp.o): In function `Channel_Handler':
/home/cl/server/ddsvn/MessageDispatch/../NetWork/Channel_Handler.h:14: undefined reference to `vtable for Channel_Handler'
/usr/local/lib/libMessageDispatch.a(Channel_Manager.cpp.o):(.rodata._ZTI15Channel_Manager[typeinfo for Channel_Manager]+0x28): undefined reference to `typeinfo for Channel_Handler'
/usr/local/lib/libMessageDispatch.a(Message.cpp.o): In function `Message':
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:49: undefined reference to `Binary_Stream::Binary_Stream(int)'
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:98: undefined reference to `Binary_Stream::~Binary_Stream()'
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:100: undefined reference to `Binary_Stream::Binary_Stream(int)'
/usr/local/lib/libMessageDispatch.a(Message.cpp.o): In function `Message::resize(int)':
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:187: undefined reference to `Stream_Base::resize(int)'
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:196: undefined reference to `Stream_Base::resize(int)'
/usr/local/lib/libMessageDispatch.a(Message.cpp.o): In function `~Message':
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:203: undefined reference to `Binary_Stream::~Binary_Stream()'
/home/cl/server/ddsvn/MessageDispatch/Message.cpp:203: undefined reference to `Binary_Stream::~Binary_Stream()'
/usr/local/lib/libMessageDispatch.a(Message.cpp.o):(.rodata._ZTV7Message[vtable for Message]+0x20): undefined reference to `Stream_Base::clone_stream()'
/usr/local/lib/libMessageDispatch.a(Message.cpp.o):(.rodata._ZTI7Message[typeinfo for Message]+0x10): undefined reference to `typeinfo for Binary_Stream'
/usr/local/lib/libMessageDispatch.a(Connector_Manager.cpp.o): In function `Stream_Connector':
/home/cl/server/ddsvn/MessageDispatch/../NetWork/Stream_Connector.h:42: undefined reference to `vtable for Stream_Connector'
/usr/local/lib/libMessageDispatch.a(Context.cpp.o): In function `Context':
/home/cl/server/ddsvn/MessageDispatch/Context.cpp:15: undefined reference to `Dispatch_Thread::Dispatch_Thread()'
/usr/local/lib/libMessageDispatch.a(Context.cpp.o): In function `Context::initialize()':
/home/cl/server/ddsvn/MessageDispatch/Context.cpp:113: undefined reference to `Timer_Queue::instance()'
/home/cl/server/ddsvn/MessageDispatch/Context.cpp:113: undefined reference to `Timer_Queue::start()'
/home/cl/server/ddsvn/MessageDispatch/Context.cpp:116: undefined reference to `Task::activate(int, int*)'
/home/cl/server/ddsvn/MessageDispatch/Context.cpp:121: undefined reference to `Task::activate(int, int*)'
/usr/local/lib/libMessageDispatch.a(Re_Connect_Handler.cpp.o): In function `Re_Connect_Handler::process_re_connect(Context&, int)':
/home/cl/server/ddsvn/MessageDispatch/Re_Connect_Handler.cpp:23: undefined reference to `Timer_Queue::instance()'
/home/cl/server/ddsvn/MessageDispatch/Re_Connect_Handler.cpp:23: undefined reference to `Timer_Queue::schedule_timer(Smart_Ptr<Timer_Handler>, Time_Value const&, Smart_Ptr<Ref_Object>, EDispatchType, Dispatch_Thread*)'
/usr/local/lib/libMessageDispatch.a(IO_Thread.cpp.o): In function `IO_Thread':
/home/cl/server/ddsvn/MessageDispatch/IO_Thread.cpp:4: undefined reference to `Task::Task()'
/home/cl/server/ddsvn/MessageDispatch/IO_Thread.cpp:7: undefined reference to `Task::~Task()'
/usr/local/lib/libMessageDispatch.a(IO_Thread.cpp.o): In function `~IO_Thread':
/home/cl/server/ddsvn/MessageDispatch/IO_Thread.cpp:12: undefined reference to `Task::~Task()'
/home/cl/server/ddsvn/MessageDispatch/IO_Thread.cpp:12: undefined reference to `Task::~Task()'
/usr/local/lib/libMessageDispatch.a(IO_Thread.cpp.o):(.rodata._ZTI9IO_Thread[typeinfo for IO_Thread]+0x10): undefined reference to `typeinfo for Task'
collect2: ld returned 1 exit status
make[2]: *** [DemoServer] Error 1
make[2]: Leaving directory `/home/cl/server/ddsvn/DemoServer/Debug'
make[1]: *** [CMakeFiles/DemoServer.dir/all] Error 2
make[1]: Leaving directory `/home/cl/server/ddsvn/DemoServer/Debug'
make: *** [all] Error 2

我希望这只是我对CMake处理依赖关系的简单误解。这个编译没有错误,但在链接过程中失败了。
NetWork依赖于CommBase,MessageDispatch依赖于NetWork和CommBase,我该如何在DemoServer中指定?

阅读您的错误消息:链接CXX可执行文件 . ;; /usr/bin/ld: 无法打开输出文件 .: 是一个目录。您不知何故将点号配置为应用程序或库的名称,当然连接器无法生成具有该名称的文件。 - Ferdinand Beyer
你不应该搜索自己构建的库,只需将其目标名称传递给 target_link_library - arrowd
为了查看实际发生的情况,您可以调用 make VERBOSE=1 命令,该命令会输出实际的编译器和链接器命令以及 CMake 生成的具体参数。 - mars
1
你的“简化示例”仍然不是最小化的。继续将其简化,直到只涉及2-4个文件,并且内容尽可能少,然后我们将更好地修复它。 - John Zwinck
1个回答

3

这里有几个问题,其中一些比其他问题更为重要。按重要性大致排序如下:

  • add_library allows you to define the library as either STATIC or SHARED, but not both.

  • target_link_libraries links the dependencies in the order they appear in the command. You should specify them from most-dependent to least. So, in your DemoServer CMakeLists.txt, it should be

    TARGET_LINK_LIBRARIES(DemoServer MessageDispatch NetWork CommBase)
    

    However, from the docs:

    Library dependencies are transitive by default. When this target is linked into another target then the libraries linked to this target will appear on the link line for the other target too.

    In other words, you should have TARGET_LINK_LIBRARIES(NetWork CommBase) in NetWork (you already do), TARGET_LINK_LIBRARIES(MessageDispatch NetWork) in MessageDispatch, and just TARGET_LINK_LIBRARIES(DemoServer MessageDispatch) for the Demo.

  • CMAKE_BUILD_TYPE would normally be set by the user via the command line (or CMake GUI). It should probably only be set inside the CMakeLists.txt if the user hasn't already done so, or if it's set to an invalid value. If you set or change the value, it would be good to tell the user via a message. You probably shouldn't be setting it in 2 different places.

  • aux_source_directory is not recommended as a means to gather lists of source files. The recommended way is to hard-code the file paths into your CMakeLists.txt, so if the source list changes, CMake automatically re-runs.

  • link_directories is rarely required, and shouldn't contain a hard-coded absolute path.

  • LIBRARY_OUTPUT_PATH and EXECUTABLE_OUTPUT_PATH are deprecated.

  • add_dependencies is not required if you have already specified these dependencies via a target_link_libraries call.


静态库中的语法错误 ^ ^,谢谢。 - nemo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接