GNU make compiling all .cpp files to .o and include .h files - c++

So i have folder that looks like this
OS
Makefile
/include
head.h
/src
main.cpp
head.cpp
/objects
How can i use Makefile to compile all .cpp files to objects folder then compile all .o files with include .h to my actual cpp program.I currently have:
CPP_FILES := $(wildcard src/*.cpp)
H_FILES := $(wildcard include/*.h)
OBJ :=$(wildcard objects/*.o)
LIBS := -Wall
CC := -std=c++14
What do I enter next to make all those .cpp files to .o and compile them with .h included.Thank you for your time

You can use pattern rules (previously known as "suffix rules") for that. As you use GNU make, you can write this line to compile all .cpp files in src/ to .o files in objects/, assuming the Makefile is placed in the top directory:
objects/%.o: src/%.cpp
$(CXX) -c $(CFLAGS) $< -o $#
In GNU make syntax $< denotes the dependency (a .cpp file in this case), $# denotes the target (the object file).
The .h files do not need to be compiled, just set up the correct include path as part of the string the CFLAGS variable contains:
CFLAGS += -I./include

Related

patsubst in makefile doesnt replace the full filepath

Im currently trying to get my makefile independend from my folder structure. So far i worked with a single specific folder containing all my .cpp files. My .o files are all placed in a seperate OBJ/ folder. However i now want my makefile to automatically grab all .cpp files from all subdirectories (any depth if possible) but still place all .o files the one same OBJ folder. This is how my makefile looks at the moment:
CC = g++ -g
SRC = Src/
OBJ = Obj/
BIN = Bin/
INC = -I Lib/GLFW/include/\
-I Lib/GLAD/include/\
-I Lib/STB/\
-I Lib/GLM/\
-I Src/Header/
LIB = -L Lib/GLFW/lib-mingw-w64 -lglfw3 -lopengl32 -lglu32 -lgdi32
EXE = $(BIN)Test.exe
SOURCEFILES = $(wildcard $(SRC)**/*.cpp)
OBJECTFILES = $(patsubst $(SRC)%.cpp,$(OBJ)%.o,$(SOURCEFILES))
all: $(SOURCEFILES) $(EXE)
$(EXE) : $(OBJECTFILES)
$(CC) -o $# $^ $(LIB)
$(OBJ)%.o: $(SRC)%.cpp
$(CC) -c $< $(INC) -o $#
It somewhat does what i want, but for some reason it currently is required to have the same folder structure of my SRC/ directory in OBJ/ aswell: If my .cpp file is SRC/foldername/name.cpp my makefile wants to create the .o as OBJ/foldername/name.o. I want it to be OBJ/name.o for all files regardless of the structure of SRC/ . What do i need to change to achieve that?
My second question is about the include path. As it can be seen in the makefile, all my header files are in a single directory Src/Header/. Is it possible to somehow also automatically get and link the right .h files from Src/ and it's subdirectories?
If you want to flatten paths, you can use notdir.
Unfortunately, because %.o is "magic", you can't just wrap it in a $(notdir).
By the way, as a matter of style, I'd leave the trailing slash out of those variables and use it in the expressions instead; it'll be much easier to read, and more flexible too.
This works for me:
SRC=srcPath
OBJ=objPath
SOURCEFILES = $(wildcard $(SRC)/**/*.cpp)
OBJECTFILES = $(addprefix $(OBJ)/, $(notdir $(patsubst $(SRC)/%.cpp, %.o, $(SOURCEFILES))))
all:
echo $(OBJECTFILES)
More pleasing alternatives surely exist, but the point is that you can use notdir to build your solution.
Flattening your object files in one single directory is not necessarily a very good idea. Your Makefile is getting more complex (see below) and there is a name collision possibility if, by accident, you have two source files with the same base name.
Anyway, it is what you want, and here is a possible solution:
SRC = Src
OBJ = Obj
SOURCEFILES = $(wildcard $(SRC)/**/*.cpp)
# $(1): full path to source file
define CompileRule
$$(OBJ)/$$(patsubst %.cpp,%.o,$$(notdir $(1))): $(1)
$$(CC) -c $$< $$(INC) -o $$#
endef
$(foreach f,$(SOURCEFILES),$(eval $(call CompileRule,$(f))))
It iteratively instantiates custom compilation rules for each of your source files. See the GNU make manual for a complete explanation.
I am not sure I fully understand your second question but if you want to find all header files in Src and build the list of -I<dir> compile options, you can probably try something like:
HEADERFILES := $(wildcard $(SRC)/**/*.h)
HEADERDIRS := $(sort $(dir $(HEADERFILES)))
INCLUDES := $(patsubst %,-I%,$(HEADERDIRS))
But it is very sub-optimal because every directory containing header files will be involved as -I<dir> in the compilation of every source file.
Last but not least, your next step could be "how do I automatically get the list of all header files a source file depends on?". If it is, you should probably have a look at this post about Auto-Dependency Generation.

