user3894299
user3894299

Reputation: 25

GNU make loop variable strange behavior

In my Makefile I am trying to copy a list of files from location1 to location2, then to location2 to location3. I got the following strange behavior:

    FILES_LIST=dir1/file1 dir2/file2 dir3/file3 ........

    mytarget:
        for file in $(FILES_LIST) ; do \
            #this works
            cp -vf location1/$$file location2/$(shell $$file##*/) ; \
            #this does not work
            cp -vf location2/$(shell $$(file)##*/) location3/ ; \
        done

I am using "$(shell $$(file)##/)" to strip out "dir1/" part of each item in FILES_LIST. The first cp works (from location1 to 2), however, the send does not, build log shows "$(shell $$(file)##/)" is evaluated to empty.

I am using GNU Make 3.81

Upvotes: 1

Views: 170

Answers (2)

Etan Reisner
Etan Reisner

Reputation: 80921

The problem is $$(file). That's not a variable evaluation. That's a Command Substitution. You meant $${file} (well not quite but we'll get to that).

There is also absolutely no reason to be using $(shell) here at all as you are already in a shell context when those lines run.

Not to mention that those $(shell) calls aren't doing anything even remotely like what you want (they aren't operating at the right time to do that).

You want this:

FILES_LIST=dir1/file1 dir2/file2 dir3/file3 ........

mytarget:
    for file in $(FILES_LIST) ; do \
        #this works
        cp -vf location1/$$file location2/$${file##*/} ; \
        #this does not work
        cp -vf location2/$${file)##*/} location3/ ; \
    done

Your $file variable is a shell variable not a make one. The call to $(shell) does not see it. You are effectively running $(shell $file##*/) which runs the $file##*/ command through the shell. That shell has no $file variable so that becomes ##*/ which is a comment and the whole thing returns nothing. (Actually I think the comment may be stripped first but that doesn't change anything.)

Upvotes: 3

Vivek
Vivek

Reputation: 330

Use $(notdir $file) command. notdir will strip out the directories and return the filename. For example, $(notdir dir1/file.h) will return file.h

Reference link for more detailed info: https://www.gnu.org/software/make/manual/html_node/File-Name-Functions.html

Upvotes: 0

Related Questions