【问题标题】:How to include source of external library for IntelliSense in a CMake project?如何在 CMake 项目中包含 IntelliSense 的外部库源?
【发布时间】:2019-10-15 21:27:22
【问题描述】:

我正在使用 Visual Studio 的 CMake 项目模板在 Visual Studio 中开发 C++ 应用程序。 要构建我的应用程序,我只需要标题和外部库,我可以像这样链接它:

# CMakeList.txt : CMake project for myapp, include source and define project specific logic here.

cmake_minimum_required (VERSION 3.8)

# Add source to this project's executable.
add_executable (myapp "myapp.cpp" "myapp.h")

# Add TIFF library
set(TIFF_INCLUDE_DIR "C:\\libs\\tiff\\out\\install\\x64-Debug\\include")
set(TIFF_LIBRARY "C:\\libs\\tiff\\out\\install\\x64-Debug\\lib\\tiffd.lib")
find_package(TIFF REQUIRED)
target_link_libraries(myapp PRIVATE TIFF::TIFF)

到目前为止,一切都很好。我可以使用 tiff 库来打开、读取、写入 tiff 文件等,并且 IntelliSense 正在赶上头文件中的声明。但是,我希望 IntelliSense 也能了解 TIFF 库的完整源代码。例如,如果我在 myapp.cpp 并且我在TIFFOpen 上的ctrl+click 它会打开与TIFFOpen 对应的标头,但是当我在标头文件中ctrl+click TIFFOpen 时,它不会转到对应的源文件,这是myapp中源文件的正常行为。这是可以理解的,因为我从来没有告诉 Visual Studio 在哪里可以找到外部库的源文件。

CMake 不需要知道外部库的源文件在哪里,因为它不会构建外部库,因此我想我不/不应该更改 CMakeLists.txt 中的任何内容

一个选项(我还没有尝试过,但我很确定它会起作用),就是将整个 tiff 库作为 myapp 的子项目包含在内。不过,我确实对这个解决方案有一些问题:

  1. 外部库在概念上不是项目的组成部分,我不打算修改外部库。这更像是一个原则问题。
  2. 只是将其作为我的项目中的子文件夹,就有可能更改我不打算更改的内容。
  3. 我不想在全部重建时重建外部库。我知道 Visual Studio / CMake 足够聪明,可以发现没有任何变化并且不会重建,但我宁愿让 Visual Studio / CMake 甚至不尝试。

在我看来,我必须在 Visual Studio 设置中的某处设置包含源文件的目录,但仍与项目相关。我最好的猜测是.vs/ProjectSettings.json 是我需要以某种方式编辑的文件,但老实说,我不知道。

或者,也许我可以在CMakeLists.txt 中编写一些命令,该命令不执行任何操作,但会触发 IntelliSense 以查看包含源文件的文件夹。再说一次,我不知道该怎么做。

简而言之,我希望 IntelliSense 能够查看外部库的所有源文件,就像查看 myapp 的源文件一样,而不会将外部库的所有源文件都包含为 myapp 的子项目。如果可能的话,我应该怎么做?

如果相关,我使用 Visual Studio 2019 社区和它附带的 CMake (3.15)。

【问题讨论】:

  • 首先,您不需要手动设置 TIFF_INCLUDE_DIR 和 TIFF_LIBRARY,因为 find_package 和 target_link_libraries 设置了所有内容,并且永远不需要这些变量。其次,cmake 有一个名为“exclude from all”的目标属性,它保证永远不会构建目标,您可以包含 tiff 项目并将其设置为该属性,但这确实违反了您根本不将其包含为子项目的意图。
  • @X.Sun 我还认为find_package() 至少会尝试搜索我的文件以找到该包,但事实并非如此。如果不设置TIFF_ 变量,我会收到此错误Could NOT find TIFF (missing: TIFF_LIBRARY TIFF_INCLUDE_DIR)。最终我更喜欢这种方式,因为我电脑上的各种应用程序都有一些版本的 TIFF 库,我更喜欢使用我个人指定的特定版本。 “排除所有”属性似乎是一个公平的妥协。我希望有一个更好的解决方案,但如果一切都失败了......
  • 在这种情况下,您可能需要检查您安装的 tiff 库在其安装文件夹中是否有完整的 cmake 导出文件,例如 TIFFConfig.cmake 和 TIFFConfigVersion.cmake,可以通过系统的 Path 变量找到它们(显然您使用的是 Windows,因此应在安装后手动设置)。现代 cmake 只需要 find_package 和 target_link_libraries。 cmake 文件也区分大小写,Tiff 和 TIFF 是不同的。但坦率地说,很多库还没有切换到现代 cmake 并且没有适当的导出,甚至是一些基本的。
  • 我还注意到您添加了“tiffd.lib”,这意味着始终使用 tiff 库的调试版本。正确的 cmake 设置会根据您的构建配置在“tiff.lib”和“tiffd.lib”之间切换,这只是一个提示,以防您在构建发布二进制文件时遇到其他问题。
  • @X.Sun 非常感谢您花时间帮助我。我刚刚下载了官方的最新版本,用VS打开,然后Build,然后Install,并没有在任何地方创建TIFFConfig.cmake或TIFFConfigVersion.cmake,但我猜libtiff-4.pc可能是TIFFConfigVersion.cmake文件

