makefilegnu-makestatus

Makefile - How to run additional commands in a target based on exit code of a previous command


I am trying to leverage make to run some jobs in parallel by generating a Makefile that looks like this:

test_all: test_1 test_2 test_3

test_1:
    @echo "Starting test 1"
    @run_some_job > test_1.log 2>&1
    # if run_some_job passed, print "Test 1 passed", else print "Test 1 failed"
    
test_2:
    @echo "Starting test 2"
    @run_some_job > test_2.log 2>&1
    # if run_some_job passed, print "Test 2 passed", else print "Test 2 failed"

test_3:
    @echo "Starting test 3"
    @run_some_job > test_3.log 2>&1
    # if run_some_job passed, print "Test 3 passed", else print "Test 3 failed"

I will invoke using make -j10 so that all of these run in parallel, capturing their stdout+stderr in individual log files.

Question: How can I do the thing I want to in that comment above? Note that here I am just doing a print, but in reality I may want to do custom things in the next command based on whether the previous command passed or failed.

if run_some_job passed, print "Test N passed", else print "Test N failed"

Solution

  • # if run_some_job passed, print "Test 1 passed", else print "Test 1 failed"

    How can I do the thing I want to in that comment above? Note that here I am just doing a print, but in reality I may want to do custom things in the next command based on whether the previous command passed or failed.

    This is a question of the shell language, in which makefile recipes are expressed, not of make itself. There are two components to it:

    1. run_some_job must indicate via its exit status whether the test passed or failed. Most natural would be to exit with status 0 on success, and with any other status (1, for example) on failure.

    2. Use a shell conditional command to select the alternative to execute.

    The latter is slightly complicated by the fact that make runs each (logical) recipe line in its own shell, but you can use semicolons (;) interchangably with newlines for most purposes in the shell language, and make provides for joining multiple physical lines into a single logical one, which serves your purposes. For example:

    test_1:
            @echo "Starting test 1"
            @if run_some_job > test_1.log 2>&1; then \
              echo "Test 1 passed"; \
            else \
              echo "Test 1 failed"; \
            fi