PDA

View Full Version : make weird behavior



muze4life
October 20th, 2010, 05:30 PM
Hi folks
I got to compile Triangle.cpp and I can only compile it if it's in the parent dir with "SRCPATH = ../", the files are laid out like this:
(dirs)/Triangle.cpp
(dirs)/Triangle/Makefile

If I put Triangle.cpp into same subdir as Makefile and set SRCPATH = ./ the compilation fails saying it can't find some other file, but SRCPATH only points out to Triangle.cpp anyway.

That seems weird to me, anyone knows what could be wrong?
I spent like an hour trying to figure out what's wrong..




MAIN = Triangle
SRCPATH = ../
SHAREDPATH = ../../../Src/GLTools/src/
SHAREDINCPATH = ../../../Src/GLTools/include/
LIBDIRS = -L/usr/X11R6/lib -L/usr/X11R6/lib64 -L/usr/local/lib
INCDIRS = -I/usr/include -I/usr/local/include -I/usr/include/GL -I$(SHAREDINCPATH) -I$(SHAREDINCPATH)GL

CC = g++
CFLAGS = $(COMPILERFLAGS) -g $(INCDIRS)
LIBS = -lX11 -lglut -lGL -lGLU -lm

prog : $(MAIN)

$(MAIN).o : $(SRCPATH)$(MAIN).cpp
glew.o : $(SHAREDPATH)glew.c
GLTools.o : $(SHAREDPATH)GLTools.cpp
GLBatch.o : $(SHAREDPATH)GLBatch.cpp
GLTriangleBatch.o : $(SHAREDPATH)GLTriangleBatch.cpp
GLShaderManager.o : $(SHAREDPATH)GLShaderManager.cpp
math3d.o : $(SHAREDPATH)math3d.cpp

$(MAIN) : $(MAIN).o glew.o
$(CC) $(CFLAGS) -o $(MAIN) $(LIBDIRS) $(SRCPATH)$(MAIN).cpp $(SHAREDPATH)glew.c $(SHAREDPATH)GLTools.cpp $(SHAREDPATH)GLBatch.cpp $(SHAREDPATH)GLTriangleBatch.cpp $(SHAREDPATH)GLShaderManager.cpp $(SHAREDPATH)math3d.cpp $(LIBS)

clean:
rm -f *.o

dwhitney67
October 20th, 2010, 06:20 PM
What's weird is your organizational skills; why would place the Makefile in a directory that resides below the source file(s)?

I've seen where a Makefile is at the same level as the source file, or where the source file(s) reside at a level below that of the Makefile, but never the other way around.

A very basic Makefile, where it and the source file(s) live at the same level:


APP = Triangle

CPP_SRCS = $(shell ls *.cpp)
CPP_OBJS = $(CPP_SRCS:.cpp=.o)

C_SRCS = $(shell ls *.c)
C_OBJS = $(C_SRCS:.c=.o)

# Verify these paths...
#
SHAREDPATH = ../../../Src/GLTools/src/
SHAREDINCPATH = ../../../Src/GLTools/include/
LIBDIRS = -L/usr/X11R6/lib -L/usr/X11R6/lib64 -L/usr/local/lib
LIBS = -lX11 -lglut -lGL -lGLU -lm
INCDIRS = -I/usr/local/include -I/usr/include/GL -I$(SHAREDINCPATH) -I$(SHAREDINCPATH)GL


LDFLAGS = $(LIBDIRS) $(LIBS)
CXXFLAGS = -Wall -pedantic -g $(INCDIRS)
CFLAGS = $(CXXFLAGS)

.PHONY: all clean


all : $(APP)

$(APP) : $(CPP_OBJS) $(C_OBJS)
$(CXX) $^ $(LDFLAGS) -o $@

.cpp.o :
$(CXX) $(CXXFLAGS) -c $<

.c.o :
$(CC) $(CFLAGS) -c $<

clean :
$(RM) $(OBJS)
$(RM) $(APP)

muze4life
October 20th, 2010, 06:33 PM
Thanks a lot,
it's because it's the Makefile the author of OpenGL SuperBible 5th ed. uses, so I thought I'd use it to try out his examples by only slightly updating the SRCPATH cause I want the Makefile and the Triangle.cpp file to be in same dir.
Do you happen to know why changing SRCPATH from "../" to "./" makes the Makefile behave weird despite moving the Triangle.cpp file accordingly?

dwhitney67
October 20th, 2010, 06:50 PM
Do you happen to know why changing SRCPATH from "../" to "./" makes the Makefile behave weird despite moving the Triangle.cpp file accordingly?

Please define what you mean by "weird". In other words, post the errors generated by make.

P.S. I was able to build a simple program at the same level as the Makefile using this:


MAIN = hello

CXXFLAGS = -Wall -pedantic -g
LDFLAGS =

SRCPATH = ./

$(MAIN) : $(MAIN).o
$(CXX) $^ $(LDFLAGS) -o $@

$(MAIN).o : $(SRCPATH)$(MAIN).cpp

clean :
$(RM) $(MAIN).o
$(RM) $(MAIN)

