如何将 dir 添加到 Makefile 中的 $PATH 中?

发布于 2024-12-27 19:42:29 字数 491 浏览 0 评论 0原文

我想编写一个可以运行测试的 Makefile。测试位于目录“./tests”中,要测试的可执行文件位于目录“./bin”中。

当我运行测试时,他们看不到 exec 文件,因为目录 ./bin 不在 $PATH 中。

当我做这样的事情时:

EXPORT PATH=bin:$PATH
make test

一切正常。但是我需要更改 Makefile 中的 $PATH。

简单的 Makefile 内容:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

它正确打印路径,但找不到文件 x.

当我手动执行此操作时:

$ export PATH=bin:$PATH
$ x

一切正常。

如何更改 Makefile 中的 $PATH?

I want to write a Makefile which would run tests. Test are in a directory './tests' and executable files to be tested are in the directory './bin'.

When I run the tests, they don't see the exec files, as the directory ./bin is not in the $PATH.

When I do something like this:

EXPORT PATH=bin:$PATH
make test

everything works. However I need to change the $PATH in the Makefile.

Simple Makefile content:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

It prints the path correctly, however it doesn't find the file x.

When I do this manually:

$ export PATH=bin:$PATH
$ x

everything is OK then.

How could I change the $PATH in the Makefile?

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

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

发布评论

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

