如何获取Makefile的当前相对目录?

bol*_*ing 183 makefile working-directory gnu-make

我在app特定目录中有几个Makefile,如下所示:

/project1/apps/app_typeA/Makefile
/project1/apps/app_typeB/Makefile
/project1/apps/app_typeC/Makefile
Run Code Online (Sandbox Code Playgroud)

每个Makefile在此路径中包含一个.inc文件:

/project1/apps/app_rules.inc
Run Code Online (Sandbox Code Playgroud)

在app_rules.inc里面我正在设置我希望在构建时放置二进制文件的目的地.我希望所有二进制文件都在各自的app_type路径中:

/project1/bin/app_typeA/
Run Code Online (Sandbox Code Playgroud)

我尝试过使用$(CURDIR),像这样:

OUTPUT_PATH = /project1/bin/$(CURDIR)
Run Code Online (Sandbox Code Playgroud)

但相反,我把二进制文件埋在整个路径名中,如下所示:( 注意冗余)

/project1/bin/projects/users/bob/project1/apps/app_typeA
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能获得执行的"当前目录",这样我才能知道app_typeX为了将二进制文件放在各自的类型文件夹中?

Nik*_*pov 240

shell函数.

你可以使用shell功能:current_dir = $(shell pwd).或者shell结合使用notdir,如果你不需要绝对路径: current_dir = $(notdir $(shell pwd)).

更新.

给定解决方案仅在make从Makefile的当前目录运行时才有效.
正如@Flimm所说:

请注意,这将返回当前工作目录,而不是Makefile的父目录.
例如,如果你运行cd /; make -f /home/username/project/Makefile,current_dir变量将是/,而不是/home/username/project/.

