检测make命令目标是路径还是虚假

时间:2015-06-13 20:30:18

标签: makefile

背景

我正在Markdown写几本书。我的文件结构如下:

                                       Description
writing/
    Makefile                        1. main Makefile (shown below)
    book.template                   2. pandoc template that uses TITLE
    books/
        current.txt                 3. contains the current book name
        book1/
            meta.mk                 4. sub-Makefile that defines TITLE
            chapters/
                01.md               5. actual text of book 1, chapter 1
                02.md
                ...
        book2/
            meta.mk
            chapters/
                01.md
                02.md
                ...
        ...

这是Makefile:

CURR_BOOK_NAME:=$(shell cat books/current.txt)
CURR_BOOK_DIR:=books/$(CURR_BOOK_NAME)/
CURR_CHAPTERS_DIR:=$(CURR_BOOK_DIR)chapters/
CURR_CHAPTERS:=$(wildcard $(CURR_CHAPTERS_DIR)*.pdf)

# suppose that each meta.mk defines the TITLE variable
include $(CURR_BOOK_DIR)/meta.mk


all: pdfs
    ...

pdfs: $(CURR_CHAPTERS)

%.pdf: %.md book.template
    pandoc -o $@ $< ...           \
        --template=book.template  \
        --variable=title:$(TITLE)

我通常一次只能处理一本书。因此,使用当前书籍的名称创建文件current.txt很方便。现在我只需输入make即可将当前书籍编译为PDF,方法是在current.txt中读取Makefile。请注意,PDF取决于特定于书籍meta.mk中定义的变量。

问题

偶尔,我想对另一本书做一个小改动。我应该如何修改Makefile,以便我不必更新current.txt然后每次更改它?更确切地说,我想检测在命令行上传递给make的参数是伪目标还是路径。例如,我希望这个过程看起来像:

$ cat books/current.txt
book1
$ ls books/*/chapters/*
books/book1/chapters/01.md  books/book1/chapters/02.md
books/book2/chapters/01.md  books/book2/chapters/02.md

$ make
pandoc -o books/book1/chapters/01.pdf ... --variable=title:One
pandoc -o books/book1/chapters/02.pdf ... --variable=title:One
$ ls books/*/chapters/*
books/book1/chapters/01.md  books/book1/chapters/02.md
books/book1/chapters/01.pdf books/book1/chapters/02.pdf
books/book2/chapters/01.md  books/book2/chapters/02.md

$ make books/book2/chapters/01.pdf
pandoc -o books/book2/chapters/01.pdf ... --variable=title:Two
$ ls books/*/chapters/*
books/book1/chapters/01.md  books/book1/chapters/02.md
books/book1/chapters/01.pdf books/book1/chapters/02.pdf
books/book2/chapters/01.md  books/book2/chapters/02.md
books/book2/chapters/01.pdf     

可能的解决方案

建议在命令行上覆盖变量:

make CURR_BOOK_NAME=book2 books/book2/chapters/01.pdf

但是,我认为这太冗长和冗余,因为它需要重复两次书的名称,并输入一次内部变量CURR_BOOK_NAME的名称。

注意

这是一个简化的例子。请询问您是否要查看实际的Makefile。另外,请随意澄清问题标题。

2 个答案:

答案 0 :(得分:1)

之前发布了以下有​​价值的答案,但在评论中对优缺点进行了简短讨论之后,回答者将其删除并留下了一个downvote,而没有选择评论。我在这里reproduce以防万一它可以帮助其他用户。我仍然在寻找一种“更复杂”的解决方案,它可以避免冗余并允许构建单独的章节。

一个简单的解决方案是将您的Makefile复制到新文件,例如book.mak并删除第一行CURR_BOOK_NAME:=$(shell cat books/current.txt)。然后像这样创建新的Makefile:

CURR_BOOK_NAME:=$(shell cat books/current.txt)

current:
    $(MAKE) -f book.mak CURR_BOOK_NAME="$(CURR_BOOK_NAME)"

book1:
    $(MAKE) -f book.mak CURR_BOOK_NAME="book1"

book2:
    $(MAKE) -f book.mak CURR_BOOK_NAME="book2"

然后当book2当前更改book1中的内容时,只需键入make book1。 makefile将找出更改内容并更新它。

如果您真的希望能够输入make books/book2/chapters/01.pdf,那么它会更复杂一些。

答案 1 :(得分:1)

我会对其进行重组,以便从每个项目的顶级目录中引用顶级Makefile。将其视为每个图书项目的支持库并相应地进行管理。

单个Makefile可以像

一样简单
include /usr/local/share/lib/bookmaker/main.mk

...假设您调用库bookmaker并将其安装在此路径中。 (它也可以存在于主目录下的某个树中。)

我认为这是对事实上的项目结构的规范化,而不仅仅是一种新的安排。您的个人书籍已经依赖于博彩公司Makefile,但强制它们存在于物理子目录中,这使得在实验克隆上工作变得更加困难(假设您将每本书作为单独的Git项目进行管理 - 如果没有,切换到此模型可能会使更有意义!)。您还可以摆脱现在显然不再需要的“当前”状态文件的轻微但令人讨厌的不便。