bashmakefile

Makefile how to generically chain on extra flags to target


So I have a test target in a Makefile. What I want to do is allow an argument to be passed which allows invokers to chain on extra flags.

For the sake of this example, I will use grep instead of what I actually have since I can give an example anyone with UNIX can run vs requiring a complex set up to test.

My goal was to have a make test that will be the default test command but allow a chain_in argument such as make test chain_on="-x" which will run the default test command but append -x flag to the end. I had this working somewhat with the following solution:

SHELL := /bin/bash

test: chain_on :=
test:
    echo bar | grep $$(if [ ! -z '${chain_on}' ]; then echo ' ${chain_on} '; fi)

Example usage make foo chain_on='bar'.

This works for simple flags like -x/--foobar or simple strings as above, but falls on its face when passing a flag with a quoted string argument.

For example make foo chain_on='-I "bar"' will run:

echo bar | grep $(if [ ! -z '-I "bar"' ]; then echo ' -I "bar" '; fi)

But that command results in an exit code 1...

echo bar | grep -I "bar" works fine though so something I have is messed up,.

I could run make foo chain_on='-I bar' but in my real use case I need the quotes because I have something like '-k "foo or bar"'.

Anyone know how to fix this or a round-about solution I can use to chain on extra arguments to a Makefile target?


EDIT: Actual example of what I have:

# SUPER - Run tests
# Arguments:
#   `chain_on=str` -> A string which will be appended to the end of the pytest command.
#       Ex: make test chain_on="-x"
tes%: chain_on :=
tes%:
    @poetry run python -m pytest \
        -o "testpaths=tests" \
        --cov=petlib \
        --cov-report term-missing:skip-covered \
        --cov-fail-under=100 \
        $$(if [ ! -z '${chain_on}' ]; then echo ' ${chain_on} '; fi)

WORKS: make test

WORKS: make test chain_on="-x"

WORKS: make test chain_on="-k foo"

DOESN'T WORK: make test chain_on='-k "dumper or loader"'


Solution

  • Adding an extra shell level should help here :

    SHELL := /bin/bash
    
    tes%: chain_on :=
    tes%:
        @bash -c "poetry run python -m pytest \
            -o 'testpaths=tests' \
            --cov=petlib \
            --cov-report term-missing:skip-covered \
            --cov-fail-under=100 \
            $$(if [ ! -z '${chain_on}' ]; then echo ' ${chain_on} '; fi)"
    

    Test with :

    make test chain_on='-k "dumper or loader"'