对于一个项目,我正在与合作伙伴一起编写决策树实现。由于我们都是 C 语言的新手并且工作速度很快,所以我们基本上将所有功能都放在一个文件中,最终超过 1600 行。这是一个开始工作的快速而肮脏的项目,但现在下一个任务让我们负责扩展和重新实现代码。在目前的情况下,这不会发生。
现在,我正在根据功能责任分解原始来源。问题是,许多功能交织在一起,我的 make 文件出现了重大错误。更具体地说,其他源文件报告在单独文件中声明的函数的隐式声明。
我真的没有使用多个文件 makefile 的经验。当前的语法是从去年系统编程类(class)中的一个简单的 shell 实现中借用的,尽管当前项目的复杂性要高出一个数量级。
cc= gcc
CFLAGS= -g -Wall -lm
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o proj2 main.o split.o tree.o id3.o output.o
我也尝试过以前的版本,其中每个目标文件都是单独编译的
main.o: main.c split.c tree.c id3.c output.c
$(CC) $(CFLAGS) -o main.c split.c tree.c id3.c output.c
重复此操作为每个源创建一个 .o
文件,然后将其编译成可执行文件。
但是,这没有用,我收到了大约 500 行编译器投诉和警告,主要是关于隐式函数声明。
所以,基本上我有两个相关的问题:
- 是否可以在不同源文件之间交织函数调用?
- 如果可以,我怎样才能让它成为可能?
最佳答案
首先谈谈您的 makefile。
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o proj2 main.o split.o tree.o id3.o output.o
这应该可以工作(如果代码是正确的)但是如果你使用的是 GNUMake(你应该使用)你可以整理它:
proj2: main.o split.o tree.o id3.o output.o
$(CC) $(CFLAGS) -o $@ $^
现在您只有一个对象列表副本需要维护。
另一个版本是错误的:
main.o: main.c split.c tree.c id3.c output.c
$(CC) $(CFLAGS) -o main.c split.c tree.c id3.c output.c
首先,您试图将所有 源文件编译成一个 目标文件,这违背了目标文件的目的。其次,您将一个目标文件命名为 main.o
,而该名称实际上应该属于由 main.cc
生成的目标文件。第三,该命令告诉编译器将所有other 源文件(split.c
、tree.c
...)编译成一个名为“main.c”的目标文件——不是非法的,但你一定会把自己绊倒。
此外,您应该尝试使用 C++,而不是 C,但那是以后的事了。
现在分解 Big Ball of Mud .我假设您知道如何将大函数分解为较小的函数,所以问题是将函数分离到不同的源文件中(然后正确地编译和链接它们)。假设 main()
调用函数 foo()
:
/* main.c */
void foo()
{
// do foo things
}
int main()
{
// do main things
foo();
return(0);
}
如您所知,foo
必须先出现,否则当 main
试图调用未声明的函数时,编译器会犹豫不决。但是我们可以预先声明foo
:
/* main.c */
void foo();
int main()
{
// do main things
foo();
return(0);
}
void foo()
{
// do foo things
}
当编译器到达对foo()
的调用时,它已经知道存在这样一个函数,并相信我们稍后会定义它。现在这里是诀窍:如果我们指示编译器进行编译,而不是链接(即生成一个像 main.o
这样的目标文件,而不是像 proj2
这样的可执行文件),它会更加信任我们:
/* main.c */
void foo();
int main()
{
// do main things
foo();
return(0);
}
这将很好地编译成 main.o
。当我们将事物链接在一起成为可执行文件时,编译器相信我们会在其他目标文件中提供 void foo()
的定义。该定义将在另一个文件中,如下所示:
/* foo.c */
void foo()
{
// do foo things
}
我们可以手工构建:
gcc -g -Wall -lm -c foo.c -o foo.o
gcc -g -Wall -lm -c main.c -o main.o
gcc -g -Wall -lm foo.o main.o -o proj2
但这很快就会变得乏味,所以我们将编写一个 makefile:
cc= gcc
CFLAGS= -g -Wall -lm
proj2: main.o foo.o
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
到目前为止一切顺利。如果这些都清楚了,那么我们可以继续处理头文件...
关于c - 使用 make & C 计算多文件编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7656033/