CMake linking error (collect2: ld returned 1 exit

2019-06-07 14:31发布

The project structure below is a simplified example.

├── 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)

Linking CXX executable 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

I'm hoping this is a really simple lack of understanding of how CMake handles dependencies. This compiles without error, but fails during linking

NetWork is dependent on CommBase, MessageDispatch dependent on NetWork and CommBase,how can i specify in DemoServer

标签: c++ cmake
1条回答
迷人小祖宗
2楼-- · 2019-06-07 14:56

There are a few issues here, some more critical than others. Roughly in order of importance:

  • 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.

查看更多
登录 后发表回答