makefile 中的变量解引用

发布于 2024-10-24 20:07:40 字数 796 浏览 1 评论 0原文

给定一个路径列表,我想将 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 部分,而只是列表中的第一个。 有人可以告诉我如何解决这个问题吗?

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 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最冷一天 2024-10-31 20:07:40

发生这种情况是因为您混合了两个扩展阶段。在调用 shell 执行规则之前,所有 make 变量和函数都会展开。因此,$$elems 变为 $elems,然后该字符串用作 $(dir ...)的输入$(notdir ...) 函数。该字符串不包含 /,因此 dir 返回 ./notdir 返回 $元素。最后在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)

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)
面如桃花 2024-10-31 20:07:40

我建议使用 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

当然,此时 echo 是多余的,你也可以这样做:

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

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
蛮可爱 2024-10-31 20:07:40

我现在找到了另一种方法来做到这一点......

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

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

不知道我以前是如何错过这个的。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文