Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using make to move .o files to a separate directory

I've tried numerous attempts to move my .o files to my obj folder, but no matter what I do, it simply just doesn't work.

Judging from the makefile provided, what is the best method to move .o files to a specified folder?

BIN = bin/
OBJ = obj/
TARGET = opengl_03
DEPS = main.o  displayinit.o initializer.o algorithms.o matrix3f.o window.o vertex3.o
CC = g++
CFLAGS = -g 
LIBS = -lglut -lGLEW -lGL 
INCLUDEPATH = -L/usr/include/ -L/usr/lib/ -L/usr/lib/x86_64-linux-gnu/

$(TARGET) : $(DEPS)
    $(CC) $(CFLAGS) -o $(BIN)$(TARGET) $(DEPS) $(LIBS) $(INCLUDEPATH) 

displayinit.o : displayinit.cpp displayinit.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c displayinit.cpp && mv displayinit.o $(OBJ)displayinit.o
initializer.o : initializer.cpp initializer.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c initializer.cpp $(OBJ)
algorithms.o : algorithms.cpp algorithms.h
    $(CC) -c algorithms.cpp $(OBJ)
matrix3f.o : matrix3f.cpp matrix3f.h
    $(CC) $(LIBS) $(INCLUDEPATH)  -c matrix3f.cpp $(OBJ)
vertex3.o : vertex3.cpp vertex3.h
    $(CC) $(LIBS) $(INCLUDEPATH)  -c vertex3.cpp $(OBJ)
window.o : window.cpp window.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c window.cpp $(OBJ)
main.o : main.cpp
    $(CC) $(LIBS) $(INCLUDEPATH) -c main.cpp $(OBJ)
like image 467
zeboidlund Avatar asked Dec 28 '11 10:12

zeboidlund


2 Answers

To specify where the object is created use -o

window.o : window.cpp window.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c window.cpp -o $(OBJ)/$@

Here is what you could do:

  1. specify the directory where you want the object files to go

    OBJDIR    =   objdir
    
  2. Create a list of object files that need to be compiled, from the list of all .cpp files by replacing .cpp with .o and add the prefix $(OBJDIR)/ to it:

    OBJ = $(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp)))
    

    So your $(OBJ) will look like: objdir/window.o objdir/main.o and so on

  3. Add a target to create the directory if it does not exist:

    $(OBJDIR):
        mkdir $(OBJDIR)
    
  4. Make the directory target before you make your main target:

    all: $(OBJDIR) myapp
    
  5. Rule to compile all the .o object files in $(OBJDIR) from .cpp files in the current directory:

    $(OBJDIR)/%.o: %.cpp
        $(GCC) $(CPPFLAGS) -c $< -o $@
    

    This will result in something like:

    g++ -c main.cpp -o objdir/main.o
    
  6. Your main target is unchanged:

    $(TARGET): $(OBJ)
        $(GCC) $(LDFLAGS) -o $@ $^ 
    

    This will look like:

    g++  -o myapp objdir/window.o objdir/main.o 
    
  7. For completeness add clean target to cleanup objects:

    clean:
        @rm -f $(TARGET) $(wildcard *.o)
        @rm -rf $(OBJDIR) 
    
  8. And define .PHONY targets, e.g. these will be made even if directories or files with the same name exist:

    .PHONY: all clean
    

So it should look like:

OBJDIR    =   objdir
OBJ       =   $(addprefix $(OBJDIR)/, $(patsubst %.cpp, %.o, $(wildcard *.cpp)))
TARGET    =   my app

.PHONY: all clean

all: $(OBJDIR) $(TARGET)

$(OBJDIR):
    mkdir $(OBJDIR)

$(OBJDIR)/%.o: %.cpp
    $(GCC) $(CPPFLAGS) -c $< -o $@

$(TARGET): $(OBJ)
    $(GCC) $(LDFLAGS) -o $@ $^ 

clean:
    @rm -f $(TARGET) $(wildcard *.o)
    @rm -rf $(OBJDIR) 

And if you have files such as main.cpp and a.cpp this is what make would do:

> ls
Makefile a.cpp    main.cpp

> make
mkdir objdir
g++ -I. -c a.cpp -o objdir/a.o
g++ -I. -c main.cpp -o objdir/main.o
g++ -o myapp objdir/a.o objdir/main.o 

> ls
Makefile a.cpp    main.cpp objdir   myapp

> make clean
> ls
Makefile a.cpp    main.cpp

And if you want to read more details about any of the above have a look at GNU make doc page

like image 167
stefanB Avatar answered Nov 03 '22 13:11

stefanB


In response to the comment, some more tips:

1) Remove some redundancy

This part is very repetitive:

displayinit.o : displayinit.cpp displayinit.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c displayinit.cpp && mv displayinit.o $(OBJ)displayinit.o
initializer.o : initializer.cpp initializer.h
    $(CC) $(LIBS) $(INCLUDEPATH) -c initializer.cpp $(OBJ)
algorithms.o : algorithms.cpp algorithms.h
    $(CC) -c algorithms.cpp $(OBJ)
# ...

You can replace it by two parts:

1) a more general rule, something like:

%.o: %.cpp
    $(CC) -c $(LIBS) $(INCLUDEPATH) $< -o $@

$< and $@ are automatic variables, $@ expands to the name of currently built target and $< is the first dependency ($^ would be "all the dependencies", there are more such vars - see the Make manual).

2) any additional deps (i.e. headers):

displayinit.o: displayinit.h
matrix3f.o: matrix3f.h
main.o: main.h window.h displayinit.h

#etc

Note: For each .o file, its dependencies should contain:

  • the .cpp from which it is built (the dependency is from the general rule),
  • all .h files which are included from that .cpp files (which you need to add later).

Note that you omitted the latter part in your original makefile. This would cause you some problems one day.

2) Generate the deps automatically

Basically every time you add an #include in any of your files, you'd need to modify your makefile to reflect the new dependency between .cpp/.o and .h files. This is very troublesome, but fortunately there are automated solutions for that. There are two approaches for C/C++ here:

  • Use your compiler to generate the dependencies for you (gcc/g++ -MM for instance).
  • Use an additional tool such as makedepend.

Either way, you need to include that set of dependencies dynamically in the makefile. This needs some trickery, but once you have it, you never have to worry about dependencies. Have a google for "C++ makefile dependencies", there should be plenty of resources.


Here's a to-the-point doc about Make.

like image 42
Kos Avatar answered Nov 03 '22 14:11

Kos