Makefile 通用GNU生成文件目录路径

Makefile 通用GNU生成文件目录路径,makefile,Makefile,我正试图通过使用一个通用的makefile来整合一些构建信息。我的问题是我想使用来自不同子目录级别的makefile,这使得工作目录值(pwd)不可预测。例如: # Makefile.common TOP := $(shell pwd) COMPONENT_DIR := $(TOP)/component COMPONENT_INC := $(COMPONENT_DIR)/include COMPONENT_LIB := $(COMPONENT_DIR)/libcomponent.a 如果我包含

我正试图通过使用一个通用的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
,如是,则
$(顶部)
目录不正确,其他所有内容如下:

# other_component/Makefile
include ../Makefile.common
# $(COMPONENT_LIB) is incorrectly other_component/component
获取
Makefile.common
的最佳方法是使用它自己的目录路径,而不是更易变的
pwd

您是否尝试过:

# 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了,所以这可能不起作用或者需要一些调整。

您应该能够使用,如下所示:

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

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


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

ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
如果未安装realpath:

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

编辑:请确保使用
:=
而不是
=
,因为后者会导致
make
使用后期绑定,并且
MAKEFILE\u列表可能由于以后的包含而发生更改。

common.mk
中编写常用内容。然后将common.mk放在默认目录中,在遇到include语句时进行查找。有关常见目录的信息,请参阅查找

您还可以将common.mk放在自定义目录中,然后键入
make-I customdir

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

include common.mk
仅此而已。无需担心路径和移动问题。

我的解决方案:

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

这也适用于调用
make-f/opt/some/dir/Makefile
,当您的in
/opt/other/path/subdir

同意时,这将起作用。我希望有一种方法可以做到这一点,它不需要在makefile部分进行准备(除了包含),但这肯定是一个很好的回退。这在我的dev box上运行得非常好,但我意识到目标机器运行的是Make3.79,Make3.80中添加了MAKEFILE_列表功能:MAKEFILE_列表似乎不包含完整路径,而只包含相对路径。这是事实,但如果它对任何人都有帮助的话:下面是一个片段,它将为您提供一个绝对路径,但不依赖于realpath(基于此答案和):
TOP:=$(dir$(CURDIR)/$(word$(words$(words$(MAKEFILE_列表))$(MAKEFILE_LIST))
Xavier,你应该把它作为一个答案,而不是一个评论。事实是好的(甚至是鼓励的),这是一个活生生的网站。这就是我给出绝对路径的好方法:
TOP:=$(abspath$(dir$(lastword$(MAKEFILE_LIST))
$(abspath…
是在GNU make 3.81中引入的(2006年4月1日)与
$(lastword…)同时发布
根据我的快速网络搜索。Xavier Holt的解决方案适用于GNU make的旧版本。我应该注意的是,这是建立在上面JesperE的示例表单上的。但是,它提供了一个在+1基础上构建的绝对路径。此解决方案是完美的,可移植的。我已经在Unix和Windows/Cygwin上成功地测试了它。另外请注意able/DIRECTIONAL。在我看来,
realpath
make
的一个内置函数——不是对已安装的二进制文件()的依赖。这里使用的是gnu make内置函数。另外,与
shell dirname
不同,可能更容易使用
dir
内置函数。这很有趣,但对于复杂的项目和部署来说太幼稚了。