jww
jww

Reputation: 102296

info guarded by conditional in recipe?

We have a library project and its transitioning from unaligned data access common in the old i386/i686/x86_64 to aligned data access. The impetus is GCC and vectorization, which is causing crashes at -O3 (GCC is even vectorizing string compares with SSE4 primitives).

If someone runs make and a particular define is not present, then we want to print a info message warning them. I'm having trouble crafting the recipe.

The following recipe produces an error when run (it uses TAB, and not spaces):

.PHONY check_defines
check_defines:
    CONFIG_ALIGNED := $(shell $(EGREP) -i -c "[[:space:]]*#[[:space:]]*define[[:space:]]*NO_UNALIGNED_DATA_ACCESS" config.h)
    CXX_ALIGNED := $(shell echo $(value CXXFLAGS) | $(EGREP) -i -c "-DNO_UNALIGNED_DATA_ACCESS")
    ifeq ($(CONFIG_ALIGNED)$(CXX_ALIGNED),00)
        $(info Warning: NO_UNALIGNED_DATA_ACCESS is not defined)
    endif

The error is:

$ make check_defines
GNUmakefile:383: *** missing separator.  Stop.

Line 383 is the CONFIG_ALIGNED := .... The manual on 5.1 Recipe Syntax is not really helpful to me.

How do I craft the rule to perform the test within a recipe?

Upvotes: 0

Views: 879

Answers (2)

Johan Boulé
Johan Boulé

Reputation: 2090

In the recipee, you need to put make's parser out of shell mode with any $(...) expression.

.PHONY: check_defines
check_defines:
    $(eval CONFIG_ALIGNED := $(shell echo 0))
    $(eval CXX_ALIGNED := $(shell echo 0))
    $(if $(filter 00,$(CONFIG_ALIGNED)$(CXX_ALIGNED)), \
        $(warning Warning: NO_UNALIGNED_DATA_ACCESS is not defined) \
    )

Note that the variables declared are not local to the rule, so you might as well not declare them and put the shell expressions directly in the if expression.

Upvotes: 3

Jonathan Wakely
Jonathan Wakely

Reputation: 171333

Makefiles are not parsed like a script and executed imperatively. A recipe is not a sub-routine.

The page you linked to explicitly tells you that the body of the recipe is treated as shell commands, not make declarations/expressions:

  • A variable definition in a “rule context” which is indented by a tab as the first character on the line, will be considered part of a recipe, not a make variable definition, and passed to the shell.
  • A conditional expression (ifdef, ifeq, etc. see Syntax of Conditionals) in a “rule context” which is indented by a tab as the first character on the line, will be considered part of a recipe and be passed to the shell.

So you can't declare make variables or use make conditionals. You can only use shell commands.

Try something like:

CONFIG_ALIGNED := $(shell $(EGREP) -i -c "[[:space:]]*#[[:space:]]*define[[:space:]]*NO_UNALIGNED_DATA_ACCESS" config.h)
CXX_ALIGNED := $(shell echo $(value CXXFLAGS) | $(EGREP) -i -c "-DNO_UNALIGNED_DATA_ACCESS")
ifeq ($(CONFIG_ALIGNED)$(CXX_ALIGNED),00)
CHECK_FAILED := 1
endif

.PHONY check_defines
check_defines:
        if [ $(CHECK_FAILED) = 1 ]; then echo Warning: NO_UNALIGNED_DATA_ACCESS is not defined; exit 1; fi

Or check the condition using the shell:

CONFIG_ALIGNED := $(shell $(EGREP) -i -c "[[:space:]]*#[[:space:]]*define[[:space:]]*NO_UNALIGNED_DATA_ACCESS" config.h)
CXX_ALIGNED := $(shell echo $(value CXXFLAGS) | $(EGREP) -i -c "-DNO_UNALIGNED_DATA_ACCESS")

.PHONY check_defines
check_defines:
        if [ $(CONFIG_ALIGNED)$(CXX_ALIGNED) = 00 ]; then echo Warning: NO_UNALIGNED_DATA_ACCESS is not defined; exit 1; fi

Or do it all with the shell, declaring shell variables instead of make variables:

.PHONY check_defines
check_defines:
        config_aligned=`$(EGREP) -i -c "[[:space:]]*#[[:space:]]*define[[:space:]]*NO_UNALIGNED_DATA_ACCESS" config.h`
        cxx_aligned=`echo $(value CXXFLAGS) | $(EGREP) -i -c "-DNO_UNALIGNED_DATA_ACCESS")`
        if [ $${config_aligned}$${cxx_aligned} = 00 ]; then echo Warning: NO_UNALIGNED_DATA_ACCESS is not defined; exit 1; fi

(This version might not work if CXXFLAGS contains any shell-outs such as `pkg-config --cflags foo` as that would confuse the shell)

Upvotes: 2

Related Questions