Newbie question about project structures and makefiles - c++

I have a project with this structure
/project
Makefile
.gitignore
/bin
/src
file1.cpp
file2.cpp
file3.cpp
/include
definitions.h
/obj
I played around with the Makefile but I couldn't seem to get what I wanted, first I tried:
CC = g++
CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/
All: build
obj/%.o: src/%.cpp
$(CC) $(CFLAGS) -c $^
build:
$(CC) $(CFLAGS) file1.o file2.o file3.o -o bin/main$(compiler)
but this returned the error
make: *** No rule to make target 'file1.o', needed by 'build'. Stop.
so I tried
CC = g++
CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/
All: build
%.o: src/%.cpp
$(CC) $(CFLAGS) -c $^
build:
$(CC) $(CFLAGS) file1.o file2.o file3.o -o bin/main$(compiler)
and it compiled, putting all the .o files in the main directory, which is unideal. Furthermore, I can't run the binary file unless I specifically opened a terminal in the main directory and enter ./bin/maing++, opening a terminal in the bin folder and entering ./maing++ doesn't work, and so does running the .exe file manually, what did I do wrong? what I want is all the .o files made in obj/ and to be able to run the executable manually
UPDATE:
I changed the makefile to
CC = g++
CFLAGS = -std=c++2b -Wno-parentheses -Iinclude/ -Idoc/
SOURCES := $(wildcard src/*.cpp)
OBJECTS := $(patsubst src/%.cpp, obj/%.o, $(SOURCES))
All: build
obj/%.o: src/%.cpp
$(CC) $(CFLAGS) -c $< -o $#
build: $(OBJECTS)
$(CC) $(CFLAGS) $^ -o bin/is$(compiler)
this will put all obj files in the correct folder, its a simple program so running the executable would pop up a terminal window and print some text, I'm going to reiterate that I had to specifically open a terminal in the main directory and enter ./bin/maing++, opening a terminal in the bin folder and entering ./maing++ doesn't work, and so does running the .exe file manually

Related

Makefile not giving the expected compilation results

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.

Makefile does not evaluate OBJECTS variable

I am trying to build a Makefile that will build a shared library with g++ and I find that it is not evaluating the OBJECTS variable. This is on Ubuntu 18.04 and all the files are in the same current directory. Secondly it is completely skipping the source file compilation and proceeding directly to evaluate the linking instruction. As a clarification I am using GNU Make 4.1
Here is what I get when I type make all
g++ -shared -pthread -o tree.so
g++: fatal error: no input files
compilation terminated.
Makefile:12: recipe for target 'tree.so' failed
make: *** [tree.so] Error 1
Here is my Makefile code
CC=g++
CFLAGS = -I/usr/local/include -Wall -std=c++17 -O3 -march=native -Ofast -ftree-vectorize
LIBS=-shared -pthread
SOURCES=$(wildcard *.cpp)
OBJECTS=$(wildcard *.o)
TARGET=tree.so
all:$(TARGET)
$(TARGET) : $(OBJECTS)
$(CC) $(LIBS) -o $(OBJECTS) $(TARGET)
$(OBJECTS):$(SOURCES)
$(CC) -c -g $(CFLAGS) $(SOURCES)
clean:
rm -f $(OBJECTS) $(TARGET)
If you only have the *.cpp files in your directories, then there is not any *.o yet, so your $(wildcard *.o) will expand to nothing.
What you want is to get the *.cpp files and compute the corresponding *.o files:
OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES))
or equivalently:
OBJECTS=$(SOURCES:.cpp=.o)
Now, your compiler command is not the best one, because if you touch any source file all will be compiled. You can use instead:
$(OBJECTS): %.o: %.cpp
$(CC) -c -g $(CFLAGS) $< -o $#
So that only the touched files are actually rebuilt.
Also you have the linking command wrong. It should be:
$(TARGET) : $(OBJECTS)
$(CC) $(LIBS) -o $(TARGET) $(OBJECTS)
because the argument to the -o option is the output file, that is the target.

Build (make) lib every time, recompile project only if lib is newer

I have the following project structure:
lib/
Makefile
src/...
inc/...
build/
inc/...
lib/libmylib.a
subproj1/
src/main.cpp
Makefile
The Makefile in the lib folder is designed to create the file libmylib.a and copy the relevant header files to the build/inc folder.
I want the Makefile in subproj1 to always call make -C ../lib, but only re-compile file if headers have changed, and re-link only if necessary (one object file or libmylib.a is newer).
I have the following (non-defined variables such as CC are defined in another file):
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS) $(LIBDIR)/build/lib/libmylib.a
$(CC) $^ -o $# $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(LIBDIR)/build/lib/libmylib.a
mkdir -p $(OBJDIR)
$(CC) -c -o $# $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $#) $<
$(LIBDIR)/build/lib/libmylib.a:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean $(LIBDIR)/build/lib/libmylib.a
clean:
$(RM) obj/* $(MAIN)
The above will re-compile main.cpp even if nothing has changed in the lib folder. If I remove $(LIBDIR)/build/lib/libmylib.a from the $(OBJDIR)/%.o rule, the .cpp file will not be re-compiled if a header changed (I would need to run make twice).
Is there a way to have the .cpp files in subproj1 being compiled only if the header files in lib have changed (or if the .cpp files themselves have changed), and to get myexe built only if one of the .cpp has been re-compiled (newer .o) or if libmylib.a is newer?
With recursive makefiles you need to execute the sub-project makefiles in correct order because the dependency tree is incomplete (e.g. this makefile does not know that updating $(LIBDIR)/build/lib/libmylib.a also updates those headers). It is easy to do that with a shell script or a top-level makefile.
Alternatively, your makefile must execute the sub-makefiles unconditionally in correct order, which can be done with shell function, e.g.:
LIBDIR := ../lib
pid := $(shell ps -o ppid= $$$$)
$(shell ${MAKE} -C ${LIBDIR} >/proc/$(pid)/fd/1 2>/proc/$(pid)/fd/2)
That $(LIBDIR)/build/lib/libmylib.a rule should be removed, the object files should not depend on the .a and it should not be marked as .PHONY.
This makes sure that building in ${LIBDIR} happens before this makefile analyzes file timestamps in ${LIBDIR}.
Now your auto-generated header dependencies should just work.
This might be a bit cleaner.
LIBDIR = ../lib
SRCDIR = src
OBJDIR = obj
SRCS = $(SRCDIR)/main.cpp
MAIN=myexe
OBJS = $(SRCS:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEPS = $(OBJS:.o=.d)
all: makelib
$(MAKE) $(MAIN)
debug: CFLAGS += -g -DDEBUG
debug: LFLAGS += -g
debug: $(MAIN)
$(MAIN): $(OBJS)
$(CC) $^ -o $# $(LIBS) $(LFLAGS)
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
mkdir -p $(OBJDIR)
$(CC) -c -o $# $(CFLAGS) $(INCS) -MD -MF $(patsubst %.o, %.d, $#) $<
makelib:
make -C $(LIBDIR)
-include $(DEPS)
.PHONY: clean makelib
clean:
$(RM) obj/* $(MAIN)
The main target all requires makelib to be built, and then it recursively calls itself for the target $(MAIN) (so all of $(MAIN)'s dependencies will be recalculated after makelib has finished building).

need help creating a static c++ library using make

I am trying to create a static library based on the file layout given below.
/library
Makefile
/include
.h files
/src
.cpp files
/build
.o files
/lib
.a file
When I run make all with the current code in my makefile given below it gives me the error:
make: *** No rule to make target src/%.cpp', needed bybuild/BaseGfxApp.o'. Stop.
CPP_FILES = $(wildcard src/*.cpp)
OBJ_FILES = $(addprefix build/,$(notdir $(CPP_FILES:.cpp=.o)))
CC_FLAGS = -c -Wall
all: libphoto.a
libphoto.a: $(OBJ_FILES)
ar rcs lib/$# $^
build/%.o: src/%.cpp
g++ $(CC_FLAGS) $# $<
I am fairly new to 'make' and I honestly have no clue where to go from here. I would appreciate some input or help. Thanks!
It could be that you are missing a makefile in your src/ directory.
dont put paths in the rules
%.o: %.cpp
g++ $(CC_FLAGS) $# $<
I think the main problem is you are not giving the proper path to the files you are trying to build. But also you missed some flags for g++. I think the following changes should work (not properly tested).
CPP_FILES = $(wildcard src/*.cpp)
OBJ_FILES = $(patsubst src/%.cpp,build/%.o,$(CPP_FILES))
CXXFLAGS = -Wall
all: prereqs lib/libphoto.a
lib/libphoto.a: $(OBJ_FILES)
ar rcs $# $^
build/%.o: src/%.cpp
g++ -c $(CXXFLAGS) -o $# $<
prereqs:
mkdir -p lib
mkdir -p build
.PHONY: prereqs
clean:
rm $(OBJ_FILES) lib/libphoto.a

Makefile error: No such file or directory

I've got this directory structure:
.\src contains all the source code (.h and .cpp)
.\bin should have all the .o and .bin
. has Makefile
This is my current Makefile:
CFLAGS = -Wall -pedantic -g
CC = g++
EXEC = flrfile
SRC_DIR = src
BIN_DIR = bin
SOURCES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(patsubst $(SRC_DIR)/%,%,$(SOURCES))
OBJ := $(patsubst %.cpp,%.o,$(OBJ))
OBJ := $(addprefix ../$(BIN_DIR)/,$(OBJ))
all: flrfile
../$(BIN_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
$(CC) $(CFLAGS) -c $(SRC_DIR)/%.cpp -o $#
$(EXEC): $(OBJ)
#mkdir -p $(BIN_DIR)
$(CC) $(CFLAGS) $(BIN_DIR)/$(OBJ) -o $(BIN_DIR)/$(EXEC)
.PHONY : clean
clean:
-rm -rf $(BIN_DIR)
When I run make I get this error:
g++ -Wall -pedantic -g -c src/%.cpp -o ../bin/FixedLengthFieldsRecord.o
g++: error: src/%.cpp: No such file or directory
g++: fatal error: no input files
compilation terminated.
make: *** [../bin/FixedLengthFieldsRecord.o] Error 4
Why is this? I have little to no understanding of Makefile to be honest...
The correct line for compiling should look like this:
$(BIN_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
$(CXX) -o $# -c $< $(CFLAGS)
Which means: "for every file matching the pattern "%.o" in $(BIN_DIR), compile it using the associated $(SRC_DIR)/%.cpp as argument (first dependency)
Additional comment: I suspect some missing dependencies: usually, a .c or cpp source file doesn't only depend on the corresponding header file, but might also include other headers from the project.