makefile中的变量解除引用

时间:2011-03-21 05:29:36

标签: shell makefile

给定一个路径列表,我想分离出makefile中列表中每个元素的目录部分和文件名部分。如下所示

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

但是变量解除引用存在问题。我得到输出为

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

而我希望它是

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

不知何故$(@ D)和$(@ F)没有给出列表中的第一个所有dir和fileName部分。 有人可以告诉你如何解决这个问题吗?

3 个答案:

答案 0 :(得分:4)

这是因为你混合了两个扩展阶段。在调用shell来执行规则之前,所有make变量和函数都会被扩展。因此$$elems变为$elems,然后此字符串将用作$(dir ...)$(notdir ...)函数的输入。此字符串不包含/,因此dir返回./notdir返回$elems。最后,在shell中执行以下命令。

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

William Pursell通过使用shell函数给出了可能的解决方法。另一种可能性是在执行规则之前执行扩展,如:

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)$(@F)没有提供所有dir和fileName部分,因为它们提供了当前规则调用目标的文件和目录。每个时刻只有一个目标。但是,您可以使用这些自动变量来执行您想要的操作,方法是让make执行循环,而不是shell,如下所示:

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

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

答案 1 :(得分:1)

我建议使用shell而不是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

当然,在这一点上,回声是多余的,你也可以这样做:

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

答案 2 :(得分:0)

我现在找到了另一种方法......

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

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

不知道我之前是怎么错过的。