What is the variable $(MAKE) in a makefile?
Asked Answered
E

5

45

I am currently learning how to write makefiles. I've got the following makefile (which was automatically generated for a C-project that should run on an ARM chip), and I'm trying to understand it:

    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

I'm trying to wrap my head around the line $(MAKE) --no-print-directory post-build in the rule for making the .elf file.

I cannot find a definition for the variable $(MAKE), so I assume that it is something built-in. What is this line actually doing?

Eigenfunction answered 16/8, 2016 at 15:17 Comment(1)
gnu.org/software/make/manual/html_node/…Lafreniere
E
41

It's a recursive invocation of make itself, forwarding the -t, -n and -q options. This makes sense: you want the nested make invocations to run with these options as well.

Escapee answered 16/8, 2016 at 15:29 Comment(2)
Thank you very much for your answer. I got another (not really related) question. Why do the @echo commands in post-build have a - character preceding? The @echo commands in the rule for making the executable doesn't have it.Eigenfunction
@K.Mulier, - is used to ignore errors if a command failed (with non-zero exit status). see this post for details. However, I don't really understand why it is there in @echo.Fulbert
W
9

From the docs:

The value of this variable is the file name with which make was invoked

It is useful in cases where to make some target you'd have to call its makefile, but you are doing some sort of dry run with -t (--touch), -n (--just-print), or -q (--question) flags. That behaviour would propagate recursively if ($MAKE) is used.

Wellbeloved answered 16/8, 2016 at 15:29 Comment(7)
What exactly is " the file name with which make was invoked " ?Eigenfunction
Remainder of paragraph from the doc: 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.Wellbeloved
So, if I start the GNU make program by double clicking the file C:\Apps\SysGCC\arm-eabi\bin\make.exe, then the $(MAKE) variable will expand to the String "C:\Apps\SysGCC\arm-eabi\bin\make.exe"?Eigenfunction
Okay, 'double clicking' is somewhat too simplistic because that implies no options given to it. But you get the point ;-)Eigenfunction
> if I start the GNU make program by double clicking the file Yes, it should be. You could try writing a simple makefile that does echo $(MAKE) or something like that to be sure.Wellbeloved
That's a great idea! Thank you so much for your helpEigenfunction
thanks for including the doc linkPithos
W
6

Meaning of the variable MAKE in a Makefile

What is the variable $(MAKE) in a makefile?

See the make manual (run man make locally), section 5.7.1: https://www.gnu.org/software/make/manual/make.html#MAKE-Variable.

Let me emphasize the part where it says: "Recursive make commands should always use the variable MAKE, not the explicit command name make." "Recursive" here simply means you are calling make inside of a makefile. So, when you call the outer Makefile with make, it in turn calls make again via the MAKE special variable rather than via make directly. See the manual below:

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.

Woodpecker answered 3/7, 2021 at 22:44 Comment(0)
A
3

Please don't get confused with the earlier answers saying recursive call. $MAKE is the default variable which gets replaced with "make".

And in your scenario, $MAKE is used in commands part (recipe) of makefile. It means whenever there is a change in dependency, make executes the command make --no-print-directory post-build in whichever directory you are on.

For example if I have a case where in

test.o: test.c
      cd /root/
      $(MAKE) all

It says, if there is a change in test.c, execute make all in /root directory.

Astri answered 30/8, 2019 at 11:9 Comment(2)
This example demonstrates a very common mistake. Each line of a make recipe is handed to the shell independently. Thus, if you want to execute something in the directory /root then the recipe should be something like cd /root/ && $(MAKE) all. As written, the line cd /root/ will cd into /root and exit. Then $(MAKE) all is executed in the current directory not /root/. This is covered in GNU Make docs.Aeolotropic
Agreed :) Newbie thenAstri
B
0

As above answers have mentioned, it is used for calling the running Makefile recurssively, Lets take an example below:

I_am_first_target:
    @echo
    @echo "----------------------------------------"
    @echo "Hello from First target"
    $(MAKE) I_am_second_target
    @echo 
    @echo "Hello again from First target, Second Target has finished it's business"
    @echo "----------------------------------------"
    @echo 
I_am_second_target:
    @echo "========================================"
    @echo "Hello I am Second target and I am trying to run in between First Target"
    @echo  "========================================"

output:

make I_am_first_target

Here if you see we wanted second target to run while we are at first target still, it might be some intermediate work from second target. So we execute $(MAKE) I_am_second_target to get it done before exiting First target. Note that there are keywords "Entering" and "Leaving" pointing to path of same Makefile.

Barby answered 6/6, 2024 at 10:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.