标题比较夸张,但郑重声明本人不是标题党,只是也没有想到适合的名字。这里通用不是核心,核心是“如何炼成”, 这个系列会一步步的从最简单的makefile逐步导向一个较为通用的makefile(没有“复杂”两字)。您可以在这个过程中,学到makefile的基本语法,也可以学到makefile的常见技巧,同时我相信,您也会对如何做代码修改有所领悟
我们从最简单的helloworld程序开始,hello.h声明了sayHello方法,hello.cpp定义了实现。main.cpp中调用了方法sayHello()。
主要源码
/*
* hello.h
*/
#ifndef HELLO_H_
#define HELLO_H_
void sayhello();
#endif /* HELLO_H_ */
/*
* hello.cpp
*/
#include "hello.h"
#include <stdio.h>
void sayhello() {
printf("Hello World!\n");
}
// Name : main.cpp
// Author : crylearner
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C, Ansi-style
#include "hello.h"
int main(void) {
sayhello();
return 0;
}
## makefile
#
## 定义obj文件的编译规则
hello.o : hello.cpp hello.h
g++ -Wall -c $< -o $@
main.o : main.cpp hello.h
g++ -Wall -c $< -o $@
## 定义可执行文件hello.exe的编译规则
hello.exe: hello.o main.o
g++ -Wall -o $@ $^
## 约定俗成,大家已经习惯性的总是将all默认的make终极目标。
## 在这个例子中,就是生成hello.exe
.PHONY : all
all: hello.exe
## 定义 目标clean,一般就是删除所有obj文件,以及可执行文件。
.PHONY : clean
clean:
rm -f hello.o main.o hello.exe
对上面的makefile做个简单解释。hello.o, main.o 是生成可执行文件hello.exe必须依赖的两个obj文件。而这两个obj文件又分别依赖于源文件hello.cpp hello.h 、 main.cpp hello.h.
首先我们高度赞扬这个makefile的简洁性(呵呵,实际是源代码的简洁),然后,不得不吐槽的它的弱智啊
1. makefile内容依赖于源文件。如果再增加一个world.cpp, 则必须再修改makefile后才能编译。只好期望源文件不要太多了
2. 生成obj文件时,依赖的源文件和头文件是手动添加的,不会自动推导。这就导致以后修改源文件时,必须同步维护makefile中头文件依赖关系。太累了
3. g++ 以及相应的编译选项都是写死的,如果想要交叉编译一个arm平台上运行的可执行文件,哦,又要修改makefile
4. 没有编译产品的信息,好歹给个立牌坊的机会
嗯,作为庖丁的我们,现在开始游刃,今天的工作就是先将makefile一股脑儿塞到build目录下。(,虽然现在其实只有一个文件,但我们都知道这叫圈地运动。先把build目录这块地圈上,囤着,以后建别墅,盖山庄,还是拿来放羊,都是我的地盘)
这种塞文件 的方法,在makefile中可以直接使用include XXX的语法来表示。
## makefile
#
include build/main.mk
原文makefile中的内容全部移动到build/main.mk
最后,我们再用变量稍微点缀一下makefile,使他看起来稍微形式化一些,于是现在main.mk看起来是这个样子。我的整形手术应该还不是太好,各位客官还能认出来吧
# main.mk
RM:=rm -f
CXX:=g++
CXXFLAGS:=-Wall
OBJS:=hello.o main.o
TARGET:=hello.exe
## 定义obj文件的编译规则
hello.o : hello.cpp hello.h
$(CXX) $(CXXFLAGS) -c $< -o $@
main.o : main.cpp hello.h
$(CXX) $(CXXFLAGS) -c $< -o $@
## 定义可执行文件hello.exe的编译规则
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^
## 约定俗成,大家已经习惯性的总是将all默认的make终极目标。
## 在这个例子中,就是生成hello.exe
.PHONY : all
all: $(TARGET)
## 定义 目标clean,一般就是删除所有obj文件,以及可执行文件。
.PHONY : clean
clean:
$(RM) $(TARGET) $(OBJS)
今天的工作到此为止