一、cmake模板
|--CMakeLists.txt
|--extern
|--src
|--|--subsrc1
|--|--|--CMakeLists.txt
|--|--subsrc2
|--|--|--CMakeLists.txt
|--|--main.cc
|--|--CMakeLists.txt
|--test
|--|--CMakeLists.txt
|--vcpkg.json
根目录的CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(PROJECT_XXX VERSION 0.0.0 )
#C/C++标准
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
#设置编译器
set (CMAKE_C_COMPILER "/usr/bin/gcc")
set (CMAKE_CXX_COMPILER "/usr/bin/g++")
######### build 变量 #####
set(CMAKE_BUILD_TYPE Debug#[[Release | Debug| RelWithDebInfo |MinSizeRel]])
set(CMAKE_BUILD_PARALLEL_LEVEL 4)#编译处理器数量
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)#clang
set(CMAKE_GENERATOR "Unix Makefiles")#“Ninja”、“Unix Makefiles”、“Visual Studio”
#add_compile_options()#等同CMAKE_CXXFLAGS_RELESE,前者可以对所有的编译器设置,后者只能是C++编译器
########## vcpkg #######
#set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
#set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH};${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-linux/lib/pkgconfig")
#lib&&bin输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/bin)#可执行文件
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/lib)#动态库
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build/lib/static)#静态库
###### sub directory #####
add_subdirectory(src)
#add_subdirectory(external)
########## TEST ##########
if(FALSE)
enable_testing()
add_subdirectory(test)
add_test(NAME test COMMAND ${PROJECT_NAME} -arg1 -arg2)
endif()
########## istanll #######
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
# 1.target 放到 DESTINATION 指定的目录
#install(TARGETS ... RUNTIME DESTINATION bin)#exe
#install(TARGETS ... LIBRARY DESTINATION lib)#*.so
#install(TARGETS ... ARCHIVE DESTINATION lib/static)#*.lib
#install(TARGETS ... PUBLIC_HEADER DESTINATION include)#公共头文件的安装路径
#install(TARGETS ... RESOURCE DESTINATION <dir>)#私有头文件的安装路径
# 2.普通文件 放置放到 DESTINATION 指定的目录,eg:readme.md config.ini
#install(FILES ... DESTINATION etc)
# 3.目录
#install(DIRECTORY ... DESTINATION ...)
# 4.脚本 放置到 DESTINATION 指定的目录,eg:install.sh
#install(PROGRAMS ... DESTINATION ...)
# 5.target集合
#install(TARGETS ... EXPORT export_name RUNTIME DESTINATION bin)#exe
#install(EXPORT export_name NAMESPACE namespace DESTINATION <dir>)
########## PACK ##########
if(FALSE)
# 安装包名称
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
# 版本号
set(CPACK_PACKAGE_VERSION "1.0.0")
# 描述信息
set(CPACK_PACKAGE_DESCRIPTION "My awesome application")
# 许可证
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0 + Common Clause 1.0")
# vendor
set(CPACK_PACKAGE_VENDOR "vesoft")
# 安装包图标
#set(CPACK_PACKAGE_ICON )
#配置软件包类型和生成器ZIP、TGZ、RPM、NSIS
set(CPACK_GENERATOR ZIP)#二进制包
#set(CPACK_SOURCE_GENERATOR ZIP)#源码包
#安装系统依赖库
include(InstallRequiredSystemLibraries)
#安装安装包时的依赖关系
#set(CPACK_DEBIAN_PACKAGE_DEPENDS "")#Debian自动安装依赖
#set(CPACK_RPM_PACKAGE_REQUIRES "")
#添加脚本和配置
#set(CPACK_PRE_INSTALL_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/pre_install_script.sh")#安装前,目录权限
#set(CPACK_POST_INSTALL_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/post_install_script.sh")#安装后,systemctl自启动脚本
# 设置支持指定安装目录的控制为 ON;设置安装到的目录路径
#set(CPACK_SET_DESTDIR ON)
#set(CPACK_INSTALL_PREFIX )
include(CPack)
endif()
LIB
######### Target LIB #########
aux_source_directory(目录 LIBS_SRC_LISTS)
set(LIBS_NAME )
add_library(${LIBS_NAME } "")#默认是STATIC
target_include_directories(${LIBS_NAME} PRIVATE )
target_sources(${LIBS_NAME} PRIVATE ${LIBS_SRC_LISTS})
#target_link_libraries(${LIBS_NAME} )
target_compile_options(${LIBS_NAME} PRIVATE -Wall
-O3 -std=c++11 )
target_compile_definitions(${LIBS_NAME} PRIVATE
CMAKE_BUILD_TYPE=Release
CMAKE_EXPORT_COMPILE_COMMANDS=ON)
EXE
######### Target EXE #########
aux_source_directory(目录 EXE_SRC_LISTS)
add_executable(${PROJECT_NAME} )
#target_include_directories(${PROJECT_NAME} RIVATE )
target_sources(${PROJECT_NAME} PRIVATE ${EXE_SRC_LISTS})
#target_link_libraries(${PROJECT_NAME} )
target_compile_options(${PROJECT_NAME} RRIVATE -Wall
-O3 -std=c++11 )
target_compile_definitions(${PROJECT_NAME} PRIVATE
CMAKE_BUILD_TYPE=Release
CMAKE_EXPORT_COMPILE_COMMANDS=ON)
FIND
######### FIND FILE #######
#find_package(Eigen3 REQUIRED)
#find_path (<VAR> name1 [path1 path2 ...])
#find_file (<VAR> name1 [path1 path2 ...])
#find_library (<VAR> name1 [path1 path2 ...])
vcpkg
######### VCPKG #########
set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
#增加*.cmake的寻找路径
#list(APPEND CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/vcpkg_installed/x64-linux/share/gtest)
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
####### 清单pkgconfig模式 ###
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBRARY_NAME REQUIRED libname)#变量 libname.pc
target_include_directories(${TARGET_NAME} ${LIBRARY_NAME_INCLUDE_DIRS})#头文件目录
target_link_directories(${PROJECT_NAME} PRIVATE ${LIBRARY_NAME_INCLUDE_DIRS})#链接目录
target_link_libraries(${TARGET_NAME} ${LIBRARY_NAME_LIBRARIES})#链接库
闭源库
######### 闭源库 ##########
add_library(${LIBNAME} STATIC IMPORTED)
set_property(TARGET ${LIBNAME} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_LIST_DIR}/extern/{LIBNAME}/lib-vc2019/glfw3.lib)
target_include_directories( ${LIBNAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}/extern/${LIBNAME}/include)
test
二、参数设置
编译选项
CMAKE_BUILD_TYPE Release | Debug| RelWithDebInfo |MinSizeRel
三、命令解释
3.1 find命令
find_path:用于找到指定文件或目录路径的命令(安装ini文件)
find_path(<VAR> name1 [path1 path2 ...])
eg:
find_path(STDIO_H_INCLUDE_DIR stdio.h
/usr/include
/usr/local/include)
其中,<VAR>
是用于存储找到的路径的变量名。name1
是要查找的文件或目录的名称。path1
,path2
等是可选的搜索路径。
find_path命令特别适用于需要在构建过程中动态查找头文件路径的情况
find_file:用于查找指定文件的路径
find_file(<VAR> name1 [path1 path2 ...])
eg:
find_file(EXAMPLE_FILE example.txt)
执行上述命令后,如果找到了example.txt文件,路径将存储在EXAMPLE_FILE变量中,否则该变量将为空。
find_file(EXAMPLE_FILE example.txt
/usr/data
/home/user/data
)
这将在/usr/data和/home/user/data目录下搜索example.txt文件
其中,<VAR>
是一个变量,用于存储找到的文件路径。name1
是要查找的文件的名称。path1
,path2
等是可选的搜索路径。
find_library:用于查找指定库文件的路径
find_library(<VAR> name1 [path1 path2 ...])
其中,<VAR>
是用于存储找到的库文件路径的变量名。name1
是要查找的库文件的名称(不包括前缀lib
和文件扩展名)。
使用案例
cmake_minimum_required(VERSION 3.12)
project(MyProject)
# 查找名为 mylibrary 的库文件
find_library(MYLIBRARY_LIB mylibrary)
# 如果找到了库文件
if(MYLIBRARY_LIB)
message("Found mylibrary at: ${MYLIBRARY_LIB}")
# 添加库文件的路径到链接器
target_link_libraries(MyExecutable ${MYLIBRARY_LIB})
else()
message(FATAL_ERROR "mylibrary not found")
endif()
find_program:用于查找指定可执行程序的路径
find_program(<VAR> name1 [path1 path2 ...])
eg:
find_program(MYPROGRAM_EXECUTABLE myprogram
/usr/bin
/usr/local/bin
)
这将在/usr/bin
和/usr/local/bin
目录下搜索myprogram
可执行程序。
使用案例
cmake_minimum_required(VERSION 3.12)
project(MyProject)
# 查找名为 myprogram 的可执行程序
find_program(MYPROGRAM_EXECUTABLE myprogram)
# 如果找到了可执行程序
if(MYPROGRAM_EXECUTABLE)
message("Found myprogram at: ${MYPROGRAM_EXECUTABLE}")
# 在构建过程中使用可执行程序
add_custom_target(run_myprogram COMMAND ${MYPROGRAM_EXECUTABLE})
else()
message(FATAL_ERROR "myprogram not found")
endif()
在这个案例中,假设我们的项目想要运行名为myprogram
的可执行程序。
通过find_program(MYPROGRAM_EXECUTABLE myprogram)
命令,CMake会尝试在系统的默认可执行程序搜索路径中找到名为myprogram
的可执行程序。
如果成功找到了可执行程序,CMake会将路径存储在变量MYPROGRAM_EXECUTABLE
中,并通过add_custom_target
命令定义一个自定义目标,使得我们可以在构建过程中使用该可执行程序。
如果未找到可执行程序,则会输出错误消息并终止构建过程
find_package: CMake中用于查找和加载第三方库的命令
使用案例
cmake_minimum_required(VERSION 3.12)
project(MyProject)
# 查找并加载 OpenCV
find_package(OpenCV 4 REQUIRED)
# 检查是否找到库
if(OpenCV_FOUND)
message("Found OpenCV version ${OpenCV_VERSION}")
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(MyApp main.cpp)
target_link_libraries(MyApp ${OpenCV_LIBS})
else()
message(FATAL_ERROR "OpenCV not found")
endif()
# 添加其他项目配置和构建指令...
变量
<PackageName>_FOUND
:
表示是否找到了指定的库。它是一个布尔值,如果找到了库,则为TRUE
,否则为FALSE
。<PackageName>_VERSION
:
当找到库时,它表示所找到的库的版本号。该值可能是一个字符串或一个列表。<PackageName>_INCLUDE_DIRS
:
包含着所找到的库的头文件路径的变量。这允许您在项目中包含库的头文件。<PackageName>_LIBRARIES
:
存储了所找到的库的完整库文件路径的变量。通过这个变量,您可以将所需的库链接到项目的可执行文件或库中。这些变量的命名约定在不同的
Find
模块中可能会有所不同,因此请查阅库的相关文档来获取详细的变量名称和用途。
3.2 file 执行与文件和目录相关的操作
它可以用于创建、复制、删除、重命名、读取文件内容等操作。以下是一些 file()
命令的常见用法:
-
file(COPY ...)
:
将指定的文件或目录复制到指定的目标目录下。该命令可以用于将文件复制到构建目录或安装位置。file(COPY source_file DESTINATION destination_directory)
-
file(REMOVE ...)
:
删除指定的文件或目录。file(REMOVE file_path)
-
file(RENAME ...)
:
将文件或目录重命名。file(RENAME old_name new_name)
-
file(READ ...)
:
读取文件内容到变量中。file(READ file_path variable_name)
-
file(WRITE ...)
:
将字符串内容写入文件中。file(WRITE file_path "content")
-
file(APPEND ...)
:
将字符串内容追加到文件末尾。file(APPEND file_path "content")
这只是 file()
命令的一些常见用法示例,实际上它还有很多其他用法,例如创建目录、查找文件、获取文件属性等。您可以在 CMake 官方文档中查找 file()
命令的完整参考以获取更详细的信息和用法示例。
3.3 自定义命令
在很多时候,需要在cmake
中创建一些目标,如clean
、copy
等等,这就需要通过add_custom_target
来指定。同时,add_custom_command
可以用来完成对add_custom_target
生成的target
的补充。
区别
在CMake中,"add_custom_command"和"add_custom_target"是两个常用的命令,用于定义自定义编译命令和自定义构建目标。它们之间的区别如下:
- add_custom_command:
- add_custom_command用于定义在构建时执行的自定义命令。它可以用来生成文件、生成代码、运行脚本等。add_custom_command通常被用作目标的依赖项。
- add_custom_command并不会创建真正的构建目标,它仅仅是一个构建过程中执行的命令。因此,默认情况下,add_custom_command不会导致重新构建整个项目。
- add_custom_target:
- add_custom_target用于定义一个构建目标,该目标不与实际的文件或输出相关联,而是与一组其他规则相关联。
- add_custom_target可以用来执行一系列自定义命令或构建步骤。它对于组织和管理构建过程非常有用。
- add_custom_target通常用作构建系统的入口点,通过依赖其他目标和规则来执行自定义构建任务。
总结来说,add_custom_command用于定义构建过程中的自定义命令,而add_custom_target用于定义自定义构建目标。两者可以结合使用,以实现更复杂的构建逻辑。
add_custom_target:自定义构建目标
add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
…
)
# Name:定义的target的名字
# COMMAND:该target要执行的命令
add_custom_target(
target_name
[COMMAND command1 [ARGS] [args1...]]
[COMMAND command2 [ARGS] [args2...] ...]
[DEPENDS [depend1...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM]
[USES_TERMINAL]
)
其中,常用的参数和选项包括:
target_name:自定义构建目标的名称。
COMMAND:指定要执行的命令。
DEPENDS:指定自定义目标所依赖的其他目标或文件。
WORKING_DIRECTORY:设置命令的工作目录。
COMMENT:添加对命令或目标的注释。
VERBATIM:保留命令中的转义字符,确保按原样传递给底层的构建工具。
USES_TERMINAL:指示命令是否会使用终端。
通过使用 add_custom_target,可以在构建过程中定义各种自定义的构建目标,例如运行测试、生成文档、执行代码检查等。这些目标可以依赖其他目标或文件,并根据需要执行自定义的命令或操作
add_custom_target 命令不会生成实际的构建产物(如可执行文件或库),它只是定义了一个自定义的构建目标。您可以通过 add_dependencies 命令将这个自定义目标与其他目标关联起来,以确保在构建过程中执行相关的自定义操作。
使用案例
add_custom_target(RunTests
COMMAND run_tests.sh
DEPENDS test_files
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Running tests..."
)
add_dependencies(RunTests MyApp)
在这个示例中,RunTests 是一个自定义目标,通过执行 run_tests.sh 脚本来运行测试。它依赖于 test_files 目标(或文件),并在 ${CMAKE_BINARY_DIR} 目录下执行。通过 COMMENT 可以添加注释,说明正在运行的操作。最后,通过 add_dependencies 将 RunTests 目标与 MyApp 目标关联起来,以确保在构建 RunTests 目标时先构建 MyApp 目标。
使用教程
-
创建自定义目标:
首先,使用add_custom_target
命令创建一个自定义构建目标并指定它的名称。add_custom_target(MyTarget)
在上述示例中,我们创建了一个名为
MyTarget
的自定义目标,这个目标还没有定义任何操作。 -
添加命令:
使用COMMAND
选项来添加要执行的命令或操作。add_custom_target(MyTarget COMMAND echo "Hello, World!" )
在这个例子中,我们在
MyTarget
目标中添加了一个命令,即输出 “Hello, World!”。您可以根据实际需求添加更多的命令或操作。 -
添加依赖项:
使用DEPENDS
选项来指定MyTarget
目标所依赖的其他目标或文件。add_custom_target(MyTarget COMMAND echo "Hello, World!" DEPENDS other_target file.txt )
在上述示例中,我们将
MyTarget
目标设置为依赖于other_target
目标和file.txt
文件。这意味着在构建MyTarget
之前,CMake 将确保先构建other_target
目标和检查file.txt
文件的更新。 -
设置工作目录和注释:
使用其他选项如WORKING_DIRECTORY
和COMMENT
来设置工作目录和添加注释。add_custom_target(MyTarget COMMAND echo "Hello, World!" DEPENDS other_target file.txt WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Running custom commands..." )
在上述示例中,我们设置了
MyTarget
的工作目录为${CMAKE_BINARY_DIR}
,并添加了一个注释以描述正在执行的操作。 -
添加到其他目标的依赖项:
使用add_dependencies
命令将自定义目标与其他目标关联起来。add_executable(MyApp main.cpp) add_custom_target(MyTarget COMMAND echo "Hello, World!" DEPENDS other_target file.txt WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Running custom commands..." ) add_dependencies(MyApp MyTarget)
在这个例子中,我们将自定义目标
MyTarget
添加为可执行文件MyApp
的依赖项。这意味着在构建MyApp
时,CMake 将确保先构建MyTarget
。
add_custom_command:自定义编译命令
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[BYPRODUCTS [files...]]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
[JOB_POOL job_pool]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[DEPENDS_EXPLICIT_ONLY])
其中,常用的参数和选项包括:
TARGET
:指定目标(可执行文件或库),表示该自定义命令与构建目标相关联。PRE_BUILD
、PRE_LINK
、POST_BUILD
:指定自定义命令在何时执行,分别表示前置构建、前置链接和后置构建。COMMAND
:指定要执行的命令。WORKING_DIRECTORY
:设置命令的工作目录。COMMENT
:添加对命令的注释。MAIN_DEPENDENCY
:指定自定义命令所依赖的主文件。DEPENDS
:指定自定义命令所依赖的其他文件。BYPRODUCTS
:指定由命令生成的副产品文件。IMPLICIT_DEPENDS
:指定命令的隐式依赖关系,这些依赖关系可能是根据源文件的语言推断出来的。USES_TERMINAL
:指示命令是否会使用终端(仅在可执行文件的情况下)。
通过使用 add_custom_command
,可以在构建过程中执行各种自定义的命令,如生成代码、拷贝文件、运行脚本等。这允许您在构建过程中执行与编译和链接无关的任意操作。
请注意,add_custom_command
命令必须与 add_custom_target
或 add_executable
/ add_library
配合使用,以将其与构建目标关联起来。
使用案例
add_custom_command
命令用于在构建过程中执行自定义的命令。下面是一个简单的教程,介绍了如何使用 add_custom_command
:
-
添加生成文件的自定义命令:
首先,使用add_custom_command
命令定义一个用于生成文件的自定义命令。add_custom_command( OUTPUT generated_file.txt COMMAND generate_file.py DEPENDS generate_file.py )
在上述示例中,我们定义了一个自定义命令,它使用 Python 脚本
generate_file.py
来生成一个名为generated_file.txt
的文件。DEPENDS
参数指定生成文件的依赖项,例如脚本文件本身。 -
将生成的文件作为构建目标使用:
可以将生成的文件作为构建目标的一部分使用,例如作为源文件或目标文件。add_executable(MyApp main.cpp generated_file.txt)
在上述示例中,我们将生成的文件
generated_file.txt
作为一个源文件之一与main.cpp
一起使用,构建一个名为MyApp
的可执行文件。 -
声明生成文件的依赖关系:
使用add_dependencies
命令将自定义命令与其他目标关联起来。add_custom_command( OUTPUT generated_file.txt COMMAND generate_file.py DEPENDS generate_file.py ) add_executable(MyApp main.cpp) add_dependencies(MyApp generated_file.txt)
在这个例子中,我们在自定义命令与目标之间建立了依赖关系。通过
add_dependencies
命令,MyApp
目标将在构建之前先构建generated_file.txt
。
使用 add_custom_command
,您可以执行各种自定义的命令或操作,并将其与构建目标进行关联。这使得您可以在构建过程中执行额外的操作,例如生成代码、复制文件、预处理资源等。根据自己的项目需求,您可以根据需要实现适合的自定义命令,并根据构建逻辑设置相关的依赖关系。
3.4 配置文件
configure_file命令是CMake提供的一个常用命令,用于在构建过程中根据模板文件生成配置文件
四、自动化测试
当使用CTest来运行测试时,通常需要按照以下步骤进行配置和执行:
-
创建测试目录:在项目中创建一个用于存放测试脚本和测试数据的目录。可以将该目录命名为
tests
或者其他合适的名称。 -
编写测试脚本:在测试目录中创建一个或多个测试脚本文件,用于描述测试用例和测试步骤。测试脚本可以使用CTest的命令和语法来定义测试行为、验证结果等。以下是一个简单的示例:
# tests/mytest.cmake # 定义一个测试用例 add_test(NAME MyTest COMMAND my_program input_data.txt output_data.txt) # 验证测试结果 set_tests_properties(MyTest PROPERTIES PASS_REGULAR_EXPRESSION "Expected output")
-
创建CTest配置文件:在项目的根目录中创建一个名为
CTestTestfile.cmake
的配置文件,用于配置测试设置、测试套件和测试驱动程序等细节。该文件会被CTest自动加载。以下是一个简单的示例:# CTestTestfile.cmake # 添加测试目录 add_subdirectory(tests)
-
构建项目:使用CMake构建项目,此时确保CTest被启用并已成功集成到项目中。
-
运行CTest:在项目构建完成后,在构建目录中运行
ctest
命令来执行测试。可以使用ctest --verbose
来显示详细的测试输出。$ ctest
或者使用图形界面工具来运行CTest,例如运行
ccmake
或cmake-gui
命令来查看和运行CTest。 -
查看测试结果:CTest将测试结果输出到终端或CTest的GUI前端。你将看到每个测试的状态(通过、失败、跳过等),以及相关的错误消息和日志文件。
这只是一个简单的CTest使用示例,你可以根据项目的特定需求和测试要求自定义和扩展CTest的功能。参阅CTest文档以获取更多详细信息和更高级的CTest配置选项。
记住,在编写测试脚本时,应该尽可能涵盖项目的各方面,并验证预期的行为和结果。测试是质量保证过程的重要组成部分,能够提供反馈以确保项目的正确性和可靠性。
五、安装
5.1 Linux的rpath机制
在 CMake 中,可以通过使用 CMAKE_INSTALL_RPATH
或者 CMAKE_BUILD_RPATH
属性来设置可执行文件的 rpath。
CMAKE_INSTALL_RPATH
:用于指定在安装过程中可执行文件的 rpath。可执行文件会被安装到目标目录,同时 rpath 会被设置为CMAKE_INSTALL_RPATH
指定的路径。可以通过在 CMakeLists.txt 文件中设置该属性来达到目的。
set(CMAKE_INSTALL_RPATH <path>)
其中 <path>
是要设置的 rpath 的路径。
CMAKE_BUILD_RPATH
:用于指定在构建过程中可执行文件的 rpath。可执行文件在构建过程中会被放置在构建目录,同时 rpath 会被设置为CMAKE_BUILD_RPATH
指定的路径。可以通过在 CMakeLists.txt 文件中设置该属性来达到目的。
set(CMAKE_BUILD_RPATH <path>)
同样,<path>
是要设置的 rpath 的路径。
注意:
<path>
可以是多个路径的列表。可以使用;
分隔路径。- 在设置
CMAKE_INSTALL_RPATH
和CMAKE_BUILD_RPATH
时,可以使用 CMake 的 generator expressions,以便根据不同的配置和平台展开不同的路径。 CMAKE_INSTALL_RPATH
和CMAKE_BUILD_RPATH
可以同时设置,并且它们的优先级会根据具体的情况决定。
设置 CMAKE_INSTALL_RPATH
或 CMAKE_BUILD_RPATH
后,重新运行 CMake 构建过程,可执行文件的 rpath 会被相应地设置。这样,在运行时可执行文件会使用 rpath 指定的路径来查找动态库,从而确保动态库能够正确加载。
需要注意的是,rpath 机制在不同的操作系统上有所不同,具体的设置和行为可能会有所差异。确保根据目标平台和操作系统的要求进行适当的配置和测试。
5.2 CMAKE_INSTALL_RPATH
的使用案例
以下是一个使用 CMAKE_INSTALL_RPATH
的简单示例:
cmake_minimum_required(VERSION 3.12)
project(MyApp)
# 设置可执行文件的源文件
set(SOURCES main.cpp)
# 设置生成可执行文件
add_executable(myapp ${SOURCES})
# 设置动态库的搜索路径
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# 安装规则
install(TARGETS myapp
RUNTIME DESTINATION bin
DESTINATION "${CMAKE_INSTALL_PREFIX}"
# 设置 rpath 为 CMAKE_INSTALL_RPATH 变量的值
INSTALL_RPATH "${CMAKE_INSTALL_RPATH}"
)
在这个示例中,假设项目目录结构如下:
.
├── CMakeLists.txt
├── main.cpp
└── lib
└── mylib.so
main.cpp
是可执行文件的源文件。lib
目录下包含一个名为mylib.so
的动态库文件。
在 CMakeLists.txt 中,我们首先定义了可执行文件的源文件,并通过 add_executable()
命令添加了一个名为 myapp
的可执行目标。
接下来,我们通过 set()
命令设置了 CMAKE_INSTALL_RPATH
的值为 $ORIGIN/lib
。这里使用了 $ORIGIN
变量,它表示可执行文件所在的目录。
最后,在安装规则中,我们使用 install()
命令将可执行文件安装到指定的目录,并通过 INSTALL_RPATH
属性将 CMAKE_INSTALL_RPATH
的值传递给 rpath。
在构建并运行项目时,可执行文件 myapp
将被安装到目标目录(例如安装到 /usr/local/bin
),同时 rpath 将被设置为 /usr/local/bin/lib
。这样在运行时,可执行文件就能够找到并加载位于 lib
目录下的动态库文件。
请注意,实际的 rpath 设置可能因操作系统、CMake 版本和项目结构而有所不同,上述示例仅为了说明如何使用 CMAKE_INSTALL_RPATH
。根据具体的需求和情况,可能需要进行适当的调整。
5.3 CMAKE_BUILD_RPATH
的使用案例
以下是一个使用 CMAKE_BUILD_RPATH
的简单示例:
cmake_minimum_required(VERSION 3.12)
project(MyApp)
# 设置可执行文件的源文件
set(SOURCES main.cpp)
# 设置生成可执行文件
add_executable(myapp ${SOURCES})
# 设置动态库的搜索路径
set(CMAKE_BUILD_RPATH "$ORIGIN/lib")
# 构建规则
set_target_properties(myapp PROPERTIES
# 设置 rpath 为 CMAKE_BUILD_RPATH 变量的值
BUILD_RPATH "${CMAKE_BUILD_RPATH}"
)
在这个示例中,假设项目目录结构如下:
.
├── CMakeLists.txt
├── main.cpp
└── lib
└── mylib.so
main.cpp
是可执行文件的源文件。lib
目录下包含一个名为mylib.so
的动态库文件。
在 CMakeLists.txt 中,我们首先定义了可执行文件的源文件,并通过 add_executable()
命令添加一个名为 myapp
的可执行目标。
接下来,我们通过 set()
命令设置了 CMAKE_BUILD_RPATH
的值为 $ORIGIN/lib
。这里使用了 $ORIGIN
变量,它表示构建目录。
最后,使用 set_target_properties()
命令,将 BUILD_RPATH
属性设置为 CMAKE_BUILD_RPATH
的值。这样,在构建过程中,可执行文件 myapp
的 rpath 将被设置为构建目录下的 lib
目录。
在构建项目时,生成的可执行文件 myapp
将具有指定的 rpath,以便在运行时正确加载位于构建目录下的动态库文件。
请注意,实际的 rpath 设置可能因操作系统、CMake 版本和项目结构而有所不同,上述示例仅为了说明如何使用 CMAKE_BUILD_RPATH
。根据具体的需求和情况,可能需要进行适当的调整。
六、闭源包引用
#glfw
add_library(glfw STATIC IMPORTED)
set_property(TARGET glfw PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/extern/glfw/lib-vc2019/glfw3.lib)
target_include_directories(glfw INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/extern/glfw/include)
#引用
target_link_libraries(main glfw)
七、vcpkg包管理
6.1 安装
-
打开终端。
-
克隆 Vcpkg 存储库:
git clone https://github.com/microsoft/vcpkg.git
-
进入 Vcpkg 目录:
cd vcpkg
-
运行
bootstrap-vcpkg.sh
脚本以初始化和构建 Vcpkg:./bootstrap-vcpkg.sh sudo ln -s $HOME/vcpkg/vcpkg /usr/bin cat "EXPORT VCPKG_ROOT=/home/chao/vcpkg" &>> ~/.bashrc
-
运行以下命令将 Vcpkg 安装到系统目录
/usr/local
:sudo ./vcpkg integrate install
输入您的密码以进行身份验证。
-
现在,Vcpkg 已成功安装到您的 Ubuntu 系统上。
-
使用 Vcpkg 安装和管理库。
-
在终端中,使用以下命令安装所需的库:
./vcpkg install <library-name>
将
<library-name>
替换为您要安装的库的名称。 -
安装完成后,您可以在代码中使用 Vcpkg 安装的库来进行开发和构建。
-
请注意,使用 Vcpkg 在 Ubuntu 上安装库可能需要满足一些依赖项和构建工具的要求。在某些情况下,您可能需要在 Ubuntu 上预先安装一些依赖项,以便成功安装和使用特定的库
6.2 vcpkg.json
-
在项目的根目录下创建一个名为 vcpkg.json 的文件。
-
打开 vcpkg.json 并编辑文件,按照 JSON 格式的语法来定义您的库和其设置。下面是一个示例:
{ "name": "myproject", "version": "0.1", "dependencies": [ { "name": "library1", "version": "1.2" }, { "name": "library2", "version": "2.0" } ] }
上述示例中,“name” 指定项目名称,“version” 指定项目版本,“dependencies” 下列出了项目所依赖的库。
-
定义库的依赖项。每个依赖项都需要指定名称 (“name”) 和版本 (“version”)。此外,您还可以指定特定的库功能(如果有)。
-
保存 vcpkg.json 文件。
-
在终端中,导航到项目的根目录。
-
运行以下命令,使用 Vcpkg 安装项目依赖项:
vcpkg install
Vcpkg 将根据 vcpkg.json 文件中定义的库和版本信息,自动下载、安装和构建所需的库。
-
安装完成后,您可以在项目中使用已安装的库进行开发和构建。
vcpkg.json 是一个方便的方法,可以在项目级别上配置 Vcpkg。通过使用该文件,可以轻松地与其他人共享项目依赖项和配置,并确保每个人都能够使用相同的库版本。
6.3 多包管理器共存
if(USE_VCPKG)
find_package(<VCPKG_PACKAGE> REQUIRED)
include_directories(${<VCPKG_PACKAGE>_INCLUDE_DIRS})
target_link_libraries(MyProject ${<VCPKG_PACKAGE>_LIBRARIES})
else()
find_package(<APT_PACKAGE> REQUIRED)
include_directories(${<APT_PACKAGE>_INCLUDE_DIRS})
target_link_libraries(MyProject ${<APT_PACKAGE>_LIBRARIES})
endif()