如何多次调用Makefile recipe/rule?

How to call Makefile recipe/rule multiple times?

用下面的例子:

.PHONY: hook1 hook2

# Default target
all: hook1 hook2 hook1
    echo "Calling all"

hook1:
    echo "Calling hook1"

hook2:
    echo "Calling hook2"

我得到了输出:

$ make
echo "Calling hook1"
Calling hook1
echo "Calling hook2"
Calling hook2
echo "Calling all"
Calling all

但我希望它调用规则 hook1 两次。这是因为在 Latex 上,我需要使用相同的命令行多次调用相同的程序。然后我想重用 make 规则。例如,我希望上面的最小代码是 运行 as:

$ make
echo "Calling hook1"
Calling hook1
echo "Calling hook2"
Calling hook2
echo "Calling hook1"
Calling hook1
echo "Calling all"
Calling all

两次调用相同的规则。这是我完整的主要 Makefile 代码下面的代码,如果有人感兴趣的话。我试图创建虚拟规则 pdflatex_hook1pdflatex_hook2 以便我可以执行调用层次结构 pdflatex_hook biber_hook pdflatex_hook,但这并没有愚弄 make 并且它仍然忽略了我最后一次调用 pdflatex_hook2:

#!/usr/bin/make -f
# 
ECHOCMD:=/bin/echo -e

# The main latex file
THESIS_MAIN_FILE = modelomain.tex

# This will be the pdf generated
THESIS_OUTPUT_NAME = thesis

# This is the folder where the temporary files are going to be
CACHE_FOLDER = setup/cache

# Find all files ending with `main.tex`
LATEX_SOURCE_FILES := $(wildcard *main.tex)

# Create a new variable within all `LATEX_SOURCE_FILES` file names ending with `.pdf`
LATEX_PDF_FILES := $(LATEX_SOURCE_FILES:.tex=.pdf)


# GNU Make silent by default
# 
MAKEFLAGS += --silent
.PHONY: clean pdflatex_hook1 pdflatex_hook2 %.pdf %.tex

# How do I write the 'cd' command in a makefile?
# 
.ONESHELL:

# Default target
all: biber


##
## Usage:
##   make <target>
##
## Targets:
##   biber             build the main file with bibliography pass
##   pdflatex          build the main file with no bibliography pass
##

# Print the usage instructions
# https://gist.github.com/prwhite/8168133
help:
    @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\$$//' | sed -e 's/##//'


# Where to find official (!) and extended documentation for tex/latex's commandline options (especially -interaction modes)?
# https://tex.stackexchange.com/questions/91592/where-to-find-official-and-extended-documentation-for-tex-latexs-commandlin
PDF_LATEX_COMMAND = pdflatex --time-statistics --synctex=1 -halt-on-error -file-line-error
LATEX = $(PDF_LATEX_COMMAND)\
--interaction=batchmode\
-jobname="$(THESIS_OUTPUT_NAME)"\
-output-directory="$(CACHE_FOLDER)"\
-aux-directory="$(CACHE_FOLDER)"


# Run pdflatex, biber, pdflatex
biber: biber_hook pdflatex_hook2

    # Calculate the elapsed seconds and print them to the screen
    . ./setup/scripts/timer_calculator.sh
    showTheElapsedSeconds "$(current_dir)"

# Internally called rule which does not attempt to show the elapsed time
biber_hook: pdflatex_hook1

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    biber "$(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME)"


# This rule will be called for every latex file and pdf associated
pdflatex: $(LATEX_PDF_FILES)

    # Calculate the elapsed seconds and print them to the screen
    . ./setup/scripts/timer_calculator.sh
    showTheElapsedSeconds "$(current_dir)"

# Not show the elapsed time when called internally
pdflatex_hook1: $(LATEX_PDF_FILES)
pdflatex_hook2: $(LATEX_PDF_FILES)


%.pdf: %.tex

    # Start counting the compilation time and import its shell functions
    . ./setup/scripts/timer_calculator.sh

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    @$(LATEX) $<
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf

这里,当我调用规则 make biber 时,我得到了输出:

$ make biber
This is pdfTeX, Version 3.14159265-2.6-1.40.18 (MiKTeX 2.9.6400)
entering extended mode
gross execution time: 62751 ms