Link .h files and .c files from different directory using makefile

I'm trying to compile a program called um from a current folder with um.c
and include some external implementations. The .h files are in one directory but the .c files implementing these .h files are in a different directory. Below is my makefile. It seems that the compiler knows where to look for the .h file. However, the linker fails and produces the error:
ld: symbol(s) not found for architecture x86_64
clang: fatal error: linker command failed with exit code 1
Makefile:
# define the C compiler to use
CC = gcc
# define any compile-time flags
CFLAGS = -g -O -Wall -Wextra -Werror -Wfatal-errors -std=c99 -pedantic
# define any directories containing header files other than /usr/include
INCLUDES = -I/Users/nguyenmanhduc/Documents/C\ library/cii/include
# define library paths in addition to /usr/lib
LFLAGS = -L/Users/nguyenmanhduc/Documents/C\ library/cii/src
# define any libraries to link into executable:
LIBS = -lm
# define the C source files
SRCS = um.c
# define the C object files
OBJS = $(SRCS:.c=.o)
# define the executable file
MAIN = um
.PHONY: depend clean
all: $(MAIN)
#echo Simple compiler named um has been compiled
$(MAIN): $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)
.c.o:
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $#
clean:
$(RM) *.o *~ $(MAIN)
depend: $(SRCS)
makedepend $(INCLUDES) $^
This question might seem weird because I have little experience with makefile but is there a way that I can link .h and .c files in different folders using makefile.
Thanks!
The problem here is not that your additional .c files are in different directories: it's that you didn't tell your Makefile that they exist at all!
Here's where you list the source inputs (I guess you didn't see the comment?):
# define the C source files
SRCS = um.c
Add the other .c files whose compiled .os are what you want to link.
For example:
# define the C source files
SRCS = um.c ../wot.c ../hah/lol.c
There is no hard and fast rule but, the way you've constructed this Makefile, those relative paths should resolve just fine.
You don't link .c files, you link .o files.
You appear to be stating is that some of your .c files are in a different directory.
No matter, you have to explicitly list those .c files, in your makefile, just like you are listing the .c files in the directory with the makefile. You have to compile the .c files in a different directory, and then link them, just like you're compiling and linking the .c files in the same directory as the makefile. They're not going to compile themselves.
Another approach would be to have a separate makefile in that other directory, that compiles and builds an archive library, and then in this directory link with that archive library.

Example makefile for building simple c project recompiling when headers change

Does anyone have a complete makefile that can do the following:
Rebuilds the project if a HEADER file changes
The cpp files are listed in the makefile
The header files are NOT listed in the makefile
The header files are allowed to have different names than the cpp files
Some of the cpp files do not have header files
I have seen instructions for figuring out how to make the make tool figure out header dependencies, but none of these instructions provide anything remotely resembling a working example. A simple example would be as follows: main.cpp C1.cpp C1.h C2.cpp C2.h
CXX = g++
OBJECTS := main.o C1.o C2.o
all: $(OBJECTS)
%.o : %.cpp
$(CXX) $(CPPFLAGS) -Wall -MMD -c $< -o $#
-include *.d
EDIT: As TobySpeight points out, this won't work if you build an object file, rename or delete one of the prerequisite source or header files, then try to rebuild the object file; the .d file will still require the missing file, and the build will fail. I neglected to include lines to deal with that case:
%.h: ;
%.cpp: ;
(This is effective, but crude. The more precise approach is to put some sed commands in the %.o rule, so as to add specific null rules to the .d file, one for each prerequisite, but the sed commands are ugly, and the approach above is good enough for almost all cases.)
You can also use CMake for this. Everything you need to write is:
add_executable (exec main.cpp C1.cpp C2.cpp)

