1

Edit

After writing this I noticed some things and went back over the file. I changed the line:

$(CXX) -MT $(BUILD_DIR)/$(@:.d=.o) -MM $(CXXFLAGS) $^ > $@

To the following:

$(CXX) -MM $(CXXFLAGS) $^ > $@

Since it seemed kind of redundant to first take the generated dependency files, name them into .o files and then turn them back into .d files.

Now the target actually makes, but it will still not remake when the header files are changed.

Original

I have this makefile I created as part of a course, and everything works fine when running make, building for both the host and target. The problem arises when a change occurs in a header file(example: part1.h), this implementation was made specifically to take this into account, and it seemed to work.

A few weeks on now, and I finally realised it doesn't work as intended, as it will not recompile after a change to any of the header files. (part1.h or part2.h).

I took a look into the dependency files generated by the target:

$(BUILD_DIR)/%.d: %.cpp

An example of part1.d has the following contents:

build/host/build/host/part1.o: part1.cpp part1.h

To me, the double directory listing is an error, but so I tried changing the line:

$(CXX) -MT $(BUILD_DIR)/$(@:.d=.o) -MM $(CXXFLAGS) $^ > $@

To the following, removing the BUILD_DIR variable:

$(CXX) -MT $(@:.d=.o) -MM $(CXXFLAGS) $^ > $@

Doing this solves the double directory listing problem, but gives me a linker error:

build/host/main.o: file not recognized: File format not recognized

I'm trying to find some solution to this, which will make sure that the program is recompiled when changes are made to the header files.

I'm trying to figure out what I'm missing, I've looked at the related literature and everything seems to match up.

SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.o))
DEPS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.d))
EXE=prog
CXXFLAGS=-I.

#Make sure that default choice for make is the host
ifndef (${ARCH})
    ARCH=host
endif

#Making for host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
BIN_DIR=bin/host
endif

# Making for target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
BIN_DIR=bin/target
endif

$(BIN_DIR)/$(EXE): $(DEPS) $(OBJECTS)
    $(CXX) $(CXXFLAGS) -o $@ $(OBJECTS)

#Generate dependency files. Place them in build/host or build/target depending on choice
$(BUILD_DIR)/%.d: %.cpp
    $(CXX) -MT $(BUILD_DIR)/$(@:.d=.o) -MM $(CXXFLAGS) $^ > $@

#Generate object files. Place them in build/host or build/target, depending on choice.
$(BUILD_DIR)/%.o: %.cpp
    $(CXX) -o $@ -c $^

#Create the build dir,
${BUILD_DIR}:
    mkdir -p ${BUILD_DIR}

#Create the bin dir
${BIN_DIR}:
    mkdir -p ${BIN_DIR}


.PHONY:clean
clean:
    rm -f $(BUILD_DIR)/*.o $(BIN_DIR)/$(EXE) $(BUILD_DIR)/*.d

ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
NT93
  • 316
  • 2
  • 15

1 Answers1

1

If you generate the dependencies as part of the compilation not only do you avoid having to take the extra step, you also rely on the compiler to generate the correct paths. This entails a few other changes to your makefile but I found it simpler to just rewrite it, make has a number of features to simplify some of the other operations.

arch ?= host

build_dir := build/$(arch)
bin_dir   := bin/$(arch)

ifeq ($(arch),target)
prefix := arm-devkit-
endif

sources := main.cpp part1.cpp part2.cpp
objects := $(sources:%.cpp=$(build_dir)/%.o)
deps    := $(objects:.o=.d)

target := $(bin_dir)/prog

CXX      := $(prefix)$(CXX)
CPPFLAGS := -MMD -MP

$(target): CC := $(CXX)
$(target): $(objects) | $(bin_dir)
    $(LINK.o) $^ $(LDLIBS) -o $@

$(build_dir)/%.o: %.cpp | $(build_dir)
    $(COMPILE.cpp) $(OUTPUT_OPTION) $<

$(build_dir) $(bin_dir): ; mkdir -p $@

.PHONY: clean
clean: ; $(RM) $(target) $(objects) $(deps)

-include $(deps)
user657267
  • 20,568
  • 5
  • 58
  • 77
  • I accepted your solution, however I'm using a fix I found on the other comment to my post, simply because I'm not confident that I understand exactly what your solution is doing. Since I might be required to explain how my code works, I'll keep using my revised code which might be more lengthy, but I understand all the things happening. I will try to study your code to see how it works, so thank you very much for taking the time to answer. – NT93 Sep 24 '16 at 18:28