设置lib的属性
1. target_include_directories
target_include_directories
是CMake的一个命令,用于特定的目标添加包含目录,包含目录是编译器在查找头文件会搜索的目标。
set(_INCLUDE_DIR
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/3rdparty/plog
${CMAKE_SOURCE_DIR}/3rdParty/OpenCV460/include
)
set(_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src)
target_include_directories(${output_name_dynamic} PUBLIC
$<BUILD_INTERFACE:${_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>
)
1.1 BUILD_INTERFACE 和 <INSTALL_INTERFACE:include> 生成表达式
BUILD_INTERFACE
是CMake生成表达式的一部分,,通常用在target_include_directories
或target_link_libraries
等命令中,用于区分构建阶段和安装阶段。生成表达式是CMake的一种特性,它们在生成阶段被求值。
在构建阶段会被求值为一个路径,但是在安装阶段会被求值为空。
例如,下面的命令为目标添加一个包含目录:
target_include_directories(my_target PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include
)
在这个例子中,${CMAKE_SOURCE_DIR}/include
目录在构建阶段会被添加到包含目录中,但是在安装阶段不会。这意味着构建阶段,编译器会在${CMAKE_SOURCE_DIR}/include
目录中查找文件,但是在安装阶段不会。
这种使用生成表达式的方式可以在构建和安装阶段使用不同的包含目录,这在创建可安装的库时非常有用。
同理: $<INSTALL_INTERFACE:dir>
生成表达式在构建阶段被求值为空,在安装阶段被求值为dir。
这个命令使得在安装阶段添加包含目录。
2. set_target_properties
set_target_properties(${output_name_dynamic}
PROPERTIES
DEBUG_POSTFIX "d"
CXX_STANDARD 17
)
CMake代码使用set_target_properties
命令为${output_name_dynamic}
目标设置了一些属性。
- FOLDER Lib设置了目标在IDE中的文件夹。在这个例子中,目标会被放在名为"Lib"的文件夹中。
- CXX_STANDARD 17设置了目标的C++标准。在这个例子中,目标会使用C++17标准进行编译。
3. install FILES 安装头文件及PDB
使用 install (FILES) 安装头文件
install(FILES ${mfmeidabase_HEADERS} DESTINATION include/aibase)
install(FILES ${media_HEADERS} DESTINATION include/media)
install(FILES ${simple_HEADERS} DESTINATION include/mediawrapper)
安装PDB
install(FILES $<TARGET_PDB_FILE:${output_name_dynamic}> DESTINATION bin OPTIONAL)
4. install TARGETS 安装 库
这段CMake代码使用install命令为${output_name_dynamic}
目标设置了安装规则。
EXPORT ${output_name_dynamic}Targets
表示在安装目标时,也会导出一个名为${output_name_dynamic}Targets
的导出文件。这个导出文件可以被其他CMake项目使用,以便在其他项目中使用这个目标。
LIBRARY DESTINATION lib表示库目标(如果存在)会被安装到lib目录。
ARCHIVE DESTINATION lib表示静态库目标(如果存在)会被安装到lib目录。
RUNTIME DESTINATION bin表示运行时目标(例如可执行文件和模块)会被安装到bin目录。
INCLUDES DESTINATION include表示目标的公共头文件会被安装到include目录。
这些目录是相对于安装前缀的,安装前缀可以在调用CMake时通过CMAKE_INSTALL_PREFIX
变量设置。例如,如果安装前缀是/usr/local,那么库目标会被安装到/usr/local/lib目录,运行时目标会被安装到/usr/local/bin目录,公共头文件会被安装到/usr/local/include目录。
5. include(CMakePackageConfigHelpers)
include(CMakePackageConfigHelpers)
是CMake的一个命令,它包含了CMakePackageConfigHelpers
模块。
CMakePackageConfigHelpers
模块提供了一些函数和宏,用于创建和安装CMake包配置文件。这些配置文件可以让其他CMake项目更容易地使用你的项目。
例如,CMakePackageConfigHelpers
模块提供了configure_package_config_file
函数,你可以使用这个函数来创建一个包配置文件。这个函数会将一个输入文件复制到一个输出文件,并替换输入文件中的一些变量。
这个模块还提供了write_basic_package_version_file
函数,你可以使用这个函数来创建一个包版本文件。这个函数会生成一个文件,这个文件定义了一个CMake变量,这个变量包含了包的版本信息。
5.1 write_basic_package_version_file
write_basic_package_version_file(
${output_name_dynamic}Version.cmake
COMPATIBILITY AnyNewerVersion)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${output_name_dynamic}Version.cmake"
DESTINATION share/MFMeidaCapture)
这段CMake代码使用write_basic_package_version_file函数创建了一个包版本文件。
${output_name_dynamic}Version.cmake
是输出文件的名字,${output_name_dynamic}
是一个变量,它应该在之前被设置为一个字符串。
COMPATIBILITY AnyNewerVersion
表示这个包与任何新版本兼容。这意味着如果其他项目要求一个更高的版本,CMake会认为这个包满足要求。
write_basic_package_version_file函数会生成一个文件,这个文件定义了一个CMake变量,这个变量包含了包的版本信息。这个文件可以被其他CMake项目使用,以便在其他项目中使用这个包。
此外还需要用install 来安装到目标地址,不然不会生成。
5.2 安装 xxxTarget.cmake
install(EXPORT ${output_name_dynamic}Targets
FILE ${output_name_dynamic}Targets.cmake
NAMESPACE mfcap::
DESTINATION share/MFMeidaCapture)
- FILE
${output_name_dynamic}Targets.cmake
表示导出文件的名字是${output_name_dynamic}Targets.cmake
。 NAMESPACE mfcap::
表示在导出文件中,所有的目标都会被添加一个mfcap::的命名空间前缀
这个install命令会在安装阶段生成一个导出文件,这个导出文件包含了目标的信息,例如目标的类型、源文件、编译选项、依赖关系等。这个导出文件可以被其他CMake项目使用,以便在其他项目中使用这个目标。
例如,如果${output_name_dynamic}
被设置为mylib,那么这个命令会创建一个名为mylibTargets.cmake的导出文件。这个文件可以被其他项目使用,以便在其他项目中使用mfcap::mylib目标。
NAMESPACE
在这个例子中,如果MyTargets导出文件中有一个名为mylib的目标,那么在导出文件中,这个目标的名字会变成mfcap::mylib。
其他CMake项目中使用这个命名空间前缀来引用这个目标。例如,你可以使用find_package(mfcap)和target_link_libraries(my_target mfcap::mylib)来在你的项目中使用mfcap::mylib目标。
这个命名空间前缀有两个作用:
- 避免命名冲突。如果两个不同的包都导出了一个名为mylib的目标,那么使用命名空间可以避免冲突。
- 明确指出目标来自哪个包。如果你看到一个名为mfcap::mylib的目标,你就知道这个目标来自mfcap包。
6. config_file
configure_file(MFMeidaCaptureConfig.cmake.in MFMeidaCaptureConfig.cmake @ONLY)
这段CMake代码使用configure_file函数来生成一个配置文件。
- MFMeidaCaptureConfig.cmake.in是输入文件的名字。这个文件包含一些CMake变量
- MFMeidaCaptureConfig.cmake是输出文件的名字。
- @ONLY表示只有@VAR@形式的变量会被替换。如果没有@ONLY,那么${VAR}形式的变量也会被替换。
一个典型的xxxConfig.cmake.in
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
check_required_components("@PROJECT_NAME@")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/MFMeidaCaptureConfig.cmake"
DESTINATION share/MFMeidaCapture)
@PACKAGE_INIT@是一个变量,它会被替换为一些初始化代码。
@targets_export_name@是一个变量,它会被替换为导出文件的名字。
@PROJECT_NAME@是一个变量,它会被替换为项目的名字。
check_required_components(“@PROJECT_NAME@”)
check_required_components(“@PROJECT_NAME@”)是一个CMake命令,它用于检查是否找到了所有需要的组件。
这个命令通常在find_package命令之后使用。例如:
find_package(MyPackage REQUIRED COMPONENTS comp1 comp2)
check_required_components(MyPackage)
在这个例子中,find_package命令会尝试找到MyPackage包,并且需要comp1和comp2这两个组件。然后,check_required_components命令会检查是否真的找到了这两个组件。
如果没有找到所有需要的组件,check_required_components命令会生成一个错误消息,并停止CMake的处理过程
7. find_package
cmake_minimum_required(VERSION 3.10)
project(MFInstallDemo)
set(CMAKE_CXX_STANDARD 17)
set(MFMeidaCapture_DIR "${CMAKE_CURRENT_SOURCE_DIR}/MFMeidaCapture/share/MFMeidaCapture")
find_package(OpenCV HINTS ../3rdparty/OpenCV460)
find_package(MFMeidaCapture REQUIRED)
add_executable(MFInstallDemo main.cpp)
get_target_property(MFCapDll mfcap::MFMeidaCapture IMPORTED_LOCATION_RELWITHDEBINFO)
get_target_property(MFCapDllDebug mfcap::MFMeidaCapture IMPORTED_LOCATION_DEBUG)
target_link_libraries(
MFInstallDemo
${OpenCV_LIBS}
mfcap::MFMeidaCapture
)
target_include_directories(
MFInstallDemo
PRIVATE
${CMAKE_SOURCE_DIR}/../3rdparty/plog/
${MFMeidaCapture_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
# "${CMAKE_CURRENT_SOURCE_DIR}/../3rdparty/OpenCV460/include"
)
add_custom_command(TARGET MFInstallDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<IF:$<CONFIG:DEBUG>,${MFCapDllDebug},${MFCapDll}>"
$<TARGET_FILE_DIR:MFInstallDemo>
)
add_custom_command(TARGET MFInstallDemo POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<IF:$<CONFIG:DEBUG>,${OpenCV_DIR}/x64/vc16/bin/opencv_world460d.dll,${OpenCV_DIR}/x64/vc16/bin/opencv_world460.dll>"
$<TARGET_FILE_DIR:MFInstallDemo>)