gpt4 book ai didi

c - 使用 make & C 计算多文件编译

转载 作者:太空宇宙 更新时间:2023-11-04 00:54:28 24 4
gpt4 key购买 nike

对于一个项目,我正在与合作伙伴一起编写决策树实现。由于我们都是 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.ctree.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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com