null
null

Reputation: 1433

Order of "order-only" prerequisites not kept in a multithreaded makefile

Let's consider this makefile:

.PHONY: flash_bin
flash_bin: | build flash

CODE_CHANGED=0

.PHONY: build
build:
    @echo "Run Build Process"
    @if [ ! -f build_process ] || [ $(CODE_CHANGED) -eq 1 ]; then \
        touch build_process; \
    fi;


flash: tmp_config_file build_process
    @echo "Flash to ESP"
    @touch flash


tmp_config_file:
    @echo "Config flashed"
    @touch $@

At first glance, this piece of code may not make sense, but this is only a simplified version, which illustrates the following problem:

When runing make, the output is as expected. At first, the build rule is executed. It may rebuild some code, indicated through the file build_process. After that, the flash rule is triggered. The code is only flashed to some devices if a configuration file has been flashed earlier (indicated through tmp_config_file) or if it has been rebuilt earlier (indicated through build_process). As you can see, this makefile only works if the build rule is evaluated before flash, because flash depends on the result of build.

So far, so good. Now I run make -j8 and I get a make: *** No rule to make target 'build_process', needed by 'flash'. Stop. Apparently, the order of the order-only prerequisites is not kept anymore and make does not wait until build has finished.

Does this mean that order-only prerequisites only work in a single threaded makefile? If so, why? Is it possible to keep the order, but to execute the individual rules in a multithreaded fashion?

EDIT: I know, you can force the expected behavior this way:

.PHONY: flash_bin
flash_bin: 
  $(MAKE) build; \
  $(MAKE) flash

But still I am interested why order-only cannot be used reliably in a multithreaded makefile

Upvotes: 0

Views: 665

Answers (1)

raspy
raspy

Reputation: 4261

When you run make in parallel, it means that it can schedule many targets for execution at the same time. Since there is no dependency defined between targets build and flash, make assumes that they can both be run at the same time. It happens to work in single thread accidentally, since the Makefile creates a file which it does not declare, and flash depends on this accidentally created file.

It does not even require multithreading to make it fail, just run target flash without prior running build, e.g.:

$ make flash
Config flashed
make: *** No rule to make target 'build_process', needed by 'flash'.  Stop.

I believe you should either make flash depend on build, or rename target build to build_process.

Upvotes: 1

Related Questions