【问题标题】:How to run a C program when it has multiple files?C程序有多个文件时如何运行?
【发布时间】:2016-10-01 04:08:41
【问题描述】:

在一个程序中,我有一个 list.c 文件、list.h 文件和 run.c 文件。在 run.c 文件中,代码包含我的主程序以及“#include list.h”。在我的 list.h 文件中,我的函数是无效的并且正在被定义。最后,在我的 list.c 文件中,我再次包含 list.h,并且我了解了每个函数将要执行的操作的含义和代码。我制作了一个看起来像这样的makefile:

SOURCES = run.c list.c
OBJECTS= run.o list.o
HEADERS = list.h
CC = gcc
CFLAGS = -g -Wall

lab1: $(OBJECTS)
(tab)    $(CC) $(CFLAGS) $(OBJECTS) -o lab1

clean:
(tab)    rm -fR *o lab1

我的任何代码都没有错,因为它已经完成,我只是在复制代码。但是,我不确定如何使用 makefile 来运行这些多个文件。我只在使用 gcc 编译并使用“./”之后才熟悉运行器文件。我的 makefile 是否有问题,或者是否有以不同方式编译这些文件的步骤?

感谢您的帮助

【问题讨论】:

  • 您需要一个$(OBJECTS) 的目标,它将利用SOURCES。通常,您的lab1 目标是最终的可执行文件,并且应该有用于链接的命令,即$(CC) $(LDFLAGS) $(OBJECTS)...。您需要一个目标和相应的命令来描述如何构建这些对象,即$(CC) $(CFLAGS) $(SOURCES) ...。这可能会有所帮助:mrbook.org/blog/tutorials/make
  • @yano 阅读链接后,我按照它所说的方式编译它,它给了我makefile中的所有文件。我假设它编译?我将如何运行这些多个文件来测试它?
  • 编译命令末尾的- lab1 似乎不正确。你是说-o lab1 吗?
  • 我会将 clean 命令更改为 rm -f *.o lab1。您拥有的命令有点危险。它将递归删除任何以o 结尾的目录。
  • 其他cmets和答案都说了。如果所有东西都编译好了,你应该有一个lab1 可执行文件。执行ls -l,您应该会看到lab1x 可执行标志,然后只需./lab1 即可运行它。如果那不存在,那就错了。运行make -d 将输出有关make 正在做什么的更详细信息,如果出现问题,可能会提供线索。

标签: c makefile


【解决方案1】:

给定的 makefile 正在工作并生成一个可执行的lab1 文件。但是,.o 文件依赖于list.h 文件,并没有捕获到这种依赖关系。

您应该指定构建 .o 文件的目标,如下所示:

SOURCES = run.c list.c
OBJECTS= run.o list.o
HEADERS = list.h
CC = gcc
CFLAGS = -g -Wall

lab1: $(OBJECTS)
(tab)    $(CC) $(CFLAGS) $(OBJECTS) -o lab1

%.o: %.c $(HEADERS)
    $(CC) -c $(CFLAGS) $< -o $@

clean:
    rm -fR *o lab1

注意事项:使用此 makefile,如果 HEADERS 的列表增加,任何标头的更改将保证重建 all .o 文件。

例如,假设我们还有buf.c,它使用buf.h。现在HEADERS = list.h buf.h。如果我们更改buf.h,我们的makefile 将同时重建list.obuf.o,即使buf.o 重建就足够了。

为了解决这个问题,我们可以使用更详细的 makefile 来标识每个 .o 文件的特定标头先决条件,其规则如下:

list.o: list.c list.h
    $(CC) -c $(CFLAGS) $< -o $@

buf.o: buf.c buf.h
    $(CC) -c $(CFLAGS) $< -o $@

【讨论】:

  • 您不需要分别指定每个.o,因为您可以将其概括为.c.o 的规则。您甚至不需要这样做,因为符合 POSIX 的make 实用程序默认实现.c.o 规则。您只需指定$OBJECTS,AFAIK。
  • @Rhymoid 由于您提到的隐含 .c.o 规则,听起来原始问题的 makefile 工作得很好。我同意我的两个 .c -> .o 规则可以替换为一个 %.o: %.c $(HEADERS) 规则。我已经编辑了我的答案。但是,根据gnu.org/software/make/manual/html_node/Suffix-Rules.html.c.o 等后缀规则不能有$(HEADERS) 等先决规则。根据gnu.org/software/make/manual/html_node/Using-Implicit.html 的隐式规则也是如此。抓住这个先决条件可能比忽略它要好。
【解决方案2】:

解决方案 1:只需将每个 .c 文件单独列出作为输入并编译一次

gcc list.c run.c -o lab1

解决方案 2:分别编译每个 .c 文件

gcc -c list.c
gcc -c run.c
gcc -o lab1 list.o run.o

您的项目小而简单,完全通用的 makefile 是多余的:

SOURCES = run.c list.c
CC = gcc
CFLAGS = -g -Wall

all:
    $(CC) $(CFLAGS) $(SOURCES) -o lab1

clean:
    rm -fR *o lab1

all: 是一个默认目标,当您只需键入不带参数的 make 时就会执行该目标。

【讨论】:

  • 这个问题有两个方面(一个是直接问题,一个是初期问题)。直接的问题是每次运行makemake all 时它都会重新编译所有内容,因为从未创建过all,因此将执行该命令。最初的问题是,如果您使用all: lab1lab1: 加上CC 命令修复直接问题,那么如果标题发生更改,它将不会重新编译程序 - 并且可能不会重新编译源文件任何一个。您应该链接目标文件,并且您应该指定目标文件依赖于标头。
  • 对于这个大小的项目,单独编译可能不会快多少。对于更大规模的项目,它更为重要。
  • 因此声明“您的项目足够小且简单”。提交者正在尝试完成他的作业,而不是创建可扩展的构建基础架构。我的经验是,这种东西对学生来说是一个绊脚石,而不是帮助(这个作业是第一个实验室的事实特别有说服力),当有必要时,人们自然会学习更先进的技术。试图教学生如何为琐碎的项目构建适当的 makefile 注定会失败。不过,这只是我的看法——这里有很多信息可以看到双方。
【解决方案3】:

编译后,它确实生成了一个我可以运行的 lab1 文件,并且一切正常。我的 makefile 最终工作正常,我完全没有注意到它正在制作一个名为 lab1 的文件。我确实将我的 makefile 更改为上述选项,这也有效。谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 2020-04-23
    • 2011-07-28
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    相关资源
    最近更新 更多