Reputation: 1740
I have a project that I am trying to create a Makefile for. The folder structure looks like this:
|-- bin
|-- build
|-- Makefile
|-- src
| |-- some_files.cpp
| |-- some_files.h
| |-- ForestFactory
| |-- MMParSet
| |-- century
| |-- century_carbon.cpp
| |-- century_carbon.h
| `-- grass
`-- src_multithread
|-- __history
and I have tried to use this reference to create a Makefile. The Makefile I have is
CC := g++
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
INSTALLBINDIR := /usr/local/bin
TARGET := bin/formind
# CPP files
SOURCES := $(shell find $(SRCDIR) -type f -name *.cpp)
# remove the src path and add the build path and the .o extension
OBJECTS := $(addprefix $(BUILDDIR)/,$(patsubst %.cpp,%.o,$(notdir $(SOURCES))))
CFLAGS := -std=c++11 -stdlib=libc++
INC := -I/usr/local/include -I $(SRCDIR) -I $(SRCDIR)/century -I $(SRCDIR)/grass -I $(SRCDIR)/MMParSet -I $(SRCDIR)/ForestFactory
$(TARGET): $(OBJECTS)
@mkdir -p $(TARGETDIR)
@echo " Linking..."
@echo " $(CC) $^ -o $(TARGET)"
$(CC) $^ -o $(TARGET)
$(BUILDDIR)/%.o: $(SRCDIR)/%.cpp
@mkdir -p $(BUILDDIR)
@echo " $(CC) $(CFLAGS) $(INC) -c -o $@ $<"
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
clean:
@echo " Cleaning...";
@echo " $(RM) -r $(BUILDDIR) $(TARGET)"
$(RM) -r $(BUILDDIR) $(TARGET)
.PHONY: clean
When I try to make
I get the following error message:
make: *** No rule to make target `build/century_carbon.o', needed by `bin/formind'. Stop.
The source files come from a nested set of subdirectories inside src. My understanding was that the OBJECTS
variable should contain the complete paths of the final object files, so that I have something like
$SOURCES = src/century/century_carbon.cpp ... src/for_branching.cpp ... src/grass/grass_log.cpp ...
$OBJECTS = build/century_carbon.o ... build/for_branching.o ... build/grass_log.o ...
Is there something wrong in the way I wrote the compilation rules?
Upvotes: 2
Views: 7282
Reputation: 9952
The problem is with the nested source directory century
. If you add to the makefile:
info:
@echo " Info..."
@echo " SOURCES = $(SOURCES)"
@echo " OBJECTS = $(OBJECTS)"
then make info
gives:
Info...
SOURCES = src/century/century_carbon.cpp src/some_files.cpp
OBJECTS = build/century_carbon.o build/some_files.o
This check shows that your construction of these macros is ok. And it also shows, as you report, that make
will then tell us:
make: *** No rule to make target 'build/century_carbon.o', needed by 'bin/formind'. Stop.
If you add an additional rule, with the directory century
specified:
$(BUILDDIR)/%.o: $(SRCDIR)/century/%.cpp
@mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
then your build will proceed.
An alternative solution is to use VPATH
. Add the line:
VPATH = src:src/century
and also remove $(SRCDIR)/
from your rule, which now becomes:
$(BUILDDIR)/%.o: %.cpp
@mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
Update: The above answer could be improved in two ways:
Use vpath
rather than VPATH
, for more precise control of the searches.
Automatically generate the argument for vpath
/ VPATH
.
This is suprisingly simple: just replace my hard-coded VPATH
line with:
vpath %.cpp $(sort $(dir $(SOURCES)))
Upvotes: 3