【问题标题】:Portable makefile creation of directories可移植的makefile创建目录
【发布时间】:2011-03-14 18:52:48
【问题描述】:

我希望通过制作一个相当通用的 makefile 来为我节省一些精力,该文件将为我整理相对简单的 C++ 项目,只需对 makefile 进行最少的修改。

到目前为止,我已经得到它,因此它将使用同一目录和指定子目录中的所有 .cpp 文件,将所有这些文件放在 obj 子目录中的匹配结构中,并将生成的文件放在另一个名为的子目录中bin。差不多就是我想要的。

但是,尝试获取它以便创建所需的 obj 和 bin 目录(如果它们不存在)会为跨平台工作提供尴尬 - 具体来说,我只是在 Windows 7 和 Ubuntu 上进行测试(可以不记得版本),我不能让它同时在两者上工作。

Windows 误读了mkdir -p dir 并创建了一个-p 目录,显然这两个平台分别使用\/ 作为路径分隔符——使用错误的时候我会出错。

以下是 makefile 中一些相关的选定部分:

# Manually edited directories (in this example with forward slashes)
SRC_DIR = src src/subdir1 src/subdir2

# Automagic object directories + the "fixed" bin directory
OBJ_DIR = obj $(addprefix obj/,$(SRC_DIR))
BIN_DIR = bin

# Example build target
debug: checkdirs $(BIN)

# At actual directory creation
checkdirs: $(BIN_DIR) $(OBJ_DIR)
$(BIN_DIR):
    @mkdir $@

$(OBJ_DIR):
    @mkdir -p $@

这是我在过去一周左右从我一直在阅读的东西(主要是在 StackOverflow 上)整理出来的,所以如果碰巧我正在遵循一些可怕的不良做法或任何类似性质的东西,请告诉我。

简而言之:

是否有一种简单的方法可以通过单个 makefile 以提供尽可能多的可移植性的方式创建目录?

【问题讨论】:

  • “那些不懂 auto{make} 的人注定要重新发明它,很糟糕。”您可以使用一行 Makefile.am 来做到这一点。请注意,我实际上不建议您跳到 automake,但请注意,这些问题已经常得到解决。最终,您可能会转向已经为您解决这些问题的工具,而 automake 就是这样一种工具。
  • @William 很公平。这与任何事情一样都是一个学习练习(在此之前,我对 makefile 的理解非常少 - 之前几乎所有东西都是通过 IDE 的 make-it-work-for-you 魔法构建的)。听我说,我的目标是一些对于 makefile 来说太深的东西,所以当我有更多时间可用时,也许我会将 automake 添加到我的“要查看的东西”列表中。

标签: cross-platform makefile portability


【解决方案1】:

我不知道自动配置。我对它的每一次体验都很乏味。 zwol's solution 的问题在于,在 Windows 上 mkdir 返回错误,这与 Linux 上的 mkdir -p 不同。这可能会破坏您的制作规则。解决方法是忽略命令前带有- 标志的错误,如下所示:

-mkdir dir

问题在于make 仍然会向用户抛出一个丑陋的警告。解决方法是在mkdir 失败后运行“始终为真”命令,如here 所述,如下所示:

mkdir dir || true

问题在于 Windows 和 Linux 对于 true 的语法不同。

不管怎样,我在这上面花了太多时间。我想要一个在类 POSIX 和 Windows 环境中都可以工作的make 文件。最后我想出了以下几点:

ifeq ($(shell echo "check_quotes"),"check_quotes")
   WINDOWS := yes
else
   WINDOWS := no
endif

ifeq ($(WINDOWS),yes)
   mkdir = mkdir $(subst /,\,$(1)) > nul 2>&1 || (exit 0)
   rm = $(wordlist 2,65535,$(foreach FILE,$(subst /,\,$(1)),& del $(FILE) > nul 2>&1)) || (exit 0)
   rmdir = rmdir $(subst /,\,$(1)) > nul 2>&1 || (exit 0)
   echo = echo $(1)
