【问题标题】:Creating a Makefile in Raspbian在 Raspbian 中创建 Makefile
【发布时间】:2014-12-11 08:53:04
【问题描述】:

我正在尝试在 Raspbian (Raspberry Pi) 中为我的 C 程序创建一个 Makefile。 我的程序由一堆 .c 和 .h 文件组成。我看过无数的 Makefile,但我就是不明白它是如何与多个文件一起工作的。 Makefile 中总是有 .o 文件,但据我所知,目标文件是编译的结果,所以我没有任何 o。文件,因为我正在尝试编译我的 .c 文件。

请向我解释这是如何工作的。

编辑:

谢谢。所以我尝试了这个,它开始编译,但出现“多重定义”错误。示例:

这些是我的文件:

main.c main.h
calibration.c calibration.h
file.c file.h
frame.c frame.h
gamepad.c gamepad.h
gpio.c gpio.h
uart.c uart.h
types.h

这是我的生成文件:

all: main

main: main.o calibration.o file.o frame.o gamepad.o gpio.o uart.o

%.o: %.c
    gcc -c -std=c99 -Wall $< -o $@ -lncurses

我可以把'types.h'放在哪里? 对于每个文件,我都会收到“多个定义”错误

【问题讨论】:

  • 您将源 (.c) 文件编译成 对象 (.o) 文件。对于gcc,添加-c 选项。然后,当您拥有目标文件时,将它们链接在一起。如果您正确设置了依赖项,则只有您更改的源文件才会在您调用 make 时重新编译为目标文件。
  • 所以我一次编译一个 .c 文件,然后创建一个生成文件,将所有目标文件链接在一起?
  • @user3030653 :没有make文件可以做到这一点。如果您的真正问题是编译和链接多个源,而不是对 makefile 的特定需求,那么像 Code::Blocks 这样的 IDE 将为您解决这个问题,并且可以通过 aptget 在 RPi 上使用,并且具有其他优势,例如 GUI GDB 接口和代码语法高亮和导航。

标签: c makefile raspbian


【解决方案1】:

make 规则的基本语法是:

target … : prerequisites …
    recipe
    …
    …

分号左侧是目标。目标是您的目标文件 (.o)。分号右侧是创建此文件所需的文件。这些文件是源文件(.c)。

让我们举一个基本的例子来说明这样的规则可能是什么样子。

%.o: %.c
    gcc -c $< -o $@

% 符号是通配符。 %.o 表示以.o 结尾的所有内容。所以,如果你想创建一个目标文件,你可以说make file.omake 会尝试找到一个规则来创建这个目标。这恰好是我刚刚作为示例展示的规则,因为file.o 匹配%.o

然后是recipe。这就是将要执行的。通常它是关于调用编译器(gcc),并将源文件提供给它以生成目标文件。这就是我们对gcc -c $&lt; -o $@ 所做的事情。 $&lt;$@ 分别表示 targetprerequisites

那么,当您“只是”想要构建程序时会发生什么?你通常会输入make,它就会生成。键入 make 时使用的默认规则是 all。因此,如果您制定了有关all 的规则,那么您可以指定要创建哪些文件来构建您的程序。此类规则的示例:

all: main

然后,当调用make 时,它会找到该规则并发现它需要main。要创建main,您需要另一个规则:

main: file.o

这条规则说要构建main,你需要file.o。因此,当您将所有示例规则放在一起时,您会得到:

all: main

main: file.o

%.o: %.c
    gcc -c $< -o $@

请注意,您可以指定多个文件,因此您可以说 file.o main.o other_file.o 等,而不是 file.o。如果他们能找到创建规则,则将满足您指定的每个先决条件。

【讨论】:

  • 我明白了。但是这如何与多个源文件一起工作?我可以用我的程序名称创建一个目标并将我的所有源文件放在先决条件中吗?
  • 查看我的编辑。如果您还有其他问题,我很乐意为您解答。
  • 谢谢。所以我尝试了这个,它开始编译,但出现“多重定义”错误。示例:这些是我的文件:main.c main.hcalibration.ccalibration.h file.c file.h frame.c frame.h gamepad.c gamepad.h gpio.c gpio.h uart.c uart.h types .h 这是我的makefile: all: main main: main.ocalibration.o file.o frame.o gamepad.o gpio.o uart.o %.o: %.c gcc -c -std=c99 -Wall $
  • 那个错误与makefile没有太大关系。头文件包含在源文件中。如果您将源文件传递给编译器,编译器将使用所谓的“预处理器”,请使用 Google 了解更多相关信息。您可能多次包含相同的头文件,这意味着将出现多个定义。为此使用“标题卫士”。
  • 然后找出为什么你的源文件中有多个定义。这在每种情况下都可能不同。也许你包含两次相同的头文件,等等。
【解决方案2】:

一个非常简单但典型的 makefile 可能如下所示

SOURCES = source1.c source2.c source3.c
OBJECTS = $(SOURCES:%.c=%.o)

TARGET = myExecutable

$(TARGET): $(OBJECTS)
    gcc $^ -o $@

%.o: %.c
    gcc -c $< -o $@

复杂的部分:

  • SOURCES = source1.c source2.c source3.c这是一个变量定义,它将字符串"source1.c source2.c source3.c赋给变量SOURCES

  • $(SOURCES:%.c=%.o) 这是patsubst text function 的简写。它从$(SOUCES) 变量中获取所有文本,并将模式%.c 替换为%.o,即它需要例如字符串source1.c 并将其替换为source1.o

  • $(TARGET): $(OBJECTS) 这使得myExecutable 依赖于所有对象文件,这意味着如果修改了一个对象文件,则将执行规则中的命令。

  • gcc $^ -o $@ 这会调用gcc 命令,将所有依赖项($^)作为参数(即所有目标文件)传递,并告诉gcc 输出一个名为目标 ($@)。

  • %.o: %.c 这是使目标文件依赖于其源文件的规则。因此,如果您有source1.c,那么source1.o 将取决于该源文件。

  • gcc -c $&lt; -o $@ 这是将源文件(第一个依赖项,$&lt;)编译为目标文件(使用-c 选项)并将其命名为规则目标(@ 987654346@)。

另请注意,如果您在没有特定目标的情况下调用 make,则将选择第一条规则。对于上述生成文件,$(TARGET): $(OBJECTS) 规则将确保所有目标文件都是从源文件构建的,然后将目标文件链接到生成的可执行文件中。

【讨论】:

    猜你喜欢
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 2015-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    相关资源
    最近更新 更多