LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-08-2009, 01:24 PM   #1
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Rep: Reputation: 31
makefile help


I'm trying to figure out how Make handles directories. How can I modify this makefile so it will put all of the .o files in a separate build directory?
Code:
CC=g++
LIBS=-lgsl -lgslcblas
basedir=.
srcdir=$(basedir)/src
builddir=$(basedir)/build
SRCS=$(srcdir)/*.cpp
OBJS=*.o

.PHONY:	all

all:	bandit

main.o:	main.cpp	$(SRCS)
	$(CC) -c	main.cpp

JBandit.o:	$(srcdir)/JBandit.cpp
	$(CC) -c	$(srcdir)/JBandit.cpp


JBanditX1.o:	$(srcdir)/JBanditX1.cpp
	$(CC) -c	$(srcdir)/JBanditX1.cpp

bandit:	main.o	JBandit.o	JBanditX1.o
	$(CC) -o bandit $(LIBS) $(OBJS)
This compiles but it puts all of the object files in the base directory. I tried modifying the rules by adding a prefix, e.g:
Code:
$(builddir)/main.o:	main.cpp	$(SRCS)
	$(CC) -c	main.cpp
but make ignores this and still puts main.o in the base directory. And if I refer to the build directory in the dependencies for bandit, make complains about "no rule ..."

I want to keep main.cpp in the base directory, all other sources in the src directory, and all object files in the build directory.

Thanks.
 
Old 12-08-2009, 01:53 PM   #2
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
Note the custom implicit rule:
Code:
CXXFLAGS = -g -pipe -O3 -Wall -Wextra -Weffc++ -ansi -pedantic -MD
LDFLAGS = -lgsl -lgslcblas
LINK.o = $(LINK.cpp)

SRCS = $(wildcard *.cpp) $(wildcard src/*.cpp)
OBJS = $(SRCS:%.cpp:obj/%.o)
DEPS = $(DEPS:%.cpp:obj/%.d)

.PHONY: all clean

all: bandit

bandit: $(OBJS)

obj/%.o: %.cpp
	mkdir -p `dirname $@`
	$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) $< -o $@

clean
	$(RM) $(DEPS) $(OBJS) core

-include $(DEPS)

Last edited by tuxdev; 12-08-2009 at 02:59 PM.
 
1 members found this post helpful.
Old 12-08-2009, 02:30 PM   #3
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Thanks, tuxdev, I can hardly see any resemblance between yours & mine. I'll have to study it tonight -- there's much that I don't understand, but have to go to class now. If you can post a link to something that explains what you did (hopefully something more compact than the entire gnu make manual) that would be great.
 
Old 12-08-2009, 03:20 PM   #4
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
The relevant section in the GNU make manual is http://www.gnu.org/software/make/man...Implicit-Rules

I'm also doing a few other tricks, like using GCC's automated dependency tracking.
 
1 members found this post helpful.
Old 12-09-2009, 02:45 AM   #5
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
I'm still having a hard time with this. Your makefile didn't do anything. At first it was saying "nothing to do for all", so I added a rule under bandit. Then it said "undefined reference to main" so I added rule for main. Then it was failing on undefined references to JBandit and JBanditX1, so it seems that for some reason the wildcard definitions weren't working. I couldn't figure out how to fix them, so I finally put back separate rules for those sources as well. clean wasn't deleting the .d files or the executable. (It never made an "obj" directory either.)

So, in order to get it to work, I went back to writing a separate line for each target (although I see now that I don't have to write explicit rules for each object file).

But I still can't figure out how to put the .o files in a separate directory. I haven't found anything in the make manual about this.

So here's what I have now. I added some dependencies that I had omitted from my original makefile.
Code:
CXXFLAGS = -g -pipe -O3 -Wall -Wextra -Weffc++ -ansi -pedantic -MD
LDFLAGS = -lgsl -lgslcblas
LINK.o = $(LINK.cpp)
VPATH = src include

SRCS = src/*.cpp
INCLS = include/*.h
OBJS = main.o JBandit.o JBanditX1.o

.PHONY: all clean

all: bandit

bandit: $(OBJS)
	$(CXX)	$(CXXFLAGS)	$(LDFLAGS)	$(OBJS)	-o bandit

main.o: main.cpp $(SRCS) $(INCLS)

JBandit.o: src/JBandit.cpp include/JBandit.h

JBanditX1.o: src/JBanditX1.cpp include/JBanditX1.h

clean:
	$(RM)	bandit *.o	*.d

-include $(DEPS)
It works, but still doesn't use the directory structure I wanted, and doesn't use any of those nice pattern substitution rules.

Can you see what's wrong with the wildcard statements in your makefile? Also, what are the lines "LINK.o = $(LINK.cpp)" and "-include $(DEPS)" for? I don't understand what they are doing.
 
Old 12-09-2009, 09:56 AM   #6
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
The wildcards should only fail if: 1. you aren't really using GNU make or 2. the files aren't where I think they are.

The point of LINK.o = $(LINK.cpp) is to change the default linker for .o files from the C linker (cc) to the C++ linker (g++). That allows GCC to know how to make "bandit" from the .o files properly without any extra effort.

The -include relates to the -MD flag for GCC automated dependency tracking.

Don't go adding rules willy-nilly, the point of the implicit rule is to completely avoid the need to write any manually (which is what you ended up doing anyway).

Last edited by tuxdev; 12-09-2009 at 09:57 AM.
 
1 members found this post helpful.
Old 12-09-2009, 12:58 PM   #7
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Yes, I am trying to learn how to use the implicit rules as much as possible. I am definitely using Gnu Make 3.81.

I think you understand where the files are. main.cpp is in the project root directory (jbandit). The other source files are in the jbandit/src directory. All headers are in the jbandit/include directory.

I went back to your version, and tried again to modify it only to the minimum extent necessary to get it to work. My code is below, with comments embedded describing why (I think) the changes were needed.

I had to use VPATH to get it to find the files in obj.
I had to define OBJS explicitly; couldn't work out how to use % subst.
DEPS never seems to get defined.
I had to add an explicit rule to link the executable bandit.
I added a separate dependency line for main.o because main depends on all of the class headers.
Finally, I tried (unsuccessfully) to add a %-substitution expression for the class headers to the dependency line for the other (class) object files, but when I did, for some mysterious reason it failed to compile main.o, even though there is a separate rule for main.o.

Can you shed any light on any of these?

(It's not as bad as it looks here -- plain code is posted below this.)
Code with comments:
Code:
CXXFLAGS = -g -pipe -O3 -Wall -Wextra -Weffc++ -ansi -pedantic -MD
LDFLAGS = -lgsl -lgslcblas
LINK.o = $(LINK.cpp)

#without VPATH "No rule to make target `obj/JBandit.o` needed by `bandit`
VPATH = src include

SRCS = $(wildcard *.cpp) $(wildcard src/*.cpp)
INCLS = $(wildcard include/*.h)

#Can't define OBJS by %-substitution -- because obj doesn't exist yet?
OBJS = obj/main.o obj/JBandit.o obj/JBanditX1.o
#OBJS = $(SRCS:%.cpp:obj/%.o)

#I left your DEPS definition here, but it seems that $(DEPS) is never defined.
#Whenever I run `make test`, the "DEPS" line is empty.
DEPS = $(DEPS:%.cpp:obj/%.d)

.PHONY: all clean test

all: bandit

#without an explicit rule for bandit, only .o files are compiled (no executable)
bandit: $(OBJS)
	$(CXX)	$(CXXFLAGS)	$(LDFLAGS)	$(OBJS)	-o bandit


#I think I need this rule for main.o because (1)main.cpp is not in srcs directory and
#(2)main depends on all headers whereas the individual classes in srcs each depends
#only on its own header

obj/main.o: main.cpp $(INCLS)

#however, if I add %.h to the following rule, i.e.
#obj/%.o: %.cpp	%.h
#it compiles JBandit.o and JBanditX1.o but NOT main.o, and says
#g++: obj/main.o:No such file or directory
#make: *** [bandit] Error 1
#on the other hand, if I write
#obj/%.o: %.cpp	$(INCLS)
#it works, but this is really not the correct dependency since each of the
#class .cpp files depends only on its own header.
#It also works if I omit the header dependency altogether, but then a header
#could be changed without triggering a recompile of the object file.

obj/%.o: %.cpp
	mkdir -p	`dirname $@`
	$(CXX)	-c	$(CXXFLAGS)	$(CPPFLAGS)	$<	-o	$@

clean:
	$(RM)	bandit
	$(RM)	obj/*
	rmdir	obj

test:
	@echo "SRCS: $(SRCS)"
	@echo "INCLS: $(INCLS)"
	@echo "OBJS: $(OBJS)"
	@echo "DEPS: $(DEPS)"

-include $(DEPS)
Plain code:
Code:
CXXFLAGS = -g -pipe -O3 -Wall -Wextra -Weffc++ -ansi -pedantic -MD
LDFLAGS = -lgsl -lgslcblas
LINK.o = $(LINK.cpp)
VPATH = src include

SRCS = $(wildcard *.cpp) $(wildcard src/*.cpp)
INCLS = $(wildcard include/*.h)
OBJS = obj/main.o obj/JBandit.o obj/JBanditX1.o
DEPS = $(DEPS:%.cpp:obj/%.d)

.PHONY: all clean test

all: bandit

bandit: $(OBJS)
	$(CXX)	$(CXXFLAGS)	$(LDFLAGS)	$(OBJS)	-o bandit

obj/main.o: main.cpp $(INCLS)

obj/%.o: %.cpp
	mkdir -p	`dirname $@`
	$(CXX)	-c	$(CXXFLAGS)	$(CPPFLAGS)	$<	-o	$@

clean:
	$(RM)	bandit
	$(RM)	obj/*
	rmdir	obj

test:
	@echo "SRCS: $(SRCS)"
	@echo "INCLS: $(INCLS)"
	@echo "OBJS: $(OBJS)"
	@echo "DEPS: $(DEPS)"

-include $(DEPS)
 
Old 12-09-2009, 01:31 PM   #8
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
Quote:
#without VPATH "No rule to make target `obj/JBandit.o` needed by `bandit`
Not sure why it's not finding stuff - it really should, unless something else is weird.

Quote:
#Can't define OBJS by %-substitution -- because obj doesn't exist yet?
%-sub is a simple text macro - it just pastes the text, doesn't even glance at the filesystem.

Quote:
#I left your DEPS definition here, but it seems that $(DEPS) is never defined.
#Whenever I run `make test`, the "DEPS" line is empty.
Hehe, it'd help if it used SRCS in the #-sub. Oops.

Quote:
#without an explicit rule for bandit, only .o files are compiled (no executable)
Not sure why it isn't, the LINK.o = $(LINK.cpp) should automatically take care of things.

Quote:
#I think I need this rule for main.o because (1)main.cpp is not in srcs directory and
#(2)main depends on all headers whereas the individual classes in srcs each depends
#only on its own header
The automated dependency tracking is *exactly* to avoid needing to do anything special for (2).
 
Old 12-09-2009, 03:05 PM   #9
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Quote:
Hehe, it'd help if it used SRCS in the #-sub.
I did notice that and tried to replace DEPS with SRCS and it still did nothing.

But voila ...
Code:
OBJS = $(SRCS:%.cpp=obj/%.o)
DEPS = $(SRCS:%.cpp=obj/%.d)
succeeds at defining OBJS and DEPS. Needed a "=" instead of ":". That does almost what I wanted, but it creates a objs/srcs subdirectory where I wanted objs to be a flat file, so my solution is this:
Code:
OBJS = $(addprefix obj/, $(notdir $(SRCS:%.cpp=obj/%.o)))
DEPS = $(addprefix obj/, $(notdir $(SRCS:%.cpp=obj/%.d)))
which puts all of the .o and .d files in objs with no subdirectory.


Quote:
The automated dependency tracking is *exactly* to avoid needing to do anything special for (2).
That's great to know. I tested it and it definitely does the trick.

Quote:
Not sure why it isn't, the LINK.o = $(LINK.cpp) should automatically take care of things.
I can't find any documentation on this. Can you point me in the right direction?
 
Old 12-10-2009, 12:31 PM   #10
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
Quote:
which puts all of the .o and .d files in objs with no subdirectory.
Are you *really* sure you want to do this? Filenames can clash badly. Might not be an issue for this particular project right now, but later..

Quote:
I can't find any documentation on this. Can you point me in the right direction?
It's something I discovered while I was reading through the output of "make -p". When run in a directory without a Makefile, it dumps all the variables and implicit rules provided for free. One of these rules is:
Code:
%: %.o
	$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
Hmm.. perhaps I've been using LDFLAGS when I should be using LDLIBS.. Learn something new every day
 
Old 12-10-2009, 09:30 PM   #11
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Quote:
Are you *really* sure you want to do this? Filenames can clash badly. Might not be an issue for this particular project right now, but later..
Yes, I think you're right. I've changed it back to "OBJS = $(SRCS:%.cpp=obj/%.o)" so it preserves the directory structure in obj/.

Quote:
Hmm.. perhaps I've been using LDFLAGS when I should be using LDLIBS.. Learn something new every day
For what it's worth, I tried replacing LDFLAGS with LDLIBS but it seems to make no difference -- I still need the explicit rule to generate an executable.

I have another question: where is "core" defined? When I had "$(RM) core" under clean, it had no effect. I have to explicitly name "bandit" in the clean section in order to delete it. The Make Manual uses core in the example in Appendix C but doesn't say anything about it, and I can't find any mention of core in the output of make -p.
 
Old 12-10-2009, 09:37 PM   #12
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
"core" is the name of a core dump, sometimes produced when your program crashes.
 
Old 12-10-2009, 10:04 PM   #13
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by tuxdev View Post
"core" is the name of a core dump, sometimes produced when your program crashes.
How is that relevant to this makefile entry?:
Code:
clean:
	$(RM) $(DEPS) $(OBJS) core

Last edited by r.stiltskin; 12-10-2009 at 10:05 PM.
 
Old 12-10-2009, 10:12 PM   #14
tuxdev
Senior Member
 
Registered: Jul 2005
Distribution: Slackware
Posts: 2,012

Rep: Reputation: 115Reputation: 115
It's just something I do so that a clean really does get rid of everything but the executable and the source.
 
Old 12-10-2009, 10:30 PM   #15
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
OK. Many thanks for your help.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
make: Warning: Both `makefile' and `Makefile' exist ? malli42108 Solaris / OpenSolaris 5 10-24-2009 09:09 AM
Is it mandatory to have the name of the makefile as 'Makefile' for kernal module comp narender.d Linux - Kernel 3 05-29-2009 06:26 AM
how to get (makefile -f makefile )output into the textview widget in Pygtk sailu_mvn Programming 3 02-28-2005 03:57 AM
generate Makefile from Makefile.in without calling ./configure ? chris78 Programming 2 05-02-2004 12:23 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:47 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration