Conditional execute within Makefile - makefile

I would like to check if a file exists in a Makefile and run a recipe if it doesn't exist and stop after creating it else continue working with the file that exists and execute more recipes. I think this is best illustrated with an example in my Makefile:
GEN_C_FILES: GEN_C_FLS
$(shell cat $(DESIGN_TOP).c.tmp c_template.c.tmp > $(DESIGN_TOP).c )
$(DESIGN_TOP).c:
$(MAKE) GEN_C_FILES
#(echo $(DESIGN_TOP).c created and modify it to suit the design before running COMPILE)
exit 1
COMPILE: $(DESIGN_TOP).c
#(echo bsub -I compile_script-batch $(DESIGN_TOP).c -log $(DESIGN_TOP).log)
#(bsub -I compile_script -batch $(DESIGN_TOP).c -log $(DESIGN_TOP).log)
I can accomplish what I want but the exit produces an error message. I want it to exit if the recipe of $(DESIGN_TOP).c is executed but if the recipe is not executed the file exist and so it need not be generated and the rest of COMPILE target should complete by running the compile on bsub. Is there a better way to accomplish this without generating the error on exit?. Thanks

You can't make it work as you want when running make COMPILE. The only way to get make to stop in the middle of a build process and not proceed any further is to fail. But, instead you can change what make wants to build in the first place, like this:
GOAL = $(if $(wildcard $(DESIGN_TOP).c),COMPILE,$(DESIGN_TOP).c)
all: $(GOAL)
$(DESIGN_TOP).c:
cat $(DESIGN_TOP).c.tmp c_template.c.tmp > $#
#echo $# created and modify it to suit the design
COMPILE: $(DESIGN_TOP).c
bsub -I compile_script -batch $< -log $(DESIGN_TOP).log
Now if you run make or make all and the source file does not exist, the prerequisite of all will be the source file and nothing else, so it will be built then make will stop.
If the source file does exist, then the prerequisite of all will be COMPILE and it will be built.

Related

Is it possible to run a command when the makefile finishes without an external script?

I would like to run #echo "Make complete." When the makefile finishes running. The problem is I can't figure out a way for it to do that without putting it at the end of of every option, but I wouldn't like to do that since for example the all option would echo "Make complete." multiple times. I also know I could run a script such as:
make $1
echo "Make complete."
But that solution is messy because it uses 2 files and it wouldn't work if the user didn't type an argument.
I am using GNU Make.
You can have a wrapper makefile calling the real makefile:
$(MAKECMDGOALS):
$(MAKE) -f makefile.real $#
#echo "Make complete."
There are caveats and some extra things that need doing to handle multiple targets and passing on the environment and other options, which I'm sure the SO community will add as comments to this answer.

Modify working makefile to do pre-stage before compiling and linking

I'm using this makefile as an example:
https://gist.github.com/mihaitodor/bfb8e7ad908489fdf3ceb496573f306a
Before compiling/linking I need to do a pre-stage, consisting of cd to a directory and run a script. Without the pre-stage it compiles & links fine.
I think I need to change the all rule:
all : $(TESTS)
I have tried this:
all : cd /bla/bla ./my_script $(TESTS)
and I have tried this:
all :
cd /bla/bla ./my_script
$(TESTS)
but it stops the compile/linking stage.
Given the URL above, where should I insert my pre-stage?
The short answer is you should likely create a new recipe, and make any bottom level target that is dependent on your script running be dependent on it. Something like:
.ran_my_script: $(GTEST_SRCS_)
cd /bla/bla ./my_script
touch $#
test_mihai.o gtest_main.o gtest.o : .ran_my_script
This way it will run your script before it attempts to generate any of the listed targets. It then touches a file $# (.ran_my_script). This will then be newer than any of the .o files meaning the script will not rerun unless someone modifies one of the scripts dependencies (i.e. $(GTEST_SRCS_)). You'll have to figure out what artifcats are actually dependent on your script, and what artifacts your script is dependent on.
Notice that if any of the sources change, then .ran_my_script will be considered out of date, as will anything that depends on it. This means that if you modify any source, it will rebuild all .o files. I'm assuming this is what you want.
Because I'm assuming you're new to makefiles, I will point out two things: first $# resolves to the target name (.ran_my_script in the above example), and second, that the last line of this causes .ran_my_script to be a dependency of test_mihai.o and friends -- but because it does not have any recipes associated with it, this line does not override any other recipes against the same targets specified prior to or later on in the makefile.
As to why what you were doing doesn't work:
all: cd /bla/blah ./my_script $(TESTS)
indicates that the target all is dependent on the targets cd, /bla/bla, ./my_script, and $(TESTS). It will attempt to build all of these before it builds all. Of course, you likely do not have a rule to build cd, etc, so this will fail.
Your next example,
all :
cd /bla/bla ./my_script
$(TESTS)
You create a target all, with two recipes. First, it will attempt to run your script, and then it will attempt to run whatever $(TESTS) resolves to. Notice that $(TESTS) in this case is not a bash command, so this would fail as well.
You might be tempted to do something like this:
all : $(TESTS)
cd /bla/bla ./my_script
but this would cause your script to be run as part of the all target, which runs after everything in $(TESTS) has already been completed.

