我们有一个创建makefile的练习,它应该"创建一个项目bbfoo。BBFOO由Barbaz和Foo链接。巴尔巴兹与巴尔和巴兹相连。使用编译器 cc(在我的系统上是 gcc(和链接器 ld。
我创建了三个简单的 c 文件:
酒吧:
int one() {
return 1;
}
baz.c:
int two() {
return 2;
}
福克
#include <stdio.h>
int main() {
printf("bar: %dn", one());
printf("baz: %dn", two());
return 0;
}
和以下生成文件:
bar: bar.c
cc -c -g -o bar.o bar.c
baz: baz.c
cc -c -g -o baz.o baz.c
barbaz: bar baz
ld -shared -o barbaz.o bar.o baz.o
foo: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
bbfoo: barbaz foo
ld -lc --entry=main -o bbfoo.out barbaz.o foo.o
$ 制作 bbfoo
工作没有错误,并创建了相应的文件。但是当我尝试运行该项目时
$ ./bbfoo.out
它显示"找不到文件或文件夹"。
当我使用 gcc 时,它完美无缺:
$ gcc -o bbfoo.out bar.c baz.c foo.c
$ ./bbfoo.out
酒吧: 1
巴兹: 2
我的错误是什么?甚至可以链接这样的项目(分两步(吗?
生成文件使用ld
进行链接,但gcc
示例使用编译器驱动程序进行链接。你也应该这样做:
bbfoo: barbaz foo
gcc -o bbfoo.out barbaz.o foo.o
编译器驱动程序可能(在您的情况下显然确实(包含一堆特定于系统的东西,使您的程序实际工作。通常不建议尝试直接运行链接器。
如果你想看看它真正使用的链接行是什么,你可以使用 GCC 的-v
标志,如果你愿意,也可以将标志从中复制到你的 makefile 中。但是,您将来就有可能无法接受重要的更改。
如果你使用make,你应该坚持它的基本原则,我们可以总结为:
FILE-to-create: files-used-to-create-FILE
shell-commands-that-create-FILE
这非常重要,因为 make 比较文件的上次修改时间以确定哪些是过期的,哪些是最新的。这不是一种形式,它确实改变了功能。因此,在您的情况下,您应该拥有:
bar.o: bar.c
cc -c -g -o bar.o bar.c
baz.o: baz.c
cc -c -g -o baz.o baz.c
foo.o: foo.c
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c
barbaz.so: bar.o baz.o
ld -shared -o barbaz.so bar.o baz.o
bbfoo: barbaz.so foo.o
ld -lc --entry=main -o bbfoo barbaz.so foo.o
请注意,make 有一些不错的功能,可以帮助分解这种简单的规则集。例如,自动变量($@
,$^
...(,隐式规则(例如,用于从*.c
源文件构建*.o
对象文件(,隐式规则使用的隐式变量(CFLAGS
,LD
...(,特定于目标的变量值(查看foo.o
的CFLAGS
声明(等等。例:
CFLAGS := -g
foo.o: CFLAGS += -Wno-implicit-function-declaration
barbaz.so: bar.o baz.o
$(LD) -shared -o $@ $^
bbfoo: barbaz.so foo.o
$(LD) -lc --entry=main -o $@ $^
是的,目标文件根本没有规则,make 已经知道如何构建它们。
发布的代码包含很多缺点。
建议:
酒吧.H
#ifndef BAR_H
#define BAR_H
int one( void );
#endif
酒吧:
#include "bar.h"
int one() {
return 1;
}
巴兹·
#ifndef BAZ_H
#define BAZ_H
int one( void );
#endif
baz.c:
#include "baz.h"
int two() {
return 2;
}
福克
#include <stdio.h>
#include "bar.h"
#include "baz.h"
int main( void ) {
printf("bar: %dn", one());
printf("baz: %dn", two());
return 0;
}
makefile.mak
.PHONY all
all: bbfoo.out
bar: bar.c bar.h
cc -c -g -o bar.o bar.c -Ibar.h
baz: baz.c baz.h
cc -c -g -o baz.o baz.c -Ibaz.h
libbarbaz.so: baz.o bar.o
ld -shared -o libbarbaz.so bar.o baz.o
foo: foo.c baz.h bar.h
cc -c -g -Wno-implicit-function-declaration -o foo.o foo.c -Ibar.h -Ibaz.h
bbfoo.out: foo.o libbarbaz.so
ld -lc --entry=main -o bbfoo.out foo.o -lbarbaz
使用make
中找到的快捷方式变量将大大缩短此生成文件,但会使其更加神秘