Makefile for different .cpp files in different folders - c++

I have the following folder structure:
Project project:
folder1
sourceFile1_1.cpp
sourceFile1_2.cpp
folder2
sourceFile2.cpp
folder3
sourceFile3.cpp
main.cpp
makefile
And I'd like to create a makefile which builds the project. The source files can have dependencies among them, but there is not any cyclic dependency.
This is the makefile I have right now:
all: project.exe
clean:
rm main.o project.exe
project.exe: main.o
g++ -g -o main main.o
main.o:
g++ -c -g main.cpp
But when I run it, I get Cannot open include file: 'whatever....h': No such file or directory
Does someone know what I'm doing wrong?

cannot open include file, means that the compiler was not able to find the file. The compiler uses the include path to search for include files. You can look at the documentation here for more information about how you can set this include path.

Related

Proper makefile dependency list (C++)

A lot of the examples I see regarding make files are somewhat inconsistent in regards to what files are considered dependencies of main.o and I was wondering what is the safest and most efficient way of going about creating a makefile.
An example from https://www.tutorialspoint.com/makefile/makefile_quick_guide.htm:
hello: main.o factorial.o hello.o
$(CC) main.o factorial.o hello.o -o hello
main.o: main.cpp functions.h
$(CC) -c main.cpp
factorial.o: factorial.cpp functions.h
$(CC) -c factorial.cpp
hello.o: hello.cpp functions.h
$(CC) -c hello.cpp
As you can see, the header file functions.h is a dependency of main.o.
An example from my textbook:
myprog.exe : main.o threeintsfcts.o
g++ main.o threeintsfcts.o -o myprog.exe
main.o : main.cpp threeintsfcts.cpp threeintsfcts.h
g++ -Wall -c main.cpp
threeintsfcts.o : threeintsfcts.cpp threeintsfcts.h
g++ -Wall -c threeintsfcts.cpp
clean :
rm *.o myprog.exe
As you can see, the header file .h and it's .cpp are dependencies of main.o.
I've also seen another example (from https://www.youtube.com/watch?v=_r7i5X0rXJk) where the only dependency of main.o is main.cpp.
Something like:
myprog.exe : main.o threeintsfcts.o
g++ main.o threeintsfcts.o -o myprog.exe
main.o : main.cpp
g++ -Wall -c main.cpp
threeintsfcts.o : threeintsfcts.cpp threeintsfcts.h
g++ -Wall -c threeintsfcts.cpp
clean :
rm *.o myprog.exe
When a main.cpp includes a .h file, should both the .h and its respective .cpp be included as dependencies?
One of the thoughts that came into my head was this: why should any .h file be included as a dependency anyways? Wouldn't a change in any .h file register as a change in the respective .cpp file since the contents of the .h are just going to be copy and pasted into the respective .cpp file through #include?
I am also unsure of whether to have the respective .cpp as a dependency.
(ex. main.o : main.cpp threeintsfcts.cpp threeintsfcts.h).
I think doing so would go against one of the main benefits of makefiles which is the efficiency of modular compilation. (You would have to recompile the main whenever threeintsfcts.cpp changes).
However, it might make sense to do so in case threeintsfcts.cpp changes the name of one of its functions used in main and you forget to change it in main.
Each object file target needs to depend on its source file, obviously, but also all header files that it is including. The make program itself does not parse the source files, so it doesn't know what headers a source file includes. If one of the header files is missing and modified, the source file will not be automatically recompiled by make.
Because tracking the header file dependencies manually is cumbersome and error-prone, there are tools to automate it, see e.g. this question.
Other source files should however not be dependencies, because one source file should not be including another, so there cannot be any dependency that isn't resolved in the later linker step in the main executable target.
Any change in one source file that would affect a change in the compilation step of another source file would have to be through a change in the former source file's header file which is included in the later one. Therefore the header dependencies are sufficient.
Therefore I see no justification for the textbook example you posted. The first example is fine however, as long as the project size is small enough to track the dependencies manually. The third example is wrong, because it wont recompile main.cpp if the header file changes. (Assuming threeintsfcts.h is included in main.cpp, which is the only thing making sense)
The example from your textbook:
main.o : main.cpp threeintsfcts.cpp threeintsfcts.h
g++ -Wall -c main.cpp
is wrong. The purpose of separating source code into two files is so that they can be compiled independently; if one depends on the other, they have been separated incorrectly.
"...Why should any .h file be included as a dependency anyways?
Wouldn't a change in any .h file register as a change in the
respective .cpp file since the contents of the .h are just going to be
copy and pasted into the respective .cpp file through #include?"
If threeintsfcts.h is the only file that has been changed, then main.cpp has not been changed. Make is not smart enough to parse main.cpp and deduce that threeintsfcts.h ought to be a prerequisite of main.o. (There are ways to get Make to do that, but you must master the basics first.)
...In case threeintsfcts.cpp changes the name of one of its functions
used in main and you forget to change it in main.
In that case you will not be able to build the executable; Make can (and will) inform you of the problem, but not fix it, no matter how you arrange the prerequisite lists.
No you shouldn't have .cpp dependency to main, the whole point of Makefile is for separate compilation.
If you were to include .cpp as a dependency to main, then every time the implementation of that cpp changes main and the cpp would get recompiled which is not what we want. Rather, we only want the cpp file to get re-compiled and main stay the same.
I think that the example from your textbook is a mistake.
I could be wrong, Makefiles is an old friend for me, so I want to know what others have to say on the matter.
I'm answering based on what I personally do and this is what also makes sense to me.

