Makefile的顺序永远无法满足。

huangapple go评论57阅读模式
英文:

Makefile order is never satisfied

问题

I have the following project Structure:

| .
| ..
| 
| Makefile
| a
  | .
  | ..
  | Dockerfile
  \ Makefile
\ b
  | .
  | ..
  | Dockerfile
  \ Makefile

a/Makefile:

all:
    docker build -t a-image .

b/Makefile:

all:
    docker build -t b-image .

b/Dockerfile:

FROM a-image
...

Makefile:

all: a b

a:
    make -C a/ all

b: a
    make -C b/ all

For some reason, when I run make all in the root directory of the project, I never get a built and receive an error while building b as it depends on a:

...
pull access denied for a-image, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
...

What am I doing wrong?

英文:

I have the following project Structure:

| .
| ..
| 
| Makefile
| a
  | .
  | ..
  | Dockerfile
  \ Makefile
\ b
  | .
  | ..
  | Dockerfile
  \ Makefile

a/Makefile:

all:
<TAB>docker build -t a-image .

b/Makefile:

all:
<TAB>docker build -t b-image .

b/Dockerfile:

FROM a-image
...

Makefile:

all: a b

a:
<TAB>make -C a/ all

b: a
<TAB>make -C b/ all

For some reason, when I run make all in the root directory of the ptoject, I never get a built and receive an error while building b as it depends on a.

...
pull access denied for a-image, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
...

What am I doing wrong?

答案1

得分: 4

Make的主要操作方式是围绕着“文件”展开的。您的Makefile会告诉它,如果文件a不存在,那么创建它的规则在这里;如果b不存在,a必须存在(如果需要,可以构建它),并且在这里有创建它的规则。

然而,在您的示例中,ab都是已经存在于磁盘上的目录。Make能够查看磁盘并说“一个名为a的文件系统条目已经存在”,然后跳过相应的规则。

如果您正在使用GNU Make,并且只是想将Make用作脚本运行器而不是构建系统,您可以将目录规则声明为.PHONY。这将导致Make忽略文件已经存在的事实,并始终将这些规则视为过时。

# 在顶层Makefile中,不缩进的位置
.PHONY: a b

我建议更好的方法是接受Make的面向文件的模型。无论何时执行某个操作,请确保创建一个文件并使用touch(1)来更新其时间戳,以记录这一事实。例如,在a/Makefile中,您可以使用一个标志文件来记录镜像构建:

.PHONY: all
all: .docker-build

.docker-build: Dockerfile
        docker build -t a-image .
        touch "$@"

现在,在父级Makefile中,您知道make -C a将创建a/.docker-build,并且您可以将其用作依赖目标。

.PHONY: all
all: b/.docker-build

a/.docker-build:
        $(MAKE) -C a

b/.docker-build: a/.docker-build
        $(MAKE) -C b

如果删除.PHONY行,这将与任何Make实现一起工作。

英文:

Make's principal mode of operations is around files. Your Makefile says, if a file a doesn't exist, here are rules to create it; and if b doesn't exist, a must (build it if necessary), and here are rules to create it.

In your example, though, both a and b are directories that exist on disk. Make is able to look at the disk and say "a filesystem entry named a already exists" and skip the corresponding rules.

If you're using GNU Make and are just trying to use Make as a script runner rather than a build system, you can declare the directory rules as .PHONY. This will cause Make to ignore the fact that the files already exist, and always consider those rules out-of-date.

# in the top-level Makefile, anywhere, unindented
.PHONY: a b

I might suggest a better approach is to embrace Make's file-oriented model. Whenever you do something, make sure you create a file and update its timestamp with touch(1) to record that fact. In a/Makefile, for example, you could use a sentinel file to record the image build

.PHONY: all
all: .docker-build

.docker-build: Dockerfile
        docker build -t a-image .
        touch "$@"

Now in the parent Makefile, you know that make -C a will create a/.docker-build, and you can use that as the dependency target.

.PHONY: all
all: b/.docker-build

a/.docker-build:
        $(MAKE) -C a

b/.docker-build: a/.docker-build
        $(MAKE) -C b

If you delete the .PHONY lines this will work with any Make implementation.

huangapple
  • 本文由 发表于 2023年5月22日 21:18:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76306609.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定