【问题标题】:Create folder for the parent name dynamically为父名称动态创建文件夹
【发布时间】:2018-09-06 07:15:44
【问题描述】:

我需要根据父目录创建目录

例如:

如果我有如下项目

project1
-File1
-Makefile

在make文件中我想做如下的事情

mkdir project1

然后它应该看起来像

project1
-File1
-Makefile
-project1

但我想动态地执行此操作,即mkdir parent folder,因为假设在 makefile 中我不知道父文件夹的名称是什么。是否可以?它应该是带有父文件夹名称的空文件夹。

作为先决条件,它应该始终有父文件夹

我尝试了以下建议:

更新

all: build

build:
    mkdir $(basename "$PWD")

这创建了以下内容:

project1
-File1
-Makefile
-WD

这样在root下创建了一个文件夹,可以,但是名字是WD,打错了,应该是project1

【问题讨论】:

  • mkdir $(basename "$PWD")?
  • 您要创建当前文件夹的父文件夹吗?但是它已经存在了,否则你不能在当前文件夹中......我不明白。
  • @RenaudPacalet - 我想用parent foldername 创建另一个空文件夹,但假设我没有名字,我只知道我需要上一层才能阅读名称,然后创建它
  • @Cyrus - 我现在试试,另外我应该如何将名称放入变量中?
  • @shopiaT:Cyrus 解决方案几乎是正确的,只需将$ 符号加倍("$$PWD")或使用"$(PWD)""$$(pwd)"。但它有两个缺点: 1. 它调用 shell,而在大多数情况下不需要这样做 2. 只有当您从 Makefile 所在的目录调用 make 时,它​​才有效。有关详细信息,请参阅我的答案。

标签: linux bash unix makefile gnu-make


【解决方案1】:

我假设:

  1. 您正在使用 GNU make。
  2. 您只有“合理”的文件和目录名称,没有空格、特殊字符甚至更糟。如果您将 makefile 命名为“my favorite make file”,则以下内容将不起作用。
  3. 您希望在包含 Makefile 的目录中创建子目录。

首先,您需要获取包含 Makefile 的目录的路径和基本名称。而这并不是那么简单。以下应该适用于所有情况,除非您将 Makefile 放在文件系统的根 / 或具有“unreasonable”文件和目录名称。将其放在 Makefile 的开头,任何 include 指令之前:

DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
BASE := $(notdir $(patsubst %/,%,$(DIR)))
DIRNAME := $(DIR)$(BASE)

抱歉,它看起来过于复杂,但所有部分都在这里是有充分理由的(请参阅最后的详细信息)。如果您真的希望它在所有情况下都有效,那么您需要它们。

接下来你需要创建没有错误的子目录,即使它已经存在:

$(DIRNAME):
    mkdir -p $@

$@,在配方中,扩展为目标,在本例中为$(DIRNAME);强烈建议尽可能使用这些自动变量。不要忘记-p 选项,否则如果子目录存在,配方将失败。

最后,你必须保证在你真正需要子目录之前执行了命令。例如,假设您有一个all 目标,但您希望在构建all 目标之前存在子目录。你可以写一个简单的依赖:

all: $(DIRNAME)
    <all-recipe>

$(DIRNAME):
    mkdir -p $@

但在这种情况下,每次修改子目录的内容,都会重新构建all目标,可能没用。这就是order-only prerequisites 有用的地方。它们必须存在,但制造商不考虑它们的最后修改日期。

总而言之,以下应该做你想要的:

DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
BASE := $(notdir $(patsubst %/,%,$(DIR)))
DIRNAME := $(DIR)$(BASE)

all: | $(DIRNAME)
    <all-recipe>

$(DIRNAME):
    mkdir -p $@

注意|,它介绍了仅限订购的先决条件。

关于构建要创建的子目录名称的说明:

  1. 您可以从不同的目录调用 make:

    make -C <path-to-project>
    make -f <path-to-project>/Makefile
    

    所以,$(shell basename "$$PWD") 或任何变体(例如$(notdir $(PWD)))只有在您从 Makefile 所在的目录调用 make 时才会起作用。即使从其他地方调用 make,获取 Makefile 绝对路径的正确方法是 $(abspath $(lastword $(MAKEFILE_LIST)))。请记住将其放在任何 include 指令之前。展开结果示例:/home/john/project1/Makefile.

  2. $(dir &lt;some-path&gt;) 只保留目录部分,删除文件部分。示例:/home/john/project1/

  3. $(patsubst %/,%,&lt;some-path&gt;) 删除结尾的 /(如果有)。示例:/home/john/project1

  4. $(notdir &lt;some-path&gt;) 删除直到并包括最后一个 / 的目录部分。示例:project1

因此,如果您的 Makefile 是 /home/john/project1/Makefile,并且即使您从 /home/john/project1 以外的任何地方调用 make 和 make -Cmake -fDIRBASEDIRNAME 变量也会扩展如:

DIR: /home/john/project1/
BASE: project1
DIRNAME: /home/john/project1/project1

【讨论】:

  • 非常感谢! DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) BASE := $(notdir $(patsubst %/,%,$(DIR))) DIRNAME := $(DIR)$(BASE) 比使用 PARENT_DIR=$(shell basename "$(PWD)") 更好,只是为了验证:)
  • 现在我读了第二遍 :) 似乎更好 :) 也适用于mac/linux/windows ?
  • 顺便说一句,MAKEFILE_LIST 是什么?
  • @shopiaT MAKEFILE_LIST 是按解析顺序进行解析的所有 Makefile 的列表。要获得完整的描述,请访问the GNU make manual
  • @shopiaT:对于 Linux,只要使用 GNU make 就没有问题。对于 Mac 也是如此,但您可能必须使用 Mac PortsHomebrew 安装 GNU make。抱歉,我无法测试,我目前没有 Mac。而对于 Windows,我很抱歉,我根本不使用它。但我很确定 GNU make 以一种或另一种方式移植到它上面(cygwin 或等效项?)。
猜你喜欢
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 2015-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多