Sfoglia il codice sorgente

Merge branch 'main' of http://120.24.178.115:10880/cong/MarkdownLog into main

usuifohe 1 anno fa
parent
commit
112e889e80
100 ha cambiato i file con 2367 aggiunte e 0 eliminazioni
  1. 3 0
      .gitignore
  2. 1 0
      Build-Project/CMake/.gitignore
  3. BIN
      Build-Project/CMake/Image/001.png
  4. BIN
      Build-Project/CMake/Image/002.png
  5. BIN
      Build-Project/CMake/Image/003.png
  6. BIN
      Build-Project/CMake/Image/004.png
  7. BIN
      Build-Project/CMake/Image/005.png
  8. BIN
      Build-Project/CMake/Image/006.png
  9. BIN
      Build-Project/CMake/Image/007.png
  10. BIN
      Build-Project/CMake/Image/008.png
  11. 640 0
      Build-Project/CMake/README.md
  12. 24 0
      Build-Project/CMake/src/demo1/CMakeLists.txt
  13. 7 0
      Build-Project/CMake/src/demo1/add.c
  14. 7 0
      Build-Project/CMake/src/demo1/div.c
  15. 11 0
      Build-Project/CMake/src/demo1/head.h
  16. 14 0
      Build-Project/CMake/src/demo1/main.c
  17. 7 0
      Build-Project/CMake/src/demo1/mult.c
  18. 8 0
      Build-Project/CMake/src/demo1/sub.c
  19. 11 0
      Build-Project/CMake/src/demo2/CMakeLists.txt
  20. 11 0
      Build-Project/CMake/src/demo2/include/head.h
  21. 7 0
      Build-Project/CMake/src/demo2/src/add.c
  22. 7 0
      Build-Project/CMake/src/demo2/src/div.c
  23. 14 0
      Build-Project/CMake/src/demo2/src/main.c
  24. 7 0
      Build-Project/CMake/src/demo2/src/mult.c
  25. 8 0
      Build-Project/CMake/src/demo2/src/sub.c
  26. 12 0
      Build-Project/CMake/src/demo3/CMakeLists.txt
  27. 11 0
      Build-Project/CMake/src/demo3/include/head.h
  28. 7 0
      Build-Project/CMake/src/demo3/src/add.c
  29. 7 0
      Build-Project/CMake/src/demo3/src/div.c
  30. 14 0
      Build-Project/CMake/src/demo3/src/main.c
  31. 7 0
      Build-Project/CMake/src/demo3/src/mult.c
  32. 8 0
      Build-Project/CMake/src/demo3/src/sub.c
  33. 12 0
      Build-Project/CMake/src/demo4/CMakeLists.txt
  34. 11 0
      Build-Project/CMake/src/demo4/include/head.h
  35. 7 0
      Build-Project/CMake/src/demo4/src/add.c
  36. 7 0
      Build-Project/CMake/src/demo4/src/div.c
  37. 14 0
      Build-Project/CMake/src/demo4/src/main.c
  38. 7 0
      Build-Project/CMake/src/demo4/src/mult.c
  39. 8 0
      Build-Project/CMake/src/demo4/src/sub.c
  40. 71 0
      Build-Project/CMake/src/demo5/CMakeLists.txt
  41. 11 0
      Build-Project/CMake/src/demo5/include/head.h
  42. 7 0
      Build-Project/CMake/src/demo5/src/add.c
  43. 7 0
      Build-Project/CMake/src/demo5/src/div.c
  44. 14 0
      Build-Project/CMake/src/demo5/src/main.c
  45. 7 0
      Build-Project/CMake/src/demo5/src/mult.c
  46. 8 0
      Build-Project/CMake/src/demo5/src/sub.c
  47. 7 0
      Build-Project/CMake/src/demo6/CMakeLists.txt
  48. 11 0
      Build-Project/CMake/src/demo6/include/head.h
  49. 9 0
      Build-Project/CMake/src/demo6/src/main.c
  50. 34 0
      Build-Project/CMake/src/demo7/CMakeLists.txt
  51. 11 0
      Build-Project/CMake/src/demo7/include/head.h
  52. 9 0
      Build-Project/CMake/src/demo7/src/main.c
  53. 1 0
      Build-Project/GN/.gitignore
  54. 2 0
      Build-Project/GN/Demo/.gn
  55. 7 0
      Build-Project/GN/Demo/BUILD.gn
  56. 21 0
      Build-Project/GN/Demo/build/BUILD.gn
  57. 46 0
      Build-Project/GN/Demo/build/BUILDCONFIG.gn
  58. 90 0
      Build-Project/GN/Demo/build/toolchain/BUILD.gn
  59. 13 0
      Build-Project/GN/Demo/configs/BUILD.gn
  60. 9 0
      Build-Project/GN/Demo/dll/BUILD.gn
  61. 6 0
      Build-Project/GN/Demo/dll/mylib.cpp
  62. 3 0
      Build-Project/GN/Demo/dll/mylib.h
  63. 12 0
      Build-Project/GN/Demo/exe/BUILD.gn
  64. 8 0
      Build-Project/GN/Demo/src/app.cpp
  65. 6 0
      Build-Project/GN/Demo/src/app.h
  66. 8 0
      Build-Project/GN/Demo/src/main.cpp
  67. 6 0
      Build-Project/GN/Demo/src/utils/utils.cpp
  68. 5 0
      Build-Project/GN/Demo/src/utils/utils.h
  69. BIN
      Build-Project/GN/Image/001.png
  70. BIN
      Build-Project/GN/Image/002.png
  71. 514 0
      Build-Project/GN/README.md
  72. 4 0
      Build-Project/README.md
  73. BIN
      Build-Project/内存知识/Image/001.png
  74. BIN
      Build-Project/内存知识/Image/002.png
  75. BIN
      Build-Project/内存知识/Image/003.png
  76. BIN
      Build-Project/内存知识/Image/004.png
  77. BIN
      Build-Project/内存知识/Image/005.png
  78. BIN
      Build-Project/内存知识/Image/006.png
  79. BIN
      Build-Project/内存知识/Image/007.png
  80. BIN
      Build-Project/内存知识/Image/008.png
  81. 103 0
      Build-Project/内存知识/README.md
  82. BIN
      Build-Project/内存知识/What Every Programmer Should Know About Memory.pdf
  83. BIN
      Build-Project/程序员的自我修养/Image/001.png
  84. BIN
      Build-Project/程序员的自我修养/Image/002.png
  85. BIN
      Build-Project/程序员的自我修养/Image/003.png
  86. BIN
      Build-Project/程序员的自我修养/Image/004.png
  87. 378 0
      Build-Project/程序员的自我修养/README.md
  88. BIN
      UE5/引擎开发记录/GIF/001.gif
  89. BIN
      UE5/引擎开发记录/Image/001.png
  90. BIN
      UE5/引擎开发记录/Image/002.png
  91. BIN
      UE5/引擎开发记录/Image/003.png
  92. BIN
      UE5/引擎开发记录/Image/004.png
  93. BIN
      UE5/引擎开发记录/Image/005.png
  94. BIN
      UE5/引擎开发记录/Image/006.png
  95. BIN
      UE5/引擎开发记录/Image/007.png
  96. BIN
      UE5/引擎开发记录/Image/008.png
  97. BIN
      UE5/引擎开发记录/Image/009.png
  98. BIN
      UE5/引擎开发记录/Image/010.png
  99. BIN
      UE5/引擎开发记录/Image/011.png
  100. BIN
      UE5/引擎开发记录/Image/012.png

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+Debug
+x64
+.vs

+ 1 - 0
Build-Project/CMake/.gitignore

@@ -0,0 +1 @@
+build/

BIN
Build-Project/CMake/Image/001.png


BIN
Build-Project/CMake/Image/002.png


BIN
Build-Project/CMake/Image/003.png


BIN
Build-Project/CMake/Image/004.png


BIN
Build-Project/CMake/Image/005.png


BIN
Build-Project/CMake/Image/006.png


BIN
Build-Project/CMake/Image/007.png


BIN
Build-Project/CMake/Image/008.png


+ 640 - 0
Build-Project/CMake/README.md

