tvStatic
tvStatic

Reputation: 966

Make: is it possible to have "shortcut" targets to resume builds

Let's say I have an output file that is expensive to make. It also requires an environment setup process that is also expensive to run. The recipe to create the output also creates an intermediate file that is then used to create the output file.

output_file :
    expensive_env_setup ; \
    generate_file

Where generate_file also creates intermediate_file. Given the intermediate_file and the correct parameters, generate_file can resume generating the file, in the event that the second part of the generation failed.

What I am trying to do is allow resume building from the intermediate_file if the build process failed after generating intermediate_file. I don't want to split the build process into separate recipes since the environment setup is also expensive and this would make the build process longer for successful builds.

For example, I could do the following:

output_file : intermediate_file :
    expensive_env_setup ; \
    generate_file -resume intermediate_file

intermediate_file :
    expensive_env_setup ; \
    generate_file -intermediate intermediate_file

Where the intermediate_file recipe only generates that file, but this would mean that the environment setup process would need to be run twice.

Is there a way to signify that the output_file recipe may generate a particular intermediate file, and make will rebuild using intermediate_file recipe if the intermediate_file was generated but the output_file was not (ie the second part failed)?

Upvotes: 0

Views: 66

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 29250

Very old question but as I just solved a similar issue... Make conditionals are one of the solutions, we can use them to test the presence of the intermediate file:

ifeq ($(wildcard intermediate_file),intermediate_file)
GENERATEFLAGS := -resume
DEPS          := intermediate_file
else
GENERATEFLAGS := -intermediate
DEPS          :=
endif

output_file: $(DEPS)
    expensive_env_setup; \
    generate_file $(GENERATEFLAGS) intermediate_file

clean:
    rm -f output_file intermediate_file

Demonstration (with a modified Makefile to emulate the processing, print progress information and allow interrupting the long processing):

$ cat Makefile
ifeq ($(wildcard intermediate_file),intermediate_file)
GENERATEFLAGS := -resume
DEPS          := intermediate_file
else
GENERATEFLAGS := -intermediate
DEPS          :=
endif

output_file: $(DEPS)
    @printf 'expensive_env_setup\n'; \
    printf 'generate_file $(GENERATEFLAGS) intermediate_file\n'; \
    touch intermediate_file; \
    if [ -n "$(STOP)" ]; then printf 'Interrupted\n'; exit 0; fi; \
    touch intermediate_file; \
    touch output_file

clean:
    rm -f output_file intermediate_file
$ make
expensive_env_setup
generate_file -intermediate intermediate_file
$ ls
Makefile  intermediate_file  output_file
$ touch intermediate_file
$ make
expensive_env_setup
generate_file -resume intermediate_file
$ ls
Makefile  intermediate_file  output_file
$ make
make: 'output_file' is up to date.
$ make clean
rm -f output_file intermediate_file
$ make STOP=1
expensive_env_setup
generate_file -intermediate intermediate_file
Interrupted
$ ls
Makefile  intermediate_file
$ make
expensive_env_setup
generate_file -resume intermediate_file
$ ls
Makefile  intermediate_file  output_file
$ make
make: 'output_file' is up to date.

Note: the $(DEPS) variable guarantees that in case intermediate_file and output_file both exist but intermediate_file is newer, we update output_file with the -resume option.

Upvotes: 1

Related Questions