目录的可移植 makefile 创建

发布于 2024-09-08 18:15:18 字数 1124 浏览 2 评论 0原文

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

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

然而,尝试获取它以便创建所需的 obj 和 bin 目录(如果它们不存在)会导致跨平台工作变得很尴尬 - 具体来说,我只是使用 Windows 7 和 Windows 进行测试。 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 创建目录并提供尽可能多的可移植性?

I'm looking to save myself some effort further down the line by making a fairly generic makefile that will put together relatively simple C++ projects for me with minimal modifications required to the makefile.

So far I've got it so it will use all .cpp files in the same directory and specified child directories, place all these within a matching structure in a obj subdir and place the resulting file in another subdir called bin. Pretty much what I want.

However, trying to get it so that the required obj and bin directories is created if they don't exist is providing awkward to get working cross-platform - specifically, I'm just testing with Windows 7 & Ubuntu (can't remember version), and I can't get it to work on both at the same time.

Windows misreads mkdir -p dir and creates a -p directory and obviously the two platforms use \ and / respectively for the path separator - and I get errors when using the wrong one.

Here is a few selected portions of the makefile that are relevant:

# 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 $@

This has been put together by me over the last week or so from things I've been reading (mostly on Stack Overflow), so if it happens to be I'm following some horrible bad practice or anything of that nature please let me know.

Question in a nutshell:

Is there a simple way to get this directory creation to work from a single makefile in a way that provides as much portability as possible?

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

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

发布评论

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

评论(3

无风消散 2024-09-15 18:15:18

我不知道自动配置。我的每一次经历都是乏味的。 zwol 的解决方案的问题是在 Windows 上 mkdir 返回一个错误,与 Linux 上的 mkdir -p 不同。这可能会破坏你的 make 规则。解决方法是忽略命令前带有 - 标志的错误,如下所示:

-mkdir dir

这样做的问题是 make 仍然会向用户抛出丑陋的警告。解决方法是在 mkdir 失败后运行“always true”命令,如所述 此处,如下所示:

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. 操作系统检测 makefile

I don't know autoconf. Every experience I've had with it has been tedious. The problem with zwol's solution is that on Windows mkdir returns an error, unlike mkdir -p on Linux. This could break your make rule. The workaround is to ignore the error with - flag before the command, like this:

-mkdir dir

The problem with this is that make still throws an ugly warning for the user. The workaround for this is to run an "always true" command after the mkdir fails as described here, like this:

mkdir dir || true

The problem with this is that Windows and Linux have different syntax for true.

Anyway, I spent too much time on this. I wanted a make file that worked in both POSIX-like and Windows environments. In the end I came up with the following:

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

The functions/variables are used like so:

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

Rationale for the definitions:

  • mkdir: Fix up the path and ignore any errors.
  • del: In Windows del doesn't delete any files if one of the files is specified to be in a directory that doesn't exist. For example, if you try to delete a set of files and dir/file.c is in the list, but dir doesn't exist, no files will be deleted. This implementation works around that issue by invoking del once for each file.
  • rmdir: Fix up the path and ignore any errors.
  • echo: The output's appearance is preserved and doesn't show the extraneous "" in Windows.

I spent a lot of time on this. Perhaps I would have been better off spending my time learning autoconf.

See also:

  1. OS detecting makefile
习惯成性 2024-09-15 18:15:18

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

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

在 Unix 上,您需要这样:

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

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

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

Windows mkdir always does what Unix mkdir does with the -p switch on. And you can deal with the backslash problem with $(subst). So, on Windows, you want this:

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

and on Unix you want this:

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

Choosing between these is not practical to do within a makefile. This is what Autoconf is for.

As a side note, never, ever use the @command feature in your makefiles. There will come a day when you need to debug your build process on a machine you do not have direct access to, and on that day, you will regret it.

情丝乱 2024-09-15 18:15:18

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

I solved the portability problem by creating a Python script called mkdir.py and calling it from the Makefile. A limitation is that Python must be installed, but this is most likely true for any version of 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文