- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一个用 C++ 编写的项目,我正在使用 cmake 来构建它。该项目有许多子项目,其中一个是其他子项目所需的库。我可以编译 .so 并将其移动到构建目录添加_库,和安装(目标...)
但是我还需要将 lib 的头文件安装在构建目录的 include 目录下。我使用 install(FILES ...) 来完成它,但它似乎根本没有做任何事情。
为了演示它,我通过 qtcreator 创建了一个测试项目,
& ls test
CMakeLists.txt empty.hh main.cpp
$ cat test/CMakeLists.txt
project(test)
cmake_minimum_required(VERSION 2.8)
install(FILES empty.hh DESTINATION include)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
$ cat test/main.cpp
#include
using namespace std;
int main()
{
cout << "Hello World!" << endl;
return 0;
}
$ cat test/empty.hh
#ifndef EMPTY_HH
#define EMPTY_HH
#endif // EMPTY_HH
If the files under "test" qtcreator will compile (by default) the files to test-build.
$ ls test-build/
CMakeCache.txt CMakeFiles Makefile cmake_install.cmake test test.cbp
$ ./test-build/test
Hello World!
如您所见,没有包含目录或空的.hh 文件。也试过用
install(FILES empty.hh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
但是还是看不到头文件。
$ cmake --help
cmake version 2.8.12
如果你有任何想法,请告诉我。
最佳答案
在构建时使用install
命令来移动文件通常是一种糟糕的方法。该命令旨在用于设置文件和目标,这些文件和目标将在用户执行 make install
或等效操作时安装。由于您没有运行 make install
,我想这就是 install(FILES ...)
命令似乎不起作用的原因。
这里有一些略有不同的方法来完成这项工作。
如果没有必要,我建议不要移动标题。假设您的库名为 MyLib
,那么您可以通过 target_include_directories
将这些 header 作为 MyLib
目标的一部分提供。 :
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
这意味着如果有一个依赖目标,例如 MyExe
:
target_link_libraries(MyExe MyLib)
然后它会自动访问 MyLib
的源目录。
如果库的目录结构不适合将 API header 与其余源和 header 分开,这可能不太理想。 Say MyLib
由以下文件组成:my_lib.cpp、my_lib_api.hh(API header - 供其他项目包含)和 my_lib_detail.hh(不供其他项目包含)。理想的结构是将 API header 与其余部分分开,例如
/my_lib
- CMakeLists.txt
- src/
- my_lib.cpp
- my_lib_detail.hh
- include/
- my_lib/
- my_lib_api.hh
有了这个结构你就可以指定
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
和MyLib
源将能够包含#include "my_lib_detail.hh"
和#include "my_lib/my_lib_api.hh"
,但依赖目标的源代码只能包含#include "my_lib/my_lib_api.hh"
。
因此,如果 MyLib
只有一个平面结构或没有将内部 header 与 API header 分开,您可能需要将 API header 复制到构建树中的某个位置并添加 target_include_directories
调用的路径。在这种情况下,如果 MyLib
本身不需要访问复制的文件(只是源代码树中的原始文件),您可以使用 INTERFACE
而不是 PUBLIC
在 target_include_directories
调用中。
然而,这个问题的关键(我想是在回答你的实际问题)是将这些文件复制为配置过程(当 CMake 运行时)或构建过程(当 make 运行时)的一部分 - 而不是作为安装过程。
因此,我们假设 MyLib
没有上面显示的有用目录结构,而是扁平的(即 CMakeLists.txt 和三个源文件都在同一个目录中)目录)。我们可以使用构建后命令将 API header 复制到构建树中:
project(my_lib)
cmake_minimum_required(VERSION 2.8.12.2) # for 'target_include_directories'
add_library(MyLib SHARED my_lib.cpp my_lib_api.hh my_lib_detail.hh)
target_include_directories(MyLib INTERFACE "${CMAKE_BINARY_DIR}/include"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/include/my_lib")
add_custom_command(TARGET MyLib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/my_lib_api.hh"
"${CMAKE_BINARY_DIR}/include/my_lib"
COMMENT "Copying MyLib public headers to ${CMAKE_BINARY_DIR}/include/my_lib"
VERBATIM)
然后对于 MyExe
的 CMakeLists.txt,你可以这样做:
project(my_exe)
cmake_minimum_required(VERSION 2.8.12.2)
add_executable(MyExe main.cpp)
target_link_libraries(MyExe MyLib)
# Copy MyLib.so to this build dir to allow MyExe to find it at runtime
add_custom_command(TARGET MyExe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:MyLib>"
"$<TARGET_FILE_DIR:MyExe>"
VERBATIM)
这对于 MSVC 不会按原样工作 - 您需要处理 Windows 导出库(有关更多详细信息,请参阅 CMake wiki 和 GenerateExportHeader
的文档),但它只涉及添加诸如以下是 MyLib
的 CMakeLists.txt:
include(GenerateExportHeader)
generate_export_header(MyLib
BASE_NAME MyLib
EXPORT_MACRO_NAME MyLib_EXPORT
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"
STATIC_DEFINE MyLib_BUILT_AS_STATIC)
如果你确实需要这个,你必须在 target_include_directories(MyLib ...)
中将 INTERFACE
更改为 PUBLIC
,因为 MyLib
本身将需要访问生成的文件 "${CMAKE_BINARY_DIR}/include/my_lib/my_lib_export.hh"
。
关于c++ - cmake install(FILES ...) 似乎不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27665939/
我是 Maven 新手,正在尝试了解它是如何工作的。 我知道生命周期由多个阶段组成。阶段称为他们的魔力。如果调用一个阶段,则前面的所有阶段也会执行。例如,当我调用 mvn install 时就会发生这
我想安装Ros(机器人操作系统)的驱动程序,我有两个选项:二进制安装和从源代码编译安装。我想知道哪种安装更好,每种安装有哪些优点和缺点。 最佳答案 源:又称源代码,通常位于某种 tarball 或 z
以及更具体的问题。我的理解对吗: “nuget install”总是安装到您运行它的目录吗? “choco install”安装到特殊的 choco 目录,然后运行脚本在系统中传播它? “nuget
我创建了 Android 项目,但随后我立即得到出现错误的信息。 Warning:(22, 12) Dependency on a support library, but the SDK insta
我的安装程序有 32 位和 64 位版本,它们具有(几乎)完全相同的代码和自定义操作序列(只有与此问题无关的细微差别) 我希望我的安装程序能够检测它之前是否已安装,并在这种情况下运行我自己的代码,而不
我在TFS版本中使用npm install cmd。我总是得到以下警告: npm WARN optional dep failed, continuing fsevents@0.3.1 如何删除此警告
是否可以将install(TARGETS ...)与在add_subdirectory添加的目录中定义的目标一起使用? 我的用例是,我想为gtest构建一个rpm的e.gg。 gtest项目恰好有一个
我需要使用 MSI 创建安装程序,其目的是根据用户的区域(从环境变量读取)调用正确的安装程序。也就是说,这个安装程序应该有 3 个文件(它们本身就是安装程序),一个用于美国,一个用于欧洲,一个用于亚洲
我正在尝试通过 Android Studio 3.5 在我的小米 RedMi S2 上运行我的应用程序。在手机上安装应用程序时抛出错误: Installation did not succeed. T
使用govendor时,go install、govendor install +local和govendor install +vendor,^program有什么区别? govendor inst
我用谷歌搜索了很多,但找不到答案。因此,在 Windows Installer 属性值中可以存储多少个字符。如果你给出答案,你能提供答案的来源吗? 最佳答案 我问 Windows Installer
Cuda v9.0 有几个补丁 我应该安装最新补丁还是安装所有补丁? https://developer.nvidia.com/cuda-90-download-archive?target_os=W
我正在尝试通过它的文档安装 phalcon!在这一步我有一个错误: installation/FreeBSD Command: pkg_add -r phalcon 错误: 'pkg_add' is
我有一个安装,如果应用程序退出,它会升级该应用程序的先前版本。当安装处于升级模式时,我想跳过某些操作。如何确定安装是在升级模式还是首次安装模式下运行? 我正在使用 Wise Installer,但我认
MSI 数据库包含一个表 MsiFileHash 。根据文档MsiFileHash 表用于存储 Windows Installer 包提供的源文件的 128 位哈希。 有人知道使用/应该使用什么哈希算
我尝试在本地和全局运行 npm install browserify (-g) 但我总是遇到以下错误 npm ERR! peerinvalid The package bn.js does not s
我有一个用于我正在构建的 python 模块的 SConstruct 文件: import distutils.sysconfig env = Environment(CPPPATH=['includ
使用 Installshield 2010 和 Basic MSI 项目。 我有一个之前由我的安装程序安装的 exe。该 exe 需要在安装程序升级期间运行。有没有办法保证安装程序不会尝试关闭进程?基
我是围棋初学者。我试图编译一个 go 项目,但找不到任何解释“/...”的文档或文章。 cd ~/src/ephenation-server go install -v ./... 等待您的帮助。 最
我试过在选择和不选择‘安装Mongo指南针’选项的情况下运行安装程序,但我仍然无法安装它,也无法取消安装。然后,此设置对话冻结20-30分钟以上,没有任何进展。这实际上就是从他们的website(ht
我是一名优秀的程序员,十分优秀!