Jim Moriarty
Jim Moriarty

Reputation: 301

execute shell commands inside a target in makefile

I'm new to makefile. I'm trying to perform some shell operation inside a makefile under a target. I made a new_target without modifying the working code. The code looks like this:

all: new_target existing_target
    

new_target:
    TEST_FILES:=$(wildcard $(HOME)/Test/*.cpp)
    for f in $(TEST_FILES); do \
        $(shell ls) $$f; \
    done

Error:

TEST_FILES:=/docker_home/myhome/Test/b.cpp /docker_home/myhome/Test/file.cpp /docker_home/myhome/Test/a.cpp
/bin/sh: 1: TEST_FILES:=/docker_home/myhome/Test/b.cpp: not found
Makefile:6: recipe for target 'new_target' failed
make: *** [new_target] Error 127

The idea is to perform a shell operation(similar to ls) on all the .cpp files in a particular directory

Upvotes: 2

Views: 6529

Answers (2)

Altaf
Altaf

Reputation: 3076

You need to run it in below way as TEST_FILES is a make variable and you should not mix make and shell:

TEST_FILES:=$(wildcard $(HOME)/Test/*.cpp)
new_target:
    for f in $(TEST_FILES); do \
        ls $$f; \
    done

Note :
When it is time to execute recipes to update a target by make , they are executed by invoking a new sub-shell for each line of the recipe, unless the .ONESHELL special target is in effect. So you dont require a $(shell) explicitly.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180508

This ...

TEST_FILES:=$(wildcard $(HOME)/Test/*.cpp)

... is (GNU) make syntax that assigns a value to a make variable. Your recipe instructs the shell to execute it as if it were a shell command. Obviously, that doesn't work.

Additionally, $(shell ls) doesn't do what you intend. It will run the ls command without arguments in make's working directory, at the time the makefile is parsed, and insert the results into the command to be run. If you want to run a shell command in your recipe then just put the command in the recipe.

The easiest solution would probably be to move that line outside the recipe (and dedent it):

TEST_FILES:=$(wildcard $(HOME)/Test/*.cpp)

new_target:
    for f in $(TEST_FILES); do \
        ls $$f; \
    done

Note that the $(wildcard) function will be evaluated and the results assigned to TEST_FILES at the time that the makefile is parsed, not when the new_target target is built, but that appears unlikely to be an issue in this case.

Of course, unless you need TEST_FILES for something else, too, a much cleaner way would be to merge it together and get rid of wildcard:

new_target:
    for f in $(HOME)/Test/*.cpp; do \
        ls $$f; \
    done

Or, best of all for this particular case:

new_target:
    ls $(HOME)/Test/*.cpp

Upvotes: 3

Related Questions