makefile rebuilding everytime when object file dumped in other dir

I have a makefile which keeps on rebuilding the c++ source everytime i do compilation. I figured out the reason is i am dumping object files in a separate directory.
One line from make file is :
$(CPP_COMPILER) $(COMPILE_FLAGS) $(RELEASE_OPT_FLAGS) -c Test.cpp $(INCLUDE_PATH) -o objfiles/$(OUTDIR)/Test.o
Can i put some rule with which make first check this dir (objfiles) and if not needed do not re-build the source everytime?
Thanks for your help.
You should make the rule itself refer to the correct path:
objfiles/$(OUTDIR)/Test.o: Test.cpp
$(CPP_COMPILER) $(COMPILE_FLAGS) $(RELEASE_OPT_FLAGS) -c Test.cpp $(INCLUDE_PATH) -o objfiles/$(OUTDIR)/Test.o
If you still want Test.o as the makefile target, you can easily add one then:
Test.o: objfiles/$(OUTDIR)/Test.o

Environment variable to configure the location of the cpp source files

I am writing a cpp library for myself and I have put the deader files in a folder <root>/include and the cpp files in <root>/src folder. To add my include path to the environment, I have appended <root>/include to CPLUS_INCLUDE_PATH. Now, the problem I am facing is that I am getting an error during the linking step because the linker is unable to find the implementation of my class. Is there any environment variable where I can mention this like the way I have done for the header files?
You cannot do that. The linker needs compiled code and cannot deal with your source files. What you can do is to write a Makefile that will compile all your source files in the /src folder and link compiled files to the target. Example of a Makefile doing this:
ROOT = YOUR_ROOT_DIRECTORY_HERE
LDFLAGS = OPTIONS_TO_LINKER_HERE
CPPFLAGS = OPTIONS_TO_COMPILER_HERE
SRC=$(wildcard $(ROOT)/src/*.cpp)
your_app: $(SRC)
g++ $(CPPFLAGS) $(LDFLAGS) -o $# $^
Compile your application using: make your_app, or make.

Makefile cannot find include path

A Makefile in the subdirectory of my project doesn't see the include path ONLY when it is used from the main Makefile of my project. I don't have much experience with Makefiles and a lot of what I've been reading is pretty confusing. Here is the layout of my directory (with what I have so far since I just started the project):
main/
Inventory/
Item.h
Item.cpp
Makefile
tools/
include/
json/
json.h
jsoncpp.cpp
Makefile
main.cpp
Makefile
Here is the Makefile in the main directory:
INCLUDE = -IInventory/
CC = g++
DEP = tools/jsoncpp.o Inventory/Item.o
Main: main.o $(DEP)
cd tools/ && make
cd Inventory/ && make
$(CC) -o Main main.o $(DEP) $(INCLUDE)
main.o main.cpp
$(CC) -c main.cpp $(INCLUDE)
Here is the Makefile in the tools directory:
INCLUDE = -Iinclude/
CC = g++
jsoncpp.o: jsoncpp.cpp
$(CC) -c jsoncpp.cpp $(INCLUDE)
When I call make from the tools/, it works just fine. But when I call make from the main directory I get this error:
g++ -c -o tools/jsoncpp.o tools/json.cpp
tools/jsoncpp.cpp:76:23: fatal error: json/json.h: No such file or directory
#include "json/json.h"
^
compilation terminated.
Now I partially believe that it can't find the include directory for whatever reason, but the first line in that error is fairly odd to me because of that weird gap between g++ and -c. Since my project will soon get pretty big, how can I fix this?
If it's in -I directive, it should be #include <json/json.h> otherwise #include "include/json/json.h"
EDIT: Include directory is taken from current directory, so in main/ you have to use -Itools/include
Solution: Implicit rules were used so correct variable CXXFLAGS+=$(INCLUDE) must be set for compilation. See: make manual
And the main problem is Main: main.o $(DEP) - files in DEP must exist already otherwise it'll use implicit rules. Later after that cd tools/ && make is done.
#include <json/json.h> <- preprocessor will search in all includes paths
see gcc Include Syntax :
#include <file> This variant is used for system header files. It searches for a file named file in a standard list of system
directories. You can prepend directories to this list with the -I
option (see Invocation).
#include "file" This variant is used for header files of your own program. It searches for a file named file first in the directory
containing the current file, then in the quote directories and then
the same directories used for . You can prepend directories to
the list of quote directories with the -iquote option.

How to create a makefile for several .cpp files with .h files and main.cpp without a .h

I have:
main.cpp
distance.cpp
distance.h
adjacencyList.cpp
adjacencyList.h
Here is my makefile:
all: distance main adjacencyList
g++ distance.o main.o adjacencyList.o
main.o: main.cpp
g++ main.cpp -lstdc++
adjacencyList.o: adjacencyList.cpp
g++ adjacencyList.cpp -lstdc++
distance.o: distance.cpp
g++ distance.cpp -lstdc++
clean:
rm -rf *.o all
I am getting this error. So I'm pretty sure I'm doing something wrong with main because it is not a class like the other two and does not have a .h file.
Update:
After trying Ben Voigt's solution I am getting 1 error:
Your rules to create object files are missing the -c option, for "compile only". So they are trying to link, and failing because there is no main().
Then, your all target names an executable for each of the compilation units. Again, that's wrong because they don't all have main(). You should have only one executable. all should also be configured as a phony target, because it doesn't build an actual file named all.
All your rules are failing to control the name of the output file.
All your rules are failing to pass flags.
Your rules are missing dependencies on the headers, so editing headers won't cause the right files to be recompiled.
Really, you should get rid of the compile and link rules and let make use its built-in ones. Focus on your build targets and dependencies.
Your end makefile should look something like this (of course, using spaces not tabs)
all : main
.PHONY : all clean
CC = g++
LD = g++
main : main.o adjacencyList.o distance.o
main.o: main.cpp adjacencyList.h distance.h
adjacencyList.o: adjacencyList.cpp adjacencyList.h
distance.o: distance.cpp distance.h
clean:
rm -rf *.o main
Wild guess: it is possible you are missing a semi-colon somewhere before including adjacencyList.h.
Check each header files and make sure each class definition is properly terminated with a semi-colon