0
votes

I am using gcc -MM to generate prerequisites of dependencies rules for compiling source files into object files. I want to specify a directory to hold object files and executable in the value of some variable BIN_DIR=bin/release/. There are two cases:


CASE 1

%.d: *.h *.cc Makefile
     @$(CXX) -MM $(CXXFLAGS) *.cc > $@.$$$$; \
     sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; $(RM) -rf $@.$$$$

Though unfamiliar to sed, I learned that the purpose of the sed utility is to translate (for example):

main.o : main.cc defs.h

into:

main.o main.d : main.cc defs.h

My question is how to change it further to: bin/release/main.o bin/release/main.d : main.cc defs.h

If someone could explain the usage of sed here, that would be greatly appreciated!


CASE 2

Makefile.depend: *.h *.cc Makefile
    $(CXX) -MM $(CXXFLAGS) *.cc > Makefile.depend

In the file Makefile.depend, you will see each rule is like this example:

main.o : main.cc defs.h

How to change it to be:

bin/release/main.o : main.cc defs.h

Thanks and regards!


NOTE:

I don't know why I cannot comment now. So I put my update here:

VPATH is to specify the directory of source code. But then you have to run make -f path2Makefile from where you want the object files be. Here I'd like to be able to run make -f path2 Makefile from anywhere. So it is prefered to specify directory for object files.


To Beta:

Thanks for your help! Please excuse me for not being able to comment on your answer. The problem with your method on second case is that after the command, some rules with several lines will recieve the prefix at every single line. e.g.

main.o : main.cc defs.h \

src/misc.h

becomes:

$(BIN_DIR)main.o : main.cc defs.h \

$(BIN_DIR) src/misc.h

2
Oh, I beg your pardon. It's been quite a while since I touched my dependecy-handlers, so I'd forgotten. Let me try to fix it...Beta

2 Answers

1
votes

For case 1 you can use:

sed 's,\($*\)\.o[ :]*,$(BIN_DIR)\1.o $(BIN_DIR)$@ : ,g'

Regular expressions are notoriously hard to read for beginners, but basically this says "take the target stem (remember that as thing 1) followed by .o, gobble up any spaces and colons that follow, and replace the whole thing with BIN_DIR, the remembered thing, .o, space, BIN_DIR, the target of the rule, a space and a colon".

Case 1 will cause you some trouble. For one thing, you will always rebuild main.o and main.d whether you really need to or not. There are several ways to fix this-- the simplest is to make the targets $(BIN_DIR)main.d and $(BIN_DIR)main.o, but there are more sophisticated methods you can try later.

For case 2, this should do the trick:

sed 's,^,$(BIN_DIR),'

Here the regex says "change the beginning of the line to BIN_DIR".

EDIT: second try

sed 's,\(.*:\),$(BIN_DIR)\1,'

This says "find something that ends with a colon and stick BIN_DIR in front of it". The next step in bulletproofing would be "suck in multiple lines and put BIN_DIR in front of every word-like thing preceding a colon", but that's probably not necessary, knock wood.

0
votes

Look up 'vpath' in the gnu.org make manual. I think it's what you need.