【问题标题】:Modern CMake, using target_link_library for external binary library现代 CMake,使用 target_link_library 作为外部二进制库
【发布时间】:2019-03-04 14:35:54
【问题描述】:

我正在尝试使用现代 CMake 使用外部二进制库。我一直在阅读许多示例,并试图理解 CMake 文档,但我无法将其应用于我的具体案例。

这是“现代”CMake 演讲:https://www.youtube.com/watch?v=eC9-iRN2b04 他描述了我想使用的 CMake 模块化方法。

我的外部模块如下所示:

/usr/local/...
include
├── corvusoft
│   └── restbed
│       ├── byte.hpp
│       ├── common.hpp
│       ├── context_placeholder_base.hpp
│       ├── context_placeholder.hpp
│       ├── context_value.hpp
│       ├── http.hpp
│       ├── logger.hpp
│       ├── request.hpp
│       ├── resource.hpp
│       ├── response.hpp
│       ├── rule.hpp
│       ├── service.hpp
│       ├── session.hpp
│       ├── session_manager.hpp
│       ├── settings.hpp
│       ├── ssl_settings.hpp
│       ├── status_code.hpp
│       ├── string.hpp
│       ├── uri.hpp
│       ├── web_socket.hpp
│       └── web_socket_message.hpp
└── restbed
library
├── librestbed.a
├── librestbed.so -> librestbed.so.4
├── librestbed.so.4 -> librestbed.so.4.7
└── librestbed.so.4.7

这是我编写 CMakeList 文件的最新努力:

cmake_minimum_required(VERSION 2.6)
project(ktest1 CXX)
set (CMAKE_CXX_STANDARD 11)

set(LIB_PATH /usr/local/library)
set(RESTBED_INCLUDE /usr/local/include/corvusoft/restbed) 
set(HEADER_FILES "${RESTBED_INCLUDE}/session.hpp")
message(${HEADER_FILES})

add_library(restbed ${LIB_PATH})
add_executable(ktest1 main.cpp)

