Using ‘make again’ to clean and remake - makefile

I want to have a phony target to ‘remake’ a project via make again instead of typing make clean && make or make clean all (which seems like I wanted to ‘clean all’) or making an alias/function/script to do this.
Is it safe to specify something like this:
again: clean all
in a sense that prerequisites are reliably updated from left to right?
Or, maybe, is it better to do a recursive call like in
again:
$(MAKE) clean # maybe ‘&& \’ here
$(MAKE) all
I mean, may there be any pitfalls or incompatibilities in either approach which could make creating e.g. a shell function or an alias to make clean && make safer?
Thank you.

Is it safe to specify something like this:
again: clean all
in a sense that prerequisites are reliably updated from left to right?
That's not safe, because all does not depend on clean so if someone runs make -j2 again then the two targets can be run in parallel.
Your second approach will work better, because it ensures that $(MAKE) all cannot start before $(MAKE) clean has completed. It's not entirely safe though, because if someone does make -j2 clean again then those two targets could run in parallel, which would be roughly equivalent to make clean & make clean all, which would still allow the all step to run in parallel with the first clean.
A better option would be:
again: clean
$(MAKE) all
This way if someone does make clean again then it only does the clean once, and if they do make -j2 clean again it still ensures that the clean target finishes before $(MAKE) all runs.

Related

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.

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".

always run a script when running 'make' before compiling

I'm using automake.
I'd like to have a script run each time I run 'make'.
This script does a git diff and generates an MD5 sum of the diff.
The hash is written as a #define in repos_version.h
e.g.:
#define REPOS_DIFF "-190886e9f895e80c42cf6b426dc85afd"
The script only rewrites this file if it doesn't exist or if the diff has is different to what is in repos_version.h already. But the script needs to be run for each make.
main.c includes repos_version.h and prints out the hash when the executable is run.
Here's Attempt 1 for Makefile.am
all: config.h
#chmod +x gen_diff_hash.sh
#./gen_diff_hash.sh
$(MAKE) $(AM_MAKEFLAGS) all-recursive
This work, but I get the following error
Makefile:1234: warning: overriding recipe for target all'
Makefile:734: warning: ignoring old recipe for targetall'
Here's Attempt 2 for Makefile.am
all-local:
#chmod +x gen_diff_hash.sh
#./gen_diff_hash.sh
main.c: repos_version.h
However, this doesn't work, as all-local seems to be run too late. A second run of 'make' does get the desired result, but that's not a runner.
So neither are great.
Any ideas?
I've been reading through the automake hooks documentation, but I can't see anything that suits my needs.
You could ensure the script is always run every time Make loads the Makefile, by executing it via $(shell ./gen_diff_hash.sh) and assigning it to a throwaway variable (or using it in some other construct like an ifeq or something).
Note, that this is not POSIX, and on Make implementations other than GNU this isn't valid syntax. GNU Make 4.x supports using VAR != ./gen_diff_hash.sh as well, which is compatible with BSD Make at least.
But maybe it would be a better idea to create a .PHONY: gendiff target that runs the script, and make the header depend on this gendiff. The target would then be re-evaluated every time Make checks if repos_version.h is up-to-date, rather than every time Make is run at all.

How can I ctreate a simple makefile for minGW + gfortran

I am absolutely new in gfortran+minGW.
I need to create makefile.
When I run
$ gfortran -c q.f
All is ok!
But how can I run makefile like this?
CC = gfortran
q.o : q.f
$(CC) -c q2.o q2.f
I receive error “CC: command not found”.
(OS – Win 7 (64))
Tanks!!!
It kind of looks like you're trying to run the makefile as a regular script. Try
$ make
or
$ make -f mymakefilename
if you named the file something other than "makefile" or "Makefile".
You can potentially just execute the makefile, but if so you need a "shebang" line, something like
#!/usr/bin/make
at the top of the file, but frankly hardly anyone uses that option. Just use the make(1) command.
Update
It's because they're in the wrong order. Makefiles process (by default) the first target in the file. When you run make it sees the rule to make, q.o from q.f, it compiles it, and says, "Okay, I'm done."
If you put the q.exe target first, it says "Hmmm, I want to build q.exe and to do that I need a q.o. Do I have a q.o? No? Okay, hen I'll build a q.o. I have a rule for that -- I can build a q.o from q.f. okay, that's done. Now can I build q.exe? Oh, yes, I can. I'll build q.exe. Anything? Nope, I'm done."
If you were to use the commend
$ make q.exe
then you'd explicitly tell make to make q.exe, which would cause the same thing to happen, but better you should reorder your makefile and get used to the way they work.

How can I capture GNUMake differences between two directories

I have a tricky issue with gmake, when I build from the parent directory, something is different and the make does not build all the .o(s) it needs and fails, but if I cd to the directory and do a make it builds them fine.
How can I get GNUmake to tell me the difference between these two runs? There must be some make variables set in the parent that break the child, but I need help figuring out how to track them down.
If running make from the parent directory fails to build foo.o, then try make foo.o. If that fails then try running make -n foo.o in both directories (to print the commands instead of executing them) to see what it's doing differently. If it succeeds, then it's not even trying to build foo.o when run from the parent directory; make -n may shed some light, and as a last resort make -d will give you a torrent of information about the decision process, why it's doing what it's doing.
Here's a handy trick to see the value of variables. Put this rule in your makefile:
show_%:
#echo $# is $($*)
Now you can run make show_FOO and it will tell you the value of the variable FOO.
Finally, are you sure you know where you build your .o files? Make is very good at using things there to build files here, but not the other way around, so it can lose track of intermediate files if you're not careful.

Resources