harrisonmg
harrisonmg

Reputation: 33

How to change the return value of a `make` command

I have a number of makefiles that build and run tests. I would like to create a script that makes each one and notes whether the tests passed or failed. Though I can determine test status within each make file, I am having trouble finding a way to communicate that status to the caller of the make command.

My first thought is to somehow affect the return value of the make command, though this does not seem possible. Can I do this? Is there some other form of communication I can use to express the test status to the bash script that will be calling make? Perhaps by using environment variables?

Thanks

Edit: It seems that I cannot set the return code for make, so for the time being I will have to make the tests, run them in the calling script instead of the makefile, note the results, and then manually run a make clean. I appreciate everyone's assistance.

Upvotes: 0

Views: 3405

Answers (3)

tripleee
tripleee

Reputation: 189679

The default behavior of make is to return failure and abandon any remaining targets if something failed.

for directory in */; do
    if ( cd "$directory" && make ); then
        echo "$0: Make in $directory succeeded" >&2
    else
        echo "$0: Make in $directory failed" >&2
    fi
done

Upvotes: 1

bobbogo
bobbogo

Reputation: 15493

Simply ensure each test leaves its result in a file unique to that test. Least friction will be to create test.pass if thes test passes, otherwise create test.fail. At the end of the test run gather up all the files and generate a report.

This scheme has two advantages that I can see:

  • You can run the tests in parallel (You do us the -jn flag, don't you? (hint: it's the whole point of make))
  • You can use the result files to record whether the test needs to be re-run (standard culling of work (hint: this is nearly the whole point of make))

Assuming the tests are called test-blah where blah is any string, and that you have a list of tests in ${tests} (after all, you have just built them, so it's not an unreasonable assumption).

A sketch:

fail = ${@:%.pass=%.fail}

test-passes := $(addsuffix .pass,${tests})
${test-passes}: test-%.pass: test-%
      rm -f ${fail}
      touch $@
      $* || mv $@ ${fail}

.PHONY: all
all: ${test-passes}
all:
# Count the .pass files, and the .fail files
      echo '$(words $(wildcard *.pass)) passes'
      echo '$(words $(wildcard *.fail)) failures'

In more detail:

  • test-passes := $(addsuffix .pass,${tests})
    If ${tests} contains test-1 test-2 (say), then ${test-passes} will be test-1.pass test-2.pass
  • ${test-passes}: test-%.pass: test-%
    You've just gotta love static pattern rules.
    • This says that the file test-1.pass depends on the file test-1. Similarly for test-2.pass.
  • If test-1.pass does not exist, or is older than the executable test-1, then make will run the recipe.
    • rm -f ${fail}
      ${fail} expands to the target with pass replaced by fail, or test-1.fail in this case. The -f ensures the rm returns no error in the case that the file does not exist.
    • touch $@ — create the .pass file
    • $< || mv $@ ${fail}
      Here we run the executable
      • If it returns success, our work is finished
      • If it fails, the output file is deleted, and test-1.fail is put in its place
      • Either way, make sees no error
  • .PHONY: all — The all target is symbolic and is not a file
  • all: ${test-passes}
    Before we run the recipe for all, we build and run all the tests
    • echo '$(words $(wildcard *.pass)) passes'
      Before passing the text to the shell, make expands $(wildcard) into a list of pass files, and then counts the files with $(words). The shell gets the command echo 4 passes (say)

You run this with

$ make -j9 all

Make will keep 9 jobs running at once — lovely if you have 8 CPUs.

Upvotes: 0

user657267
user657267

Reputation: 21000

Make will only return one of the following according to the source

#define MAKE_SUCCESS 0
#define MAKE_TROUBLE 1
#define MAKE_FAILURE 2

MAKE_SUCCESS and MAKE_FAILURE should be self-explanatory; MAKE_TROUBLE is only returned when running make with the -q option.

That's pretty much all you get from make, there doesn't seem to be any way to set the return code.

Upvotes: 1

Related Questions