Search code examples
variablesmakefileevaluate

Variable in Makefile always evaluates to false


I am trying to execute a script when a file exist within a makefile. I tried the solution below as well as ifdef DRP_FILE and others, but the ifeq always evaluates to false (see output).

I feel like I am making a mistake with my spacing (tabs/spaces), executing the code as either make commands or shell commands - but I don't know where I am going wrong. And a search didn't reveal anything helpful.

# Makefile for testing
# Variables
BASE_DIR ?= $(shell pwd)/..
DRP_ROUTE_APP := app
BOARD:=sample
PLAT:=plat

# Targets
.PHONY: test
test: install-config
    @echo "Test passed!"

install-config:
ifneq ($(DRP_ROUTE_APP),)
    $(eval ROOTFS_OVERLAY:=/projects/$(PLAT)/$(BOARD)/rootfs_overlay)
    $(eval DRP_PATH:=$(shell find $(BASE_DIR)$(ROOTFS_OVERLAY)/etc/sfl/cfg/ -regextype posix-extended -regex '.*.txt'))
    $(eval DRP_FILE:=$(if $(DRP_PATH),$(shell basename $(realpath $(DRP_PATH)))))

    # Debug information
    @echo "DRP_PATH: $(DRP_PATH)"
    @echo "DRP_FILE: $(DRP_FILE)"

    ifeq ($(strip $(DRP_FILE)),)
        $(error "drp route file not found")
    else
        $(MAKE) run-drp-setup
    endif
endif

run-drp-setup:
    @echo "$(BASE_DIR)/./drp_setup.sh -f $(DRP_PATH) -s $(DRP_ROUTE_APP)"

Output make -f testmakefile test

testmakefile:22: *** "drp route file not found".  Stop.

Any pointers would be appreciated.


Solution

  • You can't mix and match "shell commands" and "make commands" like this. Make doesn't have a shell built in. It runs a shell as a separate process. And there's no way for the shell processing and the makefile processing to communicate back and forth as they run.

    The way make invokes a recipe is that FIRST, all the make constructs in the entire recipe are expanded. All make variables, all make functions, etc. are all expanded first. Then once that is done and all values are expanded, make will run a shell and give the resulting expanded output to the shell as a set of commands to run. Then make waits for the shell to exit and checks its exit code. If it's 0 then the command succeeded and make continues. If the exit code is not 0 then make considers that the recipe failed.

    So, you just can't combine things like $(eval ...), $(error ...), etc. inside recipes because those things are always expanded first.

    Similarly, all make constructs like ifeq etc. are preprocessor statements in makefiles. They are processed as the makefile is read in, before make decides which targets even need to be rebuilt much less tries to run recipes.

    So in short, if you have things you need to do that rely on shell commands that are run as part of your recipe you must write the entire thing in shell syntax. You cannot use make functions or variables set by eval etc. But here it doesn't seem like any of this is needed anyway, it just makes your makefile more complicated. Why don't you just use:

    # Makefile for testing
    # Variables
    BASE_DIR ?= $(shell pwd)/..
    DRP_ROUTE_APP := app
    BOARD := sample
    PLAT := plat
    
    ifneq ($(DRP_ROUTE_APP),)
      ROOTFS_OVERLAY := /projects/$(PLAT)/$(BOARD)/rootfs_overlay
      DRP_PATH := $(shell find $(BASE_DIR)$(ROOTFS_OVERLAY)/etc/sfl/cfg/ -regextype posix-extended -regex '.*.txt')
      DRP_FILE := $(if $(DRP_PATH),$(shell basename $(realpath $(DRP_PATH))))
    endif
    
    # Targets
    .PHONY: test
    test: install-config
            @echo "Test passed!"
    
    install-config:
    ifneq ($(DRP_ROUTE_APP),)
            @echo "DRP_PATH: $(DRP_PATH)"
            @echo "DRP_FILE: $(DRP_FILE)"
            if test -z '$(strip $(DRP_FILE))'; then \
                echo "drp route file not found"; exit 1; \
            else \
                $(MAKE) run-drp-setup; \
            fi
    endif
    
    run-drp-setup:
             @echo "$(BASE_DIR)/./drp_setup.sh -f $(DRP_PATH) -s $(DRP_ROUTE_APP)"