Vinod
Vinod

Reputation: 1091

A C++ makefile issue

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

Answers (1)

Sam Varshavchik
Sam Varshavchik

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

Related Questions