From: Danuvius <dan...@gm...> - 2012-05-26 14:22:40
|
Greetings! I have a bit of a makefile issue which I've failed not only to solve but even to understand. The below seems to work fine (pairing the proper .cpp file with the corresponding .o file) when I don't do the monkeying around to get the .o files to end up in a separate output directory. But once the output directory is prefixed to the .o files, every object files is compiled by taking the first file (main.cpp) as the source... which, obviously leads to nothing workable. I searched google and attempted to make sense of autovariables via the makefile documentation... but still don't understand why the observed outcome is happening. However I have a nagging suspicion that this is one of those situation that may be solved by changing a single character, or, at most, a few on a single line. I'd be grateful for any assistance, or even suggestions pointing me in new directions toward figuring it out on my own. Thank you in advance! -- Danuvius ----- CC=g++ INDIR=./src OUTDIR=./bin INCLUDES=-I./sfml-1.6/include -I./lua-5.2.0/src LINCLUDES=-L./sfml-1.6/lib -L./lua-5.2.0/src LIBRARIES=-lsfml-graphics-s -lsfml-window-s -lsfml-system-s -llua52 CFLAGS=-c $(INCLUDES) -Wall -O3 -o $(OUTDIR) LFLAGS=-static-libgcc -static-libstdc++ $(LINCLUDES) $(LIBRARIES) TSOURCES=main.cpp Logger.cpp TOBJECTS=$(TSOURCES:.cpp=.o) SOURCES=$(addprefix $(INDIR)/,$(TSOURCES)) OBJECTS=$(addprefix $(OUTDIR)/,$(TOBJECTS)) EXECUTABLE=$(OUTDIR)/vilag all: $(SOURCES) $(EXECUTABLE) run: $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) $(LFLAGS) $(OBJECTS) -o $@ $(OBJECTS): $(SOURCES) $(CC) $(CFLAGS) $< -o $@ clean: rm -rf $(OUTDIR)/*.o ----- |
From: Keith M. <kei...@us...> - 2012-05-26 16:32:07
|
On 26/05/12 15:22, Danuvius wrote: > I have a bit of a makefile issue which I've failed not only to solve > but even to understand. > > The below seems to work fine (pairing the proper .cpp file with the > corresponding .o file) when I don't do the monkeying around to get the > .o files to end up in a separate output directory. > > But once the output directory is prefixed to the .o files, every > object files is compiled by taking the first file (main.cpp) as the > source... which, obviously leads to nothing workable. > TSOURCES=main.cpp Logger.cpp > TOBJECTS=$(TSOURCES:.cpp=.o) > > SOURCES=$(addprefix $(INDIR)/,$(TSOURCES)) > OBJECTS=$(addprefix $(OUTDIR)/,$(TOBJECTS)) > $(OBJECTS): $(SOURCES) > $(CC) $(CFLAGS) $< -o $@ This is all kinds of wrong! First, you've set up $(OBJECTS) to be a list of object file names, each prefixed by a path name, and $(SOURCES) to be a list of source file names, again with each prefixed by a (different) path name; now, your predicate: $(OBJECTS): $(SOURCES) makes *every* object file depend on *every* source; this is *not* what you want! Second, your command: $(CC) $(CFLAGS) $< -o $@ uses the $< autovariable in a context which is neither a suffix rule, nor a pattern rule; this is invalid usage, since those are the *only* contexts in which $< is strictly valid. (In GNU make, this improper usage does actually assign $< as the *first* prerequisite -- main.cpp in your case, which explains why every one of your object files is compiled from main.cpp; in most generic make implementations, $< expands to nothing at all, when used in this invalid context). To fix your problem, you should use a pattern rule, (which *is* a valid context for use of $<): %.o: %.cpp $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< (using $(CXX) as the preferred alias for the C++ compiler; $(CC) is traditionally reserved for the C compiler), or, in this case, you could just use the built-in pattern rule, by omitting *any* explicit rule for building .o files from .cpp sources. Now, to get your object files in a separate directory from your sources, the method I would recommend is to have your object file directory as the current working directory -- make a copy of, or a link to, the Makefile within it, for convenience -- and add a VPATH or vpath specification within that Makefile, to point to the source directory; e.g. where you have: project/ +--- src/ | +--- source.cpp +--- obj/ | +--- Makefile you would add: VPATH = ../src to project/obj/Makefile, then cd to project/obj to run make, (and you *don't* muck about with all the $(addprefix ...) nonsense -- just refer to your sources by a simple file name alone, and leave the VPATH mechanism to add the appropriate directory prefix). -- Regards, Keith. |
From: Danuvius <dan...@gm...> - 2012-05-28 22:08:25
|
Thank you, Keith! Both for the explanations as to what's wrong and the suggestions for fixing it. I now have something that appears to work as desired. Sincerely, Danuvius |
From: NightStrike <nig...@gm...> - 2012-06-04 01:42:24
|
On Mon, May 28, 2012 at 12:08 PM, Danuvius <dan...@gm...> wrote: > Thank you, Keith! Both for the explanations as to what's wrong and > the suggestions for fixing it. > > I now have something that appears to work as desired. If you felt like doing some additional work to get something that might be easier to maintain, you can look into automake for writing this for you. You could achieve your original makefile by creating an automake Makefile.am file that is as small as this: =============== SFML = ./sfml-1.6 LUA = ./lua-5.2.0 bin_PROGRAMS = vilag vilag_SOURCES = main.cpp Logger.cpp vilag_CFLAGS = -Wall -O3 vilag_CPPFLAGS = -I$(SFML)/include -I$(LUA)/src vilag_LDADD = -L$(SFML)/lib -lsfml-graphics-s -lsfml-window-s -lsfml-system-s -L$(LUA)/src -llua52 =============== That's of course completely untested, and you need to pair it with a configure.ac file, but that's easily created automatically with autoscan. What you have works, so you obviously don't have to, but you might find that you like it, so I figure I'll toss it out there. Cheers! |