Reputation: 885
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
Upvotes: 0
Views: 127
Reputation: 82491
$(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 $@
Upvotes: 1