else
   mkdir = mkdir -p $(1)
   rm = rm $(1) > /dev/null 2>&1 || true
   rmdir = rmdir $(1) > /dev/null 2>&1 || true
   echo = echo "$(1)"
endif

函数/变量的使用方式如下:

rule:
    $(call mkdir,dir)
    $(call echo,  CC      $@)
    $(call rm,file1 file2)
    $(call rmdir,dir1 dir2)

定义的理由:

  • mkdir:修正路径并忽略任何错误。
  • del:在 Windows 中,del 不会删除任何文件,如果指定文件之一位于不存在的目录中。例如,如果您尝试删除一组文件并且dir/file.c 在列表中,但dir 不存在,则不会删除任何文件。此实现通过为每个文件调用一次 del 来解决该问题。
  • rmdir:修正路径并忽略任何错误。
  • echo:输出的外观被保留,不会在 Windows 中显示无关的 ""

我花了很多时间在这上面。也许花时间学习 autoconf 会更好。

另见:

  1. OS detecting makefile

【讨论】:

  • 这正是我想要的。但是由于某种原因,MinGW 因“捕获到中断/异常(代码 = 0xc0000005)”而崩溃。调试了一阵子,发现跟结束符有关系,所以我把它放在一个$(shell)里面,一切正常。此外,在 Windows 上使用“如果不存在”有一个更简单的 mkdir 解决方案: mkdir = $(shell if not exist $(subst /,\,$(1)) mkdir $(subst /,\,$(1)) )
【解决方案2】:

Windows mkdir 总是做 Unix mkdir-p 开关打开时所做的事情。您可以使用 $(subst) 处理反斜杠问题。因此,在 Windows 上,您需要这样:

$(BIN_DIR) $(OBJ_DIR):
        mkdir $(subst /,\\,$@)

在 Unix 上你想要这个:

$(BIN_DIR) $(OBJ_DIR):
        mkdir -p -- $@

在 makefile 中选择这些是不切实际的。这就是 Autoconf 的用途。

附带说明,永远不要在您的 makefile 中使用 @command 功能。总有一天,您需要在无法直接访问的机器上调试构建过程,而那一天,您会后悔的。

【讨论】:

  • 好的,这很方便,在我继续学习任何基于自动的版本之前,我的目标是尽量减少版本之间所需的差异。但是,您是否介意简要解释一下@command 功能的作用?正如我在问题中所说,我已经从各种来源构建了 makefile,而以前的知识很少,所以一定是从 somewhere 中提取的,但现在不记得从哪里或相关性...跨度>
  • 如果你在任何 Makefile 命令前面加上@,Make 不会在执行命令之前将命令打印到终端。这似乎是一个很棒的功能——滚动的噪音更少,是的——直到你不得不只使用那个终端脚本来调试你的构建过程,然后你就陷入了一个痛苦的世界。
  • 关于最后一条语句:这种行为(回显或不回显命令)可以通过 make 命令行轻松驱动,方法是定义(或不​​定义)一个包含 @ 的变量,并编写每个前面有这个变量的命令。参见skramm.blogspot.fr/2013/04/writing-portable-makefiles.html,第 5 节
【解决方案3】:

我通过创建一个名为 mkdir.py 的 Python 脚本并从 Makefile 调用它来解决可移植性问题。一个限制是必须安装 Python,但这很可能适用于任何版本的 UNIX。

#!/usr/bin/env python

# Cross-platform mkdir command.

import os
import sys

if __name__=='__main__':
    if len(sys.argv) != 2:
        sys.exit('usage: mkdir.py <directory>')
    directory = sys.argv[1]
    try:
        os.makedirs(directory)
    except OSError:
        pass

【讨论】:

    猜你喜欢
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2017-10-29
    • 2014-03-19
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    相关资源
    最近更新 更多