Running makefile by its name

I'm learning about makefiles. I've written a simple hello world like makefile named just makefile2 but when I run mingw32-make makefile2 I get:
Nothing to be done for 'makefile2'.
When I run just only mingw32-make (without supplying the file name) it works.
My question is it a rule to have only one makefile in the folder and to run it we don't provide a file name at all?
Is it possible to run specific makefile providing it's name?
PS. I'm using MinGW on Windows 10
Usually you need the -f option to tell make to use another file than Makefile or makefile, like
make -f makefile2
Without the -f flag, you tell make to build the target named (in your case) makefile2.

Ignore clean command in Makefile

I have a project to compile with a lot of makefiles including a clean command. That's why i always have to start over again if there is an error (because the clean command is called in many Makefiles)
Question:
Is there any possibility to tell make to ignore the clean command? I would have to touch > 100 Makefiles otherwise. I would like make to start on the last error, not compiling all done stuff again
Example Makefile entries:
clean: cleansubdirs $(DIR) $(DIR1)
$(DIR2)
It's possible to redefine the recipe of an explicit target as simple as that:
noclean.mk
clean:;
cleansubdirs:;
# more stuff...
Now run make -f Makefile -f noclean.mk and it will work without actual cleaning files. However, make will issue several warnings about "overriding/ignoring old recipes".

makefile recursive -q mode Error 1

I am trying to run a recursive invocation of "question mode", and I get an error in a very unique scenario.
I am using MAKE 3.81, and this has been tested on two completely separate environments.
I call "make -q", then that makefile calls "$(MAKE) -C sub/a/", then that makefile calls "$(MAKE) -f ../../makefile.b"
The testcase is as simple as I can make it. Can someone tell me why I get this error:
nachum:/home/nachum/makefile_bug[1497]$make -q
make -C sub/a
make[1]: Entering directory `/home/nachum/makefile_bug/sub/a'
make -f ../../makefile.b
make[1]: *** [b] Error 1
make[1]: Leaving directory `/home/nachum/makefile_bug/sub/a'
make: *** [a] Error 2
nachum:/home/nachum/makefile_bug[1498]$
Here are the makefiles:
makefile:
a:
$(MAKE) -C sub/a
sub/a/makefile:
b:
$(MAKE) -f ../../makefile.b
makefile.b:
all:
echo hi
The whole point of this exercise is to be able to check if sub projects need to be recompiled so I can properly build the top level project when necessary. Otherwise I have to use timestamps for everything. (I previously used timestamps, but I realized that caused extra confusion for other things.)
There are some weird workarounds for this problem. For example, if the recipe for a (in makefile) has an additional line above the call to $(MAKE), ie:
makefile:
a:
#echo hi
$(MAKE) -C sub/a
The problem goes away, AND the dependencies (in my full testcase) still work. Also using make directly seems to change the behavior (as opposed to $(MAKE)).
Any help would be appreciated.
Thanks,
Nachum
Your problem is roaming around the -q option specified. -q would run no command but give exit status if up to date. When you use ${MAKE} make -q -C sub/a is executed. after little permutation and combination I found that we can't use -q with -C option. If you want quite then use make --quite or if you just want to check the timestamps then try with -t (touch but don't compile) or '-n` (dry run).

Resources