cmake学习笔记

1. 基础项目

基本的cmakelist

1
2
3
● cmake_minimum_required(VERSION3.10)
● project(Tutorial)
● add_executable(Tutorialhttp://tutorial.cxx)

设置C++11编译器

1
2
●set(CMAKE_CXX_STANDARD11)
●set(CMAKE_CXX_STANDARD_REQUIREDTrue)

设置版本号,配置一个头文件

1
2
3
4
5
6
7
8
9
10
11
12
●project(TutorialVERSION1.0)
●configure_file(http://TutorialConfig.h.inTutorialConfig.h)
●TODO 10: TutorialConfig.h.in
// the configured options and settings for Tutorial#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
●#include"TutorialConfig.h"
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}

2. 链接库

添加一个库

1
2
3
4
●add_library(MathFunctionshttp://mysqrt.cxx)
●add_subdirectory(MathFunctions)
●target_link_libraries(Tutorial PUBLIC MathFunctions)
●target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/MathFunctions")

条件链接

1
2
3
4
5
6
7
8
9
10
11
●option(USE_MYMATH"Use tutorial provided math implementation"ON)
●if(USE_MYMATH)
add_subdirectory(MathFunctions)
ist(APPEND EXTRA_LIBS MathFunctions)
list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
●target_link_libraries(TutorialPUBLIC${EXTRA_LIBS})
●target_include_directories(TutorialPUBLIC"${PROJECT_BINARY_DIR}"${EXTRA_INCLUDES})
●#ifdef USE_MYMATH#include"MathFunctions.h"#endif
●#ifdef USE_MYMATHconstdoubleoutputValue=mysqrt(inputValue);#elseconstdoubleoutputValue=sqrt(inputValue);#endif
●#cmakedefine USE_MYMATH

3. 增加对库的使用规范

1
2
3
4
5
6
7
8
9
10
11
●https://cmake.org/cmake/help/latest/command/target_compile_definitions.html#command:target_compile_definitions
●https://cmake.org/cmake/help/latest/command/target_compile_options.html#command:target_compile_options
●https://cmake.org/cmake/help/latest/command/target_include_directories.html#command:target_include_directories
●https://cmake.org/cmake/help/latest/command/target_link_directories.html#command:target_link_directories
●https://cmake.org/cmake/help/latest/command/target_link_options.html#command:target_link_options
●https://cmake.org/cmake/help/latest/command/target_precompile_headers.html#command:target_precompile_headers
●https://cmake.org/cmake/help/latest/command/target_sources.html#command:target_sources

●target_include_directories(MathFunctionsINTERFACE${CMAKE_CURRENT_SOURCE_DIR})
●if(USE_MYMATH)add_subdirectory(MathFunctions)list(APPENDEXTRA_LIBSMathFunctions)endif()
●target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")

4. 生成器表达式

1
2
3
4
5
6
7
8
9
add_library(tutorial_compiler_flagsINTERFACE)
target_compile_features(tutorial_compiler_flagsINTERFACEcxx_std_11)
target_link_libraries(TutorialPUBLIC${EXTRA_LIBS}tutorial_compiler_flags)
注意下面这个是子目录下的(可以用父目录的makelist定义)
target_link_libraries(MathFunctionstutorial_compiler_flags)

●set(gcc_like_cxx"$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")set(msvc_cxx"$<COMPILE_LANG_AND_ID:CXX,MSVC>")
●target_compile_options(tutorial_compiler_flagsINTERFACE"$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>""$<${msvc_cxx}:-W3>")
●target_compile_options(tutorial_compiler_flagsINTERFACE"$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>""$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>")

5. 条件生成器表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$<condition:true_string>
$<IF:condition,true_string,false_string>

当condition为真则返回true_string字符串,否则返回空字符串
例如:

target_compile_options(tutorial_compiler_flags INTERFACE
"$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
"$<${msvc_cxx}:-W3>"
)
当msvc_cxx变量为真则添加-W3编译选项
嵌套生成器表达式:
$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>

https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7)

BUILD_INTERFACE
同一构建系统下(非Installed 目标使用)

add_compile_options("$<$<CONFIG:Debug>:-g;-ggdb;-O0>")
add_compile_options("$<$<CONFIG:Release>:-Wall;-O2>")

6. 安装和测试

1
2
3
4
5
6
7
8
9
10
11
12
13
●cmake --install .	
●cmake --install . --config Release
●cmake --install . --prefix "/home/myuser/installdir"

●set(installable_libsMathFunctionstutorial_compiler_flags)install(TARGETS${installable_libs}DESTINATIONlib)
●install(FILESMathFunctions.hDESTINATIONinclude)
●install(TARGETSTutorialDESTINATIONbin
●install(FILES"${PROJECT_BINARY_DIR}/TutorialConfig.h"DESTINATIONinclude)
●enable_testing()
●add_test(NAMERunsCOMMANDTutorial25)
●add_test(NAMEUsageCOMMANDTutorial)set_tests_properties(UsagePROPERTIESPASS_REGULAR_EXPRESSION"Usage:.*number")\
●add_test(NAMEStandardUseCOMMANDTutorial4)set_tests_properties(StandardUsePROPERTIESPASS_REGULAR_EXPRESSION"4 is 2")
●function(do_testtargetargresult)add_test(NAMEComp${arg}COMMAND${target}${arg})set_tests_properties(Comp${arg}PROPERTIESPASS_REGULAR_EXPRESSION${result})endfunction()# do a bunch of result based testsdo_test(Tutorial4"4 is 2")do_test(Tutorial9"9 is 3")do_test(Tutorial5"5 is 2.236")do_test(Tutorial7"7 is 2.645")do_test(Tutorial25"25 is 5")do_test(Tutorial-25"-25 is (-nan|nan|0)")do_test(Tutorial0.0001"0.0001 is 0.01")

7. 支持上传测试结果到dashboard

todo

8. 添加系统自查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
●include(CheckCXXSourceCompiles)
●check_cxx_source_compiles("
#include <cmath>
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include <cmath>
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)

●if(HAVE_LOG AND HAVE_EXP)target_compile_definitions(MathFunctionsPRIVATE"HAVE_LOG""HAVE_EXP")endif()

●#include<cmath>
●#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = std::exp(std::log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;

9. 添加自定义命令及生成文件

1
2
3
4
●add_executable(MakeTablehttp://MakeTable.cxx)
●add_custom_command(OUTPUT${CMAKE_CURRENT_BINARY_DIR}/Table.hCOMMANDMakeTable${CMAKE_CURRENT_BINARY_DIR}/Table.hDEPENDSMakeTable)
●add_library(MathFunctionshttp://mysqrt.cxx${CMAKE_CURRENT_BINARY_DIR}/Table.h)
●target_include_directories(MathFunctionsINTERFACE${CMAKE_CURRENT_SOURCE_DIR}PRIVATE${CMAKE_CURRENT_BINARY_DIR})# link our compiler flags interface librarytarget_link_libraries(MathFunctionstutorial_compiler_flags)

10. 动态库编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
●set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

#if defined(_WIN32)
# if defined(EXPORTING_MYMATH)
# define DECLSPEC __declspec(dllexport)
# else
# define DECLSPEC __declspec(dllimport)
# endif
#else // non windows
# define DECLSPEC
#endif

namespace mathfunctions {
double DECLSPEC sqrt(double x);
}

# state that SqrtLibrary need PIC when the default is shared libraries
set_target_properties(SqrtLibrary PROPERTIES
POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
)

11. 生成导出配置

todo

12. 打包Debug、Release模式

1
2
3
4
5
6
7
8
9
10
11
12
13
●set(CMAKE_DEBUG_POSTFIX d)  
●set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
●set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
include("release/CPackConfig.cmake")

set(CPACK_INSTALL_CMAKE_PROJECTS
"debug;Tutorial;ALL;/"
"release;Tutorial;ALL;/"
)

首先是把自动生成的cpack配置文件引用进来,然后给CPACK_INSTALL_CMAKE_PROJECTS添加两个成员。成员中需要有分号分隔的4个内容,分别是install directory, install project name, install component, install subdirectory。
●cpack --config MultiCPackConfig.cmake
只set CMAKE_DEBUG_POSTFIX没设置set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}):

13. PUBLIC PRIVATE INTERFACE

1
2
3
4
●PUBLIC    在public后面的库会被Link到你的target中,并且里面的符号也会被导出,提供给第三方使用。
●PRIVATE 在private后面的库仅被link到你的target中,并且终结掉,第三方不能感知你调了啥库
●INTERFACE 在interface后面引入的库不会被链接到你的target中,只会导出符号
https://zhuanlan.zhihu.com/p/82244559

14. CMake 条件、循环、跳出循环

1
2
3
4
5
6
7
8
https://blog.csdn.net/m0_57845572/article/details/118520448

messagetutorial_compiler_flags
message([<mode>] "message text" ...)

mode 的值包括 FATAL_ERROR、WARNING、AUTHOR_WARNING、STATUS、VERBOSE等。我主要使用其中的 2 个——FATAL_ERROR、STATUS。
FATAL_ERROR:产生 CMake Error,会停止编译系统的构建过程; STATUS:最常用的命令,常用于查看变量值,类似于编程语言中的 DEBUG 级别信息。
"message text"为显示在终端的内容。

15. 引入闭源/编译好的库:使用IMPORTED关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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)

第一步是add_library,并指定IMPORTED。这代表是外部已经编译好的库

第二步是set_preperty。指定外部库的位置。

第三步是设定头文件。注意要用INTERFACE

cmake_minimum_required(VERSION 3.20)
project(tryIMPORTED)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(main main.cpp)

设定外部库

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)

opengl
find_package(OpenGL REQUIRED)
target_link_libraries(main OpenGL::GL)

16. pkg-config

在使用 CMake 作为项目构建工具时,有一些库并没有提供 cmake 文件,往往提供的是 pkg-config 的 .pc 文

17. 汇编文件编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
vs:
1、右键 .asm 文件,点击“属性”。

2、在项类型里选择“自定义生成工具”。

3、点击应用,然后点击左边“自定义生成工具”里的“常规”。

4、在“命令行”里输入

ml64 /Fo $(IntDir)%(fileName).obj /c %(fileName).asm
在“输出”里输入

$(IntDir)%(fileName).obj
5、点击“确定”,然后重新编译。

cmakelists:

add_library(target, "xxx.asm")
enable_langange(ASM_MASM)