Vox754
October 20th, 2010, 06:55 PM
Hi folks
...
If I put Triangle.cpp into same subdir as Makefile and set SRCPATH = ./ the compilation fails saying it can't find some other file, but SRCPATH only points out to Triangle.cpp anyway.

...
Saying that it doesn't work is useless if you don't post the compilation errors.

Perhaps the main file is including files relative to the current directory?


#include "../bla/bla.h"
#include "./yada/yada.h"

So it fails when you move the main file.

And I agree with dwhitney, the original Makefile is crazy. Specifying the files like
$(SRCPATH)$(MAIN).cpp is also ugly.

Seems like you are using a bad tutorial or book.

At this point I suspect you already know to compile from the command line, and understand that Makefiles are a way to avoid typing too much in the terminal, and help keep the program's source code organized and updated.

I would make a pause and try to learn more about Makefiles so you can write them yourself, and avoid relying on boilerplate code from someone else. Read the GNU make manual (http://www.gnu.org/software/make/manual/make.html).

muze4life
October 20th, 2010, 07:04 PM
I get this error if I make SRCPATH=./ and put Triangle.cpp in same dir as Makefile:


make
g++ -c -o Triangle.o Triangle.cpp
Triangle.cpp:4: fatal error: GLTools.h: No such file or directory
compilation terminated.
make: *** [Triangle.o] Error 1
make -n in this case yields:


make -n
g++ -c -o Triangle.o Triangle.cpp
g++ -g -I/usr/include -I/usr/local/include -I/usr/include/GL -I../../../Src/GLTools/include/ -I../../../Src/GLTools/include/GL -o Triangle -L/usr/X11R6/lib -L/usr/X11R6/lib64 -L/usr/local/lib ./Triangle.cpp ../../../Src/GLTools/src/glew.c ../../../Src/GLTools/src/GLTools.cpp ../../../Src/GLTools/src/GLBatch.cpp ../../../Src/GLTools/src/GLTriangleBatch.cpp ../../../Src/GLTools/src/GLShaderManager.cpp ../../../Src/GLTools/src/math3d.cpp -lX11 -lglut -lGL -lGLU -lm
Thus I noticed the extra "g++ -c -o Triangle.o Triangle.cpp" command which doesn't appear when Triangle.cpp is in parent dir with SRCPATH=../

If I keep Triangle.cpp in the parent dir and SRCPATH=../ then
make -n yields:


make -n
g++ -g -I/usr/include -I/usr/local/include -I/usr/include/GL -I../../../Src/GLTools/include/ -I../../../Src/GLTools/include/GL -o Triangle -L/usr/X11R6/lib -L/usr/X11R6/lib64 -L/usr/local/lib ../Triangle.cpp ../../../Src/GLTools/src/glew.c ../../../Src/GLTools/src/GLTools.cpp ../../../Src/GLTools/src/GLBatch.cpp ../../../Src/GLTools/src/GLTriangleBatch.cpp ../../../Src/GLTools/src/GLShaderManager.cpp ../../../Src/GLTools/src/math3d.cpp -lX11 -lglut -lGL -lGLU -lm
Same does the make command and compiles successfully.

Vox754
October 20th, 2010, 07:07 PM
CPP_SRCS = $(shell ls *.cpp)
CPP_OBJS = $(CPP_SRCS:.cpp=.o)

C_SRCS = $(shell ls *.c)
C_OBJS = $(C_SRCS:.c=.o)



Wut?

Why use "shell", when you can use "wildcard"?


CPP_SRCS = $(wildcard *.cpp)
CPP_OBJS = $(CPP_SRCS:.cpp=.o)

C_SRCS = $(wildcard *.c)
C_OBJS = $(C_SRCS:.c=.o)







.cpp.o :
$(CXX) $(CXXFLAGS) -c $<

.c.o :
$(CC) $(CFLAGS) -c $<


Why use Old-Fashioned Suffix Rules (http://www.gnu.org/software/make/manual/make.html#Suffix-Rules)?

I know you are old-school, that is, you are not 30-years old, and so I've noticed that you use these old tricks. Why is that? Perhaps you use a different make at work? Or just an old habit?

I'm just curious, because for new generations it's weird when an experienced programmer gives a suggestion that doesn't seem to agree with the manual.

dwhitney67
October 20th, 2010, 07:24 PM
Wut?

Why use "shell", when you can use "wildcard"?


CPP_SRCS = $(wildcard *.cpp)
CPP_OBJS = $(CPP_SRCS:.cpp=.o)

C_SRCS = $(wildcard *.c)
C_OBJS = $(C_SRCS:.c=.o)



"wildcard" will not work if the source files are scattered in various sub-directories. But "shell find . -name '*.cpp'" will.




Or just an old habit?

I'm just curious, because for new generations it's weird when an experienced programmer gives a suggestion that doesn't seem to agree with the manual.
I am old-school, and too busy to read every technical journal when it is updated. make does have built-in rules, of which some I do take advantage of.

Here's a Makefile template that I use occasionally at home, but not always:


APP = myapp

OBJDIR = .srcobjs

SRCS := $(shell find . -name '*.cpp')
SRCDIRS := $(shell find . -name '*.cpp' -exec dirname {} \; | uniq)
OBJS := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SRCS))
DEPS := $(patsubst %.cpp,$(OBJDIR)/%.d,$(SRCS))

