I am new to Makefiles and I have trouble with an undefined reference to a function. The directory structure is the following:
├── linkedlist.cc
├── linkedlist.h
│ ├── src
│ │ ├── main.cc
│ │ ├── removeduplicates.cc
│ │ ├── removeduplicates_unittest.cc
│ └── test
│ ├── Makefile
removeduplicates.cc and removeduplicates_unittest.cc import the declarations from linkedlist.h and the definitions from linkedlist.cc. Also removeduplicates.cc defines new functions that are declared in linkedlist.h but not defined in linkedlist.cc.
The sample Makefile file that uses GTest is taken from the GTest example in the repo and looks like the following. It is only modified to include the files above.
# A sample Makefile for building Google Test and using it in user
# tests. Please tweak it to suit your environment and project. You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.
# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = ../../../GMOCK_ROOT/GTEST_DIR/googletest/
# Where to find user code.
USER_DIR = ../src
BASE_DIR = ../..
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -isystem $(GTEST_DIR)/include
# Flags passed to the C++ compiler.
CXXFLAGS += -I.. -std=c++17 -g -Wall -Wextra -pthread
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = removeduplicates_unittest
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
# House-keeping build targets.
all : $(TESTS)
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o
# Builds gtest.a and gtest_main.a.
# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc
gtest_main.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest_main.cc
gtest.a : gtest-all.o
$(AR) $(ARFLAGS) $# $^
gtest_main.a : gtest-all.o gtest_main.o
$(AR) $(ARFLAGS) $# $^
# Builds a sample test. A test should link with either gtest.a or
# gtest_main.a, depending on whether it defines its own main()
# function.
removeduplicates.o : $(USER_DIR)/removeduplicates.cc $(BASE_DIR)/linkedlist.h $(BASE_DIR)/linkedlist.cc $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(BASE_DIR)/linkedlist.cc $(USER_DIR)/removeduplicates.cc
removeduplicates_unittest.o : $(USER_DIR)/removeduplicates_unittest.cc $(BASE_DIR)/linkedlist.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/removeduplicates_unittest.cc
removeduplicates_unittest : removeduplicates.o removeduplicates_unittest.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $#
I think the error comes from this line but I'm not sure how to modify it:
CXXFLAGS += -I.. -std=c++17 -g -Wall -Wextra -pthread
The error I get (among others similar) is:
/RemoveDuplicates/test/../src/removeduplicates_unittest.cc:10: undefined reference to `LinkedList::LinkedList(std::initializer_list<int>)'
Anyone knows what am I doing wrong?
EDIT1: I followed the suggestion given by #Some programmer dude but now I have functions that are defined multiple times:
g++ -isystem ../../../GMOCK_ROOT/GTEST_DIR/googletest//include -I.. -std=c++17 -g -Wall -Wextra -pthread -lpthread removeduplicates.o removeduplicates_unittest.o ../../linkedlist.o gtest_main.a -o removeduplicates_unittest
../../linkedlist.o: In function `_start':
(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.text+0x0): first defined here
../../linkedlist.o: In function `_fini':
(.fini+0x0): multiple definition of `_fini'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o:(.fini+0x0): first defined here
../../linkedlist.o:(.rodata+0x0): multiple definition of `_IO_stdin_used'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.rodata.cst4+0x0): first defined here
../../linkedlist.o: In function `data_start':
(.data+0x0): multiple definition of `__data_start'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:(.data+0x0): first defined here
../../linkedlist.o: In function `data_start':
(.data+0x8): multiple definition of `__dso_handle'
/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o:(.data+0x0): first defined here
../../linkedlist.o: In function `_init':
(.init+0x0): multiple definition of `_init'
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o:(.init+0x0): first defined here
/usr/lib/gcc/x86_64-linux-gnu/5/crtend.o:(.tm_clone_table+0x0): multiple definition of `__TMC_END__'
../../linkedlist.o:(.data+0x10): first defined here
/usr/bin/ld: error in ../../linkedlist.o(.eh_frame); no .eh_frame_hdr table will be created.
collect2: error: ld returned 1 exit status
Makefile:82: recipe for target 'removeduplicates_unittest' failed
make: *** [removeduplicates_unittest] Error 1
At the end of your Makefile you have the dependencies for the test you're building. The last of those, where you list the test executable removeduplicates_unittest you need to list the object file $(BASE_DIR)/linkedlist.o as well:
# Added this dependency
# vvvvvvvvvvvvvvvvvvvvvvvv
removeduplicates_unittest : removeduplicates.o removeduplicates_unittest.o $(BASE_DIR)/linkedlist.o gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $#
That will lead to the linkedlist.o file being linked into the executable.
Related
I am following along with the LLVM Kaleidoscope Tutorial (Ch. 3), and am encountering errors (undoubtedly from my Makefile) after attempting to link LLVM IR libraries. My Makefile and project structure:
CPP=clang++
CFLAGS=-g -Wall -std=c++14
LDFLAGS:=$(shell llvm-config --cxxflags --ldflags --system-libs --libs core)
EXEC=comp.out
SRCS:=$(shell find src -type f -name '*.cpp')
OBJS:=$(patsubst %.cpp,%.o,$(SRCS))
all: $(EXEC)
$(EXEC): $(OBJS)
$(CPP) $(CFLAGS) -o $# $^
src/%.o: src/%.cpp
$(CPP) $(CFLAGS) $(LDFLAGS) -o $# $<
src/ast/%.o: src/ast/%.cpp
$(CPP) $(CFLAGS) $(LDFLAGS) -o $# $<
.PHONY: clean
clean:
rm -f $(shell find src -type f -name '*.o')
rm -f $(EXEC)
.
└── src
├── main.cpp
├── [.cpp files]
│
├── ast
│ ├── [.cpp files]
│ │
│ └── include
│ └── [.h files]
│
└── include
└── [.h files]
When Making, I get the error:
clang++ -g -Wall -std=c++14 -I/usr/local/Cellar/llvm/12.0.1/include -std=c++14 -stdlib=libc++ -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -L/usr/local/Cellar/llvm/12.0.1/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-12 src/IMRep.cpp -o src/IMRep.o
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:19: src/IMRep.o] Error 1
From the error above, main.cpp is never compiled before compilation errors out. It only gets to the src/IMRep.cpp file (not sure if that matters). If I add the -c flag to make it:
src/%.o: src/%.cpp
$(CPP) $(CFLAGS) $(LDFLAGS) -c $< -o $#
src/ast/%.o: src/ast/%.cpp
$(CPP) $(CFLAGS) $(LDFLAGS) -c $< -o $#
I am able to run the program successfully despite the plethora of warning messages saying the linker inputs/arguments are unused. These warnings are expected because -c only compiles and doesn't link.
And in main.cpp:
#include <iostream>
int main(int argc, char *argv[])
{
return 0;
}
So this question doesn't get flagged as a dupe:
[1]: main.cpp is included in OBJS
[2]: Added -c flag and receive many warnings about unused linker arguments/input (because -c is for compilation, not linkage)
[3]: I only use $< where there is one dependency and $^ where there are multiple
[4]: Can't apply the answer to this question
[5]: All files in SRCS and OBJS are the correct files. I verified this by making a 'verbose' rule and printing those values and make verbose
Which leads me to believe that I am not linking in these libraries correctly.
Your question is, in fact, a duplicate of the #2 answer there.
When you want to create an object file you MUST use the -c option. That's what the -c option means.
If you don't want "a plethora of warning messages saying the linker inputs/arguments are unused" then, you know, don't add the linker inputs and arguments when you generate object files! Those arguments are for linking, not compiling.
Your .o rules should be:
src/%.o: src/%.cpp
$(CPP) $(CFLAGS) -c $< -o $#
src/ast/%.o: src/ast/%.cpp
$(CPP) $(CFLAGS) -c $< -o $#
Just to point out you don't need both of the above pattern rules. If you want the object files to live in the same directory as the source files you can just write:
%.o: %.cpp
$(CPP) $(CFLAGS) -c $< -o $#
And, if you switched to using the standard make variables instead of using non-standard ones:
# CPP is the C preprocessor, not C++
CXX = clang++
# CFLAGS is flags for the C compiler, not C++
CXXFLAGS := -g -Wall -std=c++14 $(shell llvm-config --cxxflags core)
LDFLAGS := $(shell llvm-config --ldflags --system-libs --libs core)
then you wouldn't need to define your own pattern rule at all because make has a built-in rule which knows how to compile a C++ source file into an object file.
I have a project for school and I want to write a Makefile, I have seen some examples of using Makefile with multiple source directories and multiple executables but still could not implement it properly to my Makefile.
PS: I'm using doctest for the unit testing (and I can't change it).
Here is the project structure (and I can't change it):
.
├── bin
├── build
├── extern
│ └── doctest.h
├── include
│ ├── file1.hpp
│ └── file2.hpp
├── src
│ ├── file1.cpp
│ └── file2.cpp
├── tests
│ ├── file1-test.cpp
│ └── file2-test.cpp
└── Makefile
I have the following directories:
bin: for all the executables.
build: for all the objects (.o).
extern: for the doctest header (this is where I would have stored any other library)
include: for all the headers (.hpp).
src: for all the classes (.cpp).
tests: for all the unit tests (also .cpp)
You can see file1.cpp as a class, file1.hpp as the class header and file1-test.cpp as the unit tests for the class.
In the exemple above I have 2 tests files but at the very end of the project I'll have a lot more, and for each test file I'll have an executable.
My goals:
I want to run make and compile all the units tests (all the .cpp in the tests/ directory).
And I want all the executables to be stored in the bin/ directory and all the binary files in the build/ directory.
Here is my Makefile:
BIN_DIR = ./bin/
BUILD_DIR = ./build/
EXTERN_DIR = ./extern/
INCLUDE_DIR = ./include/
SOURCE_DIR = ./src/
TESTS_DIR = ./tests/
vpath %.cpp $(SOURCE_DIR) $(TESTS_DIR)
CXX = clang++
CXXFLAGS = -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR)
EXEC_FILES = file1-test file2-test
BIN = $(addprefix $(BIN_DIR), $(EXEC_FILES))
all: $(BIN) | $(BIN_DIR)
$(BUILD_DIR)%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -c -o $# $^
$(BIN_DIR) $(BUILD_DIR):
mkdir -p $#
$(BIN_DIR)file1-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file1-test.o
$(CXX) -o $# $^
$(BIN_DIR)file2-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file2.o $(BUILD_DIR)file2-test.o
$(CXX) -o $# $^
clean:
-rm -f $(BIN_DIR)* $(BUILD_DIR)*
It's working well but I feel like it's doing redondant stuff that i could avoid with more knownledge in the Makefile art, especially here:
$(BIN_DIR)file1-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file1-test.o
$(CXX) -o $# $^
$(BIN_DIR)file2-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file2.o $(BUILD_DIR)file2-test.o
$(CXX) -o $# $^
For the moment this Makefile is correct because I only have 2 executables, but I'll end up with 15+ and I dont want to have 15 times this for each executable:
$(BIN_DIR)xxx-test: $(BUILD_DIR)xxx.o etc.
$(CXX) -o $# $^
What I exactly need ...:
Basically, I need to write a generic rule that will fetch all the appropriated dependencies for a given target.
After reading multiple posts I think it's all about auto-dependencies.
I'm pretty sure the final result would look like this, but sadly I can't make it works in my case:
$(BIN_DIR)%: ???
#$(CXX) -o $# $^
I already looked at this (and many other posts about the subject): http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/, but I still can't figure it out.
So how can I write an expression that will do the job, can someone give me a working exemple or something similar ?
EDIT 1:
Based on this post: Makefile (Auto-Dependency Generation).
I added these lines to my Makefile:
SRC = $(wildcard $(SOURCE_DIR)*.cpp)
SRC += $(wildcard $(TESTS_DIR)*.cpp)
The idea is to fetch all the .cpp from the source directories (src and tests). Then I added -MDD option to my CXXFLAGS variable to create a .d file for each target (atleast it's what I thought it's doing):
CXXFLAGS = -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR) -MMD
And finally, I added this:
$(BIN_DIR)%: $(SRC)
$(CXX) -o $# $^
-include $(SRC:.cpp=.d)
What I expect it to do:
Create a .d file with all the dependencies for each target.
Fetch the dependencies in the .d file and transform them to .o to get all the objects needed for the given target.
But it seems that it's not doing what I'm expecting.
EDIT 3:
After some changes I end up with this Makefile:
BIN_DIR := bin/
BUILD_DIR := build/
EXTERN_DIR := extern/
INCLUDE_DIR := include/
SOURCE_DIR := src/
TESTS_DIR := tests/
DEP_DIR := .dep/
DEPENDS := $(patsubst %.o, $(BUILD_DIR)$(DEP_DIR)%.d, $(notdir $(wildcard $(BUILD_DIR)*.o)))
EXE := $(addprefix $(BIN_DIR), Coord-test Fourmi-test)
OBJS_1 := $(addprefix $(BUILD_DIR), Coord.o)
OBJS_2 := $(addprefix $(BUILD_DIR), Coord.o Fourmi.o)
CXX := clang++
CXXFLAGS := -Wall -std=c++11 -g -O3 -I$(INCLUDE_DIR) -I$(EXTERN_DIR)
vpath %.cpp $(SOURCE_DIR) $(TESTS_DIR)
all: $(EXE)
$(BUILD_DIR):
mkdir -p $# $#/$(DEP_DIR)
$(BIN_DIR):
mkdir -p $#
$(BUILD_DIR)%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -MMD -MP -MF $(BUILD_DIR)$(DEP_DIR)$(notdir $(basename $#).d) -c $< -o $#
$(BIN_DIR)%: $(BUILD_DIR)%.o | $(BIN_DIR)
$(CXX) -o $# $^
$(BIN_DIR)Coord-test: $(OBJS_1)
$(BIN_DIR)Fourmi-test: $(OBJS_2)
.PRECIOUS: $(BUILD_DIR)%.o
-include $(DEPENDS)
clean:
-rm -f $(BIN_DIR)* $(BUILD_DIR)* $(BUILD_DIR)$(DEP_DIR)*
It's working but I'll have to add OBS_X for each new executable.
I also wanted factorize this, but I don't know if it's possible ? If someone could tell me.
$(BIN_DIR)%: $(BUILD_DIR)%.o | $(BIN_DIR)
$(CXX) -o $# $^
$(BIN_DIR)Coord-test: $(OBJS_1)
$(BIN_DIR)Fourmi-test: $(OBJS_2)
Since you know that you will always have a foo-test.o to build a foo-test program, you can write your pattern rule like this:
$(BIN_DIR)%: $(BUILD_DIR)%.o
$(CXX) -o $# $^
However, there's no way make can infer what OTHER objects might be needed to build these executables. You'll just have to tell it. So for the above examples you can add this:
$(BIN_DIR)file1-test: $(BUILD_DIR)file1.o
$(BIN_DIR)file2-test: $(BUILD_DIR)file1.o $(BUILD_DIR)file2.o
You don't need to put the recipe here, this is just adding more prerequisites to these targets. You also don't have to put in the $(BUILD_DIR)file1-test.o etc. because this is inferred from the pattern rule.
But, if you do have other object files you need to use you'll have to list them explicitly, there's no way around it.
I'm trying to use makefile for compilation of project in C++, it works fine while I have only main.cpp, but once I add somethink more it break and I can't figure out why. Notice that it even doesn't recognize main.
The error image (maybe better for reading):
The error text (just in case):
make --jobs=9 build
mkdir -p "./dist" "./dist/obj"
g++ -std=c++17 -o dist/a.out dist/obj/hh.o dist/obj/main.o
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::b()':
hh.cpp:(.text+0xc): multiple definition of `hh::b()'
dist/obj/hh.o:hh.cpp:(.text+0xc): first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [dist/a.out] Error 1
Makefile:12: recipe for target 'dist/a.out' failed
project structure
root
├───.idea
├───assets
├───dist
│ └───obj
├───doc
├───examples
└───src
My Makefile looks like this
COMPILER :=g++
CPPFLAGS :=-std=c++17
DIRS :=./dist
BUILD_DIR :=./dist
OBJS_DIR :=$(BUILD_DIR)/obj
SRC_DIR :=./src
EXEC_FILE :=a.out
# names of obj files (.o gets added later)
OBJS :=hh main
# uses linker to link everythink together
# using functions addsuffix and addprefix adding path and .o to the name of object
# files specified in variable OBJS
$(BUILD_DIR)/$(EXEC_FILE): $(addsuffix .o, $(addprefix $(OBJS_DIR)/, $(OBJS)))
$(COMPILER) $(CPPFLAGS) -o $# $^
# recipe for any file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $#
# recipe for any nested file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $#
# generates dependecies into Makefile.d
deps:
$(COMPILER) -MM $(SRC_DIR)/*.cpp > Makefile.d
-include Makefile.d
# Callable "scripts" for my IDE
.PHONY: dir_struct, clean, all, rebuild, build
all: dir_struct $(BUILD_DIR)/$(EXEC_FILE)
build: all
rebuild: clean dir_struct all
clean:
rm -r dist
dir_struct:
mkdir -p "$(BUILD_DIR)" "$(OBJS_DIR)"
just some dummy code only for testing
// main.cpp
#include "hh.h"
int main() {
hh g;
g.b();
return 0;
}
.
// hh.cpp
#include "hh.h"
hh::hh() = default;
void hh::b() {}
.
#ifndef HH_H
#define HH_H
class hh {
public:
hh();
void b();
};
#endif //HH_H
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $#
Here you use a wildcard to compile all object files using all cpp files as dependencies. This results every .o file containing only the definitions of the first cpp file listed by $(SRC_DIR)/*.cpp resulting in the name conflict.
Instead of doing this you should create .o files containing only symbols from the corresponding cpp file:
$(OBJS_DIR)/%.o: $(SRC_DIR)/%.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $#
I have a somewhat complicated source directory, and have written a makefile to compile it:
├── include
│ ├── subinc
│ │ ├── test_y.h
│ │ └── test_z.h
│ ├── test_w.h
│ └── test_x.h
├── makefile
├── src
│ ├── test_w.cpp
│ └── test_x.cpp
├── src2
│ ├── test_y.cpp
│ └── test_z.cpp
└── test.cpp
The makefile as shown below is working. But, I'm a bit confused why. It doesn't seem to be using $(DEPS), since it gives paths like ./include/./include/subinc/test_y.h when I echo it in the rule. That's obvious because of the patsubst line, but changing that to patsubst %,%,$(INCLUDES) breaks it too... (maybe that's the root of the whole problem!)
But, something funky happens when I remove that constant from the dependency list of the rule %.o, so the rule is just %.o: $(SOURCES). Upon running make, it uses the first item in $(SOURCES) as the target for every call to g++ creating object files:
$ make
g++ -c -o test.o test.cpp -I./include -I./include/subinc
g++ -c -o src/test_x.o test.cpp -I./include -I./include/subinc
g++ -c -o src/test_w.o test.cpp -I./include -I./include/subinc
g++ -c -o src2/test_z.o test.cpp -I./include -I./include/subinc
g++ -c -o src2/test_y.o test.cpp -I./include -I./include/subinc
I figured that makes sense, because $< is used.
But why does this only print the first in the dependency list when I take the second constant (of header files -- some even with bad format) out of the list?
My thought is that somehow make is intelligently matching the .cpp files in the list to the corresponding .h files in the list, and then removing them from the list each time it runs the rule....
Thanks
Makefile (working version, maybe full of bad practices...)
INCDIR=./include
SRCDIR=./src
CXX=g++
CXXFLAGS=-I$(INCDIR) -I$(INCDIR)/subinc
INCLUDES=$(shell find . -name "*.h" -o -name "*.hpp")
DEPS = $(patsubst %,$(INCDIR)/%,$(INCLUDES))
EXE=testexe
SOURCES=$(wildcard *.cpp) $(wildcard **/*.cpp)
OBJ=$(SOURCES:.cpp=.o)
####RULES
%.o: $(SOURCES) $(DEPS)
$(CXX) -c -o $# $< $(CXXFLAGS)
$(EXE): $(OBJ)
g++ -o $# $^ $(CXXFLAGS)
rm $(OBJ)
EDIT
If you'd like an MCVE for this, each test_*.h defines an empty class like
class T*{
T*(); //defined in test_*.cpp to print "T* created"
~T*(); //defined in test_*.cpp to print "T* destroyed"
};
And the main test.cpp file just creates a pointer to each of the classes, and then deletes it.
There are many issues here. First:
SOURCES=$(wildcard *.cpp) $(wildcard **/*.cpp)
GNU make uses simple globbing, which does not understand **. This behaves the same as *. Since you only have one level of subdirectory this works for you but if you add another (sub-subdirectory) level, this won't match it.
Second, this is wrong:
DEPS = $(patsubst %,$(INCDIR)/%,$(INCLUDES))
As you point out this changes the dependency paths from the (correct) ./include/xy/z.h to the (incorrect) ./include/./include/xy/z.h. I'm not sure why you're trying to change anything at all here: why not just use the INCLUDES variable content directly? Using $(patsubst %,%,$(INCLUDES)) is a no-op; it has no effect.
Third, you should be using simple expansion (:=) for these types of assignments, so that they are not rerun every time the variable is used.
Next, this is wrong:
%.o: $(SOURCES) $(DEPS)
$(CXX) -c -o $# $< $(CXXFLAGS)
This will expand to something like this after SOURCES are resolved:
%.o: test.cpp src/test_w.cpp src/test_x.cpp src2/test_y.cpp src2/test_z.cpp ./include/include/subinc/test_y.h $(DEPS)
$(CXX) -c -o $# $< $(CXXFLAGS)
What this means is that every object file depends on all source files (and all $(DEPS)). So if any source or header file ever changes ALL the object files will be rebuilt. Clearly that's not what you want.
Also, the reason it always compiles the same file is that the recipe uses $<, which represents the first prerequisite, and the first prerequisite here is test.cpp, so that's what's always compiled.
When you create a pattern rule, (at least) the first source file should (almost always) be a pattern as well, so that it changes along with the target to build each object file (in this case).
So, you want your pattern rule to look like this:
%.o: %.cpp $(INCLUDES)
$(CXX) -c -o $# $< $(CXXFLAGS)
Of course this does mean that every object file depends on all header files, so if you change any header file all your object files are rebuilt. Maybe that's OK; if not you'll need to do something more advanced.
Lastly, you asked why it your makefile seems to work properly if you create bogus paths in the $(DEPS) variable. Here's why: because those paths don't exist, make decides that your pattern rule doesn't apply (since not all the prerequisites can be created) and so it ignores your pattern rule completely.
Once that happens, make's default pattern rule for how to build an object file takes over, and that default rule builds things for you properly. However, you may notice that if you modify any of the header files, make won't rebuild your object files (because it doesn't know about that prerequisite relationship).
I have 2 directories in my project, one called Builds, who has the Makefile and a test program ( test-P0-consola.cpp ) and other one directory called P0 who constains the classes I use, cadena (string) and fecha (date).
test-P0-consola.cpp includes both of them, but Make doesn't find them.
CPP = g++
CPPFLAGS = -std=c++14 -g -Wall -pedantic
VPATH = ../P0:.:..
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} -o $#.ex $^
test-P0-consola.o: test-P0-consola.cpp fecha.hpp cadena.hpp
${CPP} -c ${CPPFLAGS} $< -o $#
fecha.o: fecha.hpp
cadena.o: cadena.hpp
It throws the fatal error "cadena.hpp doesn't exist the file or directory" when it tries to compile test-P0-consola.o, but It find them out when I force it to compile cadena or fecha. I'm using GCC and Ubuntu.
..
├── Builds
│ ├── makefile.mak
│ └── test-P0-consola.cpp
├── P0
│ ├── cadena.cpp
│ ├── cadena.hpp
│ ├── fecha.cpp
│ └── fecha.hpp
EDIT
Error:
g++ -std=c++14 -g -Wall -pedantic -c test-P0-consola.cpp
test-P0-consola.cpp:7:21: fatal error: fecha.hpp: There is no file or directory
compilation terminated.
makefile.mak:9: Failure in the instructions for the objective 'test-P0-consola.o'
make: *** [test-P0-consola.o] Error 1
Look closely at your error:
test-P0-consola.cpp:7:21: fatal error: fecha.hpp: There is no file or directory
You probably have something like:
// test-P0-consola.cpp
#include "fetcha.hpp"
But fetcha.hpp is not in that directory, so it can't find it. You either need to change the way you include the file directly (via #include "../P0/fetcha.hpp") or to change the build rule to pass in an additional include path (via -I../P0).
Note: I'm not sure there's a reason to add . to VPATH. That's kind of implicit.
Note 2: this is a bad idea:
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} -o $#.ex $^
~~~~~
Don't lie to Make. The result of running a recipe should be the target file, except for PHONY targets. The recipe here should be -o $#. If you want the .ex suffix, you should change the target to be test-consola.ex. If you still want the rule to be named test-consola, you'll want:
test-consola : test-consola.ex
test-consola : .PHONY
You should put in the makefile the include path of the .hpp files you need the compiler to use. You should use the -Ipath compiler directive, where path is the path of your include files.
See `Makefile: How to correctly include header file and its directory?
and
How to define several include path in Makefile
Something like:
CPP = g++
CPPFLAGS = -std=c++14 -g -Wall -pedantic
INC = -Iyourincludebasepath/P0
VPATH = ../P0:.:..
test-consola: test-P0-consola.o fecha.o cadena.o
${CPP} ${CPPFLAGS} ${INC} -o $#.ex $^
test-P0-consola.o: test-P0-consola.cpp fecha.hpp cadena.hpp
${CPP} -c ${CPPFLAGS} ${INC} $< -o $#
fecha.o: fecha.hpp
cadena.o: cadena.hpp