首页 > 解决方案 > CMake 错误 - 目标 foo INTERFACE_SOURCES 属性包含源目录中前缀的路径

问题描述

我正在尝试创建一个可以通过 CMake 重用的 C++ 库。当我尝试为项目安装导出文件时它失败了。我不明白为什么。这是我得到的错误。

Target "Proj_LibA" INTERFACE_SOURCES property contains path:

  "C:/projects/cmake_temp/src/libA/include/liba.hpp"

which is prefixed in the source directory.

阅读 CMake 文档和其他stackoverflow帖子意味着我设置源文件路径和/或包含目录的方式有问题。这是重现我的问题的 SSCE。

文件夹结构

cmake_temp/
          /build
          /install
          /src/
              /CMakeLists.txt
          /src/libA/
                   /include/liba.hpp
                   /CMakeLists.txt
                   /liba.cpp
                   /LibAConfig.cmake.in

/src/CMakeLists.txt

cmake_minimum_required (VERSION 3.15)
project("TestProj")

set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

set(include_install_dir ${CMAKE_INSTALL_PREFIX}/include/)
set(export_cmake ${CMAKE_INSTALL_PREFIX}/cmake)
set(lib_install_dir ${CMAKE_INSTALL_PREFIX}/lib)
set(bin_install_dir ${CMAKE_INSTALL_PREFIX}/bin)

add_subdirectory(libA)
#add_subdirectory(exec)

liba/include/liba.hpp

#ifndef liba
#define liba

#include "LibA_export.hpp"

class PROJ_LIBA_EXPORT Foo
{
public:
    Foo(const int bias);
    int add(int a, int b);
private:
    int mBias;
};

#endif //liba

src/liba/liba.cpp

#include "liba.hpp"
Foo::Foo(const int bias) : mBias(bias) {}
int Foo::add(int a, int b) { return a + b + mBias; }

src/liba/CMakeLists.txt

# Setup alias to support add_subdirectory, find_package, and fetchcontent usage
add_library(Proj_LibA SHARED)
add_library(proj::liba ALIAS Proj_LibA)
set_target_properties(Proj_LibA PROPERTIES
    EXPORT_NAME LibA
    POSITION_INDEPENDENT_CODE TRUE)

target_sources(Proj_LibA
    PUBLIC
        include/liba.hpp
    PRIVATE
        liba.cpp)

target_include_directories(Proj_LibA
   PUBLIC
      $<INSTALL_INTERFACE:${include_install_dir}>
      $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
      $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
   #PRIVATE
)

# Generate symbol export macros and add to source
include(GenerateExportHeader)
set(export_file "${CMAKE_CURRENT_BINARY_DIR}/LibA_export.hpp")
generate_export_header(Proj_LibA EXPORT_FILE_NAME ${export_file})
target_sources(Proj_LibA PUBLIC ${export_file})

# Install everything and mark it as part of the 'sdk' export package
install(TARGETS Proj_LibA
   EXPORT sdk
   ARCHIVE DESTINATION ${lib_install_dir}
   LIBRARY DESTINATION ${lib_install_dir}
   RUNTIME DESTINATION ${bin_install_dir}
)

# Install header files for package consumers
INSTALL(DIRECTORY include/ DESTINATION ${include_install_dir})

# Create the LibAConfig.cmake file for find_package
include(CMakePackageConfigHelpers)
configure_package_config_file(LibAConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/LibAConfig.cmake
  INSTALL_DESTINATION ${export_cmake}
  PATH_VARS include_install_dir)

# Create the LibAConfigVersion.cmake file for find_package
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/LibAConfigVersion.cmake
  VERSION 1.2.3
  COMPATIBILITY SameMajorVersion )

# Install the LibAConfig*.cmake files
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/LibAConfig.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/LibAConfigVersion.cmake
        DESTINATION ${export_cmake})

# Install the auto-generated export support/find_package scripts
install(EXPORT sdk
   DESTINATION ${export_cmake}
   NAMESPACE proj::)

# HELP: The above command triggers the following errors
#CMake Error in libA/CMakeLists.txt:
#  Target "Proj_LibA" INTERFACE_SOURCES property contains path:
#
#    "C:/projects/cmake_temp/src/libA/include/liba.hpp"
#
#  which is prefixed in the source directory.
#
#
#CMake Error in libA/CMakeLists.txt:
#  Target "Proj_LibA" INTERFACE_SOURCES property contains path:
#
#    "C:/projects/cmake_temp/build/libA/LibA_export.hpp"
#
#  which is prefixed in the build directory.

src/liba/LibAConfig.cmake.in

set(LibA_VERSION 1.2.3)

@PACKAGE_INIT@

set_and_check(LibA_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")

check_required_components(LibA)

有没有人对我在尝试导出我的库时应该查看什么来解决此错误有什么建议?

标签: c++cmake

解决方案


我昨天也遇到了这个问题。通读文档和“CMake 的共同维护者”的博客文章有助于对此有所了解(tldr;请参阅“安装的并发症”段落)。

这里的问题来自您liba.hpp被添加为PUBLIC目标源,它定义了头文件的绝对路径。find_package()这在本地计算机上的构建树中有效,但在安装、使用或将库复制到另一个源树时可能会有所不同。我认为很多人,包括我自己,都会做出与公共头文件相关的假设,PUBLICINTERFACE事实并非如此。引用上面的博客文章:

[...] 不要将 PRIVATE 、 PUBLIC 和 INTERFACE 关键字与标头是否是库的公共 API 的一部分混淆,这些关键字专门用于控制将源添加到哪些目标

就像在您提供的 SO 链接中一样(与您的代码中相同),答案指向BUILD_INTERFACEINSTALL_INTERFACE生成器表达式以解决包含目录的此问题。一种可能的解决方案是更加明确并在您的target_sources()

target_sources(Proj_LibA
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/liba.hpp>
        $<INSTALL_INTERFACE:include/liba.hpp>
    PRIVATE
        liba.cpp)

这可以说不是一个非常漂亮的解决方案,因为必须对每个头文件都这样做。另一种选择是简单地将标题移动到PRIVATE范围内。还有一个是使用PUBLIC_HEADERtarget 属性来定义你的标题并指定一个安装目标,我实际上没有尝试过这个,但是看到这个 SO


推荐阅读