介绍
学习CMake工具对大型项目编程是非常有帮助的。主要CMake是跨平台工具,以后想在树莓派上面也上面学习一下。
学习资源:
- IPADS新人培训(B站) github仓库
- ...
Modern CMake
makefile
这是我学习过一些makefile之后,提供的makefile模板。
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| # write makefile with me # recommond you to use the VERSION 2
# --------------------------------- VERSION 1 -------------------------------- # # CC = gcc # TARGET = hello # OBJS = main.o printhello.o
# RM = rm -rf # $(TARGET): $(OBJS) # $(CC) -o $(TARGET) $(OBJS)
# printhello.o: printhello.c # $(CC) -c printhello.c
# main.o: main.c functions.h # $(CC) -c main.c
# .PHONY: run # run: # ./$(TARGET)
# .PHONY: clean # clean: # $(RM) $(TARGET)
# --------------------------------- VERSION 2 -------------------------------- #
# CC = gcc # TARGET = hello # OBJ = main.o printhello.o
# CCFLAGS = -c -Wall
# ## $@ stands for $(TARGET) # ## $^ stands for dependencies # ## $< stands for the first one in dependencies # $(TARGET): $(OBJ) # $(CC) -o $@ $^
# %.o: %.c # $(CC) $(CCFLAGS) $< -o $@
# .PHONY: clean
# clean: # $(RM) *.o $(TARGET)
# .PHONY: run
# run: # ./$(TARGET)
# --------------------------------- VERSION 3 -------------------------------- # # sustitude
CC = gcc TARGET = hello SRC = $(wildcard *.c) # substitude the .c file as .o file in $(SRC) OBJ = $(patsubst %.c, %.o,$(SRC))
CCFLAGS = -c -Wall
## $@ stands for $(TARGET) ## $^ stands for dependencies ## $< stands for the first one in dependencies $(TARGET): $(OBJ) $(CC) -o $@ $^
%.o: %.c $(CC) $(CCFLAGS) $< -o $@
.PHONY: clean
clean: $(RM) *.o $(TARGET)
.PHONY: run
run: ./$(TARGET)
|
使用第二版本就好了。如果我学的更多了,或者学习更深入之后,我会再修改这个。(2023.12.3)
示例
1 2 3 4 5 6 7 8 9 10
| #include<iostream>
int main(int argc,const char *argv[]) { std::cout<<"Hello,World!"<<std::endl; return 0;
}
|
对应的Makefile文件如下:
1 2 3 4 5 6 7 8
| //Makefile hello: main.cpp //hello是target,下面的缩进都是command $(CXX) -o hello main.cpp //CXX是变量,可以用编译器名称来代替 echo "OK" //基本思路就是目标 文件 指令
//基本格式: // name: dependencies // commands
|
Makefile文件里面涉及到了一些shell的命令。这一部分要多去实践运用。
项目示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include<iostream>
#include"answer.hpp" int main(int argc, const char *argv[]) { int expected_answer=answer::find_the_ultimate_answer(); for(;;) { std::cout<<"What is the ultimate answer ?"<<std::endl; int answer; std::cin>>answer; if(answer==expected_answer){ std::cout<<"Correct!"<<std::endl; break; }
} return 0; }
|
其对应的Makefile文件如下:
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
| //Makefile CC:=clang CXX:=clang++
.PHONY:all //.PHONY叫做伪目标 all:answer
#这里添加answer.o目标文件 objects:=main.o answer.o
answer: $(objects) $(CXX) -o $@ $(objects)
# # Make 可以自行推断.o文件需要依赖同名的.cpp文件 # 其实并不需要在依赖中指定main.cpp和answer.cpp文件 #也不需要编译commands,它知道要用CXX变量制定的命令 #作为C++编译器 # # 这里只需要指定目标文件所依赖的头文件,使头文件变动时可以 # 重新编译对应目标文件 # # main.o: answer.hpp answer.o: answer.hpp
.PHONY: clean clean: rm -f answer$(objects)
|
最好还是用.PHONY:伪指令名
好了太难了,还是使用CMake吧!
CMake
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| cmake_minimum_required(VERSION 3.9)
project(answer)
添加可执行文件 target,类似于原来 Makefile 的:
answer: main.o answer.o main.o: main.cpp answer.hpp answer.o: answer.cpp answer.hpp
CMake 会自动找到依赖的头文件,因此不需要特别指定, 当头文件修改的时候,会重新编译依赖它的目标文件。
add_executable(answer main.cpp answer.cpp)
使用如下命令构建本项目:
cmake -B build cmake --build build ./build/answer
|
当有些库可以复用的时候,可以在CMakeLists.txt中添加如下命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| cmake_minimum_required(VERSION 3.9) project(answer)
add_library(libanswer STATIC answer.cpp)
add_executable(answer main.cpp)
target_link_libraries(answer libanswer)
使用如下命令构建本项目:
cmake -B build cmake --build build ./build/answer
|
- 使用子目录
1 2 3 4 5 6 7 8 9 10 11 12 13
| 文件目录 . ├── CMakeLists.txt ├── README.md ├── answer │ ├── CMakeLists.txt │ ├── answer.cpp │ └── include │ └── answer.hpp ├── clear.sh ├── main.cpp └── tree.txt
|
完整内容还是看我的github仓库cpp_tutorial中的modern_cmake