user mode: 58406 ms, kernel mode: 1359 ms, total: 59765
INFO - This is Biber 2.7
INFO - Logfile is 'setup/cache/thesis.blg'
INFO - Reading 'setup/cache/thesis.bcf'
INFO - Found 14 citekeys in bib section 0
INFO - Processing section 0
INFO - Looking for bibtex format file 'modeloreferences.bib' for section 0
INFO - Decoding LaTeX character macros into UTF-8
INFO - Found BibTeX data source 'modeloreferences.bib'
INFO - Overriding locale 'pt-BR' defaults 'normalization = NFD' with 'normalization = prenormalized'
INFO - Overriding locale 'pt-BR' defaults 'variable = shifted' with 'variable = non-ignorable'
INFO - Sorting list 'nty/global/' of type 'entry' with scheme 'nty' and locale 'pt-BR'
INFO - No sort tailoring available for locale 'pt-BR'
INFO - Writing 'setup/cache/thesis.bbl' with encoding 'UTF-8'
INFO - Output to setup/cache/thesis.bbl
Could not calculate the seconds to run

缺少对规则 pdflatex_hook2 的第二次调用,仅执行对 pdflatex_hook1 的第一次调用。`

我已经知道 latexmk 并使用它,但是对于上面的 biber 我想按原样进行这些调用。对于 latexmk 我使用这个 recipe/rule:

thesis: $(THESIS_MAIN_FILE)

    # Start counting the compilation time and import its shell functions
    . ./setup/scripts/timer_calculator.sh

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    # What is the difference between “-interaction=nonstopmode” and “-halt-on-error”?
    # https://tex.stackexchange.com/questions/258814/what-is-the-difference-between-interaction-nonstopmode-and-halt-on-error
    #
    # What reasons (if any) are there for compiling in interactive mode?
    # https://tex.stackexchange.com/questions/25267/what-reasons-if-any-are-there-for-compiling-in-interactive-mode
    latexmk \
    -pdf \
    -silent \
    -jobname="$(THESIS_OUTPUT_NAME)" \
    -output-directory="$(CACHE_FOLDER)" \
    -aux-directory="$(CACHE_FOLDER)" \
    -pdflatex="$(PDF_LATEX_COMMAND) --interaction=batchmode" \
    -use-make $(THESIS_MAIN_FILE)

    # Copy the generated PDF file from the cache folder
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf

    # Calculate the elapsed seconds and print them to the screen
    showTheElapsedSeconds "$(current_dir)"

相关问题:

  1. Change a make variable, and call another rule, from a recipe in same Makefile?
  2. How to manually call another target from a make target?
  3. multiple targets from one recipe and parallel execution

回答您最初的问题:

.PHONY: hook1 hook2

# Default target
all: hook1a hook2 hook1b
    echo "Calling all"

hook1a hook1b:
    echo "Calling hook1"

hook2:
    echo "Calling hook2"

产生以下输出:

echo "Calling hook1"
Calling hook1
echo "Calling hook2"
Calling hook2
echo "Calling hook1"
Calling hook1
echo "Calling all"
Calling all

如图make recipe execute twice

根据 @David White 的回答,我用双递归修复了我的主脚本:

#!/usr/bin/make -f
# 
ECHOCMD:=/bin/echo -e

# The main latex file
THESIS_MAIN_FILE = modelomain.tex

# This will be the pdf generated
THESIS_OUTPUT_NAME = thesis

# This is the folder where the temporary files are going to be
CACHE_FOLDER = setup/cache

# Find all files ending with `main.tex`
LATEX_SOURCE_FILES := $(wildcard *main.tex)

# Create a new variable within all `LATEX_SOURCE_FILES` file names ending with `.pdf`
LATEX_PDF_FILES := $(LATEX_SOURCE_FILES:.tex=.pdf)


# GNU Make silent by default
# 
MAKEFLAGS += --silent
.PHONY: clean biber pdflatex_hook1 pdflatex_hook2

# How do I write the 'cd' command in a makefile?
# 
.ONESHELL:

# Default target
all: thesis


##
## Usage:
##   make <target>
##
## Targets:
##   all        call the `thesis` make rule
##   biber      build the main file with bibliography pass
##   latex      build the main file with no bibliography pass
##   thesis     completely build the main file with minimum output logs
##   verbose    completely build the main file with maximum output logs
##

# Print the usage instructions
# https://gist.github.com/prwhite/8168133
help:
    @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\$$//' | sed -e 's/##//'


# Where to find official (!) and extended documentation for tex/latex's commandline options (especially -interaction modes)?
# https://tex.stackexchange.com/questions/91592/where-to-find-official-and-extended-documentation-for-tex-latexs-commandlin
PDF_LATEX_COMMAND = pdflatex --time-statistics --synctex=1 -halt-on-error -file-line-error
LATEX = $(PDF_LATEX_COMMAND)\
--interaction=batchmode\
-jobname="$(THESIS_OUTPUT_NAME)"\
-output-directory="$(CACHE_FOLDER)"\
-aux-directory="$(CACHE_FOLDER)"


# Run pdflatex, biber, pdflatex
biber: start_timer pdflatex_hook1 biber_hook pdflatex_hook2

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    # Copies the PDF to the current folder
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf

    # Calculate the elapsed seconds and print them to the screen
    . ./setup/scripts/timer_calculator.sh
    showTheElapsedSeconds "$(current_dir)"


start_timer:

    # Start counting the elapsed seconds to print them to the screen later
    . ./setup/scripts/timer_calculator.sh


# Internally called rule which does not attempt to show the elapsed time
biber_hook:

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    # Call biber to process the bibliography
    biber "$(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME)"


# How to call Makefile recipe/rule multiple times?
# 
pdflatex_hook1 pdflatex_hook2:

    @$(LATEX) $(LATEX_SOURCE_FILES)


# This rule will be called for every latex file and pdf associated
latex: $(LATEX_PDF_FILES)

    # Calculate the elapsed seconds and print them to the screen
    . ./setup/scripts/timer_calculator.sh
    showTheElapsedSeconds "$(current_dir)"


# Dynamically generated recipes for all PDF and latex files
%.pdf: %.tex

    # Start counting the compilation time and import its shell functions
    . ./setup/scripts/timer_calculator.sh

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    @$(LATEX) $<
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf


thesis: $(THESIS_MAIN_FILE)

    # Start counting the compilation time and import its shell functions
    . ./setup/scripts/timer_calculator.sh

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    # What is the difference between “-interaction=nonstopmode” and “-halt-on-error”?
    # https://tex.stackexchange.com/questions/258814/what-is-the-difference-between-interaction-nonstopmode-and-halt-on-error
    #
    # What reasons (if any) are there for compiling in interactive mode?
    # https://tex.stackexchange.com/questions/25267/what-reasons-if-any-are-there-for-compiling-in-interactive-mode
    latexmk \
    -pdf \
    -silent \
    -jobname="$(THESIS_OUTPUT_NAME)" \
    -output-directory="$(CACHE_FOLDER)" \
    -aux-directory="$(CACHE_FOLDER)" \
    -pdflatex="$(PDF_LATEX_COMMAND) --interaction=batchmode" \
    -use-make $(THESIS_MAIN_FILE)

    # Copy the generated PDF file from the cache folder
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf

    # Calculate the elapsed seconds and print them to the screen
    showTheElapsedSeconds "$(current_dir)"


verbose: $(THESIS_MAIN_FILE)

    # Start counting the compilation time and import its shell functions
    . ./setup/scripts/timer_calculator.sh

    # Creates the shell variable `current_dir` within the current folder path
    $(eval current_dir := $(shell pwd)) echo $(current_dir) > /dev/null

    # What is the difference between “-interaction=nonstopmode” and “-halt-on-error”?
    # https://tex.stackexchange.com/questions/258814/what-is-the-difference-between-interaction-nonstopmode-and-halt-on-error
    #
    # What reasons (if any) are there for compiling in interactive mode?
    # https://tex.stackexchange.com/questions/25267/what-reasons-if-any-are-there-for-compiling-in-interactive-mode
    latexmk \
    -pdf \
    -jobname="$(THESIS_OUTPUT_NAME)" \
    -output-directory="$(CACHE_FOLDER)" \
    -aux-directory="$(CACHE_FOLDER)" \
    -pdflatex="$(PDF_LATEX_COMMAND) --interaction=nonstopmode" \
    -use-make $(THESIS_MAIN_FILE)

    # Copy the generated PDF file from the cache folder
    cp $(CACHE_FOLDER)/$(THESIS_OUTPUT_NAME).pdf $(current_dir)/$(THESIS_OUTPUT_NAME).pdf

    # Calculate the elapsed seconds and print them to the screen
    showTheElapsedSeconds "$(current_dir)"


# Using Makefile to clean subdirectories
# 
#
# Exclude directory from find . command
# 
GARBAGE_TYPES := "*.gz(busy)" *.aux *.log *.pdf *.aux *.bbl *.log *.out *.toc *.dvi *.blg\
*.synctex.gz *.fdb_latexmk *.fls *.lot *.lol *.lof *.idx

DIRECTORIES_TO_CLEAN  := $(shell /bin/find -not -path "./**.git**" -not -path "./pictures**" -type d)
GARBAGE_TYPED_FOLDERS := $(foreach DIR, $(DIRECTORIES_TO_CLEAN), $(addprefix $(DIR)/,$(GARBAGE_TYPES)))

clean:
    rm -rfv $(GARBAGE_TYPED_FOLDERS)


# veryclean:
#   git clean -dxf