【问题标题】:Understanding Makefile with .c=.o and $<使用 .c=.o 和 $< 理解 Makefile
【发布时间】:2026-02-07 07:20:04
【问题描述】:

这是我的第一个 Makefile,我无法弄清楚使用的一些语法。问题标记如下:

C := gcc

CFLAGS := -Wall -Werror -std=

PROG := program_1\
    program_2\
    program_3

SRCS := program_1.c \
    program_2.c \
    program_3.c

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

all: ${OBJS}
  ${CC} ${OBJS} -o ${PROG}

clean:
    rm -f ${PROG} ${OBJS}


.c.o:
    ${CC} ${CFLAGS} -c $<
  1. .c=.o 是什么意思?在 OBJS := ${SRCS:.c=.o}

  2. 不确定$&lt; 在这里是什么意思,.c.o

    .c.o: ${CC} ${CFLAGS} -c $&lt;

【问题讨论】:

    标签: c makefile


    【解决方案1】:

    首先,您的Makefile 有一个错误,它没有达到预期的目标。你试过了吗?

    第二,写得不好;不遵循当前的最佳做法。

    因此,我将首先向您展示您的 Makefile 的更好版本,既正确,又使用最佳实践编写:

    CFLAGS := -Wall -Werror -std=
    
    SRCS := program_1.c \
        program_2.c \
        program_3.c
    
    OBJS := ${SRCS:c=o} 
    PROGS := ${SRCS:.c=}
    
    .PHONY: all
    all: ${PROGS}
    
    ${PROGS} : % : %.o Makefile
        ${CC} $< -o $@
    
    clean:
        rm -f ${PROGS} ${OBJS}
    
    %.o: %.c Makefile
        ${CC} ${CFLAGS} -c $<
    

    现在,您的问题的答案是:

    ${SRCS:.c=.o} 的意思是,取变量值${SRCS},这是一个由空格分隔的单词组成的字符串,对于每个单词,将后缀.c 替换为.o。我在我的代码中删除了.,因为它不是必需的,并且通常只替换点后的后缀。

    如果您熟悉的话,此语法类似于 bash 字符串后缀替换(一个单词)。

    $&lt; 在“recipe”中使用时,表示“第一个先决条件”——上一行中: 之后的第一件事。

    最后一个问题不再相关:.o.c 语法已过时,目前不推荐使用。

    请看看我的“10 条诫命”——我在这篇文章中的回答:

    makefile enforce library dependency ordering

    ,他们会给你一个关于最佳实践的想法。然后你也可以阅读 GNU Make 手册,关于上面引号中的术语,我没有在这里解释。

    【讨论】:

    • 感谢您的全面回答。我只是按照工作中给我的示例生成文件。 Makefile 中的哪些行确保例如 program_1.o 从 program_1.c 链接并且它将生成目标 program_1 ?
    • @user3630406 这些是“模式”规则,其中包含%% 就像 shell 中的通配符 *。当然,规则中的所有% 都必须匹配相同的字符串。第一条规则尝试在${PROGS} 中的单词之间进行匹配。第二,没有这样的约束,它试图匹配任何其他地方没有匹配的东西。我故意不给你所有的细节,所以你必须去阅读:)请不要被冒犯。
    • 再问一个问题。我看到你放置了 %.o: %.c Makefile,为什么你把 Makefile 作为 prereq,我在看其他在线资源,似乎 %.o: %.c 就足够了?
    • @user3630406 好吧,考虑“先决条件”的正确方法是,列出所有文件,如果它们发生变化,则生成的目标也可能发生变化。因此,如果 Makefile 发生变化,则可能是该目标的配方发生了变化,在这种情况下,生成的目标也可能发生变化。因此,最好在所有先决条件行中列出所有包含的 makefile。
    • @Anže 是的,应该
    【解决方案2】:

    您没有具体说明您使用的是make 的哪个变体——有很多。我假设您使用的是 GNU make,这是使用最广泛的变体。

    在 GNU make 中,$(SRCS:.c=.o) 是一个substitution reference,它的意思是“SRCS 变量的值,其中.c 在出现在单词末尾时被.o 替换。”在您的示例中,SRCS 的值为 program_1.c program_2.c program_3.c,因此 $(SRCS:.c=.o) 表示 program_1.o program_2.o program_3.o

    .c.o 是已知的old-fashioned suffix rule 的一个示例。它告诉 GNU make “这是从同名的 .c 文件构建 .o 文件的方法。”现代的等价物是模式规则,除了使用%.o: %.c 代替.c.o 之外,它看起来是一样的。

    最后,$&lt; 是一个 automatic variable,意思是“第一个先决条件的名称”。

    【讨论】:

    • @EtanReisner $&lt; 并非在“规则”中随处使用,而仅在“食谱中”使用。而且,它在所有规则中都使用和有用,而不仅仅是后缀和模式规则。
    • @EricMelski Eric 我会恭敬地不同意你的回答。 .c=.o 表示“用.o替换的字符.c
    • 我赞同关于替代参考的分歧。它确实做到了,但细节比这更具体。虽然我很怀疑埃里克没有意识到这一点。
    • @EtanReisner 好吧,规则有两部分:目标和先决条件的声明,以及下面的配方。所以配方是规则的一部分。
    • 对不起,伙计们,我今天很自负 :) 我刚刚被告知,在我的第二职业(与编程无关)的试镜中,我“非常有才华”。对不起,无关的吹牛:)我只是想解释一下为什么我今天这么严格。