Using conditional rules in a makefile
Asked Answered
E

3

24

I capture the intent of the Makefile in pseudo code, then indicate the issues I have. I'm looking for a Makefile which is more user friendly in a test environment. The correct usage of the Makefile is one of the below.

    make CATEGORY=parser TEST=basic.
    make ALL

If a user gives "JUST" the commands as indicated below, it should print a message saying "CATEGORY defined TEST undefined" and vice-versa

    make CATEGORY=parser
    make TEST=basic

I tried writing the Makefile in following ways, but it errors out:

    help:
        echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
        echo"       make ALL

    ifdef CATEGORY
        ifdef TEST
            CATEGORY_TEST_DEFINED = 1
        else
             echo "TEST not defined"
    else
        echo "CATEGORY not defined"
    endif



    ifeq ($(CATEGORY_TEST_DEFINED), 1)
    $(CATEGORY):
        cd $(PROJ)/$(CATEGORY)
        make -f test.mk $(TEST)
    endif

    ifdef ALL
    $(ALL):
         for i in `ls`
         cd $$(i)
         make all
    endif

The questions I have are:

  1. Whether the rules in a Makefile can be selective (using ifdef to select the rules and targets).

  2. echo doesn't work. echo should help the user with correct usage.

Externalism answered 10/1, 2012 at 22:33 Comment(1)
Following up on @Beta's point, you should look at the FAQ and especially the section How do I ask questions here?.Queenhood
A
29

The problem is that echo belongs to the shell; Make can pass it to the shell in a command, but Make cannot execute it. Use info instead:

ifdef CATEGORY
$(info CATEGORY defined)
else
$(info CATEGORY undefined)
endif

If you want the rules to be conditional:

ifdef CATEGORY
ifdef TEST
$(CATEGORY):
    whatever
else
$(info TEST not defined)
else
$(info CATEGORY not defined)
endif
Annecorinne answered 11/1, 2012 at 3:37 Comment(2)
Thanks for you input. If Make cannot execute shell command, then I have seen Makefiles having (indentation is difficult here) say for eg, hello: <next line with tab> @echo "Hello There". make hello outputs -> Hello ThereExternalism
@Mike: yes, in that case echo is in a command in the hello rule. When you "make hello", Make sends that command to the shell. If you want to do it that way, you must associate the "not defined" messages with some target, which seems untidy.Annecorinne
S
12

The biggest issue here is that all ifdef/ifndef/ifeq/... statements must be at column 0 or they it will results in an error. The echo is a minor issue compared with the indentation issue.

Selah answered 6/5, 2021 at 19:6 Comment(0)
Q
4

These lines are dubious:

help:
    echo"Usage: make CATEGORY=<advanced|basic> TEST=<test-case>
    echo"       make ALL

You need a space between echo and the string, and the string needs to be terminated:

help:
    echo "Usage: make CATEGORY=<advanced|basic> TEST=<test-case>"
    echo "       make ALL"

These lines are dubious:

ifdef CATEGORY
    ifdef TEST
        CATEGORY_TEST_DEFINED = 1
    else
         echo "TEST not defined"
else
    echo "CATEGORY not defined"
endif

Surely you need an endif before the second else? (Even if it is not syntactically mandatory, I'd recommend it.)

ifdef CATEGORY
    ifdef TEST
        CATEGORY_TEST_DEFINED = 1
    else
         echo "TEST not defined"
    endif
else
    echo "CATEGORY not defined"
endif

Additionally, make only executes commands such as echo is supposed to be when processing a target (rule). It won't execute echo there; it will simply object that you cannot define commands without them being actions for a target. Despite everything that GNU Make adds to a makefile, the language in a makefile is a declarative language and not a procedural language.


Another way of handling this is to define default values for the macros:

CATEGORY = advanced
TEST     = all

Define default values that do something semi-reasonable; let the user override the default if they want to. You can have a rule such as:

${CATEGORY}/${TEST}: ...dependencies...
    ...actions...

You can leave help as the first rule. I have some directories where the first rule is:

null:
    @echo "You must specify a target with this makefile!"

This is equivalent to what you have (except that make does not echo the command before running it, so I only see the message instead of the echo command line and the message; that's the @ at work). The makefile this comes from also has a rule all which is otherwise usually the most sensible first (default) rule.

Queenhood answered 11/1, 2012 at 4:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.