【问题标题】:Running "make" in subdirectory: "No rule to make target"在子目录中运行 \"make\":\"No rule to make target\"
【发布时间】:2022-08-18 16:28:50
【问题描述】:

我试图让 GNU Make 在子目录中运行一些规则。简而言之:我有一个包含多个 Python 源目录(AWS lambdas)的项目,每个目录都有一个 pyproject.toml 文件,并且依赖项安装由诗歌管理。对于每个子目录,我需要安装 pyproject.toml 中提到的包,它会创建一个poetry.lock 文件,然后使用该文件生成一个 requirements.txt 文件(该文件被部署到 AWS 并在那里使用)。

这是我到目前为止所得到的:

POETRY := $(shell command -v poetry 2> /dev/null)
PY_LAMBDAS := $(dir $(wildcard src/python/*/pyproject.toml))

.PHONY: $(PY_LAMBDAS)

install-py-lambdas : $(PY_LAMBDAS)

$(PY_LAMBDAS) :
     $(MAKE) -C $@ requirements.txt

requirements.txt : poetry.lock
     $(POETRY) export --without-hashes --format=requirements.txt > requirements.txt

# Ignore for now
# poetry.lock : pyproject.toml
#   $(POETRY) install

# pyproject.toml : | $(VENV)/bin/python
#   $(PY8) -m venv $(VENV)

如果 lambda 目录中有一个 requirements.txt 文件,它会显示 Nothing to be done for \'requirements.txt\',这似乎很好。如果没有requirements.txt 文件,则会出错:No rule to make target \'requirements.txt\'. Stop. 我现在正在测试,poetry.lock 文件已经存在于所有目录中。

我最好的猜测是,规则在子目录中运行的事实导致某种找不到目标和规则的失败,我不知道。我需要在子目录中运行规则,因为诗歌从当前目录读取其环境,并且没有任何类型的“目标目录”选项。

我希望这是我的一个相对简单的错误!我的基本问题的任何替代解决方案都将受到欢迎。

    标签: gnu-make


    【解决方案1】:

    这里的关键是拥有单独的顶级 Makefile 来处理递归和处理实际构建的子目录 Makefile。

    相关资源:

    您将在下面找到一个可以解决您的案例的简化示例。我不知道 Python,所以我用简单的命令替换了 Python 相关的命令,但这从 Make 的角度来看应该没有什么区别——这是一种常见的 Make 模式。

    目录结构:

    $ exa --tree --long --no-permissions --no-user --no-time
      - .
      - ├── dir1
    171 │  ├── Makefile
      0 │  └── pyproject.toml
      - ├── dir2
    171 │  ├── Makefile
      0 │  └── pyproject.toml
    187 └── Makefile
    

    处理递归的顶级 Makefile 和passes the common variables to the sub-make

    $ cat Makefile 
    export BUILD_COMMAND_1 = echo `date --iso-8601=seconds`
    export BUILD_COMMAND_2 = cat
    
    PROJECTS := $(wildcard dir?)
    
    .PHONY: all $(PROJECTS)
    
    all: $(PROJECTS)
    
    $(PROJECTS):
        $(MAKE) -C $@
    

    所有子目录都有相同的 Makefile(这里我们只显示 dir1/Makefile):

    $ cat dir1/Makefile
    requirements.txt: poetry.lock
        $(BUILD_COMMAND_2) $< > $@
    
    poetry.lock: pyproject.toml
        $(BUILD_COMMAND_1) > $@
    
    .PHONY: clean
    clean:
        rm -rf poetry.lock requirements.txt
    

    首次运行顶级 Makefile 时,所有目标都已构建:

    $ make
    make -C dir1
    make[1]: Entering directory '/tmp/t/dir1'
    echo `date --iso-8601=seconds` > poetry.lock
    cat poetry.lock > requirements.txt
    make[1]: Leaving directory '/tmp/t/dir1'
    make -C dir2
    make[1]: Entering directory '/tmp/t/dir2'
    echo `date --iso-8601=seconds` > poetry.lock
    cat poetry.lock > requirements.txt
    make[1]: Leaving directory '/tmp/t/dir2'
    

    当顶层 Makefile 第二次运行并且前置要求没有改变时,不需要构建任何东西:

    $ make
    make -C dir1
    make[1]: Entering directory '/tmp/t/dir1'
    make[1]: 'requirements.txt' is up to date.
    make[1]: Leaving directory '/tmp/t/dir1'
    make -C dir2
    make[1]: Entering directory '/tmp/t/dir2'
    make[1]: 'requirements.txt' is up to date.
    make[1]: Leaving directory '/tmp/t/dir2'
    

    【讨论】:

      猜你喜欢
      • 2021-01-01
      • 2019-09-15
      • 1970-01-01
      • 1970-01-01
      • 2011-05-10
      • 2021-11-22
      • 1970-01-01
      • 2016-11-19
      • 1970-01-01
      相关资源
      最近更新 更多