0

我有一个项目,我想在其中使用nghttp2库。我正在尝试链接这个项目,CMakeLists.txt以便我可以用cmake.

我的项目结构

.
├── CMakeLists.txt
├── lib
│   ├── Catch2
│   └── nghttp2
├── README.md
└── src
    ├── main
    |  └── Main.cpp
    └── test

导入的主程序nghttp2

#include <iostream>
#include <nghttp2/asio_http2.h>
#include <nghttp2/asio_http2_server.h>
#include <boost/circular_buffer.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/thread.hpp>
#include <boost/timer/timer.hpp>
#include <boost/call_traits.hpp>
#include <boost/bind.hpp>
#include <boost/log/trivial.hpp>
#include <string>
#include <limits>

using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;

int main(int argc, char *argv[]) {
    boost::system::error_code ec;
    http2 server;

    server.handle("/", [](const request &req, const response &res) {
        res.write_head(200);
        res.end("hello, world\n");
    });

    if (server.listen_and_serve(ec, "localhost", "3000")) {
        std::cerr << "error: " << ec.message() << std::endl;
    }
}

我的CMakeLists.txt文件如下

cmake_minimum_required(VERSION 3.16.3)
project(my-project)

set(CMAKE_CXX_STANDARD 14)

set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build)
set(LIBRARY_NAME ${PROJECT_NAME})
set(TEST_NAME tests)

add_executable(
        ${PROJECT_NAME}

        src/main/Main.cpp
)

