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.
精彩评论