评论(6

疑心病 2025-01-03 19:42:29

您是否尝试过 Make 本身的 export 指令(假设你使用GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

另外,您的示例中存在一个错误:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

首先,被 echoed 的值是由 Make 而不是 shell 执行的 PATH 变量的扩展。如果它打印出预期值,那么我猜您已经在 Makefile 中或调用 Make 的 shell 中较早的位置设置了 PATH 变量。为了防止这种行为,您应该逃避美元:

test all:
    PATH=bin:$PATH
    @echo $PATH
    x

其次,无论如何这都行不通,因为 Make 在 单独的 shell。这可以通过在一行中编写配方来更改:

test all:
    export PATH=bin:$PATH; echo $PATH; x

Did you try export directive of Make itself (assuming that you use GNU Make)?

export PATH := bin:$(PATH)

test all:
    x

Also, there is a bug in you example:

test all:
    PATH=bin:${PATH}
    @echo $(PATH)
    x

First, the value being echoed is an expansion of PATH variable performed by Make, not the shell. If it prints the expected value then, I guess, you've set PATH variable somewhere earlier in your Makefile, or in a shell that invoked Make. To prevent such behavior you should escape dollars:

test all:
    PATH=bin:$PATH
    @echo $PATH
    x

Second, in any case this won't work because Make executes each line of the recipe in a separate shell. This can be changed by writing the recipe in a single line:

test all:
    export PATH=bin:$PATH; echo $PATH; x
凹づ凸ル 2025-01-03 19:42:29

根据设计 make 解析器在单独的 shell 调用中执行行,这就是为什么在一行中更改变量(例如 PATH),更改可能不会应用于下一行(请参阅此帖子)。

解决此问题的一种方法是将多个命令转换为一行(用 ; 分隔),或使用 One Shell 特殊目标(.ONESHELL,自 GNU Make 3.82 起)。

或者,您可以在调用 shell 时提供 PATH 变量。例如:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash

By design make parser executes lines in a separate shell invocations, that's why changing variable (e.g. PATH) in one line, the change may not be applied for the next lines (see this post).

One way to workaround this problem, is to convert multiple commands into a single line (separated by ;), or use One Shell special target (.ONESHELL, as of GNU Make 3.82).

Alternatively you can provide PATH variable at the time when shell is invoked. For example:

PATH  := $(PATH):$(PWD)/bin:/my/other/path
SHELL := env PATH=$(PATH) /bin/bash
随风而去 2025-01-03 19:42:29

如果您首先在 makefile 中设置 SHELL 变量,路径更改似乎是持久的:

SHELL := /bin/bash
PATH := bin:$(PATH)

test all:
    x

我不知道这是否是所需的行为。

Path changes appear to be persistent if you set the SHELL variable in your makefile first:

SHELL := /bin/bash
PATH := bin:$(PATH)

test all:
    x

I don't know if this is desired behavior or not.

懒猫 2025-01-03 19:42:29

我通常做的是显式提供可执行文件的路径:

EXE=./bin/
...
test all:
    $(EXE)x

如果我进行交叉编译,我还使用此技术在 QEMU 等模拟器下运行非本机二进制文件:

EXE = qemu-mips ./bin/

如果 make 使用 sh shell,则这应该可以工作:

test all:
    PATH=bin:$PATH x

What I usually do is supply the path to the executable explicitly:

EXE=./bin/
...
test all:
    $(EXE)x

I also use this technique to run non-native binaries under an emulator like QEMU if I'm cross compiling:

EXE = qemu-mips ./bin/

If make is using the sh shell, this should work:

test all:
    PATH=bin:$PATH x
心房的律动 2025-01-03 19:42:29

在许多版本的 Gnu Make 中,例如 Apple 在 macOS 上发布的 v3.81,对 Makefile 中的 PATH 变量的更改会影响 shell make 的启动,但不影响 make 本身。目前尚不清楚这是一个错误还是一个功能。

例如,使用此 Makefile:

SHELL := /bin/sh

TESTDIR = /tmp/testdir
export PATH := $(TESTDIR):$(PATH)

.PHONY: all prepare internal shell clean

all: prepare shell internal clean

prepare:
    @mkdir -p $(TESTDIR)
    @cp /bin/date $(TESTDIR)/mydate
    @chmod +x $(TESTDIR)/mydate

# This recipe forces `make` to invoke a shell by using command substitution
# or boolean operation
shell: prepare
    @echo "In target: shell"
    @printf "mydate is %s\n" "$(mydate -I -u)"
    @: && mydate -I -u
    @echo "End target: shell"

# This is invoked directly by `make` and does not pick up the change in PATH
internal: prepare
    @echo "In target: internal"
    mydate -I -u
    @echo "End target: internal"

clean:
    rm -rf $(TESTDIR)

您会发现 make shell 可以工作,但 make inside 却不能。

事实上,shell 是否启动之间的差异可能会导致一些非常令人困惑的行为,正如您现在所看到的。

$ make
In target: shell
mydate is 2024-02-02
2024-02-02
End target: shell
In target: internal
mydate -I -u
make: mydate: No such file or directory
make: *** [internal] Error 1

In many versions of Gnu Make, such as v3.81 which is shipped by Apple on macOS, changes to the PATH variable inside the Makefile affect the shells make launches, but do not affect make itself. It is not clear if this is a bug or a feature.

For example, with this Makefile:

SHELL := /bin/sh

TESTDIR = /tmp/testdir
export PATH := $(TESTDIR):$(PATH)

.PHONY: all prepare internal shell clean

all: prepare shell internal clean

prepare:
    @mkdir -p $(TESTDIR)
    @cp /bin/date $(TESTDIR)/mydate
    @chmod +x $(TESTDIR)/mydate

# This recipe forces `make` to invoke a shell by using command substitution
# or boolean operation
shell: prepare
    @echo "In target: shell"
    @printf "mydate is %s\n" "$(mydate -I -u)"
    @: && mydate -I -u
    @echo "End target: shell"

# This is invoked directly by `make` and does not pick up the change in PATH
internal: prepare
    @echo "In target: internal"
    mydate -I -u
    @echo "End target: internal"

clean:
    rm -rf $(TESTDIR)

You will find that make shell works, but make internal does not.

The fact that the difference is between whether a shell is launched or not can lead to some very confusing behavior, as you can now see.

$ make
In target: shell
mydate is 2024-02-02
2024-02-02
End target: shell
In target: internal
mydate -I -u
make: mydate: No such file or directory
make: *** [internal] Error 1
花海 2025-01-03 19:42:29

要仅在 Makefile 中设置 PATH 变量,请使用以下内容:

PATH := $(PATH):/my/dir

test:
@echo my new PATH = $(PATH)

To set the PATH variable, within the Makefile only, use something like:

PATH := $(PATH):/my/dir

test:
@echo my new PATH = $(PATH)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文