Reputation: 1091
I recently started using this makefile (adapted from the web) to build my C++ code:
a.exe: main.o
g++ $(CFLAGS) -o $@ $^
main.o: main.cpp code.hpp
CFLAGS=-ggdb -std=c++17 -Wall -Werror=pedantic -Wextra
#-------------------------------------------------------------
run: a.exe
./a.exe
clean:
rm -f *.o
rm -f *.exe
rm -f *.gch
rm -f *.log
build: clean a.exe
%.o: %.cpp
g++ $(CFLAGS) -c $<
#====================================================
In my .bashrc
file, I am using the following alias:
alias mkbld='make build >& build.log'
When I execute the above alias on the command line, I see that the clean before build specified in the makefile first removes all the relevant files inside the current working directory, and the files are regenerated as part of the build. However, the file build.log
is not regenerated. I would like to think that the clean before build logic should apply the same way to this file as well (although this file is not built per se), since each time the build log is written to this file, and it should be recreated each time.
Any idea why this is not happening?
Upvotes: 3
Views: 53
Reputation: 118425
When
make build >& build.log
gets executed, via your shell alias; but the shell creates the build.log
file first, and then executes make
with its standard output/error redirected to the file. It's the shell that creates the file and sets up the redirection.
So, that's the first thing that obviously happens. Then, your Makefile executes, at some point:
rm -f *.log
and this, of course, happily deletes the build.log
file that's just been created. Remember the golden rule of computer programming: a computer will always do exactly what you tell it to do, instead of what you want it to do. You told the computer to: first, create a file called build.log
, then: second, deleting all files named *.log
; and your computer diligently followed your instructions.
P.S. The standard output and error is still redirected to this now-deleted file, at this point; so, basically, everything vanishes into a void (pardon the C++ pun), never to be seen again.
There are several possible workarounds, and the best workaround depends on exactly what is your original purpose for doing things this way. Some options are:
1) Use some other extension, such as build.out
, for the captured standard output or error.
2) make the rm
command smarter, and exclude this specific file, but delete all other *.log
files.
3) make the rm
command even smarter, and have it remove only *.log
files that are older than some predetermined interval. The current timestamp on build.log
will keep it from being deleted, with this approach.
Depends on what you want to do, but this is the explanation for the behavior you're seeing.
Upvotes: 2