如何解决GNU make产生 "循环main.c "错误的问题。

问题描述 投票:1回答:2

/makefile.conf

.SUFFIXES : .c .o

cc = gcc
CFLAG = -c
OFLAG = -o
O2FLAG = -O2
WPIFLAG = -lwringPi
RM = rm -rf

TARGET_SRCS = main.c
TARGET_OBJS = $(TARGET_SRCS:$.c=$.o)
TARGET_NAMES = $(TARGET_SRCS:$.c=$)
BINARY_NAME = LED_TEST

/ makefile

include makefile.conf

$(TARGET_OBJS) : $(TARGET_SRCS)
        $(CC) $(O2FLAG) $(CFLAG) $(OFLAG) $^

我想弄清楚gnu make的工作原理和使用方法。然而,我是个初学者。

我想在我的任务中使用make(不是强制的,只是我的热情)来运行简单的代码,通过wiringpi来点亮LED。

其实只有一个main.c,而我想做的是运行以下的makefile

gcc -O2 -c -o main.o main.c

gcc -o main main.o -lwiringPi

由于我上次的代码没有工作,(不断得到循环的main.c <-main.c dependency dropped错误)。

我试着做一个只运行

gcc -O2 -c -o main.o main.c

但我还是得到循环main.c错误,我不知道那是什么意思。

我试着查了一下gnu的制作手册,但是我想了想,这要花我的命才能明白。

所以我想看看代码,用我看到的东西做一个。

我想我明白makefile.conf的概念,但 我还是不明白.SUFFIXES的功能。

我的理解是,我注意到makefile.conf中的.c和.o是一个规则,后面的代码定义了那些将在makefile中使用的变量。

我怎么才能改正这些代码呢? 当实际的 "分配 "包括添加注释在内只花了5分钟。

c linux gcc makefile
2个回答
2
投票

第一个makefile.TARGET_SRCS:$.c=$.o

main:
    gcc -O2 -c -o main.o main.c
    gcc -o main main.o -lwiringPi

当它完美地运行时 第二个makefile。

main: main.o
    gcc -o main main.o -lwiringPi

main.o: main.c
    gcc -O2 -c -o main.o main.c

当它完美地运行时 第三个makefile。

main: main.o
    gcc -o $@ $^ -lwiringPi

main.o: main.c
    gcc -O2 -c -o $@ $<

当这些都能完美运行时,你就可以使用更高级的技术了。


1
投票

如果你真的是个新手,从简单的makefile开始,直到你需要额外的功能,这通常会很有帮助。

main: main.c
        gcc -O2 -o main -lwiringPi main.c

注意在 gcc 是一个单一的标签字符。

一旦你掌握了这个窍门,你就可以用各种项目来代替,使你的 "制作规则 "更容易复制和维护。 比如说 %^ 意思是 "每一个从属来源,所以规则的改写是

main: main.c
        gcc -O2 -o main -lwiringPi $^

偶尔,你可能想提供编译器的简单重新配置,所以,如果你有十几条规则,并想在一个地方配置编译器

CC=gcc

main: main.c
        $(CC) -O2 -o main -lwiringPi $^

将扩大 CC 变量的值为 gcc 在制作时。 这种扩展的实用性是有上限的,例如,如果某样东西是 "许多相同东西中的一种",你可能不想为这个单独的项目声明一个变量。 例如,你的 WPIFLAG 很可能总是需要的,而且很可能无法成功地重新配置。 也许一个加载器标志变量更有意义。

LDFLAGS=-lwiringPi -lm -lwhatever

和一个编译器标志变量

CFLAGS=-O2 -Werror -Wfatal-errors

这将导致更合理的

main: main.c
        $(CC) $(CFLAGS) -o main $(LDFLAGS) $^

最后,您可以替换目标 main 在这种情况下,用另一个特殊的变量。$@ 意思是 "正在构建的目标"

main: main.c
        $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $^

请注意,对于对象文件,你是把所有的对象都列为依赖于你所有的源。 如果你想支持独立的对象构建规则,你需要做一些不同的事情。

main: main.o
        $(CC) $(CFLAGS) -o $@ $(LDFLAGS) $^

而且你需要为每个对象制定规则。

main.o: main.c
        $(CC) $(CFLAGS) -c -o $@ $(LDFLAGS) $^

但为每个对象打这个规则会变得很费劲。 为了使这个规则自动化,你将使用一个基于文件后缀的模式,以及一个后缀规则。

.SUFFIXES : .o .c

.c.o :
        $(CC) $(CFLAGS) -c $<

请注意,上面的规则依赖于$(CC)的默认行为,即生成一个 something.osomething.c 编制了 -c 标志。 如果你想让输出文件显式化

.SUFFIXES : .o .c

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

这个后缀规则就像一个宏一样。 当有人需要 thing.o它将从 thing.c 如果 thing.c 存在,即使没有明确的规则,也会有 thing.c

有了这个,你就可以把你所有的对象收集到原来的。main 目标。 (我们将删除CFLAGS,因为不会发生编译,只会发生链接)

main: main.o other.o first.o list.o end.o
        $(CC) -o $@ $(LDFLAGS) $^

但有些人觉得列出对象很麻烦,于是喜欢把它们放在一个变量中

main: $(OBJS)
        $(CC) -o $@ $(LDFLAGS) $^

这意味着您将需要声明和设置 OBJS

OBJS = main.o other.o first.o list.o end.o

但跟踪中间文件有点奇怪,为什么不跟踪实际来源呢?

SOURCES = main.c other.c first.c list.c end.c

好吧,但我们如何获得所需的 OBJSSOURCES? 我们将解除防御 SOURCES,将后缀修改为 .o

OBJS = ${SOURCES:.c=.o}

最终结果

SOURCES = main.c other.c first.c list.c end.c
OBJS = ${SOURCES:.c=.o}

CC=gcc 
CFLAGS=-O2 -Werror -Wfatal-errors
LDFLAGS=-lwiringPi -lm -lwhatever


.SUFFIXES : .o .c

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

main: ${OBJS}
        $(CC) -o $@ $(LDFLAGS) $^
© www.soinside.com 2019 - 2024. All rights reserved.