Cmake 链接共享库:包含库中的头文件时“没有这样的文件或目录”

Kat*_*Lee 4 c++ cmake shared-libraries

我正在学习使用 Cmake 构建一个库。构建库的代码结构如下:

include:  
   Test.hpp       
   ITest.hpp     // interface
src:
   Test.cpp
   ITest.cpp
Run Code Online (Sandbox Code Playgroud)

在CMakeLists.txt中,我用来建库的语句是:

file(GLOB SRC_LIST "src/iTest.cpp" "src/Test.cpp" "include/Test.hpp"
        "include/iTest.hpp"  "include/deadreckoning.hpp")
add_library(test SHARED ${SRC_LIST})
target_link_libraries( test ${OpenCV_LIBS})  // link opencv libs to libtest.so
Run Code Online (Sandbox Code Playgroud)

然后我又写了一个测试文件(main.cpp),把库复制粘贴到同一个目录下,链接库,调用库里面的函数。这个 CMakeLists.txt 是

cmake_minimum_required(VERSION 2.8)
project(myapp)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -O3 -Wall -ftree-vectorize -ffast-math -funroll-loops")

add_executable(myapp main.cpp)
target_link_libraries(myapp "/home/labUser/test_lib/libtest.so")
Run Code Online (Sandbox Code Playgroud)

如果我不将头文件包含在库中,则 main.cpp 将成功编译并运行:

#include <iostream>
using namespace std;

int main(){
    cout << "hello world" << endl;
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

但是当我包含头文件时#include "ITest.hpp",它有错误:

fatal error: iTest.hpp: No such file or directory
  #include "iTest.hpp"   
compilation terminated.
Run Code Online (Sandbox Code Playgroud)

我不明白为什么会这样。我想我已经成功链接了库,因为当我在不包含头文件的情况下运行 main.cpp 时,它不会给出任何“链接”错误。而且我认为显然头文件在库中。为什么我不能包括它?谁能帮我解决这个问题?

十分感谢!

Ste*_*mer 6

你在这里有几个问题。

将标头传播给目标用户:

虽然您已将包含文件添加到库目标,但您需要让库目标的使用者知道如何找到标头。

因此,当您的应用myapp链接到您的库 target 时test,您需要告诉 cmake 添加./includemyapp's包含搜索路径。

有一个特殊的 cmake 变量,${CMAKE_CURRENT_LIST_DIR}它解析为当前CMakeLists.txt正在处理的目录的路径。

在您的实例,这是两者的父文件夹srcinclude

./                    <-- ${CMAKE_CURRENT_LIST_DIR} is this directory
+--- CMakeLists.txt
+--- src/
|    +---Test.cpp
|    +---ITest.cpp
+--- include/
     +---Test.hpp
     +---ITest.hpp
Run Code Online (Sandbox Code Playgroud)

为了告诉 cmake 添加一个路径到你使用的包含搜索路径 target_include_directories

为此,路径将是 ${CMAKE_CURRENT_LIST_DIR}/include

所以你要找的语法是:

target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
Run Code Online (Sandbox Code Playgroud)

请注意,这意味着您不必将"include/iTest.hpp"和添加"include/Test.hpp"到您的SRC_LISTglob 中,因为编译器将能够从上面找到它们target_include_directories

链接到您的测试库:

现在您已经创建了您的库并添加了包含目录,要在您的应用程序中实际使用它,您应该再次使用target_link_libraries,但不要指定生成.so文件的路径,而是引用您创建的库目标的名称,test

target_link_libraries(myapp test)
Run Code Online (Sandbox Code Playgroud)

现在myapp将知道如何查找,Test.hpp因为它将从您在myapp和之间创建的“依赖链接”中获取该信息test

因此,假设以下目录结构,以下 CMakeLists.txt 文件可能会起作用

src/
+--- library/
|    +--- < sources for your shared library >
+--- app/
     +--- < sources for your application >
Run Code Online (Sandbox Code Playgroud)

src/CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
project(myapp)

add_subdirectory(library)
add_subdirectory(app)
Run Code Online (Sandbox Code Playgroud)

src/library/CMakeLists.txt

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} 
    -std=c++11 
    -pthread 
    -O3 
    -Wall 
    -ftree-vectorize 
    -ffast-math 
    -funroll-loops")

find_package(OpenCV REQUIRED)

add_library(test SHARED "src/iTest.cpp src/Test.cpp")
target_link_libraries(test ${OpenCV_LIBS})  // link opencv libs to libtest.so
target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
Run Code Online (Sandbox Code Playgroud)

src/app/CMakeLists.txt

add_executable(myapp main.cpp)
target_link_libraries(myapp test)
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的回答!我试图修改库 CMakeLists,但在编译时出现错误:target_include_directories 调用了无效参数 你知道为什么吗?我需要指定 ${CMAKE_CURRENT_LIST_DIR} 在哪里吗? (2认同)