一个makefile中的变量$(MAKE)是什么?

42

我目前正在学习如何编写makefile。下面是一个自动生成的makefile,用于一个应该在ARM芯片上运行的C项目,我正在努力理解它:

    RM := rm -rf

    # All of the sources participating in the build are defined here
    -include sources.mk
    -include FreeRTOS/Supp_Components/subdir.mk
    -include FreeRTOS/MemMang/subdir.mk
    -...
    -include subdir.mk
    -include objects.mk

    ifneq ($(MAKECMDGOALS),clean)
    ifneq ($(strip $(S_UPPER_DEPS)),)
    -include $(S_UPPER_DEPS)
    endif
    ifneq ($(strip $(C_DEPS)),)
    -include $(C_DEPS)
    endif
    endif

    -include ../makefile.defs

    # Add inputs and outputs from these tool invocations to the build variables 

    # All Target
    all: FreeRTOS_T02.elf

    # Tool invocations
    FreeRTOS_T02.elf: $(OBJS) $(USER_OBJS)
        @echo 'Building target: $@'
        @echo 'Invoking: MCU GCC Linker'
        arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 -specs=nosys.specs -specs=nano.specs -T LinkerScript.ld -Wl,-Map=output.map -Wl,--gc-sections -lm -o "FreeRTOS_T02.elf" @"objects.list" $(USER_OBJS) $(LIBS)
        @echo 'Finished building target: $@'
        @echo ' '
        $(MAKE) --no-print-directory post-build

    # Other Targets
    clean:
        -$(RM) *
        -@echo ' '

    post-build:
        -@echo 'Generating binary and Printing size information:'
        arm-none-eabi-objcopy -O binary "FreeRTOS_T02.elf" "FreeRTOS_T02.bin"
        arm-none-eabi-size "FreeRTOS_T02.elf"
        -@echo ' '

    .PHONY: all clean dependents
    .SECONDARY: post-build

    -include ../makefile.targets

我试图理解在生成.elf文件的规则中,行$(MAKE) --no-print-directory post-build的含义。

我找不到变量$(MAKE)的定义,因此我假设它是内置的。这一行实际上是在做什么?


1
https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html#MAKE-Variable - Notlikethat
4个回答

39
这是 make 的递归调用,转发了 -t-n-q 选项。这是有意义的:你希望嵌套的 make 调用也使用这些选项运行。

非常感谢您的回答。我有另一个(不是很相关的)问题。为什么在后期构建中的 @echo 命令前面有一个 - 字符?而在制作可执行文件的规则中,@echo 命令却没有呢? - K.Mulier
2
@K.Mulier,“-”用于忽略错误,如果一个命令失败(退出状态为非零)。详见此帖子。然而,我不是很理解在@echo中为什么要使用它。 - LRDPRDX

9

根据文档

此变量的值是使用哪个文件名调用make命令。

在某些情况下,如果要生成某个目标,则需要调用 makefile,但您正在使用-t (--touch)、-n (--just-print)或-q (--question)标志进行某种干扰测试。如果使用($MAKE),则该行为将递归传播。


4
“ the file name with which make was invoked ” 指的是使用 make 命令时所指定的文件名。 - K.Mulier
4
如果文件名是/bin/make,那么执行的命令将是“cd subdir && /bin/make”。如果你使用一个特殊版本的make来运行顶层的makefile,那么递归调用时也会执行相同的特殊版本。 - Daerdemandt
1
如果我通过双击文件 C:\Apps\SysGCC\arm-eabi\bin\make.exe 来启动 GNU make 程序,那么 $(MAKE) 变量会扩展为字符串 "C:\Apps\SysGCC\arm-eabi\bin\make.exe" 吗? - K.Mulier
1
好的,“双击”有点过于简单化,因为这暗示它没有给出任何选项。但你懂的;-) - K.Mulier
3
是的,应该可以。你可以尝试编写一个简单的makefile,使用echo $(MAKE)或类似的命令来确认。 - Daerdemandt
显示剩余2条评论

3

Makefile中变量MAKE的含义

在makefile中,变量$(MAKE)是什么意思?

请参阅make手册(在本地运行man make),第5.7.1节:https://www.gnu.org/software/make/manual/make.html#MAKE-Variable

让我强调一下它所说的部分:“递归调用make命令时,应始终使用变量MAKE而不是显式的命令名称make” 这里的“递归调用”指的是您在makefile中调用make。因此,当您使用make调用外部Makefile时,它将通过MAKE特殊变量再次调用make,而不是直接调用make。请参阅下面的手册:

5.7.1 How the MAKE Variable Works

Recursive make commands should always use the variable MAKE, not the explicit command name make, as shown here:

subsystem:
        cd subdir && $(MAKE)

The value of this variable is the file name with which make was invoked. If this file name was /bin/make, then the recipe executed is cd subdir && /bin/make. If you use a special version of make to run the top-level makefile, the same special version will be executed for recursive invocations.

As a special feature, using the variable MAKE in the recipe of a rule alters the effects of the -t (--touch), -n (--just-print), or -q (--question) option. Using the MAKE variable has the same effect as using a + character at the beginning of the recipe line. See Instead of Executing the Recipes. This special feature is only enabled if the MAKE variable appears directly in the recipe: it does not apply if the MAKE variable is referenced through expansion of another variable. In the latter case you must use the + token to get these special effects.


3
请不要被之前提到的递归调用所困惑。 $MAKE 是默认变量,会被替换为 "make"。
在您的情况下,$MAKE 在 makefile 的命令部分(配方)中使用。这意味着每当依赖关系发生变化时,make 就会在 您当前所在的任何目录中 执行命令 make --no-print-directory post-build
例如,如果我有一个这样的情况:
test.o: test.c
      cd /root/
      $(MAKE) all

它表示如果test.c文件有变化,就在目录/root下执行make all命令。


1
这个例子演示了一个非常常见的错误。Makefile 配方中的每一行都是独立传递给 shell 的。因此,如果您想在目录 /root 中执行某些操作,则配方应该类似于 cd /root/ && $(MAKE) all。如当前写法,cd /root/ 这一行将进入 /root 并退出。然后,$(MAKE) all 将在当前目录而不是 /root/ 中执行。GNU Make 文档中已经覆盖了这一点。 - Andrew Falanga
同意 :) 新手 - user3275158

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接