how to use makefile to include .a static library and .h file from another directory in C?

I have created a .h header file, implemented and created .a static library file, both of them are in directory in say, /home/data/folder1.
I have another .c file which will use link the .h header file and the .a library file. However, the .c file is in directory /home/data/folder2.
What should I write in the Makefile (which is also located in /home/data/folder2)? Also, should I include myheader.h in the .c file that I want to compile? Here is what I have so far, but not working:
LIBB = -L/home/data/folder1/libmylib.a
HEADER = -L/home/data/folder2/myheader.h
main: main.o
gcc $(HEADER) $(LIBB) $< -o $#
main.o: main.c
gcc -c main.c
.PHONY: clean
clean:
rm -f *.o *.~ a.out main
Any help will be appreciated, thanks in advance!
Including header files and libraries from non-standard directories is simple.
You have the path to the directory containing the library and the one containing the header, so we store those in variables:
LIBB = /home/data/folder1
LIBINCLUDE = /home/data/folder2
Now GCC needs to know where to look for headers, so we simply include it in the CFLAGS. The linker (not the compiler) needs to know where to look for libraries, so we can add that to LDFLAGS:
CFLAGS += -I$(LIBINCLUDE)
LDFLAGS += -L$(LIBB)
It will use the CFLAGS and LDFLAGS automatically if you don't explicitly run GCC.
But for the link step, it needs to know that the library is needed, so:
LDFLAGS += -static -lmylib
The linker will look for libmylib.a in all of the directories named by the -L options in LDFLAGS.
Since your rules for main and main.o are explicit, change them like so (but be sure to use a tab, not 4 spaces):
main: main.o
gcc $(LDFLAGS) $< -o $#
main.o: main.c
gcc $(CFLAGS) $< -o $#

Can I compile all .cpp files in src/ to .o's in obj/, then link to binary in ./?

My project directory looks like this:
/project
Makefile
main
/src
main.cpp
foo.cpp
foo.h
bar.cpp
bar.h
/obj
main.o
foo.o
bar.o
What I would like my makefile to do would be to compile all .cpp files in the /src folder to .o files in the /obj folder, then link all the .o files in /obj into the output binary in the top-level folder /project.
I have next to no experience with Makefiles, and am not really sure what to search for to accomplish this.
Also, is this a "good" way to do this, or is there a more standard approach to what I'm trying to do?
Makefile part of the question
This is pretty easy, unless you don't need to generalize
try something like the code below (but replace space indentation with tabs near g++)
SRC_DIR := .../src
OBJ_DIR := .../obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
LDFLAGS := ...
CPPFLAGS := ...
CXXFLAGS := ...
main.exe: $(OBJ_FILES)
g++ $(LDFLAGS) -o $# $^
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
g++ $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<
Automatic dependency graph generation
A "must" feature for most make systems. With GCC in can be done in a single pass as a side effect of the compilation by adding -MMD flag to CXXFLAGS and -include $(OBJ_FILES:.o=.d) to the end of the makefile body:
CXXFLAGS += -MMD
-include $(OBJ_FILES:.o=.d)
And as guys mentioned already, always have GNU Make Manual around, it is very helpful.
Wildcard works for me also, but I'd like to give a side note for those using directory variables. Always use slash for folder tree (not backslash), otherwise it will fail:
BASEDIR = ../..
SRCDIR = $(BASEDIR)/src
INSTALLDIR = $(BASEDIR)/lib
MODULES = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(wildcard *.o)