Makefile和CMake初级使用

Makefile

  • Makefile三部分:目标、依赖、执行语句;
  • 递归执行:若不存在目标文件或目标文件修改时间早于依赖文件,则先产生对应依赖文件,再执行语句;
  • 所有.o文件均由对应.c文件生成,$<为第一个依赖文件,$@为目标,$^为所有不重复的依赖文件,以空格分开;
  • src = $(wildcard ./*.c)得到空格隔开的所有.c文件名;obj = $(patsubst %.c, %.o, $(src)) 代表将src中的所有.c替换成.o;obj = $(src: %.c=%.o) 能得到同样效果;
  • .PHONY代表clean为伪目标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
src = $(wildcard ./*.c)  
obj = $(patsubst %.c, %.o, $(src))
#obj = $(src:%.c=%.o)
target = app
CC = gcc

$(target): $(obj)
$(CC) $(obj) -o $(target)

%.o: %.c
$(CC) -c $< -o $@

.PHONY: clean
clean:
rm -rf $(obj) $(target)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CC := clang
CXX := clang++

.PHONY all
all: answer

objects := main.o answer.o
answer: $(objects)
$(CXX) -o $@ $(objects)

main.o: answer.hpp
answer.o: answer.hpp

.PHONY clean
clean:
rm -f answer(objects)

CMake

  • 视频教程
  • 在my_project目录下存放源文件和CMakeLists.txt,另新建文件夹build,进入后执行cmake ..在build目录下生成Makefile文件,再执行cmake —-build .生成可执行文件;上述命令等价于cmake -B build && cmake —-build build
  • VSCode配置:brew install cmake 后安装CMake和CMake Tools,先编写CMakeLists.txt,再Cmd+Shift+P 调出CMake: Quick Start即可;
  • 常见操作:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
cmake_minimum_required(VERSION 3.15.0) # 指定最小版本
project(My_Project) # 指定项目名称

set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -g -Werror -Wextra -pedantic -std=c++14")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -std=c++14 -O2")

add_executable(demo demo.cpp) # 生成可执行文件(Linux: demo, Windows: demo.exe)
add_library(common STATIC util1.cpp) # 生成静态库(Linux: common.a, Windows: common.lib)
add_library(common SHARED util2.cpp util3.cpp) # 生成动态库或共享库(Linux: common.so, Windows: common.dll, MacOS: common.bundle, common.dylib)

file(GLOB SRC_LIST "*.cpp" "protocal/*.cpp")
add_library(demo ${SRC_LIST})
# 或者
set(SRC_LIST main.cpp test.cpp)
list(APPEND SRC_LIST test2.cpp)
list(REMOVE_ITEM SRC_LIST test2.cpp)
# 或者
aux_source_directory(. SRC_LIST) # 搜索当前目录下所有可编译单元(.cpp文件)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})

foreach(source ${srcs})
get_filename_component(name ${source} NAME/EXT/DIRECTORY/ABSOLUTE) # 文件名/扩展名/目录路径/绝对路径
add_executable(${name} ${source})
endforeach(source)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # 设置头文件包含目录,将路径增加至CPLUS_INCLUDE_PATH变量
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I ${CMAKE_CURRENT_SOURCE_DIR}") # 等价于
link_libraries("/include/util.so") # 写在add_executable之前

link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs) # 设置链接库搜索目录,将路径增加至LD_LIBRARY_PATH变量
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L ${CMAKE_CURRENT_SOURCE_DIR}/libs") # 等价于

find_package(Protobuf REQUIRED) # 查找外部包
target_link_libraries(demo lib.a ${CMAKE_CURRENT_SOURCE_DIR}/libs/lib.so) # 设置需要链接的库

# 自动执行子目录下的CMakeLists.txt
add_subdirectory(${PROJECT_SOURCE_DIR}/src/proto)
include_directories(${PROJECT_BINARY_DIR}/src/proto)

message(${PROJECT_SOURCE_DIR})
message("build with debug mode")
message(WARNING "this is warnning message")
message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败
  • 文件目录形式:
1
2
3
4
5
6
- my_project/
- build/
- Makefile
- helloworld.exe
- CmakeLists.txt
- helloworld.cpp