便携式makefile创建目录

时间:2010-07-12 12:03:37

标签: cross-platform makefile portability

我希望通过制作一个相当通用的makefile来为自己节省一些精力,这个makefile将为我提供相对简单的C ++项目,只需对makefile进行最少的修改。

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

然而,尝试获取它以便在不存在时创建所需的obj和bin目录提供了跨平台工作的尴尬 - 具体来说,我只是使用Windows 7& amp; 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 $@

这是我在过去一周左右从我一直在阅读的内容(主要是Stack Overflow)上放到一起的,所以如果碰巧是我正在关注一些可怕的不良做法或任何性质的事情请让我知道。

问题简而言之:

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

3 个答案:

答案 0 :(得分:7)

我不知道autoconf。我所拥有的每一次经历都是乏味的。 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

答案 1 :(得分:6)

Windows mkdir始终执行Unix mkdir-p开启的操作。你可以用$(subst)处理反斜杠问题。所以,在Windows上,你想要这个:

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

在Unix上你想要这个:

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

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

作为旁注,永远不要在makefile中使用@command功能。有一天你需要在一台你无法直接访问的机器上调试你的构建过程,那一天你会后悔的。

答案 2 :(得分:0)

我通过创建一个名为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