【问题标题】:Cmake Linking Shared Library: "No such file or directory" when include a header file from libraryCmake链接共享库:从库中包含头文件时“没有这样的文件或目录”
【发布时间】:2018-04-14 02:00:44
【问题描述】:

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

include:  
   Test.hpp       
   ITest.hpp     // interface
src:
   Test.cpp
   ITest.cpp

在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

然后我又写了一个测试文件(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")

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

#include <iostream>
using namespace std;

int main(){
    cout << "hello world" << endl;
    return -1;
}

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

fatal error: iTest.hpp: No such file or directory
  #include "iTest.hpp"   
compilation terminated.

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

非常感谢!

【问题讨论】:

    标签: c++ cmake shared-libraries


    【解决方案1】:

    这里有几个问题。

    向目标用户传播标头:

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

    因此,当您的应用程序 myapp 链接到您的库目标 test 时,您需要告诉 cmake 将 ./include 添加到 myapp'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
    

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

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

    所以您要查找的语法是:

    target_include_directories(test PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
    

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

    链接到您的测试库:

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

    target_link_libraries(myapp test)
    

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

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

    src/
    +--- library/
    |    +--- < sources for your shared library >
    +--- app/
         +--- < sources for your application >
    

    src/CMakeLists.txt

    cmake_minimum_required(VERSION 3.0)
    project(myapp)
    
    add_subdirectory(library)
    add_subdirectory(app)
    

    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)
    

    src/app/CMakeLists.txt

    add_executable(myapp main.cpp)
    target_link_libraries(myapp test)
    

    【讨论】:

    • 感谢您的回答!我试图修改库 CMakeLists,但编译时出现错误:target_include_directories called with invalid arguments 你知道为什么吗?我需要指定 ${CMAKE_CURRENT_LIST_DIR} 的位置吗?
    • @KathyLee 看起来您使用的是旧版本的 cmake。你能升级到更新的版本吗? (cmake 2.8 已经很老了)
    • @KathyLee 如果无法升级,请尝试使用${CMAKE_CURRENT_SOURCE_DIR},我相信这个变量存在于 2.8 中
    • @KathyLee 对于这么小的东西,您可以添加 include_directories(include)
    • @afakih 不建议这样做,对于尝试学习 cmake 的人来说,教授最佳实践可能是个好主意
    猜你喜欢
    • 2021-10-17
    • 2020-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-07
    • 1970-01-01
    • 2016-11-01
    • 2019-02-16
    相关资源
    最近更新 更多