0

I have the following rule in my Makefile compiled with GNU make 4.1:

multiboot_check: kernel.bin
    if [ $(grub2-file --is-x86-multiboot $^) -eq 0 ]; then \
        $(info $^: valid Multiboot Version 1 header); \
    else \
        $(error $^: invalid Multiboot Version 1 header); \
    fi

When I run this, both the true and false branch are executed, resulting in the following output:

kernel.bin: valid Multiboot Version 1 header
Makefile:24: *** kernel.bin: invalid Multiboot Version 1 header.  Stop.

Why is this occurring? Is there a better way?

I have tried putting it into a single line, and even reducing the if statement to [ 0 -eq 0 ], and it still executes both branches.

Stewart Smith
  • 1,396
  • 13
  • 28

1 Answers1

1

Your recipe is equivalent to:

multiboot_check: kernel.bin
#   `make` directives evaluated for this target are not part of the recipe
    $(info $^: valid Multiboot Version 1 header)
    $(error $^: invalid Multiboot Version 1 header)
#   The recipe is...
    if [ -eq 0 ]; then \
        ; \
    else \
        ; \
    fi

To understand first why make does not order the lines as you have written them, read this answer

The residual recipe:

    if [ -eq 0 ]; then \
        ; \
    else \
        ; \
    fi

is syntactically invalid for the shell, because the unescaped $(grub2-file ...) will be expanded by make and not the shell and will expand to nothing. You want it to be a shell expansion, so you need to escape it for make:

$$(grub2-file...)

But although the residual recipe will provoke a shell syntax error, you never see it, because make evaluates:

    $(info $^: valid Multiboot Version 1 header)
    $(error $^: invalid Multiboot Version 1 header)

before the recipe is run, and the $(error ...) directive terminates make before it attempts to execute the invalid recipe.

Corrected for shell-expansion, the test:

[ $$(grub2-file --is-x86-multiboot $^) -eq 0 ]

will still fail to achieve what you apparently want. This test will determine whether the standard output of the command grub2-file --is-x86-multiboot kernel.bin is a string equal to 0. Presumably it never will be and what you actually want to determine is whether the exit code of the command is 0.

In the light of all this, a better way is:

multiboot_check: kernel.bin
    grub2-file --is-x86-multiboot $^; \
    if [ $$? -eq 0 ]; then \
        echo "$^: valid Multiboot Version 1 header"; \
    else \
        echo "$^: invalid Multiboot Version 1 header"; exit 1; \
    fi
Community
  • 1
  • 1
Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182