DEBUG = -g
INCLUDES = -I./Include
CPPFLAGS = $(DEBUG) -Wall -pedantic -ansi $(INCLUDES)
LDFLAGS =

SHELL = /bin/bash

.PHONY: all clean distclean

all: buildrepo $(APP)

$(APP) : $(OBJS)
@echo "Building $@..."
@$(CXX) $^ $(LDFLAGS) -o $@

$(OBJDIR)/%.o: %.cpp
@echo "Generating dependencies for $<..."
@$(call make-depend, $<, $@, $(subst .o,.d,$@))
@echo "Compiling $<..."
@$(CXX) $(CPPFLAGS) -c $< -o $@

clean:
$(RM) -r $(OBJDIR)

distclean: clean
$(RM) $(APP)

buildrepo:
@$(call make-repo)

define make-repo
for dir in $(SRCDIRS); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
endef


# usage: $(call make-depend, SourceFile, ObjectFile, DependFile)
define make-depend
$(CXX) -MM -MF $3 -MP -MT $2 $(CPPFLAGS) $1
endef

ifneq "$(MAKECMDGOALS)" "distclean"
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEPS)
endif
endif

dwhitney67
October 20th, 2010, 07:27 PM
I get this error...

You need to sort out the #include directives in your source code; they should be not be using relative paths. In other words, if you are including a header file, and you precede the header file name with a "../" or some other combination similar to that, remove it. The whole purpose of the -I compiler flag is to mitigate the use of relative paths.

DuneSoldier
October 20th, 2010, 08:04 PM
I also have a copy of the OpenGL Superbible. The source code is a little bit strange if I recall correctly. They do something like:

Source
Windows
Mac
Linux

With the projects, Makefiles, ect under the OS Specific directories and all pointing back to the same Source directory.

http://www.opengl.org/sdk/docs/books/SuperBible/

Vox754
October 20th, 2010, 09:11 PM
"wildcard" will not work if the source files are scattered in various sub-directories. But "shell find . -name '*.cpp'" will.

But of course it will. With "shell" you can run, well, any shell command. However, the original post wasn't about finding all the source files in the subdirectories.

My point was that, in general, it's better to use the proper make functions, instead of calling external utilities. It's essentially the same discussion as the typical "for" loop and shell expansion:


# bad
for i in `ls *.c` ; do
echo "$i"
done

# good
for i in *.c ; do
echo "$i"
done

But anyways, in this simple example using "wildcard" or "shell ls" isn't going to be a big difference... unless the *.c files contain spaces? Perhaps.



I am old-school, and too busy to read every technical journal when it is updated. make does have built-in rules, of which some I do take advantage of.

I don't mean reading any journals. I just mean reading the current manual.



Here's a Makefile template that I use occasionally at home, but not always:

I recall you have posted templates before, some of them which have the old style


.o.c :

instead of the new style


%.o : %.c :

Of course they work, only the current manual uses a different style.

By the way, one thing that irks me is when the manual lies, such as with the "define" statement: Defining Multi-Line Variables (http://www.gnu.org/software/make/manual/make.html#Multi_002dLine)

This doesn't work!


define example =
echo $<
endef


But this does


define example
echo $<
endef

dwhitney67
October 20th, 2010, 10:16 PM
But of course it will.
Ok, you are correct. The following will work:


SRCS := $(wildcard */*.cpp)

How would I go about using something similar to extract only the directory names from the results? In other words, how can I simplify:


SRCDIRS := $(shell find . -name '*.cpp' -exec dirname {} \; | uniq)

Also, if there is a better way to build a project whose source code resides in multiple directories, then please let me know how I can re-factor that Makefile I posted that uses the "find".

Vox754
October 21st, 2010, 02:17 AM
...
How would I go about using something similar to extract only the directory names from the results? In other words, how can I simplify:


SRCDIRS := $(shell find . -name '*.cpp' -exec dirname {} \; | uniq)

Also, if there is a better way to build a project whose source code resides in multiple directories, then please let me know how I can re-factor that Makefile I posted that uses the "find".
Unfortunately I'm not a make expert. I don't have the experience of messing with complicated code organization, I've just read the manual, but haven't tested most of this stuff.

To obtain the directories you could use the "$(dir names...)" function.
But I don't know if there is an easy way to implement the "uniq" function. You'd have to iterate over the directories and remove duplicates?


SRC := $(wildcard */*.cpp)
SRCDIRS := $(dir $(SRC))
SRCDIRS := $(magic $(SRCDIRS))


But does it matter? Is it an error to have the same dependency twice in a rule?

You are using "mkdir -p", so it won't error anyway. Although it could become a problem if you have hundreds of *.cpp files, and thus hundreds of repeated directories. Let's hope someone more knowledgeable finds this thread.