【问题标题】:Common GNU makefile directory path通用 GNU makefile 目录路径
【发布时间】:2010-09-24 06:56:21
【问题描述】:

我正在尝试通过使用一个通用的 makefile 来整合一些构建信息。我的问题是我想使用来自不同子目录级别的 makefile,这使得工作目录值 (pwd) 无法预测。例如:

# Makefile.common
TOP := $(shell pwd)
COMPONENT_DIR := $(TOP)/component
COMPONENT_INC := $(COMPONENT_DIR)/include
COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a

如果我从子目录中包含Makefile.common,就像这样,$(TOP) 目录不正确,其他所有内容都遵循:

# other_component/Makefile
include ../Makefile.common
# $(COMPONENT_LIB) is incorrectly other_component/component

Makefile.common 使用自己的 目录路径而不是更善变的pwd 的最佳方法是什么?

【问题讨论】:

    标签: makefile


    【解决方案1】:

    你有没有尝试过:

    # Makefile.common
    TOP ?= $(shell pwd)
    COMPONENT_DIR := $(TOP)/component
    COMPONENT_INC := $(COMPONENT_DIR)/include
    COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a
    
    # other_component/Makefile
    TOP ?= ..
    include ../Makefile.common
    

    如果 TOP 已经设置,使用 ?= 结构可以防止重新定义它。您可以在调用 make 时根据您在树中的位置将其设置为适当的值。我承认我使用 GNU make 已经有一段时间了,所以这可能无法正常工作或可能需要一些调整。

    【讨论】:

    • 同意,这样行。我希望有一种方法可以做到这一点,不需要对 makefile 进行准备(除了包含),但这肯定是一个很好的后备。
    【解决方案2】:

    你应该可以使用MAKEFILE_LIST variable,像这样:

    # This must be the first line in Makefile.common
    TOP := $(dir $(firstword $(MAKEFILE_LIST)))
    

    来自文档:

    当 make 读取各种 makefile 时,包括从 MAKEFILES 变量、命令行、默认文件或包含指令中获得的任何文件,它们的名称将自动附加到 MAKEFILE_LIST 变量中。它们是在 make 开始解析它们之前添加的。这意味着如果 makefile 做的第一件事是检查这个变量中的最后一个单词,它将是当前 makefile 的名称。但是,一旦当前的 makefile 使用了 include,最后一个单词将是刚刚包含的 makefile。

    【讨论】:

    • 这在我的开发机器上运行得非常好,但我意识到目标机器正在运行 make 3.79,并且在 make 3.80 中添加了 MAKEFILE_LIST 功能:mail-archive.com/help-make@gnu.org/msg05902.html
    • 似乎 MAKEFILE_LIST 不包含完整路径,只有相对路径。
    • 事后很多,但如果它对任何人有帮助:这是一个 sn-p,它会给你一个绝对路径,但不依赖于 realpath(基于这个答案和this blog post) :TOP := $(dir $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
    • Xavier,您应该将其发布为答案,而不是评论。在事实很好(甚至鼓励)之后,这是一个活的网站。
    • 这对我来说很有效,可以提供绝对路径:TOP := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))。根据我的快速网络搜索,$(abspath ...)$(lastword ...) 同时被引入 GNU make 3.81(2006 年 4 月 1 日)。 Xavier Holt 的解决方案适用于旧版本的 GNU make。
    【解决方案3】:

    这不是好的样式,因为它添加了另一个依赖项(即 realpath 二进制文件)。根据您的用例,这可能是可以接受的。

    ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
    

    如果您没有安装 realpath:

    $ sudo apt-get install realpath # on debian and derivatives
    

    编辑:请务必使用:= 而不是=,因为后者会导致make 使用后期绑定,而MAKEFILE_LIST 可能会因后期包含而发生更改。

    【讨论】:

    • 我应该注意到,这是建立在上面 JesperE 的示例表单之上的。但是,它提供了在其之上构建的绝对路径。
    • +1 此解决方案完美且便携。我已经在 UNIXes 和 Windows/Cygwin 上成功地测试了它。还要注意VPATH 变量/指令。
    • 在我看来 realpathmake 的内置函数——不依赖于已安装的二进制文件 (docs)。
    • realpath 这里使用的是一个 gnu make 内置函数。此外,使用内置的dir 可能更干净,而不是shell dirname
    【解决方案4】:

    把常用的东西写在common.mk。然后将 common.mk 放在 Make 在遇到 include 语句时查找的默认目录中。有关 Make 查找的常用目录,请参阅 the manual

    你也可以把common.mk放到自定义目录,然后输入make -I customdir

    在每个子文件夹的 Makefile 中,您可以这样做

    include common.mk
    

    就是这样。无需担心路径和移动的东西。

    【讨论】:

    • 有趣,但对于复杂的项目和部署来说太天真了。
    【解决方案5】:

    我的解决方案:

    cwd  :=  $(shell readlink -en $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))) 
    

    这也适用于 make -f /opt/some/dir/Makefile whenn your in /opt/other/path/subdir 之类的电话。

    【讨论】:

      猜你喜欢
      • 2017-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多