published: true
tags:
**注:**以下实验环境为Ubuntu 18.0404LTS, gcc 7.3.0
gcc -c main.c
gcc -o main main.c
,然后通过./main
执行gcc -o test main.o test.o
gcc -o main main.o test.o -lpam
;指定链接目录-L,gcc -o main main.o test.o -L/usr/local/lib/pam -lpam
gcc -D NDEBUG main.c
,并且此时NDEBUG的值为1具体见gcc文档gcc -c -O2 main.c
Makefile所做的工作就如在IDE上自动化build项目一样,但是Makefile需要我们自己编写,然后用make
工具帮我们自动化执行。要做到自动化,需要以下几点:
make
要生成的目标文件是什么make
如何去生成目标文件make
文件定义了依赖之后,当依赖文件被修改之后,make
只会重新编译那些受依赖影响的文件,而不会再浪费时间去重新编译不受影响的文件。注意:依赖是传递的,就是说A被B依赖,B被C依赖,那A被修改了,B就得重新生成,然后C肯定也得重新生成。以下给出我们的例子(求整数的倒数):
/* main.c */
#include
#include
#include "reciprocal.hpp"
int main(int argc, char **argv)
{
int i;
i = atoi(argv[1]);
printf("The reciprocal of %d is %g\n", i, reciprocal(i));
return 0;
}
// reciprocal.cpp
#include
#include "reciprocal.hpp"
double reciprocal(int i)
{
// i should be non-zero
assert(i != 0);
return 1.0 / i;
}
// reciprocal.hpp
#ifdef __cplusplus
extern "C" {
#endif
extern double reciprocal(int i);
#ifdef __cplusplus
}
#endif
我们要生成可执行文件reciprocal
,因此需要目标文件reciprocal.o
和main.o
。一般地,在Makefile中我们都会写clean
target,以便清除所有make
生成的文件(用make clean
命令)。所以,最终的Makefile如下(以下的$(CFLAGS)先不解释:
reciprocal: main.o reciprocal.o
g++ $(CFLAGS) -o reciprocal main.o reciprocal.o
main.o: main.c reciprocal.hpp
gcc $(CFLAGS) -c main.c
reciprocal.o: reciprocal.cpp reciprocal.hpp
g++ $(CFLAGS) -c reciprocal.cpp
clean:
rm -f *.o reciprocal
从上面的格式中可以明显看出:targets写在左边,如main.o,然后跟着冒号,接着是一些依赖,然后规则写在下一行(先忽略$(CFLAGS))。需要注意的是: 规则一行必须以一个Tab字符开头,不然make将会报错。运行如下:
然后我们稍微修改以下main.c
,运行结果如下:
可以看到,重新make,只有重新编译了main.c和reciprocal(因为依赖于main.o)。
接着运行make clean
:
现在我们说一下 $(CFLAGS),这是一个 make 系统变量,其中 CFLAGS 可以替换成其他变量名,如 a,b,c 等。CFLAGS
指定头文件的搜索路径,如果头文件不在 gcc 的默认搜索路径下,则需要用此参数指定,如 CFLAGS=-I/usr/include -I/path/include
,gcc 的默认搜索路径可以用 gcc -v -x c -E /dev/null
查看。
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
conditional-directive
text-if-true
endif
或者
conditional-directive
text-if-true
else
text-if-false
endif
或者
conditional-directive-one
text-if-one-is-true
else conditional-directive-two
text-if-two-is-true
else
text-if-one-and-two-are-false
endif
在 conditional-directive
中,有以下五种的格式:
此外,有一种特殊的比较,和空值比较:
ifeq ($(strip $(foo)),)
text-if-empty
endif
notdir
:剥离文件的绝对路径,只保留文件名。$(dir )
:$(dir src/foo.c hacks)
返回值是 “src/ ./”。