c++ - 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)
有没有人对我在尝试导出我的库时应该查看什么来解决此错误有什么建议?
解决方案
我昨天也遇到了这个问题。通读文档和“CMake 的共同维护者”的博客文章有助于对此有所了解(tldr;请参阅“安装的并发症”段落)。
这里的问题来自您liba.hpp
被添加为PUBLIC
目标源,它定义了头文件的绝对路径。find_package()
这在本地计算机上的构建树中有效,但在安装、使用或将库复制到另一个源树时可能会有所不同。我认为很多人,包括我自己,都会做出与公共头文件相关的假设,PUBLIC
但INTERFACE
事实并非如此。引用上面的博客文章:
[...] 不要将 PRIVATE 、 PUBLIC 和 INTERFACE 关键字与标头是否是库的公共 API 的一部分混淆,这些关键字专门用于控制将源添加到哪些目标
就像在您提供的 SO 链接中一样(与您的代码中相同),答案指向BUILD_INTERFACE
和INSTALL_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_HEADER
target 属性来定义你的标题并指定一个安装目标,我实际上没有尝试过这个,但是看到这个 SO。
推荐阅读
- html - 仅为 Safari 浏览器添加选择选项
- c++ - 通过 xarray 中的索引分配值分配整个数组
- vue.js - axios 调用带有 vuejs 和 nuxt 的方法
- c# - 用 C# 克隆一个简单的盒装类型
- javascript - 无法在纯 CSS 中显示关闭按钮
- html - CSS 和 rem:更改 html 字体大小会导致尺寸不一致
- python - 在python中使用RegEx将某个字符替换为以下模式
- c# - Azure 身份验证服务在发布后不起作用
- javascript - 反应 routings-url 的变化。但不渲染组件。刷新页面时完美呈现
- tensorflow - 同一训练集上的Tensorflow变量值不同