@@ -0,0 +1,640 @@
+# CMake
+
+[CMake 保姆级教程(上)](https://subingwen.cn/cmake/CMake-primer/)
+[CMake 保姆级教程(下)](https://subingwen.cn/cmake/CMake-advanced/)
+
+## 简单使用
+
+以 `src/demo1` 为例
+
+```bash
+$ tree
+.
+├── add.c
+├── div.c
+├── head.h
+├── main.c
+├── mult.c
+└── sub.c
+```
+
+在 `build` 文件夹中使用 `cmake ..` 生成项目
+
+```cmake
+# CMakeList.txt
+cmake_minimum_required(VERSION 3.0)
+project(CALC)
+add_executable(app add.c div.c main.c mult.c sub.c)
+# 等价于 add_executable(app add.c;div.c;main.c;mult.c;sub.c)
+```
+
+> 因为 `cmake` 生成的临时文件可能很多,所以在 build 文件夹中生成,这样不会污染根目录
+
+使用 `cmake` 之后,会生成中间文件和 `Makefile`,再使用 `make` 来执行,最后生成 `app.exe` (Windows 平台)
+
+| 命令 | 作用 |
+| --- | --- |
+| cmake_minimum_required | 指定使用的 cmake 的最低版本 |
+| project | 定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可 |
+| add_executable(可执行程序名 源文件名称) | 定义工程会生成一个可执行程序 |
+
+如果想要使用 cmake 创建指定类型的项目,可以在命令中指定
+
+![](Image/001.png)
+
+使用 `cmake -G` 可以查看可以生成的项目
+
+> `*` 标记的是默认生成项目类型
+
+如果想要生成 `Unix Makefiles` 或者其他版本的 `Visual Studio` 项目 的话,可以使用
+
+```
+cmake .. -G "Unix Makefiles"
+cmake .. -G "Visual Studio 16 2019"
+```
+
+> 为了方便使用 `make` 命令,所以后面一些测试使用 `Unix Makefiles`
+
+![](Image/002.png)
+
+> 这个 `visual studio` 项目的名称就是 `project` 中设置的 `CALC`
+
+![](Image/003.png)
+
+对应的命令就是 `add_executable(app add.c div.c main.c mult.c sub.c)`
+
+- 第一个参数 `app` 就是最后生成可执行程序的名称
+- 后面参数就是项目包含的文件名称
+
+### 定义变量
+
+如果一直使用 `add.c div.c main.c mult.c sub.c` 来表示所添加的问题,也是挺麻烦的
+
+可以定义变量来表示整个 `add.c div.c main.c mult.c sub.c` 文件
+
+```cmake
+# SET 指令的语法是:
+# [] 中的参数为可选项, 如不需要可以不写
+# SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
+
+set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
+add_executable(app  ${SRC_LIST})
+```
+
+- `SRC_LIST`: 变量名
+- `${SRC_LIST}`: 获取值
+
+#### C++版本
+
+编译 C++ 项目的时候需要指定 C++ 版本:C++11、C++14、C++17、C++20 等,有些项目会用到对应版本的特性
+
+以 g++ 编译的命令为例 
+
+```bash
+g++ *.cpp -std=c++11 -o app
+```
+
+> `-std=c++11` 对应 C++ 标准有一个宏叫做 `DCMAKE_CXX_STANDARD` 
+
+在 `cmake` 可以通过 `SET` 设置 `DCMAKE_CXX_STANDARD` 的值
+
+```cmake
+# -std=c++11
+set(CMAKE_CXX_STANDARD 11)
+# -std=c++14
+set(CMAKE_CXX_STANDARD 14)
+# -std=c++17
+set(CMAKE_CXX_STANDARD 17)
+```
+
+也可以使用在 `cmake` 命令中控制
+
+```bash
+cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
+cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14
+cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
+```
+
+#### 输出路径
+
+在CMake中指定可执行程序输出的路径,也对应一个宏,叫做`EXECUTABLE_OUTPUT_PATH`,它的值还是通过 `set` 命令进行设置
+
+```cmake
+set(HOME ./build)
+set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
+```
+
+生成 `Unix Makefiles` 项目,然后使用 `make` 执行
+
+![](Image/004.png)
+
+最后 `app.exe` 就生成在 `build/bin` 目录中
+
+> 如果路径不存在,会自动创建,无需手动生成
+
+### 文件检索
+
+如果项目中的源文件非常多,在编写 `CMakeLists.txt` 文件的时候不可能将项目目录的各个文件一一罗列出来,所以 `CMake` 提供了搜索文件的命令
+
+可以使用 `aux_source_directory` 命令或者 `file` 命令
+
+```cmake
+aux_source_directory(<dir> <variable>)
+```
+
+- `dir`: 要搜索的目录
+- `variable`: 将从 `dir` 目录下搜索的源文件列表存储到该变量中
+
+```cmake
+file(GLOB/GLOB_RECURSE 变量名 要搜索的文件路径和文件类型)
+```
+
+- `GLOB`: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中
+- `GLOB_RECURSE`: 递归搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中
+
+```cmake
+file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
+file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
+
+# message(${MAIN_SRC})
+# message(${MAIN_HEAD})
+
+message(${PROJECT_SOURCE_DIR})
+message(${CMAKE_CURRENT_SOURCE_DIR})
+
+FOREACH(item ${MAIN_SRC})
+    message(${item})
+ENDFOREACH()
+```
+
+![](Image/005.png)
+
+| 函数的变量 | 作用 |
+| --- | --- | 
+| CMAKE_CURRENT_SOURCE_DIR | 当前访问的 CMakeLists.txt 文件所在的路径 |
+| FOREACH | CMake 中遍历的写法,这里是遍历的头 |
+| ENDFOREACH | CMake 中遍历的写法,这里是遍历的尾 |
+| message | 输出指定内容 |
+
+编译项目源文件的时候,很多时候需要将源文件的**头文件**路径指定出来,这样才能保证在编译过程中编译器能找到这些文件,可以使用 `include_directories` 来包含这些头文件
+
+```cmake
+include_directories(headpath)
+```
+
+> 以 `demo2` 为例
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+set(CMAKE_CXX_STANDARD 11)
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/bin/)
+
+include_directories(${PROJECT_SOURCE_DIR}/include)
+file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
+
+add_executable(app  ${SRC_LIST})
+```
+
+### 动态库或静态库
+
+有些时候我们编写的源代码并不需要将他们编译生成可执行程序,而是生成一些静态库或动态库提供给第三方使用
+
+#### 制作静态库
+
+以 `demo3` 为例
+
+直接使用 `add_library` 制作静态库
+
+```cmake
+add_library(库名称 STATIC 源文件1 [源文件2] ...) 
+```
+
+> **STATIC**
+
+在 linux 中静态库名字分为三个部分:`lib` + 库名称 + `.a` ,但是这里只用指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充
+
+> Windows 与 Linux 的库名虽然不同,但是也只用指定名字即可
+
+- 在 `Linux` 平台下,可以直接通过 `make` 编译链接项目生成静态库
+- 在 `Windows` 平台下,通过 `CMake` 生成 `Visual Studio` 项目,通过 `Ctrl + B` 生成静态库
+
+![](Image/006.png)
+
+> `Windows` 平台就不要生成之前的说的 `Unix Makefiles` 的项目了
+
+#### 制作动态库
+
+以 `demo4` 为例
+
+制作动态库也是 `add_library` 
+
+```cmake
+add_library(库名称 SHARED 源文件1 [源文件2] ...) 
+```
+
+> **SHARED**
+
+![](Image/007.png)
+
+
+- `Linux` 平台下动态库的名字也是三部分:`lib` + 库名字 + `.so`
+- `Windows` 平台下动态库的名字以 `dll` 结尾
+
+#### 指定输出路径
+
+前面使用 `EXECUTABLE_OUTPUT_PATH` 指定了可执行程序的输出路径
+
+由于在 `Linux` 下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式 `EXECUTABLE_OUTPUT_PATH` 去指定它生成的目录
+
+但是 `Linux` 下静态库默认不具备可执行权限,所以 `EXECUTABLE_OUTPUT_PATH` 并不通用
+
+基于上面的原因,建议统一使用 `LIBRARY_OUTPUT_PATH` 来设置输出路径,该宏动态库和静态库都可以使用
+
+```cmake
+set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib)
+```
+
+### 日志
+
+> Demo5 为例
+
+```cmake
+message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
+```
+
+| category | 作用 |
+| --- | --- |
+| (无)  | 重要消息 | 
+| STATUS | 非重要消息 | 
+| WARNING | CMake 警告, 会继续执行 | 
+| AUTHOR_WARNING | CMake 警告 (dev), 会继续执行 | 
+| SEND_ERROR | CMake 错误, 继续执行,但是会跳过生成的步骤 | 
+| FATAL_ERROR | CMake 错误, 终止所有处理过程 | 
+
+![](Image/008.png)
+
+### 变量操作
+
+> Demo5 为例
+
+- 使用 `set` 进行字符串拼接
+
+```cmake
+set(变量名1 ${变量名1}${变量名2}...)
+```
+
+
+> `list` 不仅可以拼接,还有其他功能
+
+- 使用 `list(APPEND)` 进行字符串拼接
+- 使用 `list(INSERT)` 在指定的位置插入元素到列表
+- 使用 `list(PREPEND)` 在列表的开头添加一个或多个元素
+- 使用 `list(REMOVE_AT)` 移除在指定位置的元素
+- 使用 `list(REMOVE_ITEM)` 移除列表中所有匹配的元素
+- 使用 `list(REMOVE_DUPLICATES)` 移除列表中重复元素
+- 使用 `list(REVERSE)` 将列表元素顺序颠倒
+- 使用 `list(SORT)` 对列表元素进行排序
+- 使用 `list(LENGTH)` 获取列表长度
+- 使用 `list(GET)` 获取列表中指定位置的元素
+- 使用 `list(FIND)` 查找列表中第一个匹配的元素,未找到返回-1
+- 使用 `list(SUBLIST)` 获取列表中的一个子列表
+- 使用 `list(TRANSFORM)` 对列表的每个元素进行转换
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+project(ListExample)
+
+# 定义一个列表
+set(myList "item1" "item2" "item3")
+
+# APPEND
+list(APPEND myList "item4")
+message(STATUS "After APPEND: ${myList}")
+
+# INSERT
+list(INSERT myList 1 "newItem")
+message(STATUS "After INSERT: ${myList}")
+
+# PREPEND
+list(PREPEND myList "newStartItem")
+message(STATUS "After PREPEND: ${myList}")
+
+# REMOVE_AT
+list(REMOVE_AT myList 2)
+message(STATUS "After REMOVE_AT: ${myList}")
+
+# REMOVE_ITEM
+list(REMOVE_ITEM myList "item3")
+message(STATUS "After REMOVE_ITEM: ${myList}")
+
+# REMOVE_DUPLICATES
+list(APPEND myList "item4")
+list(REMOVE_DUPLICATES myList)
+message(STATUS "After REMOVE_DUPLICATES: ${myList}")
+
+# REVERSE
+list(REVERSE myList)
+message(STATUS "After REVERSE: ${myList}")
+
+# SORT
+list(SORT myList)
+message(STATUS "After SORT: ${myList}")
+
+# LENGTH
+list(LENGTH myList myListLength)
+message(STATUS "List length: ${myListLength}")
+
+# GET
+list(GET myList 0 firstElement)
+message(STATUS "First element: ${firstElement}")
+
+# FIND
+list(FIND myList "item2" index)
+message(STATUS "Index of item2: ${index}")
+
+# SUBLIST
+list(SUBLIST myList 1 2 subList)
+message(STATUS "Sublist: ${subList}")
+
+# TRANSFORM
+list(TRANSFORM myList TOUPPER)
+message(STATUS "After TRANSFORM TOUPPER: ${myList}")
+```
+
+### 宏定义
+
+> demo6 为例
+
+```cpp
+#include <stdio.h>
+#define NUMBER 3
+int main()
+{
+#ifdef DEBUG
+    printf("hello, world...\n");
+#endif
+    printf("hello, GCC!!!\n");
+    return 0;
+}
+```
+
+以上述代码为例,在 C++ 中经常会使用宏定义,可以宏定义值也可以根据宏定义执行不同的代码
+
+用 `gcc` 为例,使用 `gcc test.c -DDEBUG -o app` 来定义宏
+
+在 `cmake` 中可以使用 `add_definitions(-D宏名称)` 定义宏
+
+```cpp
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+add_definitions(-DDEBUG)
+
+add_executable(calc ./src/main.c)
+```
+
+### cmake 预定义宏
+
+> demo7 为例
+
+- 路径相关
+
+| 预定义 | 作用 |
+| --- | --- |
+| CMAKE_SOURCE_DIR | 表示顶层 CMakeLists.txt 文件所在的源代码目录 |
+| CMAKE_BINARY_DIR | 表示顶层 CMakeLists.txt 文件所在的构建目录 |
+| CMAKE_CURRENT_SOURCE_DIR | 表示当前处理的 CMakeLists.txt 文件所在的源代码目录 |
+| CMAKE_CURRENT_BINARY_DIR | 表示当前处理的 CMakeLists.txt 文件所在的构建目录 |
+| CMAKE_HOME_DIRECTORY | 表示项目的根目录,通常与 CMAKE_SOURCE_DIR 相同 |
+| PROJECT_SOURCE_DIR | 表示项目的源代码根目录 |
+| PROJECT_BINARY_DIR | 表示项目的构建根目录 |
+
+
+- 项目和版本信息
+
+| 预定义 | 作用 |
+| --- | --- |
+| PROJECT_NAME | 表示项目名称 |
+| PROJECT_VERSION | 表示项目的版本号(如果使用 project() 命令设置了版本) |
+| PROJECT_VERSION_MAJOR | 表示项目的主版本号 |
+| PROJECT_VERSION_MINOR | 表示项目的次版本号 |
+| PROJECT_VERSION_PATCH | 表示项目的补丁版本号 |
+
+- 编译器和操作系统
+
+| 预定义 | 作用 |
+| --- | --- |
+| CMAKE_C_COMPILER | 表示用于编译 C 程序的编译器名称 |
+| CMAKE_CXX_COMPILER | 表示用于编译 C++ 程序的编译器名称 |
+| CMAKE_SYSTEM_NAME | 表示操作系统的名称 |
+| CMAKE_SYSTEM_VERSION | 表示操作系统的版本 |
+| CMAKE_SIZEOF_VOID_P | 表示指针大小(用于判断是 32 位还是 64 位系统) |
+
+- 构建选项
+
+| 预定义 | 作用 |
+| --- | --- |
+| CMAKE_BUILD_TYPE | 表示当前的构建类型(如 Release、Debug) |
+| CMAKE_VERBOSE_MAKEFILE | 如果设置为 ON,会产生更详细的 makefile 输出 |
+| CMAKE_INSTALL_PREFIX | 表示安装路径的前缀 |
+
+- 检测目标系统
+
+
+| 预定义 | 作用 |
+| --- | --- |
+| WIN32 | 如果在 Windows 系统上为 TRUE |
+| UNIX | 如果在 Unix 或类 Unix 系统(包括 Linux 和 macOS)上为 TRUE |
+| APPLE | 如果在 macOS 系统上为 TRUE |
+| MSVC | 如果使用 Microsoft Visual C++ 编译器为 TRUE |
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+
+project(ExampleProject VERSION 1.2.3)
+
+message(STATUS "------------------------------------")
+
+message(STATUS "Project name: ${PROJECT_NAME}")
+message(STATUS "Project version: ${PROJECT_VERSION} (Major: ${PROJECT_VERSION_MAJOR}, Minor: ${PROJECT_VERSION_MINOR}, Patch: ${PROJECT_VERSION_PATCH})")
+
+message(STATUS "Source directory: ${CMAKE_SOURCE_DIR}")
+message(STATUS "Binary directory: ${CMAKE_BINARY_DIR}")
+message(STATUS "Current source directory: ${CMAKE_CURRENT_SOURCE_DIR}")
+message(STATUS "Current binary directory: ${CMAKE_CURRENT_BINARY_DIR}")
+
+message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
+message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}")
+
+message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
+message(STATUS "System version: ${CMAKE_SYSTEM_VERSION}")
+message(STATUS "Pointer size: ${CMAKE_SIZEOF_VOID_P}")
+
+if(WIN32)
+    message(STATUS "Building for Windows")
+elseif(UNIX)
+    message(STATUS "Building for Unix or Unix-like OS")
+    if(APPLE)
+        message(STATUS "Building for macOS")
+    endif()
+endif()
+
+message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
+
+message(STATUS "------------------------------------")
+```
+
+```bash
+-- ------------------------------------
+-- Project name: ExampleProject
+-- Project version: 1.2.3 (Major: 1, Minor: 2, Patch: 3)
+-- Source directory: F:/2_CustomProject/MarkdownLog/CMake/src/demo7
+-- Binary directory: F:/2_CustomProject/MarkdownLog/CMake/src/demo7/build
+-- Current source directory: F:/2_CustomProject/MarkdownLog/CMake/src/demo7
+-- Current binary directory: F:/2_CustomProject/MarkdownLog/CMake/src/demo7/build
+-- C compiler: C:/MinGW/bin/gcc.exe
+-- C++ compiler: C:/MinGW/bin/c++.exe
+-- System name: Windows
+-- System version: 10.0.19045
+-- Pointer size: 4
+-- Building for Windows
+-- Build type:
+-- Install prefix: C:/Program Files (x86)/ExampleProject
+-- ------------------------------------
+```
+
+如果想要使用其他 gcc.exe 或者 c++.exe,可以通过 `set` 来修改 `CMAKE_C_COMPILER` 或者 `CMAKE_CXX_COMPILER` 的值
+
+这些修改 `cmake` 预定义的变量需要在配置开始时设置,也就是在调用 `project` 或者 `enable_language` 之前
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+
+# 设置自定义编译器路径
+set(CMAKE_C_COMPILER "/path/to/custom/gcc")
+set(CMAKE_CXX_COMPILER "/path/to/custom/g++")
+
+project(CustomCompilerProject C CXX)
+
+message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
+message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}")
+
+# 其他 CMake 配置
+add_executable(myapp main.cpp)
+```
+
+除了在 `CMakeLists.txt` 中设置 `CMAKE_C_COMPILER` 等定义之外,还可以在命令行中设置
+
+```shell
+cmake -DCMAKE_C_COMPILER=/path/to/custom/gcc -DCMAKE_CXX_COMPILER=/path/to/custom/g++ -S . -B build
+```
+
+### 流程控制
+
+#### 条件判断
+
+```cmake
+if(<condition>)
+  <commands>
+elseif(<condition>) # 可选块, 可以重复
+  <commands>
+else()              # 可选块
+  <commands>
+endif()
+```
+
+- 基本表达式
+  - 如果是1, ON, YES, TRUE, Y, 非零值,非空字符串时,条件判断返回 True
+  - 如果是 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND,空字符串时,条件判断返回 False
+
+- 逻辑判断
+  - 取反 NOT `if(NOT <condition>)`
+  - 与 AND `if(<condition1> AND <condition2>)`
+  - 或 OR `if(<condition1> OR <condition2>)`
+
+- 比较
+  - 小 LESS `if(<variable|string> LESS <variable|string>)`
+  - 大 GREATER `if(<variable|string> GREATER <variable|string>)`
+  - 相等 EQUAL `if(<variable|string> EQUAL <variable|string>)`
+  - 小于等于 LESS_EQUAL `if(<variable|string> LESS_EQUAL <variable|string>)`
+  - 大于等于 GREATER_EQUAL `if(<variable|string> GREATER_EQUAL <variable|string>)`
+
+- 字符串比较
+  - 小 STRLESS
+  - 大 STRGREATER
+  - 等于 STRQUAL
+  - 小于等于 STRLESS_EQUAL
+  - 大于等于 STRGREATER_EQUAL
+
+- 文件判断
+  - 判断文件或者目录是否存在 `if(EXISTS path-to-file-or-directory)`
+  - 判断是不是目录 `if(IS_DIRECTORY path)`
+  - 判断是不是软链接 `if(IS_SYMLINK file-name)`
+  - 判断是不是绝对路径 `if(IS_ABSOLUTE path)`
+
+> 还有一些其他判断 [cmake if 官网](https://cmake.org/cmake/help/latest/command/if.html)
+
+#### 循环
+
+```cmake
+foreach(<loop_var> <items>)
+    <commands>
+endforeach()
+```
+
+使用 `foreach` 和 `endforeach` 定义循环体
+
+- 遍历 list 
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+project(ForeachLoopExample)
+
+set(myList "item1" "item2" "item3")
+
+foreach(item IN LISTS myList)
+    message(STATUS "List item: ${item}")
+endforeach()
+```
+
+- 遍历范围 `foreach(<loop_var> RANGE <stop>)`
+
+```cmake
+cmake_minimum_required(VERSION 3.0)
+project(ForeachRangeExample)
+
+foreach(i RANGE 5)
+    message(STATUS "Index: ${i}")
+endforeach()
+```
+
+- 遍历范围,带步长 `foreach(<loop_var> RANGE <start> <stop> [<step>])`
+
+```cmake
+cmake_minimum_required(VERSION 3.2)
+project(test)
+# 创建 list
+set(WORD a b c d)
+set(NAME ace sabo luffy)
+# 遍历 list
+foreach(item IN LISTS WORD NAME)
+    message(STATUS "当前遍历的值为: ${item}" )
+endforeach()
+```
+
+> 同时遍历 `WORD` 和 `NAME` 两个 `list`
+
+`while` 循环
+
+```cmake
+while(<condition>)
+    <commands>
+endwhile()
+```
+
+## 项目代码

+ 24 - 0
Build-Project/CMake/src/demo1/CMakeLists.txt

@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+set(SRC_FILES add.c;div.c;main.c;mult.c;sub.c)
+# set(CMAKE_CXX_STANDARD 17)
+
+set(HOME ./build)
+set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
+
+file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
+file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
+
+# message(${MAIN_SRC})
+# message(${MAIN_HEAD})
+
+message(${PROJECT_SOURCE_DIR})
+message(${CMAKE_CURRENT_SOURCE_DIR})
+
+FOREACH(item ${MAIN_SRC})
+    message(${item})
+ENDFOREACH()
+
+add_executable(app ${SRC_FILES})

+ 7 - 0
Build-Project/CMake/src/demo1/add.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int add(int a, int b)
+{
+    return a+b;
+}

+ 7 - 0
Build-Project/CMake/src/demo1/div.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+double divide(int a, int b)
+{
+    return (double)a/b;
+}

+ 11 - 0
Build-Project/CMake/src/demo1/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 14 - 0
Build-Project/CMake/src/demo1/main.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include "head.h"
+
+int main()
+{
+    int a = 20;
+    int b = 12;
+    printf("a = %d, b = %d\n", a, b);
+    printf("a + b = %d\n", add(a, b));
+    printf("a - b = %d\n", subtract(a, b));
+    printf("a * b = %d\n", multiply(a, b));
+    printf("a / b = %f\n", divide(a, b));
+    return 0;
+}

+ 7 - 0
Build-Project/CMake/src/demo1/mult.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int multiply(int a, int b)
+{
+    return a*b;
+}

+ 8 - 0
Build-Project/CMake/src/demo1/sub.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "head.h"
+
+// 你好
+int subtract(int a, int b)
+{
+    return a-b;
+}

+ 11 - 0
Build-Project/CMake/src/demo2/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+set(CMAKE_CXX_STANDARD 11)
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/bin/)
+
+include_directories(${PROJECT_SOURCE_DIR}/include)
+file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
+
+add_executable(app  ${SRC_LIST})

+ 11 - 0
Build-Project/CMake/src/demo2/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 7 - 0
Build-Project/CMake/src/demo2/src/add.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int add(int a, int b)
+{
+    return a+b;
+}

+ 7 - 0
Build-Project/CMake/src/demo2/src/div.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+double divide(int a, int b)
+{
+    return (double)a/b;
+}

+ 14 - 0
Build-Project/CMake/src/demo2/src/main.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include "head.h"
+
+int main()
+{
+    int a = 20;
+    int b = 12;
+    printf("a = %d, b = %d\n", a, b);
+    printf("a + b = %d\n", add(a, b));
+    printf("a - b = %d\n", subtract(a, b));
+    printf("a * b = %d\n", multiply(a, b));
+    printf("a / b = %f\n", divide(a, b));
+    return 0;
+}

+ 7 - 0
Build-Project/CMake/src/demo2/src/mult.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int multiply(int a, int b)
+{
+    return a*b;
+}

+ 8 - 0
Build-Project/CMake/src/demo2/src/sub.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "head.h"
+
+// 你好
+int subtract(int a, int b)
+{
+    return a-b;
+}

+ 12 - 0
Build-Project/CMake/src/demo3/CMakeLists.txt

@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+set(CMAKE_CXX_STANDARD 11)
+set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/bin/)
+
+include_directories(${PROJECT_SOURCE_DIR}/include)
+file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
+
+# 根据设定生成库
+add_library(calc STATIC ${SRC_LIST})

+ 11 - 0
Build-Project/CMake/src/demo3/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 7 - 0
Build-Project/CMake/src/demo3/src/add.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int add(int a, int b)
+{
+    return a+b;
+}

+ 7 - 0
Build-Project/CMake/src/demo3/src/div.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+double divide(int a, int b)
+{
+    return (double)a/b;
+}

+ 14 - 0
Build-Project/CMake/src/demo3/src/main.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include "head.h"
+
+int main()
+{
+    int a = 20;
+    int b = 12;
+    printf("a = %d, b = %d\n", a, b);
+    printf("a + b = %d\n", add(a, b));
+    printf("a - b = %d\n", subtract(a, b));
+    printf("a * b = %d\n", multiply(a, b));
+    printf("a / b = %f\n", divide(a, b));
+    return 0;
+}

+ 7 - 0
Build-Project/CMake/src/demo3/src/mult.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int multiply(int a, int b)
+{
+    return a*b;
+}

+ 8 - 0
Build-Project/CMake/src/demo3/src/sub.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "head.h"
+
+// 你好
+int subtract(int a, int b)
+{
+    return a-b;
+}

+ 12 - 0
Build-Project/CMake/src/demo4/CMakeLists.txt

@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+set(CMAKE_CXX_STANDARD 11)
+set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/bin/)
+
+include_directories(${PROJECT_SOURCE_DIR}/include)
+file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c)
+
+# 根据设定生成库
+add_library(calc SHARED ${SRC_LIST})

+ 11 - 0
Build-Project/CMake/src/demo4/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 7 - 0
Build-Project/CMake/src/demo4/src/add.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int add(int a, int b)
+{
+    return a+b;
+}

+ 7 - 0
Build-Project/CMake/src/demo4/src/div.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+double divide(int a, int b)
+{
+    return (double)a/b;
+}

+ 14 - 0
Build-Project/CMake/src/demo4/src/main.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include "head.h"
+
+int main()
+{
+    int a = 20;
+    int b = 12;
+    printf("a = %d, b = %d\n", a, b);
+    printf("a + b = %d\n", add(a, b));
+    printf("a - b = %d\n", subtract(a, b));
+    printf("a * b = %d\n", multiply(a, b));
+    printf("a / b = %f\n", divide(a, b));
+    return 0;
+}

+ 7 - 0
Build-Project/CMake/src/demo4/src/mult.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int multiply(int a, int b)
+{
+    return a*b;
+}

+ 8 - 0
Build-Project/CMake/src/demo4/src/sub.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "head.h"
+
+// 你好
+int subtract(int a, int b)
+{
+    return a-b;
+}

+ 71 - 0
Build-Project/CMake/src/demo5/CMakeLists.txt

@@ -0,0 +1,71 @@
+
+
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+# 输出一般日志信息
+message(STATUS "status: ${PROJECT_SOURCE_DIR}")
+# 输出警告信息
+message(WARNING "warning: ${PROJECT_SOURCE_DIR}")
+
+set(TEMP "Hello")
+set(TEMP ${TEMP} " World")
+message(${TEMP})
+
+# 定义一个列表
+set(myList "item1" "item2" "item3")
+
+# APPEND
+list(APPEND myList "item4")
+message(STATUS "After APPEND: ${myList}")
+
+# INSERT
+list(INSERT myList 1 "newItem")
+message(STATUS "After INSERT: ${myList}")
+
+# PREPEND
+list(PREPEND myList "newStartItem")
+message(STATUS "After PREPEND: ${myList}")
+
+# REMOVE_AT
+list(REMOVE_AT myList 2)
+message(STATUS "After REMOVE_AT: ${myList}")
+
+# REMOVE_ITEM
+list(REMOVE_ITEM myList "item3")
+message(STATUS "After REMOVE_ITEM: ${myList}")
+
+# REMOVE_DUPLICATES
+list(APPEND myList "item4")
+list(REMOVE_DUPLICATES myList)
+message(STATUS "After REMOVE_DUPLICATES: ${myList}")
+
+# REVERSE
+list(REVERSE myList)
+message(STATUS "After REVERSE: ${myList}")
+
+# SORT
+list(SORT myList)
+message(STATUS "After SORT: ${myList}")
+
+# LENGTH
+list(LENGTH myList myListLength)
+message(STATUS "List length: ${myListLength}")
+
+# GET
+list(GET myList 0 firstElement)
+message(STATUS "First element: ${firstElement}")
+
+# FIND
+list(FIND myList "item2" index)
+message(STATUS "Index of item2: ${index}")
+
+# SUBLIST
+list(SUBLIST myList 1 2 subList)
+message(STATUS "Sublist: ${subList}")
+
+# TRANSFORM
+list(TRANSFORM myList TOUPPER)
+message(STATUS "After TRANSFORM TOUPPER: ${myList}")
+

+ 11 - 0
Build-Project/CMake/src/demo5/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 7 - 0
Build-Project/CMake/src/demo5/src/add.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int add(int a, int b)
+{
+    return a+b;
+}

+ 7 - 0
Build-Project/CMake/src/demo5/src/div.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+double divide(int a, int b)
+{
+    return (double)a/b;
+}

+ 14 - 0
Build-Project/CMake/src/demo5/src/main.c

@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include "head.h"
+
+int main()
+{
+    int a = 20;
+    int b = 12;
+    printf("a = %d, b = %d\n", a, b);
+    printf("a + b = %d\n", add(a, b));
+    printf("a - b = %d\n", subtract(a, b));
+    printf("a * b = %d\n", multiply(a, b));
+    printf("a / b = %f\n", divide(a, b));
+    return 0;
+}

+ 7 - 0
Build-Project/CMake/src/demo5/src/mult.c

@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "head.h"
+
+int multiply(int a, int b)
+{
+    return a*b;
+}

+ 8 - 0
Build-Project/CMake/src/demo5/src/sub.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+#include "head.h"
+
+// 你好
+int subtract(int a, int b)
+{
+    return a-b;
+}

+ 7 - 0
Build-Project/CMake/src/demo6/CMakeLists.txt

@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(CALC)
+
+add_definitions(-DDEBUG)
+
+add_executable(calc ./src/main.c)

+ 11 - 0
Build-Project/CMake/src/demo6/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 9 - 0
Build-Project/CMake/src/demo6/src/main.c

@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main() {
+#ifdef DEBUG
+    printf("Hello, World!\n");
+#endif
+    printf("End!\n");
+    return 0;
+}

+ 34 - 0
Build-Project/CMake/src/demo7/CMakeLists.txt

@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(ExampleProject VERSION 1.2.3)
+
+message(STATUS "------------------------------------")
+
+message(STATUS "Project name: ${PROJECT_NAME}")
+message(STATUS "Project version: ${PROJECT_VERSION} (Major: ${PROJECT_VERSION_MAJOR}, Minor: ${PROJECT_VERSION_MINOR}, Patch: ${PROJECT_VERSION_PATCH})")
+
+message(STATUS "Source directory: ${CMAKE_SOURCE_DIR}")
+message(STATUS "Binary directory: ${CMAKE_BINARY_DIR}")
+message(STATUS "Current source directory: ${CMAKE_CURRENT_SOURCE_DIR}")
+message(STATUS "Current binary directory: ${CMAKE_CURRENT_BINARY_DIR}")
+
+message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
+message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}")
+
+message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
+message(STATUS "System version: ${CMAKE_SYSTEM_VERSION}")
+message(STATUS "Pointer size: ${CMAKE_SIZEOF_VOID_P}")
+
+if(WIN32)
+    message(STATUS "Building for Windows")
+elseif(UNIX)
+    message(STATUS "Building for Unix or Unix-like OS")
+    if(APPLE)
+        message(STATUS "Building for macOS")
+    endif()
+endif()
+
+message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
+
+message(STATUS "------------------------------------")

+ 11 - 0
Build-Project/CMake/src/demo7/include/head.h

@@ -0,0 +1,11 @@
+#ifndef _HEAD_H
+#define _HEAD_H
+// 加法
+int add(int a, int b);
+// 减法
+int subtract(int a, int b);
+// 乘法
+int multiply(int a, int b);
+// 除法
+double divide(int a, int b);
+#endif

+ 9 - 0
Build-Project/CMake/src/demo7/src/main.c

@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main() {
+#ifdef DEBUG
+    printf("Hello, World!\n");
+#endif
+    printf("End!\n");
+    return 0;
+}

+ 1 - 0
Build-Project/GN/.gitignore

@@ -0,0 +1 @@
+out

+ 2 - 0
Build-Project/GN/Demo/.gn

@@ -0,0 +1,2 @@
+# The location of the build configuration file.
+buildconfig = "//build/BUILDCONFIG.gn"

+ 7 - 0
Build-Project/GN/Demo/BUILD.gn

@@ -0,0 +1,7 @@
+# BUILD.gn
+group("default") {
+  deps = [
+    "//dll:mylib",
+    "//exe:my_app"
+  ]
+}

+ 21 - 0
Build-Project/GN/Demo/build/BUILD.gn

@@ -0,0 +1,21 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("compiler_defaults") {
+  if (current_os == "linux") {
+    cflags = [
+      "-fPIC",
+      "-pthread",
+    ]
+  }
+}
+
+config("executable_ldconfig") {
+  if (!is_mac) {
+    ldflags = [
+      "-Wl,-rpath=\$ORIGIN/",
+      "-Wl,-rpath-link=",
+    ]
+  }
+}

+ 46 - 0
Build-Project/GN/Demo/build/BUILDCONFIG.gn

@@ -0,0 +1,46 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (target_os == "") {
+  target_os = host_os
+}
+if (target_cpu == "") {
+  target_cpu = host_cpu
+}
+if (current_cpu == "") {
+  current_cpu = target_cpu
+}
+if (current_os == "") {
+  current_os = target_os
+}
+
+
+is_linux = host_os == "linux" && current_os == "linux" && target_os == "linux"
+is_mac = host_os == "mac" && current_os == "mac" && target_os == "mac"
+
+print("host_os = ${host_os} host_cpu = ${host_cpu} target_os = ${target_os} target_cpu = ${target_cpu} current_os = ${current_os} current_cpu = ${current_cpu}")
+
+print("is_linux = ${is_linux} is_mac = ${is_mac}")
+
+# All binary targets will get this list of configs by default.
+_shared_binary_target_configs = [ "//build:compiler_defaults" ]
+
+# Apply that default list to the binary target types.
+set_defaults("executable") {
+  configs = _shared_binary_target_configs
+
+  # Executables get this additional configuration.
+  configs += [ "//build:executable_ldconfig" ]
+}
+set_defaults("static_library") {
+  configs = _shared_binary_target_configs
+}
+set_defaults("shared_library") {
+  configs = _shared_binary_target_configs
+}
+set_defaults("source_set") {
+  configs = _shared_binary_target_configs
+}
+
+set_default_toolchain("//build/toolchain:gcc")

+ 90 - 0
Build-Project/GN/Demo/build/toolchain/BUILD.gn

@@ -0,0 +1,90 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+toolchain("gcc") {
+  tool("cc") {
+    depfile = "{{output}}.d"
+    command = "gcc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CC {{output}}"
+    outputs =
+        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
+  }
+
+  tool("cxx") {
+    depfile = "{{output}}.d"
+    command = "g++ -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+    depsformat = "gcc"
+    description = "CXX {{output}}"
+    outputs =
+        [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
+  }
+
+  tool("alink") {
+    command = "ar rcs {{output}} {{inputs}}"
+    description = "AR {{target_output_name}}{{output_extension}}"
+
+    outputs =
+        [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+    default_output_extension = ".a"
+    output_prefix = "lib"
+  }
+
+  tool("solink") {
+    soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
+    sofile = "{{output_dir}}/$soname"
+    rspfile = soname + ".rsp"
+    if (is_mac) {
+      os_specific_option = "-install_name @executable_path/$sofile"
+      rspfile_content = "{{inputs}} {{solibs}} {{libs}}"
+    } else {
+      os_specific_option = "-Wl,-soname=$soname"
+      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+    }
+
+    command = "g++ -shared {{ldflags}} -o $sofile $os_specific_option @$rspfile"
+
+    description = "SOLINK $soname"
+
+    # Use this for {{output_extension}} expansions unless a target manually
+    # overrides it (in which case {{output_extension}} will be what the target
+    # specifies).
+    default_output_extension = ".so"
+
+    # Use this for {{output_dir}} expansions unless a target manually overrides
+    # it (in which case {{output_dir}} will be what the target specifies).
+    default_output_dir = "{{root_out_dir}}"
+
+    outputs = [ sofile ]
+    link_output = sofile
+    depend_output = sofile
+    output_prefix = "lib"
+  }
+
+  tool("link") {
+    outfile = "{{target_output_name}}{{output_extension}}"
+    rspfile = "$outfile.rsp"
+    if (is_mac) {
+      command = "g++ {{ldflags}} -o $outfile @$rspfile {{solibs}} {{libs}}"
+    } else {
+      command = "g++ {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}}"
+    }
+    description = "LINK $outfile"
+    default_output_dir = "{{root_out_dir}}"
+    rspfile_content = "{{inputs}}"
+    outputs = [ outfile ]
+
+    print("link tool")
+  }
+
+  tool("stamp") {
+    command = "touch {{output}}"
+    description = "STAMP {{output}}"
+  }
+
+  tool("copy") {
+    command = "cp -af {{source}} {{output}}"
+    description = "COPY {{source}} {{output}}"
+  }
+}

+ 13 - 0
Build-Project/GN/Demo/configs/BUILD.gn

@@ -0,0 +1,13 @@
+# configs/BUILD.gn
+config("common_config") {
+  include_dirs = [
+    "//src",
+    "//dll"
+  ]
+
+  cflags = [
+    "-std=c++17"
+  ]
+
+  ldflags = []
+}

+ 9 - 0
Build-Project/GN/Demo/dll/BUILD.gn

@@ -0,0 +1,9 @@
+
+shared_library("mylib") {
+  configs += [ "//configs:common_config" ]
+
+  sources = [
+    "mylib.cpp",
+  ]
+
+}

+ 6 - 0
Build-Project/GN/Demo/dll/mylib.cpp

@@ -0,0 +1,6 @@
+#include "mylib.h"
+#include <iostream>
+
+void mylib_function() {
+    std::cout << "Function in mylib" << std::endl;
+}

+ 3 - 0
Build-Project/GN/Demo/dll/mylib.h

@@ -0,0 +1,3 @@
+#pragma once
+
+void mylib_function();

+ 12 - 0
Build-Project/GN/Demo/exe/BUILD.gn

@@ -0,0 +1,12 @@
+# exe/BUILD.gn
+executable("my_app") {
+  sources = [
+    "//src/main.cpp",
+    "//src/app.cpp",
+    "//src/utils/utils.cpp"
+  ]
+
+  deps = [ "//dll:mylib" ]
+
+  configs += [ "//configs:common_config" ]
+}

+ 8 - 0
Build-Project/GN/Demo/src/app.cpp

@@ -0,0 +1,8 @@
+#include "app.h"
+#include "utils/utils.h"
+#include <iostream>
+
+void App::run() {
+    std::cout << "App running" << std::endl;
+    Utils::doSomething();
+}

+ 6 - 0
Build-Project/GN/Demo/src/app.h

@@ -0,0 +1,6 @@
+#pragma once
+
+class App {
+public:
+    void run();
+};

+ 8 - 0
Build-Project/GN/Demo/src/main.cpp

@@ -0,0 +1,8 @@
+#include "app.h"
+#include "utils/utils.h"
+
+int main() {
+    App app;
+    app.run();
+    return 0;
+}

+ 6 - 0
Build-Project/GN/Demo/src/utils/utils.cpp

@@ -0,0 +1,6 @@
+#include "utils/utils.h"
+#include <iostream>
+
+void Utils::doSomething() {
+    std::cout << "Utils doing something" << std::endl;
+}

+ 5 - 0
Build-Project/GN/Demo/src/utils/utils.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace Utils {
+    void doSomething();
+}

BIN
Build-Project/GN/Image/001.png


BIN
Build-Project/GN/Image/002.png


+ 514 - 0
Build-Project/GN/README.md

@@ -0,0 +1,514 @@
+# gn
+
+[gn快速开始](https://github.com/chinanf-boy/gn-zh/blob/master/docs/quick_start.zh.md)
+
+> 该仓库基于 google 的 gn 仓库进行的翻译
+
+## 语法
+
+GN 使用非常简单、动态类型的语言
+
+- 布尔类型 (`true`、`false`)
+- 64有符号整数
+- string
+- 列表
+- 范围(类似字典,只用于内置的东西)
+
+### 字符串
+
+**字符串**以双引号括起来,并使用反斜杠作为转义字符
+
+但是反斜杠只支持 `\"`、 `\$`、 `\\`,反斜杠任何其他的用途都会被视为**字面反斜杠**
+
+> `"C:\foo\bar.h"` 这里的 `\b` 没有被转义
+
+**字符串**支持跟随 `$` 符号的词被变量的值替换,也可以使用 `{}` 来替换变量值
+
+以 `a = "my_path"` 为例
+
+| 写法 | 实际值 |
+| --- | --- |
+| `b = "$a/foo.cc"` | `b = "my_path/foo.cc"` |
+| `c = "$foo_{a}_bar.cc"` | `c = "foo_my_path_bar.cc"` |
+
+### 列表
+
+**列表**支持增加、删除、索引操作,但是**不支持获取列表长度**
+
+```gn
+# 增加
+a = [ "first" ]
+a += [ "second" ]  # [ "first", "second" ]
+a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
+b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
+
+# 删除
+a = [ "first", "second", "third", "first" ]
+b = a - [ "first" ]  # [ "second", "third" ]
+a -= [ "second" ]  # [ "first", "third", "fourth" ]
+
+# 索引
+a = [ "first", "second", "third" ]
+b = a[1]  # -> "second"
+```
+
+`[]` 运算符是只读的,不能用于对列表进行改变,这种i情况的主要用途是当外部脚本返回几个已知值时,可以提取
+
+```gn
+a = [ "one" ]
+a = [ "two" ]  # Error: overwriting nonempty list with a nonempty list.
+a = []         # OK
+a = [ "two" ]  # OK
+```
+
+### 条件
+
+```c
+if (is_linux || (is_win && target_cpu == "x86")) {
+        sources -= [ "something.cc" ]
+    } else if (...) {
+        ...
+    } else {
+    ...
+}
+```
+
+
+### 循环
+
+```c
+foreach(i, mylist) {
+    print(i)  # Note: i is a copy of each element, not a reference to it.
+}
+```
+
+### 文件名
+
+- 相对名称
+
+```c
+"foo.cc"
+"src/foo.cc"
+"../src/foo.cc"
+```
+
+- 源数绝对名称
+
+```c
+"//net/foo.cc"
+"//base/test/foo.cc"
+```
+
+- 系统绝对名称
+
+```c
+"/usr/local/include/"
+"/C:/Program Files/Windows Kits/Include"
+```
+
+### 构建配置-目标
+
+| 命令 | 作用 |
+| --- | --- |
+| action | 运行脚本生成文件. |
+| action_foreach | 为每个源文件运行一次脚本. |
+| bundle_dat | 一个声明数据进入 MAC/iOS 包. |
+| create_bundle | 创建一个 Mac/IOS 包. |
+| executable | 生成一个可执行文件. |
+| group | 是指一个或多个其他目标的虚拟依赖节点. |
+| shared_library | 一个 . DLL 或.SO. |
+| loadable_module | 一个 .DLL 或.SO ,只能在运行时加载. |
+| source_set | 一个轻量级的虚拟静态库(通常比实际静态库更可取,因为它将更快地构建). |
+| static_library | 是.LIB 或.file(通常你需要一个source_set取而代之) |
+
+### 构建配置-Config
+
+```gn
+# 定义 config
+config("my_config") {
+  # 预处理器宏定义
+  defines = [
+    "USE_FEATURE_X",
+    "ENABLE_LOGGING"
+  ]
+
+  # 包含目录
+  include_dirs = [
+    "//include",
+    "//third_party/lib/include"
+  ]
+
+  # 编译选项
+  cflags = [
+    "-Wall",
+    "-O2"
+  ]
+
+  # 链接选项
+  ldflags = [
+    "-lmylib"
+  ]
+}
+
+```
+
+```gn
+# 将 config 应用到目标
+# 引用自定义配置文件
+import("//configs/my_config.gni")
+
+executable("my_app") {
+  sources = [
+    "main.cc",
+    "app.cc"
+  ]
+
+  # 使用定义的 config
+  configs += [ ":my_config" ]
+}
+
+```
+
+为什么上面例子应用 config 时要用 `configs += [":my_config"]` ?
+
+这里 `+=` 表示向现有的 configs 属性追加 :my_config,保留之前的所有设置。如果直接使用 `=` 则表示直接覆盖掉之前的配置 
+
+为什么应用 config 时要写 `:my_config` ?
+
+- `:config_name` 表示当前文件中的配置
+- `//path/to:config_name` 表示绝对路劲的配置
+- `//path/to/configs:config_name` 表示绝对路径下特定目录中的配置
+
+以下面的路劲为例子
+
+```bash
+my_project/
+├── BUILD.gn
+├── config/
+│   └── my_config.gni
+└── src/
+    └── main.cc
+```
+
+在 `config/my_config.gni` 中定义
+
+```gn
+config("my_config") {
+  cflags = [
+    "-Wall",
+    "-O2"
+  ]
+}
+```
+
+在 `BUILD.gn` 中
+
+```gn
+# 导入配置文件
+import("//config/my_config.gni")
+
+executable("my_app") {
+  sources = [
+    "src/main.cc"
+  ]
+
+  # 正确的使用方式:使用绝对路径或当前作用域
+  configs = [ "//config:my_config" ]  # 绝对路径
+  # 或
+  configs += [ ":my_config" ]  # 当前作用域,假设 my_config 在当前文件中定义
+}
+```
+
+假设模块A依赖于某个配置B,希望所有依赖于 A 模块的其他模块都依赖配置 B,这个时候应该使用 **公共配置**
+
+```gn
+# 配置B
+config("my_external_library_config") {
+  includes = "."
+  defines = [ "DISABLE_JANK" ]
+}
+
+# 模块A
+shared_library("my_external_library") {
+  ...
+  # 所有依赖于这个库的目标都拿到了公共配置.
+  public_configs = [ ":my_external_library_config" ]
+}
+
+# 其他模块
+static_library("intermediate_library") {
+  ...
+  # Targets that depend on this one also get the configs from "my external library".
+  public_deps = [ ":my_external_library" ]
+}
+```
+
+### 构建配置-模板
+
+`template` 㻾创建自定义的符合构建目标。通过定义模板,可以将一组常用的构建配置封装起来,然后再多个地方复用,减少重复代码并提高构建文件的可维护性
+
+```gn
+# 定义 template
+# my_templates.gni
+
+template("my_executable_with_tests") {
+  # 定义模板参数
+  declare_args() {
+    sources = []
+    test_sources = []
+  }
+
+  # 创建可执行文件目标
+  executable(target_name) {
+    sources = sources
+  }
+
+  # 创建测试可执行文件目标
+  executable(target_name + "_test") {
+    sources = test_sources
+    deps = [ ":$target_name" ]
+  }
+}
+```
+
+使用 `template`
+
+```gn
+# 引用模板文件
+import("//path/to/my_templates.gni")
+
+# 使用模板来创建构建目标
+my_executable_with_tests("my_app") {
+  sources = [ "main.cc", "app.cc" ]
+  test_sources = [ "app_test.cc" ]
+}
+```
+
+模板的第一个参数会被用作 target_name,即目标名称。所以 `template` 中定义的 `target_name` 对应的就是 `my_app`
+
+除了定义之外,`template` 中还能定义 条件判断、循环、嵌套模板
+
+```gn
+# templates/my_templates.gni
+
+template("my_executable_with_tests") {
+  declare_args() {
+    sources = []
+    test_sources = []
+    use_optimization = false
+  }
+
+  if (use_optimization) {
+    config("optimization_config") {
+      cflags = [ "-O2" ]
+    }
+  }
+
+  executable(target_name) {
+    sources = sources
+    if (use_optimization) {
+      configs += [ ":optimization_config" ]
+    }
+  }
+
+  executable(target_name + "_test") {
+    sources = test_sources
+    deps = [ ":$target_name" ]
+  }
+}
+
+```
+
+## 交叉编译
+
+[GN如何处理跨平台编译](https://github.com/chinanf-boy/gn-zh/blob/master/docs/cross_compiles.zh.md)
+
+## 注意
+
+注意路径中不要出现中文,否则可能会出现莫名其妙的错误
+
+## 样例
+
+### Hello-GN
+
+[Hello-GN](https://github.com/mhf-air/hello-gn)
+
+
+通常来说
+
+- 项目中会有一个 `.gn` 文件
+
+`.gn` 文件是项目的入口文件,该文件会依赖其他的配置文件, `gn` 会逐级加载这些被依赖的配置文件。依赖项加载完毕之后,再从项目的根目录开始逐级加载所有 `.gn` 结尾的文件
+
+> 根目录中的 `BUILD.gn` 文件所依赖的其他的其他文件会被加载
+
+- 项目中可能存在多个`BUILDCONFIG.gn` 文件
+
+通常来说 `BUILDCONFIG.gn` 是一个特殊文件,通产用于定义全局构建配置、设置默认值、全局变量等,这些配置可以被项目中的其他 `BUILD.gn` 文件引用
+
+| 作用 | 代码 |
+| --- | --- |
+| 定义全局变量 | `declare_args() { is_debug = false }` |
+| 设置默认值 | 定义默认的编译器选项、链接器选项等 |
+| 导入公共配置 | `import("//build/config/compiler.gni")` |
+| 配置工具链 | `toolchain("win") {  }` | 
+| 定义构建逻辑 | `if(is_win) {  }` |
+
+常见变量
+
+| 变量 | 含义 |
+| --- | --- |
+| os | 操作系统 |
+| cpu | 处理器 |
+| host | 编译时的主机 |
+| target | 目标平台 |
+| current | 当前配置 |
+
+常见配置写法
+
+```gn
+if (target_os == "") {
+  target_os = host_os
+}
+
+if (target_cpu == "") {
+  if (target_os == "android") {
+    target_cpu = "arm"
+  } else {
+    target_cpu = host_cpu
+  }
+}
+
+if (current_cpu == "") {
+  current_cpu = target_cpu
+}
+if (current_os == "") {
+  current_os = target_os
+}
+```
+
+- 项目中会有一个 `build\toolchain` 文件夹,里面存放着 `BUILD.gn`
+
+
+构建项目的结构是项目根目录的 `BUILD.gn` 文件
+
+```c
+executable("hello") {
+    ...
+}
+
+shared_library("hello_shared") {
+    ...
+}
+
+static_library("hello_static") {
+    ...
+}
+```
+
+在 `build\toolchain\BUILD.gn` 中定义了工具链
+
+```c
+toolchain("gcc") {
+    tool("cc") { ... }
+    tool("alink") { ... }
+    tool("solink") { ... }
+    tool("link") { ... }
+    tool("stamp") { ... }
+    tool("copy") { ... }
+}
+```
+
+在 `GN` 中,工具链(`toolchain`)和工具(`tools`)的调用是通过目标类型(如 `executable`、`static_library`、`shared_library` 等)和默认配置来自动处理的
+
+编译 C/C++ 源文件时会自动调用 `cc` 工具,链接静态库时会调用 `alink` 工具,链接共享库时会调用 `solink` 工具,生成可执行文件时会调用 `link` 工具
+
+| 命令 | 工具 |
+| --- | --- |
+| `executable` | `cc`、`link` |
+| `static_library` | `alink` |
+| `shared_library` | `solink` |
+| `source_set` 或 `group` | `stamp` |
+
+在 `BUILDCONFIG.gn` 中通过 `set_default_toolchain("//build/toolchain:gcc")` 设置默认工具
+
+
+
+### 案例2
+
+[GN实践](https://blog.csdn.net/weixin_44701535/article/details/88355958)
+
+[GN Demo 项目](https://github.com/TechGhostForGithub/source_gn_project)
+
+`BUILD.gn` 一般作为模块的工程入口文件,可以配合 .gni 文件来划分源码或模块
+
+`.gn` 根文件是一个入口设置的文件,是 GN 中的固定规则文件,会自动被 GN 读取
+
+![](Image/001.png)
+
+一般 GN 组织一个跨平台工程分为**三大块**
+
+1. 整体工程入口,一般不经常修改
+2. GN 通用文件,一般不经常修改
+3. GN 源代码工程文件,这部分与平常在继承开发环境中类似,源文件的组织和管理就在这部分
+
+![](Image/002.png)
+
+> 各个 GN 文件的作用
+
+以根目录的 `BUILD.gn` 为例
+
+```gn
+if (!is_test) {
+    group("ccore"){
+        deps = projects
+        deps += [ "//:dispatch_for_ide" ]
+    }
+}
+
+action("dispatch_for_ide") {
+    arg = [
+        "--kernel", rebase_path("//"),
+        "--outpath", rebase_path("//out"),
+        "--cachepath", rebase_path("$root_out_dir"),
+    ]
+
+    if (is_debug) {
+        arg += [ "--buildmode", "Debug" ]
+    } else {
+        arg += [ "--buildmode", "Release" ]
+    }
+
+    arg += ["--targetcpu", "${target_cpu}"]
+    
+    script = "dispatch_for_ide.py"
+    outputs = [ "$root_out_dir/libccore_gn.a" ]
+    args = arg
+    deps = projects
+}
+```
+
+`action` 目标是定义自定义构建步骤的一个机制。它的执行时机和调用方式依赖于它在构建图中的依赖关系
+
+比如上述代码定义了名为 `dispatch_for_ide` 的 `action`,该 action 在 `group("ccore")` 被依赖,所以当 `ccore` 被执行时会执行该 `action`
+
+- `script` 字段指定了要执行脚本为 `dispatch_for_ide.py`
+- `outputs` 字段表明了会输出哪些文件,通过 `outputs` 和 `sources` 可以明确 `action` 之间的依赖关系,从而决定执行顺序
+- `args` 定义了执行脚本时会传入的参数,可以通过 `if-else` 添加不同的命令参数
+- `deps` 该 `action` 的依赖项,会先进行依赖项
+
+```gn
+if (is_win) {
+    set_sources_assignment_filter([ 
+        "*_posix.h", "*_posix.cc",
+        "*_mac.h", "*_mac.cc", "*_mac.mm",
+        "*_android.h", "*_android.cc",
+        "*_jni.h", "*_jni.cc",
+    ])
+}
+```
+
+- `source_set`:编译后的代码集合,它与静态库的唯一区别时灭有链接的符号文件,就是一遍编译后生成的 .i 文件
+- `static_library`:静态库,windows 上是 lib 库,其他平台是 .a 库
+- `shared_library`:动态库,windows 上是 dll 库,Android 平台是 .so 库, mac 和 IOS 是 dylib 库
+

+ 4 - 0
Build-Project/README.md

@@ -0,0 +1,4 @@
+| 构建 | 路径 |
+| --- | --- |
+| CMake | [CMake](./CMake/README.md) |
+| gn | [gn](./GN/README.md) |

BIN
Build-Project/内存知识/Image/001.png


BIN
Build-Project/内存知识/Image/002.png


BIN
Build-Project/内存知识/Image/003.png


BIN
Build-Project/内存知识/Image/004.png


BIN
Build-Project/内存知识/Image/005.png


BIN
Build-Project/内存知识/Image/006.png


BIN
Build-Project/内存知识/Image/007.png


BIN
Build-Project/内存知识/Image/008.png


+ 103 - 0
Build-Project/内存知识/README.md

@@ -0,0 +1,103 @@
+# 内存
+
+[每个程序员都应该知道的内存知识](./What%20Every%20Programmer%20Should%20Know%20About%20Memory.pdf) 
+
+所有内容都是从面的文件中提取
+
+首先,改文件编写于2007年,受限于时代背景,有一些已经被淘汰的计算机结构仍然会出现在文章中,不过这些并不会影响到内存知识的学习
+
+[B站说明视频](https://www.bilibili.com/video/BV1Xy4y1b7SK/)
+
+## 硬件
+
+计算机存在过一种结构,南桥北桥
+
+![](Image/001.png)
+
+北桥连接内存控制器、内存、CPU,南桥通常连接 IO 接口
+
+由于 CPU 控制通过 USB、PCI-E 等接口连接的设备时要通过南北桥之间的接口,这里会出现性能瓶颈
+
+> CPU 控制设备时要经过 FSB、北桥、南北桥接口、南桥、USB 
+
+![](Image/002.png)
+
+然后出现了第二种结构,将内存控制器与北桥分离
+
+![](Image/003.png)
+
+然后出现了第三种结构,被称为 `NUMA` 的非统一内存架构
+
+这种架构有一个明显的问题,那就是如果 `CPU1` 想要访问右下角的 `RAM` 时,需要通过 `CPU2` 和 `CPU4` 才能访问
+
+## RAM 的类型
+
+通常来说 RAM 内存分为两种:静态内存(`Static RAM`, `SRAM`) 和 动态内存(`Dynamic RAM`, `DRAM`)
+
+通常来说静态内存(`SRAM`)的速度快,但是**生产成本**和**使用成本**都比动态内存(`DRAM`)高
+
+所以一般来说,结合各种特点,`CPU` 缓存会使用 `SRAM`,主存使用 `DRAM`
+
+![](Image/004.png)
+
+上图展示了 6 晶体管 SRAM **单元**的结构。该单元的核心由 4 个晶体管(M1 ~ M4) 构成,这 4 个晶体管构成两个交叉耦合的反相器。它们有两个**稳定状态**,分别表示 0 和 1。 只要 $V_{dd}$ 通带内,状态就稳定
+
+![](Image/005.png)
+
+上图展示了常用 DRAM **单元**设计的结构,就是一个电容加一个晶体管,成本很低
+
+但是该结构存在一个问题,那就是需要不停的刷新,即需要定时写入数据让数据保持原来的样子,因为电容会漏电
+
+为了容纳大量单元,单元内电容的容量必须尽可能的低。充满电的电容可以容纳数十或数千个电子
+
+对于大多数 DRAM 来说,刷新的频率是 64ms,并且刷新期间不能访问存储器
+
+![](Image/006.png)
+
+上图就是一个简易的 DRAM 的示意图,每个单元代表一个 bit 的存储,通过指定行、列可以得到期望的 bit,执行多次获取操作就可以得到一组数据
+
+## CPU 缓存
+
+![](Image/007.png)
+
+- Regs: 寄存器
+- L1: 一级缓存
+- L2: 二级缓存
+- L3: 三级缓存
+- Main Memory: 主存
+- Local Secondary Storage: 硬盘
+- Remote Secondary Storage: 网络存储
+
+CPU 缓存从上到下,成本越来越低,速度越来越慢
+
+[不同年代各个存储单元的访问速度](https://colin-scott.github.io/personal_website/research/interactive_latency.html)
+
+CPU 缓存对用户来说是透明的,这里的用户可以是程序员、编译器等
+
+程序和数据存在时间局部性和空间局部性,空间局部性的例子就是数组,如果频繁访问一个变量那就是时间局部性。如果没有这些局部性,缓存是没有用的
+
+所以程序员需要帮助处理来使用缓存资源,不要浪费缓存机制
+
+![](Image/008.png)
+
+> I7 的缓存示例图
+
+这颗 CPU 共有 4 个核(Core0 ~ Core3),每个核心都有自己的寄存器(Regs)、一级缓存(L1, d-cache 数据缓存,i-cache 指令缓存)、二级缓存(L2)
+
+4 个核共享三级缓存(L3)
+
+`Block Size` 即一个缓存单元,这颗 CPU 一次缓存 64 KB 的数据。一般也不会说一个字节一个字节的缓存,这样命中率太低,依靠空间局部性会将目标附近的数据都缓存下来
+
+| 读取数据 | 开销 |
+| --- | --- |
+| Register 寄存器 | <= 1 |
+| L1d | ~3 |
+| L2 | ~14 |
+| Main Memory 主存 | ~240 |
+
+不命中的三种情况
+
+1. 缓存大小有限,一定会出现不命中的情况
+2. 发生冲突,需要将缓存的数据踢出,使用新的数据覆盖
+3. 系统刚启动、程序刚运行时,缓存为空,一定不命中
+

BIN
Build-Project/内存知识/What Every Programmer Should Know About Memory.pdf


BIN
Build-Project/程序员的自我修养/Image/001.png


BIN
Build-Project/程序员的自我修养/Image/002.png


BIN
Build-Project/程序员的自我修养/Image/003.png


BIN
Build-Project/程序员的自我修养/Image/004.png


+ 378 - 0
Build-Project/程序员的自我修养/README.md

@@ -0,0 +1,378 @@
+# 程序员的自我修养
+
+## 源码执行过程
+
+源码执行的过程可以被分成四部分
+
+1. 预处理(Prepressing):主要处理那些源码中以 `#` 开始的预编译指令,例如 `#include`、`#define`
+2. 编译(Compilation):把预处理完的文件进行一系列**词法分析**、**语法分析**、**语义分析**以及**优化**后生产相应的**汇编代码文件**
+3. 汇编(Assembly):汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。汇编器根据汇编指令和机器指令的对照表一一翻译就可以了
+4. 链接(Linking)
+
+以 `hello.c`、`hello1.c`、`hello2.c` 为例
+
+```cpp
+// hello2.c
+int mul(int a, int b){
+ return a * b;
+}
+
+// hello1.c
+#include "hello2.c"
+int add(int a, int b) {
+ return a + b;
+}
+
+// hello.c
+#include "hello1.c"
+int main() {
+ add(1, 2);
+ return 0;
+}
+```
+
+使用命令 `gcc -E hello.c -o hello.i`,对 `hello.c` 进行 **预处理**
+
+```cpp
+# 0 "hello.c"
+# 0 "<built-in>"
+# 0 "<command-line>"
+# 1 "/usr/include/stdc-predef.h" 1 3 4
+# 0 "<command-line>" 2
+# 2 "hello.c"
+# 1 "hello1.c" 1
+# 1 "hello2.c" 1
+int mul(int a, int b){
+ return a * b;
+}
+
+# 2 "hello1.c" 2
+int add(int a, int b) {
+ return a + b;
+}
+# 2 "hello.c" 2
+int main() {
+ add(1, 2);
+ return 0;
+}
+```
+
+> `#include` 会递归执行
+
+- 在预处理阶段删除 `#define` 并展开所有的宏定义
+- 处理的条件预编译指令 `#if`、`#ifdef`、`#elif`、`#else`、`#endif`
+- 处理 `#include` 将包含的文件插入到该预编译指令的位置
+- 删除所有的注释
+- 添加行号和文件名标识
+- 保留 `#pragma` 编译器指令,编译器要用到
+
+使用 `gcc -S hello.i -o hello.s` 将预处理后的文件编译得到汇编代代码
+
+> 汇编文件内容较多,不贴代码
+
+使用 `gcc -c hello.s -o hello.o` 得到机器指令的文件,但是这个文件还不可以执行
+
+在最后执行了**链接**之后,才能够执行
+
+## 编译器做了什么
+
+编译器就是将高级语言翻译成机器语言的工具之一
+
+> 使用汇编语言或机器指令编写程序效率低下,且机器语言和汇编依赖特定机器,一个专门为某种 CPU 编写的程序在另一种 CPU 下完全无法运行
+
+使用高级语言能够使开发者尽量少的考虑计算机本身的限制:字长、内存大小、通信方式、存储方式等
+
+![](Image/001.png)
+
+| 英文 | 中文 |
+| --- | --- |
+| Source Code | 源码 |
+| Scanner | 扫描器 |
+| Tokens | 记号 |
+| Parser | 语法分析 |
+| Syntax Tree | 语法树 |
+| Semantic Analyzer | 语义分析 |
+| Commented Syntax Tree | 语法树 |
+| Source Code Optimizer | 源码级优化器 |
+| Intermediate Representation | 中间代码 |
+| Code Generator | 目标代码生成 |
+| Target Code | 目标代码 |
+| Code Optimizer | 目标代码优化器 |
+
+### 词法分析
+
+**扫描器**:简单地进行**词法分析**,运用类似有**限状态机**的算法可以将源代码的字符序序列分割成一系列的**记号**(`Token`)
+
+通过 `Scanner` 扫描器的词法分析产生的记号 `Token` 一般分为一下几类:关键字、标识符、字面量(数字、字符串等)和特殊符号(加号、减号等)
+
+> 语法分析工具有 lex
+
+```cpp
+array[index] = (index + 4) * (2 + 6);
+```
+
+上面的代码通过扫描器之后会得到 16 个 Token
+
+| Token | 类型 |
+| --- | --- |
+| Array | 标识符 |
+| `[` | 左方括号 |
+| index | 标识符 |
+| `]` | 右方括号 |
+| = | 赋值 |
+| `(` | 左圆括号 |
+| index | 标识符 |
+| + | 加号 |
+| 4 | 数字 |
+| `)` | 右圆括号 |
+| * | 乘号 |
+| `(` | 左圆括号 |
+| 2 | 数字 |
+| + | 加号 |
+| 6 | 数字 |
+| `)` | 右圆括号 |
+
+### 语法分析
+
+语法分析器(`Grammar Parser`) 对扫描器(`Scanner`) 产生的记号进行语法分析,从而产生语法树(`Syntax Tree`),整个过程采用上下文无关语法(`Context-Free Grammar`)
+
+对于 `int x = (1 + 2;` 这种错误就是在语法分析阶段被检查出来
+
+通过**语法分析器**生成的**语法树**就是以**表达式**为节点的树
+
+![](Image/002.png)
+
+> 赋值表达式、加法表达式、乘法表达式、数组表达式、括号表达式等
+
+词法分析工具有 `yacc`(`Yet Another Compiler Compiler`),可以根据用户给定的语法规则对输入的记号序列进行解析,从而构建出一颗语法树
+
+> 对于不同的语言,编译器的开发者只需要改变语法规则,而无需为每个编译器编写一个语法分析器
+
+### 语义分析
+
+语法分析仅仅完成了对表达式的语法层面的分析,但是并不了解这个语句是否真正有意义
+
+```cpp
+int* p1 = NULL;
+int* p2 = NULL;
+int p3 = p1 * p2;
+```
+
+比如上述代码在语法分析阶段是通过的,但是在语义分析阶段不能通过
+
+编译器能分析的语义是静态语义(`Static Semantic`),也就是编译器可以确定的语义。对应的还有动态语义(`dynamic Semantic`),只有在运行期才能确定的语义
+
+- 静态语义:类型检查、变量声明检查、控制流检查等。例如,编译器会检查变量是否在使用前声明,类型转换是否合法等。这些检查在编译时就能确定,因此称为静态语义
+- 动态语义:数组越界、除零错误等。这些错误只有在程序实际运行时才能被检测到,因此称为动态语义
+
+经过语义分析之后,语法树的表达式都会被标识上类型,如果有些类型需要做隐式转换,语义分析程序会在语法树中插入相应的转换节点
+
+![](Image/003.png)
+
+### 中间语言生成
+
+现代编译器有很多层次的优化,往往在**源代码级别**会有一个优化过程
+
+这里定义的**源码级优化器**(`Source Code Optimizer`)在不同的编译器中可能会有不同的定义或者一些其他的差异
+
+比如之前的例子 `array[index] = (index + 4) * (2 + 6);` 中 **(2 + 6)** 的值在编译期就可以被确定
+
+![](Image/004.png)
+
+> 上述的语法树经过优化了
+
+但是一般不会直接优化在语法树上做优化,这比较困难,**源代码优化器** 往往将整个语法树转换成**中间代码**(`Intermediate Code`),它是语法树的顺序表示,非常接目标代码
+
+> 中间代码一般与目标机器和运行时环境无关,比如不包含数据的尺寸、变量地址和寄存器的名字等
+
+中间代码有很多类型,在不同编译器中有不同的形式,比较常见的有:**三地址码**(`Three-Address Code` Or `TAC`)和 **P-代码**(`P-Code`)
+
+**三地址码** 是常见的中间表示形式,每条三地址码指令最多包含三个地址:两个操作数和一个结果
+
+1. 四元组表示,每条三地址码可以表示为一个四元组(`4-tuple`):运算符、操作数1、操作数2、结果
+2. 简单命令
+3. 线性表示,便于编译器进行顺序处理和优化
+
+```cpp
+array[index] = (index + 4) * (2 + 6);
+```
+
+上述代码以 **三地址码** 为例,会生成如下的中间代码
+
+```cpp
+t1 = 2 + 6
+t2 = index + 4
+t3 = t2 * t1
+array[index] = t3
+```
+
+**三地址码**的优化过程主要包括消除公共子表达式、常量折叠、赋值传播等技术
+
+所以**优化程序**在三地址码的基础上进行优化时
+
+- 常量折叠:会将 `2 + 6` 计算出来得到 `t1 = 8`,然后将后面代码中的 t1 替换成数字 3
+- 复制传播:省去一个临时变量 t3,因为 t2 可以重复利用
+
+最后得到优化后的三地址码如下
+
+```cpp
+t2 = index + 4
+t2 = t2 * 8
+array[index] = t2
+```
+
+至于什么是消除公共子表达式,例子如下
+
+```cpp
+// 原始三地址码
+t1 = b + c
+a = t1
+t2 = b + c
+d = t2
+t3 = a * d
+e = t3
+
+// 因为 t1 和 t2 表达式相同
+t1 = b + c
+a = t1
+d = t1  // 直接使用 t1 而不是重新计算 b + c
+t3 = a * d
+e = t3
+```
+
+### 目标代码生成与优化
+
+**源代码级优化器**产生的中间代码标志着下面的过程都属于**编译器后端**
+
+编译器后端负责将中间代码转换为目标机器代码,并进行各种优化以提高代码的执行效率。主要包括:**代码生成器**和**目标代码优化器**
+
+代码生成器将中间代码转换成目标机器代码,这个过程十分依赖目标机器,因为不同的机器有着不同的字长、寄存器、整数数据类型和浮点数数据类型等
+
+```x86asm
+movl index, %ecx                ; 赋值 index 给 ecx
+addl $4, %ecx                   ; ecx = ecx + 4
+mull $8, %ecx                   ; ecx = ecx * 8
+movl index, %eax                ; 赋值 index 给 eax
+movl %ecx, array(, eax, 4)      ; array[index] = ecx
+```
+
+最后目标代码优化器对上述的目标代码进行优化,比如选择合适的寻址方式、使用位移来代替乘法运算、删除多余的指令等
+
+```x86asm
+movl index, %edx
+leal 32(, %edx, 8), %eax
+movl %eax, array(, %edx, 4)
+```
+
+> 乘法由一条相对复杂的 **基址比例变址寻址**(`Base Index Scale Addressing`) 的 lea 指令完成
+
+首先C++ 语言的定义极为复杂;然后现代 CPU 也相当复杂,CPU 采用了流水线、多发射、超标量等诸多复杂的特性。为了支持这些特性,编译器的机器指令优化过程也变得十分复杂
+
+使编译过程更为复杂的是有些编译器支持多种硬件平台,即允许编译器编译出多种目标 CPU 的代码
+
+> 比如 GCC 编译器就几乎支持所有 CPU 平台
+
+```cpp
+array[index] = (index + 4) * (2 + 6);
+```
+
+经过前面的扫描、词法分析、语法分析、语义分析、源代码优化、代码生成和目标代码优化后,源代码被编译成了目标代码
+
+那么问题来了,`array` 和 `index` 的地址如何得到?
+
+进而引入新的问题:代码中有变量定义在其他模块,该怎么办?
+
+## 链接器
+
+```
+0001 0100
+...
+...
+...
+1000 0111
+```
+
+在很久之前纯二进制指令(打孔纸条)控制机器时,假设 `0001` 是跳转指令,那么上述代码第一条 `0001 0100` 就是跳转到 `0100` 也就是第四条指令中
+
+但是代码并不是一成不变的,如果在第四条之前插入新的指令,那么原本第四条指令就变成第五条指令了,对应的第一条指令也要修改 `0001 0101`。这一步就是 **重定位**(`Relocation`)
+
+再后面开始使用汇编语言,使用类似 `jmp` 来替代 `0001` 表示跳转命令。可以使用符号来标记位置,比如使用 `divide` 来表示一个除法子程序的起始地址
+
+如果将之前二进制代码的第四条指令的起始地址使用符号 `foo` 来标记,那么命令就从 `0001 0100` 变成了 `jmp foo`
+
+当使用符号命名子程序或跳转目标之后,不管 `foo` 之前插入或减少了多少条指令导致 `foo` 目标地址发生了什么变化,汇编器在每次汇编程序的时候会重新计算 `foo` 这个符号的地址
+
+上述整个过程不需要人工参与,终于不用在人工进行低级繁琐的地址调整工作
+
+现在软件开发过程中,往往会拆分成多个模块,这些模块之间互相依赖有,又相对独立。这种模块化开发的好处就是代码容易阅读、理解、重用,每个模块单独开发、编译、测试,改变部分代码不用编译整个程序等
+
+C++ 模块之间通信有两种方式:模块间的**函数调用**和模块间的**变量访问**
+
+函数访问必须知道目标函数的地址,变量访问也必须知道目标变量的地址,所以总的来的两种方式都可以归结为**模块间符号的引用**
+
+这个过程也被称为**链接**
+
+链接的主要内容就是把各个模块之间互相引用的部分都处理好,使得各个模块之间能够正确地衔接
+
+链接器要做的工作跟前面说的人工调整地址本质没什么两样。**链接**过程主要包括了**地址和空间分配**(Address And Storage Allocation)、**符号决议**(Symbol Resolution)和**重定位**(Relocation)等步骤
+
+| 步骤 | 作用 | 过程 |
+| --- | --- | --- |
+| 步骤和空间分配 | 为每个模块中的代码和数据分配内存地址和存储空间 | 链接器首先扫描所有输入的可重定位目标文件,确定每个模块的大小和对齐要求。根据这些信息,链接器为每个模块分配内存地址和存储空间,确保他们在内存中的布局符合要求 |
+| 符号决议 | 将每个符号引用与其定义关联起来 | 每个模块中定义和引用的符号都会被记录在符号表中。链接器扫描所有输入的目标文件,解析每个符号的定义和引用。链接器将每个符号引用与其定义关联起来,确保所有引用都能正确解析 |
+| 重定位 | 调整代码和数据中的地址引用,使他们指向正确的内存位置 | 编译器和汇编器生成的代码和数据通常从地址 0 开始,在实际运行时会发生变化。链接器根据地址和空间分配的结果,调整代码和数据中的地址引用,使他们指向正确的内存位置。也包括修改指令中的地址引用、调整数据段中的指针等 |
+| 合并和优化 | 合并相同的代码和数据段,并进行优化以提高执行效率 | 链接器会合并相同的代码和数据段,减少冗余。链接器还会进行一些优化操作,如消除未使用的代码和数据、优化指令顺序等 |
+
+> 代码在运行的时候才会被加载到内存中,所以上述所有的内存地址都是虚拟地址,而不是物理内存地址,这些虚拟内存地址在程序运行时会被映射到实际的物理内存地址
+
+一般来说,每个模块的源代码文件经过编译器编译成**目标文件**(Object File,一般后缀为 .0),**目标文件**和**库**(`Library`) 一起链接形成最终的可执行文件
+
+最常见的库就是**运行时库**(Runtime Library),它是支持程序运行的最基本函数的集合
+
+**库**其实时一组目标文件的包,就是一些最常用的代码编译成目标文件后打包存放
+
+```cpp
+// main.c
+#include <stdio.h>
+#include <stdbool.h>
+
+extern bool foo();
+
+int main() {
+    if (foo()) {
+        printf("foo returned true\n");
+    } else {
+        printf("foo returned false\n");
+    }
+    return 0;
+}
+
+
+// foo.c
+#include <stdbool.h>
+
+bool foo() {
+    return true;
+}
+```
+
+> `c89` 中没有定义 `bool`,`c99` 中在 `stdbool.h` 中定义了 `bool`
+
+通过 `gcc -c main.c -o main.o` 和 `gcc -c foo.c -o foo.o` 生成目标文件
+
+1. 地址和空间分配:为每个模块中的代码和数据分配虚拟地址和存储空间
+   - 扫描器扫描 `main.o` 和 `foo.o` 确定模块大小和对齐要求
+   - 为 `main` 函数和 `foo` 函数分配虚拟地址
+   - 为犬奴变量和静态数据分配存储空间
+
+2. 符号决议:链接器解析每个符号的定义和引用,将符号引用与其定义关联起来
+   - 在 `main.o` 中,链接器发现 `foo` 函数是一个外部符号(`extern`),需要解析其定义
+   - 在 `foo.o` 中,链接器找到 `foo` 函数的定义,并将 `main.o` 中对 `foo` 的引用于 `foo.o` 中的定义关联起来
+
+3. 重定位:链接器调整代码和数据中的地址引用,使他们指向正确的虚拟地址
+   - 链接器修改 `main.o` 中对 `foo` 函数的调用地址,使其指向 `foo.o` 中 `foo` 函数的实际地址
+
+4. 合并和优化:链接器合并相同的代码段和数据段,并进行优化以提高执行效率
+
+## 目标文件
+

BIN
UE5/引擎开发记录/GIF/001.gif


BIN
UE5/引擎开发记录/Image/001.png


BIN
UE5/引擎开发记录/Image/002.png


BIN
UE5/引擎开发记录/Image/003.png


BIN
UE5/引擎开发记录/Image/004.png


BIN
UE5/引擎开发记录/Image/005.png


BIN
UE5/引擎开发记录/Image/006.png


BIN
UE5/引擎开发记录/Image/007.png


BIN
UE5/引擎开发记录/Image/008.png


BIN
UE5/引擎开发记录/Image/009.png


BIN
UE5/引擎开发记录/Image/010.png


BIN
UE5/引擎开发记录/Image/011.png


BIN
UE5/引擎开发记录/Image/012.png


Some files were not shown because too many files changed in this diff