运行 具有第 n 个依赖项的第 n 个目标的命令

Run a command for the nth target with the nth dependancy

我对“$<”和“$@”宏如何与元素列表一起使用有些困惑。我的最终目标是将一个 C 源文件目录编译成同名的 executables,没有扩展名。我也不想制作目标文件。

这是一个简单的 makefile,我想使用宏对其进行升级。

CC = gcc -ansi -std=c99
CCFLAGS = -Wall -pedantic -O3

all : progA progB progC

progA : progA.c
    $(CC) $(CCFLAGS) $< -o $@

progB : progB.c
    $(CC) $(CCFLAGS) $< -o $@

progC : progC.c
    $(CC) $(CCFLAGS) $< -o $@

这很好用,但我不喜欢命令的冗余。我找到了一个可行的解决方法和一个接近的解决方案,但希望可能有一个明确的选择。


解决方法:

CC = gcc -ansi -std=c99
CCFLAGS = -Wall -pedantic -O3
PRGS := $(patsubst %.c,%,$(wildcard *.c))

all : 
    make $(PRGS)

% : *.c
    $(CC) $(CCFLAGS) $@.c -o $@

这里我不喜欢的是在命令中进行的调用。 运行 'make' 在我的终端中发送一条消息,看起来像这样:

make[1]: Entering directory '/path/to/dir'
...actual commands...
make[1]: Leaving directory '/path/to/dir'

我假设这与打开同一个 makefile 有关,[1] 指的是打开文件中的第二个文件描述符 table(或类似的东西)。


接近解:

CC = gcc -ansi -std=c99
CCFLAGS = -Wall -pedantic -O3
SRCS := $(wildcard *.c)
PRGS := $(patsubst %.c,%,$(SRCS))

all : $(PRGS)

$(PRGS) : $(SRCS)
    $(CC) $(CCFLAGS) $< -o $@

这几乎可以工作,除了它总是抓住第一个依赖项!

..... progA.c -o progA
..... progA.c -o progB
..... progA.c -o progC

那么,有没有人对我的 'workaround' 有更简洁的方法或者对我的 'near solution' 有解决方案?当 运行 命令时,有没有将第 n 个目标与第 n 个依赖项匹配?

谢谢!

$(PRGS): $(SRCS) 更改不正确。它列出 every 源文件作为 every 目标的先决条件。

您想将 all 目标的先决条件设置为默认情况下要构建的每个程序。为此,您需要使用 all: $(PRGS)。不是像你原来那样再次调用 make 的方法。

(如果您确实想保留手动递归调用以使您可以在该调用上使用 make --no-print-directory 来避免出现该消息,但这仍然是错误的方法(如果您打算这样做,您我想使用 $(MAKE) 来正确处理原始 make 的参数。)

原始 makefile 的第二个问题是在 % 目标的先决条件列表中使用了 *.c。这将 every 目标的先决条件设置为目录中的 every *.c 文件。那不是你想要的。您希望每个目标都有自己的 .c 文件作为其先决条件。

你想要:

all: $(PRGS)

%: %.c
        $(CC) $(CCFLAGS) $@.c -o $@

据说 make 有一个内置规则,正好用于 foo.c -> foo 编译,所以你应该只使用它。该规则使用 $(CC)$(CFLAGS) 变量。因此,只需将它们设置为您想要的即可。

所以这个 makefile 应该做你想做的。 (请注意我是如何将一些参数移动到 CFLAGS 而不是 CC。据我所知,CC 通常应该由编译器本身而不是任何参数移动。)

CC = gcc
CFLAGS = -ansi -std=c99 -Wall -pedantic -O3
PRGS := $(patsubst %.c,%,$(wildcard *.c))

all : $(PRGS)