标签: c++ visual-studio cmake intellisense


【解决方案1】:

关于你最后的评论,在评论部分写代码很不方便,所以我就在这里发布,虽然不是答案。

libtiff-4.pc 用于 pkg-config,而不是 cmake,find_package() 不能直接在 Windows 上处理它,如果你真的想的话,需要做一些工作。手动编写所有内容可能更容易。记得根据你的配置设置tiff.libtiffd.lib。你可以使用CMAKE_BUILD_TYPE变量和if()命令如:

# set build type to release if not specified
if(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "")
    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type" FORCE)
endif()
# switch lib to link according to build type
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    # for release
    set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiff.lib")
else()
    # for debug. If you have other configs like relwithdebinfo you can add more
    set(TIFF_LIBRARY "<your_path_to_installed_lib>/tiffd.lib")
endif()

另外,删除find_package() 并使用target_link_libraries()target_inlude_directories()

set(TIFF_INCLUDE_DIR "<your_path_to_installed_headers>/include")
target_link_libraries(myapp PRIVATE ${TIFF_LIBRARY})
target_include_directories(myapp PRIVATE ${TIFF_INCLUDE_DIR})

你也可以跳过设置TIFF_LIBRARYTIFF_INCLUDE_DIR,如果你喜欢直接传递字符串。

我经常使用 Visual Studio,它是我最喜欢的 IDE。但是在 Windows 上使用 cmake 进行包管理不如 Linux 流畅。永远记得在编译和安装外部库之后设置环境变量。

find_package() 通常会查找名为&lt;libname&gt;_DIR 的系统环境变量(例如TIFF_DIR,在您的情况下未找到),用于存储已安装库的路径,然后查找&lt;libname&gt;Config.cmake和该文件夹中的&lt;libname&gt;ConfigVersion.cmakeTIFF 会失败,因为它没有它们)。

它还会搜索其他地方,详情请查看https://cmake.org/cmake/help/v3.15/command/find_package.html?highlight=find_package

所以对于那些带有 cmake 导出文件的库,添加一个具有正确名称和值的变量。这只是为了编译。

如果您希望您的应用程序在编译后运行,您还需要将已安装 lib 的二进制文件(通常是 *.dll)的路径添加到系统的 Path 变量中。在您的情况下,您应该在编译和安装后找到tiff.dlltiffd.dll 之类的东西,将该文件夹添加到Path 就可以了。

【讨论】:

  • 感谢您提供的所有信息。为了清楚起见,使用问题中列出的配置,它已经可以使用 TIFF 库(提到确实我严格链接到调试版本,我应该按照您的建议进行更改)。我的主要问题是智能感知只能到达标题。考虑到这一点,我预见到 myapp 增长时会出现麻烦,我需要更认真的调试。
【解决方案2】:

实际上,在 IDE 中显示源代码很容易。

只需使用add_library(tiff_for_ide EXCLUDE_FROM_ALL ${SOURCES}) 添加源代码,但不要在主程序中链接它。您需要为库使用不同的目标名称。为此,您需要直接或作为子模块在项目中使用源代码(如果使用 Git,如果您的 VCS 可用,则需要其他东西)。

其他选项使用ExternalModule_Add;或FetchContent_MakeAvailableadd_library 同上,以避免将第三方deps 直接添加到存储库中。

现在,只是祈祷,希望 IDE 不够智能,无法限制搜索与编译当前文件的目标链接的源。或者它足够智能,可以检测到这种情况,但当它链接到二进制文件时,无论如何都会回退到搜索整个项目文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 2018-08-25
    • 1970-01-01
    • 2015-04-29
    • 2020-07-17
    相关资源
    最近更新 更多