CMakeLists.txt
cmake_minimum_required(VERSION 3.26)
project("BinaryHacking"
VERSION 1.0
DESCRIPTION "A simple project to demonstrate basic CMake usage"
LANGUAGES C)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
FORCE)
endif()
option(BUILD_STATIC_LIBS "Build the static library" ON)
if (BUILD_STATIC_LIBS)
set(CMAKE_EXE_LINKER_FLAGS "-static")
endif()
set(CMAKE_C_FLAGS "-z execstack -fno-stack-protector -no-pie -Wl,-z,norelro")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_VERBOSE_MAKEFILE ON)
add_executable(BinaryHacking)
target_sources(BinaryHacking PRIVATE "BinaryHacking.c")
编写 CMakeLists.txt 的套路基本就是这样,先填写 project
信息,然后引用宏,定义自己的 option
,写判断语句
,然后 add_executable,target_sources
。
option(BUILD_STATIC_LIBS "Build the static library" ON)
if (BUILD_STATIC_LIBS)
set(CMAKE_EXE_LINKER_FLAGS "-static")
endif()
option
给了用户使用 ccmake 在 curses 界面下对 BUILD_STATIC_LIBS
开关选项,然后下面一个 if
根据 BUILD_STATIC_LIBS
来判断是否对 glibc 库进行静态链接生成 ELF 二进制文件,通过设置 CMAKE_EXE_LINKER_FLAGS
为 "-static"
来实现。
CMAKE_EXPORT_COMPILE_COMMANDS
会将编译命令导出到构建目录下名为 compile_commands.json
的文件,这个文件包含了许多有用的东西,比如如何构建二进制文件,Header 文件的位置,编译参数等,许多 IDE 在分析源码树和进行代码补全的时候就需要这个文件,比如 ycmd。
实际上 compile_commands.json
叫 Compilation database,是 Clang 发展出来的一种格式,记录了编译器时构建项目时的所有操作,有了这些信息,IDE就可以再次复现构建过程并使用这些信息来生成对源码树的分析信息,使用不同构建系统的源码(如 Kernel源码树)就可以导入到支持 Compilation database 的IDE中进行源码审计,并在无缝的在IDE内复现构建过程。
CMAKE_VERBOSE_MAKEFILE
也是一个很有用的 FLAG,如果设置为 ON 的话,那么在Make过程中将会打印由 CMakeLists.txt 生成的 Makefile 中所有执行的命令,就像这样:
另外 CMake 由比较详细的文档:CMake Reference Documentation — CMake 3.27.0-rc4 Documentation
需要用到什么宏直接查文档就行。
最后
之前其实很避讳写 CMakeLists.txt,
因为我自己就不会写,介于我孱弱的代码能力和能偷懒就偷懒的习惯,就没写过源码超过5000行的C/C++项目,实际上我一直都是写一个 Shell 文件直接调 gcc 编译所有源码,包括检测OS版本,install 函数,我甚至还费时间写处理 pkg-config 的解析脚本,但这样一来反倒不如使用现成的构建工具省时省力 。
但万事开头难,花了1个小时摸 cmake,其实写 CMakeLists.txt 还挺简单的,其中的宏确实好用也简单,实际上就是懒,我太懒了,真的需要脚踏实地的去做事….
等会,我好像就是因为懒得写构建脚本,懒得去写正则表达式去匹配 pkg-config 中的字符串和版本号才想学一下 cmake 来一次性解决所有问题。
笑死,最佳悖论诞生了….