Home > Mobile >  Makefile deferred compilation
Makefile deferred compilation

Time:11-08

I have a simple makefile with a variable for the compiler flags, it also contains some targets that modify that variable and append some flags.

My point with it is to be able to run, for example:

make debug perf

that would in turn add to the variable the flags required to build under that configuration. The problem is that if I run it, it does compile the executable with the debug info, and then tries to compile with the performance tools, and obviously does nothing. Can make only execute the compilation step after both targets run?

Makefile:

CFLAGS = -std=c11 -Wall -pedantic -D_GNU_SOURCE

executable: gcc $(CFLAGS) main.c -o exe

debug: CFLAGS  = -g
debug: executable

perf: CFLAGS  = -D__PERF__
perf: executable

Make version 4.2.1

CodePudding user response:

This makes no sense to me. Why would you want to compile file(s) as debug, generating a program executable that is built with debug, then in the same make command recompile the same file(s) with optimization, generating a program executable that is built with optimization.

In a single directory there can be only one file named executable, so how can you build the same file twice and have two different versions at the same time? How do you intend to run the debug executable versus the perf executable?

You either need to build different files, or you need to build them into different directories (one for debug and one for perf). I recommend the latter.

But to answer your specific question: it is not possible in make to build the same target multiple different times in the same invocation of make. Once a single make invocation tries to build a target named foo, it will never try to build that target again no matter how many other targets might list it as a prerequisite. If you re-run make again, it will try again to build foo (one time).

CodePudding user response:

One approach is to have different executable files for different flag combinations, ie

executable         # default to release build
executable.dbg     # with -g
executable.perf    # with -D__PERF__
executable.dbgperg # with both

The two advantages are

  1. you're never unsure how some executable file was built, and you never accidentally test the wrong thing / waste time trying to debug something with no debug symbols, etc.
  2. Make's file dependency logic actually works correctly

This does assume you have a manageable number of flag combinations. If there are too many, the profusion of targets may make your Makefile impractical.

CodePudding user response:

I exactly have the same requirements! :-) As this, I compile my executables with all the options in the filename like: myprog-debug-coverage and so on. All the object files goes to a directory like build-myprog-debug-coverage as example. All this has the advantage that there is no need to recompile all if you need it once for debug, do a change and compile for coverage and after next change for debug again.

The first thing you must do is to filter out all non-targets which are needed for the options like debug with:

debug:
    @:

to simply do nothing.

In addition, you filter out the non-targets with something like:

export FOUND_ACTIONS=$(filter $(ACTIONS), $(MAKECMDGOALS))

and process these variables later on into the flags you need for compilation like:

$(eval $(call CHECK_FOR_CMDGOAL,debug,export LCXXFLAGS = -DDEBUG -DGDB_HELPER -g,build_dir_ext=$(build_dir_ext)-debug))

and after that you can write your standard recipes with the found flags from the variables.

I can't give you a ready to use Makefile here as my one is a bit larger while processing a lot of flags like different compilers, memory debug libraries as efence, build for coverage and much more.

I'm in hope that you can catch the idea how to process the pseudo targets for flags and the real targets and how a Makefile can split both.

And yes, that is not how a Makefile works typically. But I believe it is really convenient at the end of the day. Giving manual CXXFLAGS and so on did not the job, as you as a user have a complete list of flags, libs and options on the comand line, which is a nightmare.

  • Related