39

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?

artless noise
  • 21,212
  • 6
  • 68
  • 105
K.Mulier
  • 8,069
  • 15
  • 79
  • 141

4 Answers4

37

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.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • 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. – K.Mulier Aug 16 '16 at 15:58
  • 2
    @K.Mulier, `-` is used to ignore errors if a command failed (with non-zero exit status). see [this post](https://stackoverflow.com/questions/3477292/what-do-and-do-as-prefixes-to-recipe-lines-in-make) for details. However, I don't really understand why it is there in `@echo`. – LRDPRDX Sep 03 '20 at 10:34
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.

Daerdemandt
  • 2,281
  • 18
  • 19
  • 4
    What exactly is " the file name with which make was invoked " ? – K.Mulier Aug 16 '16 at 15:53
  • 3
    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.* – Daerdemandt Aug 16 '16 at 16:03
  • 1
    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"`? – K.Mulier Aug 16 '16 at 16:07
  • 1
    Okay, 'double clicking' is somewhat too simplistic because that implies no options given to it. But you get the point ;-) – K.Mulier Aug 16 '16 at 16:08
  • 3
    > *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. – Daerdemandt Aug 16 '16 at 16:13
  • That's a great idea! Thank you so much for your help – K.Mulier Aug 16 '16 at 16:13
  • thanks for including the doc link – DevOops Mar 08 '22 at 23:42
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.

LRDPRDX
  • 631
  • 1
  • 11
  • 23
  • 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. – Andrew Falanga Aug 12 '21 at 19:59
  • Agreed :) Newbie then – user3275158 Apr 14 '23 at 05:24
3

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.

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265