Search code examples
phpsymfonymakefile

Why is the exit code in this Makefile target ignored?


I've got a Makefile where the exit code of a command is ignored and I do not understand why. The command is being run, but fails silently.

Here is a minimal example:

SHELL=/bin/bash
PHP_CMD = php
CONSOLE_CMD = $(PHP_CMD) ./bin/console

.PHONY: symfony-dump-assets

symfony-dump-assets: ## Dump symfony assets.
    $(CONSOLE_CMD) assetic:dump --quiet

The command should return a exit code 1 and it does when I run the command directly from an interactive shell: php ./bin/console assetic:dump --quiet

When I run the command using shell, the error message of the command is shown, but make still doesn't exit with the code of the command (1).

Only when I changed the value of the CONSOLE_CMD variable to include the full path, it works.

CONSOLE_CMD = $(PHP_CMD) $(shell pwd)/bin/console

This is what I do not understand. Why would the full path to the console command change the output of make?


Solution

  • The example you give will work and make will recognize the exit code.

    But in your comment you say:

    When I run the command using shell, the error message of the command is shown, but make still doesn't exit with the code of the command (1).

    There is no example in your question of using shell, but if you WERE to use the GNU Make shell function to run the command then definitely make will ignore that exit code. This is because make only cares about exit codes that are generated by the recipe that make invokes after it's expanded all the variables and functions and passed the results to the shell.

    In other words if you have this:

    foo: ; false
    

    make will expand the recipe false which contains no variables or functions and results in the string false, so make invokes a shell like /bin/sh -c 'false' and wait for the exit code and fail if it's not 0.

    But if you have this:

    foo: ; $(shell false)
    

    then make will expand $(shell false) which invokes the shell command and replaces it with the output of that command (which is nothing in this case), so make invokes a shell /bin/sh -c '' (or really it doesn't bother) which succeeds as a no-op, so it will succeed.

    See info on the shell function: https://www.gnu.org/software/make/manual/html_node/Shell-Function.html

    The short answer is, you should never use $(shell ...) (or $(eval ...)) inside a recipe unless you fully and completely understand how make expansion works and you have a good reason to want to circumvent make's normal expansion process.