find_package(Threads REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
find_package(Boost REQUIRED COMPONENTS thread)
find_package(Boost REQUIRED COMPONENTS log)
find_package(OpenSSL REQUIRED)

target_link_libraries(
        ${PROJECT_NAME}

        PRIVATE Threads::Threads
        PRIVATE Boost::system
        PRIVATE Boost::thread
        PRIVATE Boost::log
        PRIVATE OpenSSL::Crypto
)

set(NGHTTP2_SRC_DIR lib/nghttp2)
add_subdirectory(${NGHTTP2_SRC_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC nghttp2)

target_include_directories(
        ${LIBRARY_NAME} PRIVATE
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/${LIBRARY_NAME}>
        $<INSTALL_INTERFACE:include/${LIBRARY_NAME}>
)
target_include_directories(
        ${LIBRARY_NAME} PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
)


# Catch2
set(CATCH2_SRC_DIR lib/Catch2)
add_subdirectory(${CATCH2_SRC_DIR})
add_executable(${TEST_NAME} src/test/Test.cpp)
target_link_libraries(${TEST_NAME} PRIVATE Catch2::Catch2WithMain)
include(${CATCH2_SRC_DIR}/extras/Catch.cmake)
include(${CATCH2_SRC_DIR}/extras/ParseAndAddCatchTests.cmake)
list(APPEND CMAKE_MODULE_PATH ${CATCH2_SRC_DIR}/extras)
include(CTest)
catch_discover_tests(${TEST_NAME})

当我运行makecmake .出现以下错误

/usr/bin/ld: CMakeFiles/my-project.dir/src/main/Main.cpp.o: in function `std::_Function_handler<void (nghttp2::asio_http2::server::request const&, nghttp2::asio_http2::server::response const&), main::{lambda(nghttp2::asio_http2::server::request const&, nghttp2::asio_http2::server::response const&)#1}>::_M_invoke(std::_Any_data const&, nghttp2::asio_http2::server::request const&, nghttp2::asio_http2::server::response const&)':
/home/username/CLionProjects/myproject/src/main/Main.cpp:23: undefined reference to `nghttp2::asio_http2::server::response::write_head(unsigned int, std::multimap<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, nghttp2::asio_http2::header_value, 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, nghttp2::asio_http2::header_value> > >) const'
/usr/bin/ld: CMakeFiles/my-project.dir/src/main/Main.cpp.o: in function `operator()':
/home/username/CLionProjects/myproject/src/main/Main.cpp:24: undefined reference to `nghttp2::asio_http2::server::response::end(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const'
/usr/bin/ld: CMakeFiles/my-project.dir/src/main/Main.cpp.o: in function `main.cold':
/home/username/CLionProjects/myproject/src/main/Main.cpp:20: undefined reference to `nghttp2::asio_http2::server::http2::~http2()'
/usr/bin/ld: CMakeFiles/my-project.dir/src/main/Main.cpp.o: in function `main':
/home/username/CLionProjects/myproject/src/main/Main.cpp:20: undefined reference to `nghttp2::asio_http2::server::http2::http2()'
/usr/bin/ld: /home/username/CLionProjects/myproject/src/main/Main.cpp:22: undefined reference to `nghttp2::asio_http2::server::http2::handle(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<void (nghttp2::asio_http2::server::request const&, nghttp2::asio_http2::server::response const&)>)'
/usr/bin/ld: /home/username/CLionProjects/myproject/src/main/Main.cpp:27: undefined reference to `nghttp2::asio_http2::server::http2::listen_and_serve(boost::system::error_code&, 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&, bool)'
/usr/bin/ld: /home/username/CLionProjects/myproject/src/main/Main.cpp:20: undefined reference to `nghttp2::asio_http2::server::http2::~http2()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/my-project.dir/build.make:95: build/my-project] Error 1
make[1]: *** [CMakeFiles/Makefile2:942: CMakeFiles/my-project.dir/all] Error 2
make: *** [Makefile:141: all] Error 2

Main.cpp我可以手动编译

g++  Main.cpp -o Main.out -DBOOST_LOG_DYN_LINK -lboost_log -lnghttp2_asio -lboost_system -lcrypto -lpthread -lssl -lboost_thread

编辑:

我首先nghttp2在我的机器上安装它来编译它。然后将这一行添加到CMakeLists.txt

target_link_libraries(${PROJECT_NAME} PUBLIC /usr/local/lib/libnghttp2_asio.so)

有没有更优雅的方法来做到这一点?

4

1 回答 1

0

要回答您在编辑初始消息后添加的问题,您可以避免使用 CMake 的 find_library 手动指定 libnghttp2_asio.so 的完整路径,如下所示:

find_library(nghttp2_asio_LIBRARY NAMES nghttp2_asio)
target_link_libraries(${PROJECT_NAME} PUBLIC nghttp2_asio)

但是,您正在混合两种不同的方式将外部库添加到您的项目中。由于您已经在项目中包含了 nghttp2 的源代码,因此您不应该将您的程序与您在系统范围内安装的另一个版本的 nghttp2 链接起来,至少有两个原因:

  • 您在项目中包含的 nghttp2 标头可能与您在系统范围内安装的 nghttp2 库的版本不匹配,这可能会导致链接错误
  • 如果有人克隆了你的代码,他们也必须在他们的系统上安装 nghttp2,他们可能会遇到与前一点解释的相同的链接错误

相反,我建议您按照最初的计划从源代码构建 libnghttp2_asio。

为了解决您最初的问题,您应该链接到正确的库(nghttp2_asio 而不是 nghttp2)并在构建 nghttp2 时设置标志 --enable-asio-lib。这是您的 CMake 的外观:

set(NGHTTP2_SRC_DIR lib/nghttp2)
set(ENABLE_ASIO_LIB ON)
add_subdirectory(${NGHTTP2_SRC_DIR})
target_link_libraries(${PROJECT_NAME} PUBLIC nghttp2_asio)

此外,您必须在第一次调用 target_link_libraries 时将 Boost::asio 添加到库列表中,如 nghttp2 的文档中所述:

默认情况下不构建 libnghttp2_asio。使用 --enable-asio-lib 配置标志来构建 libnghttp2_asio。所需的 Boost 库是:Boost::Asio、Boost::System 和 Boost::Thread。

于 2021-09-04T18:15:05.873 回答