微软作为PC操作系统的霸主,确实给广大人民群众带来了便利,让一个完全不懂计算机的小白也能在一台PC上写写文档,玩玩游戏。
对开发者,微软的VS系列也是把便利性做到了极致,但便利,上手快的不好之处是让程序员对编译链接这些过程知之甚少,而在linux下进行编程学习就与win刚好相反,linux学习难度就像
l
n
x
lnx
lnx,win下的学习难度就像
e
x
e^x
ex函数。
为了更好理解一个可执行文件是怎么产生的,我们就从Makefile开始聊一聊。
假设有三个文件
/* hellomake.c */
#include "hellomake.h"
int main() {
// call a function in another file
PrintHello();
return(0);
}
/* hellofun.c */
#include <stdio.h>
#include "hellomake.h"
void PrintHello(void) {
printf("Hello makefiles!\n");
return;
}
/* hellomake.h */
void PrintHello(void);
在linux下想编译他们并产生可执行文件可以使用
gcc -o hellomake hellomake.c hellofunc.c -I./* -I.表示需要用到的头文件在当前目录 */
如果文件发生了修改,只要在命令行回滚这条命令就可以了,但是这样做有个问题就是有时会记不清命令,而且换一台电脑的话要重新输入编译命令,而且对于大型项目,改动其中的一个文件却需要重新编译整个项目,这样比较耗时,由于此类种种不便,Makefile便产生了。
先在你的工程文件夹下创建名为Makefile的文件,并输入
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c -I.
需要特别注意的是gcc前面是一个“Tab”,第一行是的意思是我想产生名为hellomake的文件,这个文件的产生依赖于hellomake.c和hellofunc.c,此时Makefile会去当前文件夹下找这两个文件,经过寻找发先这两个文件已经存在了,接下来Makefile就会去执行第二行的命令从而产生可执行文件
h
e
l
l
o
m
a
k
e
\color{green}hellomake
hellomake。
一般产生一个可执行文件需要编译产生
.
o
\color{blue}.o
.o和链接产生可执行文件两步,所以我们将这个Makefile写得更清晰一些
CC=gcc
CFLAGS=-I.
hellomake: hellomake.o hellofunc.o
gcc -o hellomake hellomake.o hellofunc.o
CC告诉make我们需要用到的编译器,CFLAGS告诉make编译时需要添加的编译选项,当make看到依赖项为
.
o
\color{blue}.o
.o文件时,make会自动去寻找相应的
.
c
\color{green}.c
.c文件,并编译他们。
这样做仿佛还是不够好,因为当hellomake.h文件发生变化时,make并不能发现文件的变化,为了解决这个问题,我们将
.
c
\color{blue}.c
.c文件与
.
h
\color{red}.h
.h文件产生依赖
CC=gcc
CFLAGS=-I.
DEPS = hellomake.h
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o
第四行的依赖项表明
.
o
\color{blue}.o
.o文件的产生需要依赖
.
c
\color{green}.c
.c和
.
h
\color{red}.h
.h文件
%.o指hellomake.o hellofunc.o
%.c指hellomake.c hellofunc.c
$@指的是":" 左边所指的内容,
$<指的是依赖的首项,即%.c
新增的语句翻译一下就是
gcc -c -o hellomake.o hellomake.c -I.
gcc -c -o hellofunc.o hellofunc.c -I.
Makefile中提供了 $^ 来表示":"右边的内容,所以我们的代码能做进一步的简化
CC=gcc
CFLAGS=-I.
DEPS=hellomake.h
OBJ=hellomake.o hellofunc.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake:OBJ
$(CC) -o $@ $^ $(CFLAGS)
在一般的工程中,我们都会把所有的 . c \color{green}.c .c和 . h \color{red}.h .h放在不同的文件夹中,同时会包含一些库文件,并且隐藏掉不是那么有用的 . o \color{blue}.o .o文件,一个真实工程中的较为完成的Makefile文件可以写成这样
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
#
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) /* 给文件加一层目录 */
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*
这只是Makefile皮毛的皮毛,但是已经勉强能用了,Makefile有很多晦涩的语法和隐式规则,那就一点点的看吧。