开发者

Variable dereferncing in makefiles

Given a list of paths I want to separate out the directory part and the filename part of each of the element of the list inside a makefile. Something like following

MYLIST = \
      开发者_如何转开发  /home/folder1/folder2/fileName1 \
        /home/folder3/folder4/fileName2 \
        /home/folder5/folder6/fileName3 \
MYLIST:
    @for elems in $(MYLIST); \
    do \
        echo $(dir $$elems); \
        echo $(notdir $$elems); \
    done

But there is a problem with the variable dereferencing. I get the output as

 ./
 home/folder1/folder2/fileName1
 ./
 home/folder3/folder4/fileName2
 ./
 home/folder5/folder6/fileName3

whereas i want it to be

         /home/folder1/folder2/
         fileName1
         /home/folder3/folder4/
         fileName2
         /home/folder5/folder6/
         fileName3

Somehow $(@D) and $(@F) are not giving all the dir and fileName parts just the first one in the list. Can somebody please tell how to get about this problem ?


This occurs because you're mixing two stages of expansion. Before invoking the shell to execute the rule all make variables and functions are expanded. So $$elems becomes $elems and this string is then used as the input for the $(dir ...) and $(notdir ...) functions. This string doesn't contain a /, so dir returns ./, and notdir returns $elems. In the end, the following command is executed in the shell.

@for elems in /home/folder1/folder2/fileName1 /home/folder3/folder4/fileName2 /home/folder5/folder6/fileName3; \
do \
    echo ./; \
    echo $elems; \
done

William Pursell has given a possible workaround by using shell functions. Another possibility would be to perform the expansion before execution of the rule, like such:

MYLIST = \
        /home/folder1/folder2/fileName1 \
        /home/folder3/folder4/fileName2 \
        /home/folder5/folder6/fileName3 \

MYDIRS = $(dir $(MYLIST))
MYFILES = $(notdir $(MYLIST))

MYLIST:
        @for elems in $(MYDIRS) $(MYFILES); \
        do \
            echo $$elems; \
        done


$(@D) and $(@F) are not giving you all dir and fileName parts because they give the file and directory of the target of the current invokation of the rule. There is only one target at each moment. You may be able to use these automatic variables, however, to do what you want, by letting make do the looping, instead of the shell, like this:

MYLIST = \
        /home/folder1/folder2/fileName1 \
        /home/folder3/folder4/fileName2 \
        /home/folder5/folder6/fileName3 \

all: $(MYLIST)
$(MYLIST):
    @echo $(@D)
    @echo $(@F)


I would suggest using the shell instead of make:


MYLIST = \
        /home/folder1/folder2/fileName1 \
        /home/folder3/folder4/fileName2 \
        /home/folder5/folder6/fileName3
MYLIST:
    for elems in $(MYLIST); \
    do \
    echo $$(dirname $$elems); \
    echo $$(basename $$elems); \
    done

Of course, at this point, the echo is redundant, and you could just as well do:

for elems in $(MYLIST); \
    do \
    dirname $$elems; \
    basename $$elems; \
    done


I found another way to do that now...

MYLIST = \
    /home/folder1/folder2/fileName1 \
    /home/folder3/folder4/fileName2 \
    /home/folder5/folder6/fileName3

MYLIST:
    @$(foreach ELEMS,$(MYLIST), echo $(dir $(ELEMS)); echo $(notdir $(ELEMS));)

Don't know how i missed this before.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