由于Linux/Unix环境下的C++开发,特别是涉及到多模块的编译时,完全离不开Makefile,所以简单了解一下后在这边做个记录。
Makefile
假设在一个工程中有4个文件,分别为:
main.cpp
1 2 3 4 5 6 7 8 9 10 11
| #include <iostream> #include "functions.h" using namespace std; int main() { printhello();
cout << "This is main:" << endl; cout << "The factorial of 5 is:" << factorial(5) << endl; return 0; }
|
printhello.cpp
1 2 3 4 5 6 7 8 9
| #include <iostream> #include "functions.h" using namespace std;
void printhello() { int i; cout << "Hello World!" << endl; }
|
factorial.cpp
1 2 3 4 5 6 7 8 9 10
| #include <iostream> #include "functions.h"
int factorial(int n) { if(n == 1) return 1; else return n * factorial(n - 1); }
|
和头文件functions.h
1 2 3 4 5
| #ifndef _FUNCTIONS_H_ #define _FUNCTIONS_H_ void printhello(); int factorial(int n); #endif
|
直接使用g++ main.cpp
是无法实现编译的,因为链接的时候会出错。
而使用g++ main.cpp factorial.cpp printhello.cpp
又实在是太麻烦。
此时就可以使用这种方式:
1 2 3 4 5 6
| g++ main.cpp -c g++ factorial.cpp -c g++ printhello.cpp -c
g++ *.o
|
其实这种方式就是理解Makefile操作原理的关键
下面通过4个Makefile的写法进一步理解。
Version 0x00
1 2
| hello: main.cpp printhello.cpp factorial.cpp g++ -o hello main.cpp printhello.cpp factorial.cpp
|
hello = 目标 后面 = 依赖
通过时间判断文件是否是最新,再判断是否执行命令
Version 0x01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| CXX = g++ TARGET = hello OBJ = main.o printhello.o factorial.o
$(TARGET): $(OBJ) $(CXX) -o $(TARGET) $(OBJ)
main.o: main.cpp $(CXX) -c main.cpp
printhello.o: printhello.cpp $(CXX) -c printhello.cpp
factorial.o: factorial.cpp $(CXX) -c factorial.cpp
|
判断依赖关系
Version 0x02
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| CXX = g++ TARGET = hello OBJ = main.o printhello.o factorial.o
CXXFLAGS = -c -Wall
$(TARGET): $(OBJ) $(CXX) -o $@ $^
%.o: %.cpp $(CXX) $(CXXFLAGS) $< -o $@
.PHONY: clean clean: rm -f *.o $(TARGET)
|
Version 0x03
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| CXX = g++ TARGET = hello SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))
CXXFLAGS = -c -Wall
$(TARGET): $(OBJ) $(CXX) -o $@ $^
%.o: %.cpp $(CXX) $(CXXFLAGS) $< -o $@
.PHONY: clean clean: rm -f *.o $(TARGET)
|
CMake
由于Makefile所使用的编译命令都收到了平台的限制,为了实现跨平台,可以使用CMake来生成Makefile。
使用CMake只需要在工程目录下编写一个CMakeLists.txt的文件
CMakeLists.txt
1 2 3 4 5
| cmake_minimum_required(VERSION 3.10)
project(hello)
add_executable(hello main.cpp factorial.cpp printhello.cpp)
|
之后只要在当前目录下使用cmake .
就可以了。
但是此时又会有一个问题,那就是当前目录下会出现很多cmake生产的文件,会导致工作目录比较乱。
可以使用这样的方式解决,就是在工作目录中再建一个build的文件夹,把这些东西都丢进去。
1 2 3
| mkdir build cd build cmake ..
|