Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ensure a target is run before all the other build rules in a makefile?

Tags:

makefile

I have a C++ project which contains a generated file that all the other C++ files depend on. I'm trying to force that file to be generated and compiled before any other compilation begins. Usually it'd be as simple as putting that file first in the all: target, but the complication is that my Makefile is also generated by a build system, and I can only append fragments to the Makefile, not edit it in general.

So, is there a way to force that generated file target to run first, via dependencies or otherwise? I've thought of using something like this:

cpp_files := $(wildcard src/*.cpp)
$(cpp_files): generated_file.cpp
generated_file.cpp:
    # generate the file here

But it doesn't seem to work. For reference, my source dir structure is like this, so I need to collect the cpp files recursively:

src/
|---file1.cpp
|---file2.cpp
|---subdir1/
    |---file3.cpp

gen/
|---generated_file.cpp
like image 774
andrei Avatar asked May 23 '12 19:05

andrei


People also ask

What is $@ in makefile?

The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run.

What command is used to call the default target in a makefile?

You can manage the selection of the default goal from within your makefile using the . DEFAULT_GOAL variable (see Other Special Variables). You can also specify a different goal or goals with command line arguments to make . Use the name of the goal as an argument.

Does order in a makefile matter?

The order of rules is not significant, except for determining the default goal : the target for make to consider, if you do not otherwise specify one. The default goal is the target of the first rule in the first makefile. If the first rule has multiple targets, only the first target is taken as the default.


2 Answers

If you're sure that's really what you want, here's one way to do it: have a rule for a dummy file which the makefile will include.

.PHONY: dummy
dummy:
    # generate the file here

-include dummy

No matter what target you specify, Make will first run the dummy rule, then restart itself.

like image 113
Beta Avatar answered Sep 19 '22 14:09

Beta


Actually, other cpp files don't depend on the generated one (in terms of Make rules). Dependency graph still looks like:

program
 |
 ^- file1.o
 |   ^- file1.c
 |
 ^- file2.o
 |   ^- file2.c
 |
 ^- generated_file.o
     ^- generated_file.c
         ^- <generator prerequisites>

Your source files could only depend on some kind of generated header file (in case when it is #included by these sources).

If you need to generate only a cpp file then the following makefile should be sufficient:

srcs := $(wildcard src/*.cpp src/*/*.cpp)

gen_file := gen/generated_file.cpp
srcs += $(gen_file)

objs := $(srcs:.cpp=.o)

.PHONY : all
all : program

program : $(objs)
    @$(LD) ...

%.o : %.c
    @$(CC) ...

$(gen_file) :
    # generate the file here

UPD.

A little improvement based on Beta's answer.

-include generator-task
.PHONY : generator-task

generator-task : $(gen_files)

$(gen_files) : $(gen_prerequisites)
    # generate the file here

Instead of running generator on each invocation of Make, this will only regenerate a file when one of its prerequisites would change.

like image 37
Eldar Abusalimov Avatar answered Sep 19 '22 14:09

Eldar Abusalimov