以下代码适用于从任何目录调用的Makefile:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
Run Code Online (Sandbox Code Playgroud)

  • 我知道这是一个老问题,但我刚刚碰到并认为这可能有用.当makefile的相对路径中有空格时,这也不起作用.具体来说,路径"Sub Directory/Makefile"`的makefile的`$(lastword"$(MAKEFILE_LIST)")`会给你``Directory/Makefile``.我不认为有任何解决方法,因为带有两个makefile的`$(MAKEFILE_LIST)`给你一个字符串`"Makefile One Makefile Two`,它不能处理空格 (9认同)
  • 它需要立即扩展值,因此应使用:=运算符.与mkfile_path:=和current_dir =一样(否则,在包含其他Makefile之后MAKEFILE_LIST发生更改时,可以稍后评估右侧值 (6认同)
  • 这不起作用.这是同样的问题.pwd打印完整的路径名,我只想要我所在的实际当前文件夹的名称. (5认同)
  • “解决方案仅在您从 Makefile 的当前目录运行 make 时才有效”是一种温和的说法,表示“实际上不起作用”。我会将最新的文章放在答案的顶部。 (5认同)
  • 那`current_dir`对我不起作用。$(PWD)确实如此,它要简单得多。 (2认同)

sle*_*cal 123

这里开始 ;

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
Run Code Online (Sandbox Code Playgroud)

显示为;

$ cd /home/user/

$ make -f test/Makefile 
/home/user/test

$ cd test; make Makefile 
/home/user/test
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助

  • 要引用*current*makefile,必须在任何`include`操作之前使用`$ MAKEFILE_LIST`([docs](https://www.gnu.org/software/make/manual/html_node/Special-Variables.html #索引makefiles_002c和 - MAKEFILE_005fLIST变量)). (8认同)
  • 这几乎对我有用,但DIR有一个领先的空白,所以一个小小的改动使得工作完美:`DIR:= $(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))) (6认同)
  • 因为减少了外部工具的依赖性.即如果在某些系统中会出现dirname命令的别名怎么办? (3认同)
  • 恕我直言,最好使用内部make-function`dir`而不是`shell dirname`,尽管它获得带有尾随`/`字符的路径名. (2认同)
  • 应该使用引号 - 至少在`dirname`的参数周围 - 以防路径中有空格. (2认同)

Tzu*_*ong 41

如果您使用的是GNU make,$(CURDIR)实际上是一个内置变量.它是Makefile驻留 当前工作目录位置,可能是Makefile所在位置,但并非总是如此.

OUTPUT_PATH = /project1/bin/$(notdir $(CURDIR))
Run Code Online (Sandbox Code Playgroud)

请参阅http://www.gnu.org/software/make/manual/make.html中的附录A快速参考

  • 从GNU Make手册(第51页):"当GNU make启动时(在处理了任何-C选项之后),它将变量CURDIR设置为当前工作目录的路径名." 不是Makefile所在位置 - 尽管它们可能是相同的. (17认同)
  • @SimonPeverett:括号中的表达式表示"当前工作目录AFTER -C选择应用".即$(CURDIR)给出"make -C xxx"和"cd xxx; make"完全相同的结果.它还删除了尾随的`/`.我尝试用`gmake` v3.81绑.但如果`make`被称为`make -f xxx/Makefile`,那你就是对的. (5认同)
  • DownSoted,因为答案在技术上并不正确,正如Simon Peverett先前评论中指出的那样. (4认同)
  • `CURDIR` 对我有用,而 `PWD` 没有。我做了 `mkdir -pa/s/d` 然后在每个文件夹中有一个 makefile,它在 `+$(MAKE) <subdir>` 之前打印了 `PWD` 和 `CURDIR`。 (3认同)

小智 26

THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
Run Code Online (Sandbox Code Playgroud)

  • ......除非你在任何路径上都有空格. (12认同)
  • ...除非你在前一行中包含了一些其他的makefile (8认同)

Sta*_*dog 25

简单、正确、现代的方法:

对于 GNU make >= 3.81,于 2006 年推出

ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
Run Code Online (Sandbox Code Playgroud)
  1. MAKEFILE_LIST当包含文件进入和超出范围时进行更改。最后一项是当前文件。

  2. lastword选取最后一项(Makefile 名称,相对于pwd

  3. realpath内置于make,并解析为来自文件系统根的规范路径

  4. dir删除文件名,只留下目录。

注意:结果ROOT_DIR将包括尾随路径分隔符(例如,nix 上的“/”或 Windows 上的“\”)

  • 这是迄今为止我发现的最好的解决方案。如果您使用“include”并且需要每个 Makefile 中的相对路径,则应将此代码放置在每个 Makefile 的开头。是的,它不适用于空格,但使用“MAKEFILE_LIST”的答案都不适用于空格,只是因为“make”在“MAKEFILE_LIST”中使用空格作为分隔符,因此你永远不知道这个空格是分隔符还是部分分隔符文件路径或文件名。那样令我伤心( (2认同)

Jes*_*olm 6

我尝试了许多这些答案,但是在带有gnu make 3.80的AIX系统上,我需要做一些旧的事情。

原来是lastwordabspath并且realpath直到3.81才被添加。:(

mkfile_path := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
mkfile_dir:=$(shell cd $(shell dirname $(mkfile_path)); pwd)
current_dir:=$(notdir $(mkfile_dir))
Run Code Online (Sandbox Code Playgroud)

就像其他人所说的那样,它不是最优雅的,因为它两次调用了shell,并且仍然存在空格问题。

但是由于我的路径中没有空格,所以无论我如何开始,它都对我有用make

  • make -f ../wherever/makefile
  • make -C ../在任何地方
  • 使-C〜/ where
  • cd ../wherewhere; 使

所有给我wherevercurrent_dir和绝对路径wherevermkfile_dir


Bru*_*sky 5

我喜欢选择的答案,但我认为实际展示它比解释它会更有帮助。

/tmp/makefile_path_test.sh

#!/bin/bash -eu

# Create a testing dir
temp_dir=/tmp/makefile_path_test
proj_dir=$temp_dir/dir1/dir2/dir3
mkdir -p $proj_dir

# Create the Makefile in $proj_dir
# (Because of this, $proj_dir is what $(path) should evaluate to.)
cat > $proj_dir/Makefile <<'EOF'
path := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
cwd  := $(shell pwd)

all:
    @echo "MAKEFILE_LIST: $(MAKEFILE_LIST)"
    @echo "         path: $(path)"
    @echo "          cwd: $(cwd)"
    @echo ""
EOF

# See/debug each command
set -x

# Test using the Makefile in the current directory
cd $proj_dir
make

# Test passing a Makefile
cd $temp_dir
make -f $proj_dir/Makefile

# Cleanup
rm -rf $temp_dir
Run Code Online (Sandbox Code Playgroud)

输出:

+ cd /tmp/makefile_path_test/dir1/dir2/dir3
+ make
MAKEFILE_LIST:  Makefile
         path: /private/tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test/dir1/dir2/dir3

+ cd /tmp/makefile_path_test
+ make -f /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
MAKEFILE_LIST:  /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
         path: /tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test

+ rm -rf /tmp/makefile_path_test
Run Code Online (Sandbox Code Playgroud)

注意:该功能$(patsubst %/,%,[path/goes/here/])用于去除斜杠。