首页 文章

便携式makefile创建目录

提问于
浏览
3

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

到目前为止,我已经得到它所以它将使用同一目录中的所有 .cpp 文件和指定的子目录,将所有这些放在 obj subdir中的匹配结构中,并将生成的文件放在另一个名为 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 $@

在过去一周左右我已经阅读了这些内容(主要是关于Stack Overflow),所以如果碰巧是我正在关注一些可怕的不良做法或任何这种性质,请告诉我 .

问题简而言之:

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

3 回答

  • 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 功能 . 有一天你需要在一台你无法直接访问的机器上调试你的构建过程,那一天你会后悔的 .

  • 0

    我不喜欢它已经很乏味了 . zwol's solution的问题是在Windows上mkdir返回错误,与Linux上的 mkdir -p 不同 . 这可能会打破你的制定规则 . 解决方法是在命令之前使用 - 标志忽略错误,如下所示:

    -mkdir dir
    

    这个问题是 make 仍然为用户抛出一个丑陋的警告 . 解决方法是在 mkdir 失败后运行"always true"命令,如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不存在't delete any files if one of the files is specified to be in a directory that doesn' . 例如,如果您尝试删除一组文件并且 dir/file.c 在列表中,但 dir 不存在,则不会删除任何文件 . 此实现通过为每个文件调用 del 一次来解决该问题 .

    • rmdir :修正路径并忽略任何错误 .

    • echo :输出's appearance is preserved and doesn' t在Windows中显示无关的 "" .

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

    也可以看看:

  • 6

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

相关问题