target_include_directories(restbed PUBLIC /usr/local/include ${RESTBED_INCLUDE})
set_target_properties(restbed PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(ktest1 PUBLIC restbed)

install(TARGETS ktest1 RUNTIME DESTINATION bin)

CMake 创建了构建文件,使运行到 100%,但是我的主程序仍然找不到库,所以我做错了。

ben@VMDebian2:~/Workspaces/test/build$ cmake ..
-- The CXX compiler identification is GNU 6.3.0
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
/usr/local/include/corvusoft/restbed/session.hpp
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ben/Workspaces/test/build
ben@VMDebian2:~/Workspaces/test/build$ ll
total 28K
-rw-r--r-- 1 ben ben  11K Mar  3 17:38 CMakeCache.txt
drwxr-xr-x 6 ben ben 4.0K Mar  3 17:38 CMakeFiles
-rw-r--r-- 1 ben ben 2.1K Mar  3 17:38 cmake_install.cmake
-rw-r--r-- 1 ben ben 6.7K Mar  3 17:38 Makefile
ben@VMDebian2:~/Workspaces/test/build$ make
Scanning dependencies of target restbed
[ 33%] Linking CXX static library librestbed.a
[ 33%] Built target restbed
Scanning dependencies of target ktest1
[ 66%] Building CXX object CMakeFiles/ktest1.dir/main.cpp.o
[100%] Linking CXX executable ktest1
CMakeFiles/ktest1.dir/main.cpp.o: In function `post_method_handler(std::shared_ptr<restbed::Session>)::{lambda(std::shared_ptr<restbed::Session>, std::vector<unsigned char, std::allocator<unsigned char> > const&)#1}::operator()(std::shared_ptr<restbed::Session>, std::vector<unsigned char, std::allocator<unsigned char> > const&) const':
main.cpp:(.text+0x25a): undefined reference to `restbed::Session::close(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::multimap<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&)'
CMakeFiles/ktest1.dir/main.cpp.o: In function `post_method_handler(std::shared_ptr<restbed::Session>)':
main.cpp:(.text+0x3b5): undefined reference to `restbed::Session::get_request() const'
main.cpp:(.text+0x46a): undefined reference to `restbed::Session::fetch(unsigned long, std::function<void (std::shared_ptr<restbed::Session>, std::vector<unsigned char, std::allocator<unsigned char> > const&)> const&)'
CMakeFiles/ktest1.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x571): undefined reference to `restbed::Resource::set_path(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x5ea): undefined reference to `restbed::Resource::set_method_handler(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void (std::shared_ptr<restbed::Session>)> const&)'
main.cpp:(.text+0x61d): undefined reference to `restbed::Service::Service()'
main.cpp:(.text+0x649): undefined reference to `restbed::Service::publish(std::shared_ptr<restbed::Resource const> const&)'
main.cpp:(.text+0x67c): undefined reference to `restbed::Service::start(std::shared_ptr<restbed::Settings const> const&)'
main.cpp:(.text+0x69c): undefined reference to `restbed::Service::~Service()'
main.cpp:(.text+0x737): undefined reference to `restbed::Service::~Service()'
CMakeFiles/ktest1.dir/main.cpp.o: In function `int restbed::Request::get_header<int, 0>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int) const':
main.cpp:(.text._ZNK7restbed7Request10get_headerIiLi0EEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_[_ZNK7restbed7Request10get_headerIiLi0EEET_RKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES2_]+0x4b): undefined reference to `restbed::Request::get_header(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const'
CMakeFiles/ktest1.dir/main.cpp.o: In function `void __gnu_cxx::new_allocator<restbed::Resource>::construct<restbed::Resource>(restbed::Resource*)':
main.cpp:(.text._ZN9__gnu_cxx13new_allocatorIN7restbed8ResourceEE9constructIS2_JEEEvPT_DpOT0_[_ZN9__gnu_cxx13new_allocatorIN7restbed8ResourceEE9constructIS2_JEEEvPT_DpOT0_]+0x32): undefined reference to `restbed::Resource::Resource()'
collect2: error: ld returned 1 exit status
CMakeFiles/ktest1.dir/build.make:95: recipe for target 'ktest1' failed
make[2]: *** [ktest1] Error 1
CMakeFiles/Makefile2:104: recipe for target 'CMakeFiles/ktest1.dir/all' failed
make[1]: *** [CMakeFiles/ktest1.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2

我做错事的主要线索是库的 librestbed.a 出现在我运行 make 的 /build 文件中,但我没有生成程序的二进制文件。

我已经尝试过 find_package(),但是我没有找到包的运气。我指向 librestbed.a 文件。

关于链接到外部二进制库的最佳方式有什么想法吗?我在 Debian 9.8 上使用 CMake 3.7.2。这是我的 main.cpp

#include <memory>
#include <cstdlib>
#include <restbed>

using namespace std;
using namespace restbed;

void post_method_handler( const shared_ptr< Session > session )
{
    const auto request = session->get_request( );

    size_t content_length = request->get_header( "Content-Length", 0 );

    session->fetch( content_length, [ request ]( const shared_ptr< Session > session, const Bytes & body )
    {
        fprintf( stdout, "%.*s\n", ( int ) body.size( ), body.data( ) );
        session->close( OK, "Hello, World!", { { "Content-Length", "13" }, { "Connection", "close" } } );
    } );
}

int main( const int, const char** )
{
    auto resource = make_shared< Resource >( );
    resource->set_path( "/resource" );
    resource->set_method_handler( "POST", post_method_handler );

    Service service;
    service.publish( resource );
    service.start( );

    return EXIT_SUCCESS;
}

我可以像这样使用 root 用户使用 clang 编译和运行这个程序:

export LD_LIBRARY_PATH=/usr/local/library
clang++ -L/usr/local/library -std=c++11 -o test main.cpp -l restbed 

谢谢

【问题讨论】:

  • add_library 看起来不对。我假设您不想构建库,只需链接它,这样target_link_libraries 就足够了。可能与target_link_directories 一起使用。
  • 我试过这个。我收到错误“无法指定此项目未构建的目标“restbed”的包含目录。”看起来我的 CMake 版本没有 target_link_directories。我已经尝试过 link_directories(${LIB_PATH}) 和 find_library(${LIB_PATH})。无论哪种方式,我都会遇到相同的错误。
  • “现代”方式在声明外部库时使用 IMPORTED 关键字。有关详细信息,请参阅以下答案:stackoverflow.com/a/10550334/3440745。请注意,IMPORTED 库的IMPORTED_LOCATION 属性应包含库文件 的绝对路径,而不是目录。
  • @horseatingweeds 你不需要为restbed 指定包含目录,因为它已经构建好了。你只需要告诉 CMake 它在哪里,你就可以链接它。但是,您确实需要将 redtbed 包含添加到 ktest1。

标签: c++ cmake


【解决方案1】:

首先,您根本不需要add_library(restbed ${LIB_PATH})。它用于在构建过程中创建您自己的库,例如 add_executable() 用于可执行文件。

其次,你必须在ktest1目标上调用target_include_directories()。

最后,在target_link_libraries() 调用中将绝对完整路径传递给库。

【讨论】:

    猜你喜欢
    • 2020-07-12
    • 2019-06-09
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    相关资源
    最近更新 更多