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 $#
Related
I am quite new to Make. I am attempting to write a Makefile to build a medium-sized Linux C/C++ application as below.
Making a simple Makefile by having all source files in one location and explicitly listing the source files works ok for me but I would like it to be more generic.
I have all my source files (C and C++) in the src folder in different subdirectories. I have header files inside an inc and inc/common folder, and then libs inside a lib folder.
The Makefile is run on the same level :
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
CXX := /bin/arm-linux-gnueabi-g++
EXE := $(BIN_DIR)/runfile
SRC := $(shell find $(SRC_DIR) -name *.cpp -or -name *.c)
OBJ := $(patsubst $(SRC_DIR)/%,$(OBJ_DIR)/%,$(addsuffix .o,$(basename $(SRC))))
CPPFLAGS := -Iinc -Iinc/common -MMD -MP
CXXFLAGS := -std=c++11 -Wall
LDFLAGS := -Llib
LDLIBS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
I get lots of errors such as below when I run it, including problems opening dependency files. I think i'm almost there, but can't see my error exactly :
compilation terminated.
/bin/arm-linux-gnueabi-g++ -Iinc -Iinc/common -MMD -MP -std=c++11 -Wall -c -o obj/main.d.o
cc -Llib obj/main.d.o -o obj/main.d
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: error adding symbols: file in wrong format
I don't see how the output you show can be generated from the makefile you show here but anyway.
This is not right:
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
A pattern rule is a template that tells make "if you want to build a target that matches this pattern, then you can build it from the prerequisites that match this pattern".
Here you are listing ALL your source files as a prerequisite for EVERY object file. Suppose SRC is set to foo.c bar.c biz.c baz.c, then this expands to:
obj/%.o : foo.c bar.c biz.c baz.c | obj
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
You're telling make that every single .o target depends on ALL the source files, not just the one for that object file. Further, the automatic variable $< always expands to the first prerequisite, which here will always be foo.c. So, you're compiling foo.c four times, creating each of the object files.
The very first important rule when debugging makefiles is to look carefully at the output (command lines) that make prints. If they are not right, then your makefile is not right. If you do that you'll see all the compile lines are compiling the same source, like:
g++ -c foo.c -o obj/foo.o
g++ -c foo.c -o obj/bar.o
g++ -c foo.c -o obj/biz.o
g++ -c foo.c -o obj/baz.o
That clearly cannot work and it's why you get link errors trying to link together all these object files: they all have the same content.
You need this:
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
which tells make how to build an object file from a single source file.
You also need to create the actual output directory that the object file will go into. Just creating $(OBJ_DIR) is not enough, if the object file appears in a subdirectory.
I have the following directory structure (on Ubuntu):
MyProject/
Here is my Makefile
MyProject/src/headers
Here are more subfolders and .hpp files
MyProject/src/sources
Here are two .cpp files (main.cpp and another.cpp)
So I have used this tutorial to write my makefile, that looks like this:
cppsrc = $(wildcard src/sources/*.cpp)
obj = $(cppsrc:.cpp=.o)
flags = -I/usr/include/boost_1_72_0/ -pthread
cross: $(obj)
i686-atom-linux-gnu-g++ -o $# $^ $(flags)
It detects the .cpp file in the subdirectory (yay!).
But it does not detect the header files included in the .cpp file. So I have included the header in another.cpp like this:
#include "src/headers/another.hpp"
The command make cross gives me this error message:
g++ -c -o src/sources/another.o src/sources/another.cpp
src/sources/another.cpp:6:10: fatal error: src/headers/another.hpp: No such file or directory
#include "src/headers/another.hpp"
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
<builtin>: recipe for target 'src/sources/another.o' failed
make: *** [src/sources/another.o] Error 1
The error message makes me believe that makeapp looks for the header file in a position like this:
MyProject/src/sources/src/headers/
Is my assumption correct? What can I do to solve this?
Hope that someone will be able to help me. Thank you in advance.
You forgot to tell your compiler to look in the local directory (-I.), but there is a more serious problem: you are compiling your files with the HOST compiler and linking them together with a CROSS compiler. This will result in errors.
To fix it, you need to set variables used in the default COMPILE.cc rule, defined as follows:
COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
%.o: %.cpp
# commands to execute (built-in):
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
So in your case:
CXX = i686-atom-linux-gnu-g++
CXXFLAGS += -I. -I/usr/include/boost_1_72_0/
LDFLAGS += -lpthread
cppsrc = $(wildcard src/sources/*.cpp)
obj = $(cppsrc:.cpp=.o)
cross: $(obj)
$(CXX) -o $# $^ $(LDFLAGS)
I have a file ./src/test.cpp:
#include "test.h"
void Hi() {
std::cout << "Hi, indeed..." << std::endl;
}
test.h is located in ./include folder.
This is my makefile:
CC = g++
CFLAGS = -Wall
INCLUDES = -I./include
SRCS = $(shell find ./src/ -name '*.cpp')
.PHONY: clean depend
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
release: $(OBJS)
$(CC) $(CFLAGS) -o app_name $(OBJS)
VPATH = ./src
../%.o: %.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c $*.cpp
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ > ./.depend;
include .depend
As a result I get an error:
g++ -c -o test.o ./src/test.cpp
./src/test.cpp:1:18: fatal error: test.h: No such file or directory
compilation terminated.
<builtin>: recipe for target 'test.o' failed
make: *** [test.o] Error 1
Also the file .depend is completely empty.
How to resolve the issue? The makefile is in root directory:
./
makefile
./src/
test.cpp
main.cpp
./include/
test.h
What G.M. is trying to say is that you have defined a pattern rule that knows how to build a target matching a pattern ../%.o. But, when you ask make to build objects, they are of the form ./xxx.o; e.g., after:
SRCS = $(shell find ./src/ -name '*.cpp')
suppose SRCS contains ./src/foo.cpp. Now after this:
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
OBJS will contain the value ./foo.o (by the way, a simpler way to get this behavior is to use the patsubst function: $(patsubst ./src/%.cpp,./%.o,$(SRCS))).
So, make will try to build the file ./foo.o. Since there's no explicit rule for this it will look for an implicit rule.
It sees your pattern rule, but that says how to build ../%.o which does not match the object file make wants to build ./foo.o, so your rule is ignored.
Then make will go look for some other implicit rules and it will find the built-in rule that knows how to build a .o file from a .cpp file, and it will use that. That rule doesn't use your variable $(INCLUDES), so your compile fails.
You need to either fix your OBJS settings to create filenames like ../foo.o instead of ./foo.o, if you really want your object files to appear in the parent directory, or else change your pattern rule to build %.o not ../%.o.
I'm just learning GNU make, but I'm having trouble linking when using .d (dependency) files. Can anyone point me in the right direction with this error:
...../part1.o: file not recognized: File truncated
recipe for target 'bin/target/prog' failed
It's a simple program containing: main.cpp, part1.cpp, part1.h, part2.cpp, part2.h
Where part1 and part2 have a method to print something.
This is from terminal when running make:
I don't get why I'm getting a warning for using #pragma once?
stud#GoldenImageASE:~/Desktop/ISU/L1/2$ make ARCH=target -f Makefile.th
Compiling...part2.cpp
arm-devkit-g++ -MTbuild/target/part2.o -MM -I. part2.cpp > build/target/part2.d
Compiling...part1.cpp
arm-devkit-g++ -MTbuild/target/part1.o -MM -I. part1.cpp > build/target/part1.d
Compiling...main.cpp
arm-devkit-g++ -MTbuild/target/main.o -MM -I. main.cpp > build/target/main.d
object file....main.o
arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o
part1.h:1:9: warning: #pragma once in main file
#pragma once
^
part2.h:1:9: warning: #pragma once in main file
#pragma once
^
object file....part1.o
arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o
object file....part2.o
arm-devkit-g++ -I. -c part2.cpp > build/target/part2.o
arm-devkit-g++ -I. -o build/target/main.o build/target/part1.o build/target/part2.o -o prog
build/target/part1.o: file not recognized: File truncated
collect2: error: ld returned 1 exit status
Makefile.th:27: recipe for target 'bin/target/prog' failed
make: *** [bin/target/prog] Error 1
My Makefile is found below:
# Variables
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
EXE=prog
CXXFLAGS =-I.
# Making for host
# > make ARCH=host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
EXE_DIR=bin/host
endif
# Making for target
# > make ARCH= target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
EXE_DIR=bin/target
endif
$(addprefix ${EXE_DIR}/,$(EXE)): $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))
# << Check the $(DEPS) new dependency
#mkdir -p $(dir $#)
$(CXX) $(CXXFLAGS) -o $(addprefix ${BUILD_DIR}/,$(OBJECTS))
$(addprefix $(BUILD_DIR)/, %.o): %.cpp
#echo "object file...."$*.o
$(CXX) $(CXXFLAGS) -c $^ > $#
# Rule that describes how a .d ( dependency ) file is created from a .cpp
# Similar to the assigment %. cpp -> %.o
${BUILD_DIR}/%.d: %.cpp
#mkdir -p $(dir $#)
#echo "Compiling..."$<
$(CXX) -MT$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
debug:
#echo "DEPS: "$(DEPS)"\n"
#echo "OBJ: " $(addprefix ${BUILD_DIR}/,$(OBJECTS))"\n"
#echo "EXE: " $(addprefix ${EXE_DIR}/,$(EXE))"\n"
.PHONY:clean
clean:
rm -f $(EXE) $(addprefix ${BUILD_DIR}/,$(DEPS)) $(addprefix ${BUILD_DIR}/,$(OBJECTS))
ifneq ($(MAKECMDGOALS),clean)
-include $(addprefix ${BUILD_DIR}/,$(DEPS))
endif
You have two unrelated problems. The first one is that you have two conflicting -o options when linking.
The actual problem you ask about is something different, but still related to the -o option: Namely that you don't have one when attempting to create the object files.
When creating the object files, the generated object file is not written to standard output, therefore your redirection will not cause the gcc frontend program to create an object file with the name you think.
For example:
arm-devkit-g++ -I. -c part1.cpp > build/target/part1.o
The above command will create an object file named part1.o in the current directory, and write the (empty) standard output to the file build/target/part1.o. That will leave build/target/part1.o empty, which is what the linker is complaining about (that's what it means when it says the file is truncated).
The command should instead look like
arm-devkit-g++ -I. -c part1.cpp -o build/target/part1.o
Note the use of the -o option to name the output file.
You need to modify the makefile to not use redirection when building the object files.
Also, you should not list the header files when building object files, only the source file you want to build, so the command
arm-devkit-g++ -I. -c main.cpp part1.h part2.h > build/target/main.o
should really be
arm-devkit-g++ -I. -c main.cpp -o build/target/main.o
You're not compiling your object files correctly. g++ doesn't output the files to stdout, it writes them to the local directly. If you want to put the object files in a specific directory, you need to use the -o option:
$(BUILD_DIR)/%.o: %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -c $^ -o $#
^^^^^^
$(BUILD_DIR):
#mkdir -p $#
Also you're building your executable incorrectly. The dependencies are insufficient and you don't have your target listed. You'll want this:
$(EXE_DIR)/$(EXE) : $(addprefix $(BUILD_DIR),$(OBJECTS)) | $(EXE_DIR)
$(CXX) $(CXXFLAGS) -o $# $^
$(EXE_DIR):
#mkdir -p $#
This will create an order-only dependency from your binary on the directory, and correctly build the binary. Note that you shouldn't have a dependency from your target on your .d files. That makes little sense. Instead, your rule for building the .os should simply also build the .ds (that rule suffers the same problem currently as your .o rule):
# build the .o and the .d in one go
$(BUILD_DIR)/%.o : %.cpp | $(BUILD_DIR)
$(CXX) $(CXXFLAGS) -o $# -c $< -MP -MMD -MF $(#:.o=.d)
AS AN EDITORIAL ASIDE, THERE IS THIS COMMON TENDENCY TO WRITE ALL VARIABLES IN MAKEFILES IN SHOUTY_CAPS. THIS IS PROVABLY MUCH MORE DIFFICULT TO READ THAN USING JUST USING snake_case. Lower case letters work just fine.
I'm trying to build a small C++ project with GNU make (version 3.81) but i must call make two times because the first run fails. This is my project directory:
project
makefile
include
lexer.hpp
src
main.cpp
lexer.l
Following is my makefile:
CC = g++
CPPFLAGS = -I include
VPATH = include src
OBJECTS = main.o lexer.o
test: $(OBJECTS)
$(CC) $(CPPFLAGS) -lfl -o $# $^
main.o: lexer.hpp main.cpp
$(CC) -c $(CPPFLAGS) $^
lexer.o: lexer.cpp
$(CC) -c $(CPPFLAGS) $^
lexer.cpp: lexer.l
flex -t $^ > src/lexer.cpp
.PHONY: clean
clean:
rm -fR $(OBJECTS) src/lexer.cpp test
The first time i run make i get the following output where make complains about not finding the lexer.cpp file. But i don't understand why make don't seek in the folders declared in VPATH.
g++ -c -I include include/lexer.hpp src/main.cpp
flex -t src/lexer.l > src/lexer.cpp
g++ -c -I include lexer.cpp
g++: error: lexer.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [lexer.o] Error 1
However if i call make again then lexer.cpp is found and the compilation works.
g++ -c -I include src/lexer.cpp
g++ -I include -lfl -o test main.o lexer.o
Why?
P.S. I apologize for poor english.
This rule is wrong:
lexer.cpp: lexer.l
flex -t $^ > src/lexer.cpp
This rule tells make that it will build a file lexer.cpp, and so that's what make is expecting it to do, and after the rule finishes make thinks that file is ready to go, and it will use that filename when other targets depend on it. But what the rule really does, is build src/lexer.cpp.
To write this rule correctly you'll need to write it as:
src/lexer.cpp: lexer.l
flex -t $^ > $#
(every make rule you write should always update the file $#, exactly).
However, in general VPATH is not good for finding generated files (object files, etc.: any file that is generated by make). It's only useful for finding source files (files make doesn't build itself).