yegor256
yegor256

Reputation: 105193

how to place .o files into a separate directory, with Makefile rule

I have the following Makefile rules:

DIR = src
SOURCES = $(shell find $(DIR) -name "*.cpp")
OBJS := $(SOURCES:.cpp=.o)

With this definition all my .o files are located in the same directories (and sub-directories) as their .cpp counterparts. Such allocation principle turns the project directory into a mess very soon (with 50+ files). I would like to make a new specific folder for .o files and place them there. I need to write a make-rule that will convert every .o file name like the following:

foo/bar/test.o —> objects/foo-bar-test.o

How can I create such a rule in Makefile? Thanks in advance!

Upvotes: 4

Views: 12075

Answers (4)

Diego Sevilla
Diego Sevilla

Reputation: 29021

I'm not sure if you can specify patterns with these modification directly, but you always can use macros (at least in GNU make). An example could be this:

define export_rule
objects/$(patsubst %.cpp,%.o,$(subst /,-,$(1))) : $(1)
    <<your rules here>>
endef


SOURCES = $(shell find $(DIR) -name "*.cpp")

$(foreach s,$(SOURCES), $(eval $(call export_rule,$(s))))

This defines the exact rules you want, avoiding (as some solutions proposed above) the name clashes in case two files with the same name reside in different directories.

Upvotes: 3

adamk
adamk

Reputation: 46824

You can try to start with something like this:

DIR = src
SOURCES = $(shell find $(DIR) -name "*.cpp")
OBJS := $(SOURCES:%.cpp=obj/%.o)

obj/%.o: %.cpp
    $(CC) -c -o $@ $^

If you don't want to mess with default build rules (taking Michael Aaron Safyan's advice), you could try to go along the lines of:

DIR = src
SOURCES = $(shell find $(DIR) -name "*.cpp")
ODIR=obj
OBJS:= $(SOURCES:%.cpp=obj/%.o)
CP=cp
MKDIR=mkdir -p

$(ODIR)/%.cpp : %.cpp
    $(MKDIR) $(DIR $@)
    $(CP) $< $@

Which will copy the cpp file to the obj directory before it is compiled there (note that this may cause some problems if you're relying on include files to reside in the same directory of the source file)

Upvotes: 3

anon
anon

Reputation:

I use a rule like this:

$(ODIR)/%.o: $(SDIR)/%.cpp 
    $(CC) -c $(INC) -o $@ $< $(CFLAGS) 

where

ODIR = object file output directory
SDIR = .cpp source file directory
INC = list of -I flags
CFLAGS = the usual

Upvotes: 6

Michael Aaron Safyan
Michael Aaron Safyan

Reputation: 95629

It is generally not a good idea to override the default build rules, as using the defaults leads to greater portability, and changing them can be incredibly fragile (believe me, I've tried to do what you've asked before. It may work for one platform, but then try to cross-compile the library or build it on a different system and you're toast). I have two suggestions for you that you will hopefully find agreeable.

  1. Define a "clean" target that cleans up the mess of ".o" files, or better yet:
  2. Use the C++ Project Template (which uses CMake), which puts ".o" files in a "build" directory.

Upvotes: 3

Related Questions