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

标签 c compiler-errors makefile

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

相关文章:

c - 在 BST 中查找 "nth"值 (C)

excel - VBA : Store value to variable

c++ - 什么可能会在此语句中生成编译器错误以推进迭代器?

C++ 错误 : Multiple definitions of class functions

makefile - makefile 中的条件 OR

将各个程序集转换为机器代码

c - Linux C : When do I need "clone" function instead of "fork"?

c - C lower_bound 的实现

typescript - 无法将 'new' 与类型缺少调用或构造签名的表达式一起使用

xml - 如何从 Perl 脚本定义 Makefile 变量?