Proper makefile dependency list (C++) - 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.

Related

Understanding makefiles

I was looking at this flow diagram to understand how makefiles really operate but I'm still struggling to 100% understand what's going on.
I have a main.cpp file that calls upon some function that is defined in function.h and function.cpp. Then, I'm given the makefile:
main: main.cpp function.o
g++ main.cpp function.o -o main
mainAssembly: main.cpp
g++ -S main.cpp
function.o: function.cpp
g++ -c function.cpp
clean:
rm -f *.o *.S main
linkerError: main.cpp function.o
g++ main.cpp function.o -o main
What's going on? From what I understand so far is that we are compiling function.cpp, which turns into an object file? Why is this necessary?
I don't know what the mainAssembly part is really doing. I tried reading the g++ flags but I still have trouble understand what this is. Is this just compiling main.cpp with the headers? Shouldn't we also convert main into an object file as well?
I guess main is simply linking everything together into an exe called main? And I'm completely lost on what clean and linkerError are trying to do. Can someone help me understand what is going on?
That flowchart confuses more than it explains as it seems needlessly complicated. Each step is actually quite simple in isolation, and there's no point in jamming them all into one chart.
Remember a Makefile simply establishes a dependency chain, an order of operations which it tries to follow, where the file on the left is dependent on the files on the right.
Here's your first part where function.o is the product of function.cpp:
function.o: function.cpp
g++ -c function.cpp
If function.cpp changes, then the .o file must be rebuilt. This is perhaps incomplete if function.h exists, as function.cpp might #include it, so the correct definition is probably:
function.o: function.cpp function.h
g++ -c function.cpp
Now if you're wondering why you'd build a single .cpp into a single .o file, consider programs at a much larger scale. You don't want to recompile every source file every time you change anything, you only want to compile the things that are directly impacted by your changes. Editing function.cpp should only impact function.o, and not main.o as that's unrelated. However, changing function.h might impact main.o because of a reference in main.cpp. It depends on how things are referenced with #include.
This part is a little odd:
mainAssembly: main.cpp
g++ -S main.cpp
That just dumps out the compiled assembly code for main.cpp. This is an optional step and isn't necessary for building the final executable.
This part ham-fistedly assembles the two parts:
main: main.cpp function.o
g++ main.cpp function.o -o main
I say that because normally you'd compile all .cpp files to .o and then link the .o files together with your libstdc++ library and any other shared libraries you're using with a tool like ld, the linker. The final step in any typical compilation is linking to produce a binary executable or library, though g++ will silently do this for you when directed to, like here.
I think there's much better examples to work from than what you have here. This file is just full of confusion.

Write a makefile to compile a .h .hpp and .cpp together into an executable

So I have a straightforward problem.
I have files List.hpp, List.h, and test_list.cpp
List.hpp contains function definitions for the List.h file.
The List.h file includes "List.hpp" in the 3rd to last line.
test_list.cpp runs the program and includes "List.h" at the top.
I need a makefile that will compile these into an executable "project.x".
So far have this:
proj2: List.o test_list.o
gcc -o proj2.x List.o test_list.o
List.o:
gcc -c List.hpp
test_list.o:
gcc -c test_list.cpp
clean:
rm *.o proj2.x
However, it results in all kinds of errors, all dealing with lines that have List <T> in them, stating that List does not name a type. I think this is because I am not properly including the header file.
How would I make this makefile?
Judging by the filename extensions and your description, you're compiling C++ code.
You should thus use a C++ compiler: g++. gcc is a C compiler and doesn't know about C++.
You should really just let make compile your code for you, it knows what to do:
proj2: test_list.o
$(CXX) $(LDFLAGS) $(LDLIBS) -o $#
clean:
rm *.o proj2
You don't normally want to compile a header in isolation. It's intended to be included in a source file, and the source file is what you compile.
Given the implicit dependencies in a typical make utility, you can reduce your Makefile a little bit:
proj2.x: test_list.o
g++ -o proj2.x test_list.o
test_list.o: test_list.cpp List.hpp
clean:
-rm *.o proj2.x
At least assuming a reasonably recent version of Make, it'll already know how to compile a .cpp file to get a .o file.
If you're having compiler errors, chances are at least pretty fair that they stem from problems in the code, not in the Makefile. The obvious exceptions would be things like your C++ code failing to link properly, because you used gcc instead of g++ to link it.
As an aside, the header dependency shown in:
test_list.o: test_list.cpp List.hpp
...is something that gcc can generate automatically with the -MM flag. For a tiny Makefile like this one, it's probably not worthwhile to mess with generating dependencies automatically, but for a large one it can be worthwhile. You can even include this as a step in the Makefile itself by running gcc with -MM to generate the dependencies (directing the output to a file) and including that file into a Makefile that does the real work).
More about dependency generation and how to use it in a Makefile:
http://scottmcpeak.com/autodepend/autodepend.html
You don't compile .h or .hpp files. You only compile .c or .cpp files. You probably want something like(Indenting with tabs, not spaces, spaces is a SO and python thing, tabs are a makefile thing):
proj2: list.cpp list.hpp list.h
g++ -o proj2.x list.cpp
clean:
rm proj2.x
Also, in your C file, you will need:
#include "List.h" /* Note the quotes: *
#include <list.h> * won't work */
And likewise for your #include "List.hpp".

how to run c++ file if header, class, and main are not in the same folder?

The code::block IDE generates the following files:
./main.cpp
./include/class.h
./src/class.cpp It include class.h with #include "class.h"
How can I run this set of files, with the three files in three different folders?
First, this program can be run by clicking IDE "build and run" button.
This program need to take some arguments, like ./a.out arg[1] arg[2]. So I cannot input arguments by clicking "build and run" button, and thus I have to use g++ to compile an output first.
But g++ is not smart enough as the IDE in finding the three files(I try g++ -I./include main.cpp, it seems that it has no problem with class.h file, but cannot find class.cpp file)
So how can I compile the three files in three different locations?
BTW, how could the class.h file find the class.cpp file in IDE/g++(scan all the files in the directory to see which contains the definition of the class functions?)?
It's a bad idea to #include source files. But this will do it:
g++ -I./include -Isrc main.cpp
Normally one would expect that the IDE has some function to just build the application, especially when there's a function to build-and-run. In addition there are those that have the possibility to supply command line arguments for the program so build-and-run will run with supplied arguments.
You have to supply the source files and the search path for includes, normally one would write:
g++ -o exec-file-name -I./include main.cpp src/class.cpp
but that may depend a bit on how you include the header file. Another note is that you normally don't compile the header file separately - it's included when you compile the .cpp files that includes it.
If on the other hand you actually want to do what you write (compile the .h file that includes the .cpp file - which is higly unorthodox) you would do:
g++ -c -I./src include/class.h
g++ -c main.cpp
g++ -o exec-file-name main.o class.o
where you need to replace the .o extension if your platform uses another extension. Note that in this case you should probably not include class.h from main.cpp since that could lead to duplicate symbols.

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

Compile Time & Memory Usage of a large C++ Project?

Suppose one has about 50,000 different .cpp files.
Each .cpp file contains just one class that has about ~1000 lines of code in it (the code itself is not complicated -- involves in-memory operations on matrices & vectors -- i.e, no special libraries are used).
I need to build a project (in a Linux environment) that will have to import & use all of these 50,000 different .cpp files.
A couple of questions come to mind:
How long will it roughly take to compile this? What will be the approx. size of the compiled file?
What would be a better approach -- keep 50,000 different .so files (compiled extenstions) and have the main program import them one by one, or alternatively, unite these 50,000 different .cpp files into one large .cpp file, and just deal with that? Which method will be faster / more efficient?
Any insights are greatly appreicated.
There is no answer, just advice.
Right back at you: What are you really trying to do? Are you trying to make a code library from different source files? Or is that an executable? Did you actually code that many .cpp files?
50,000 source files is well... a massively sized project. Are you trying to do something common across all files (e.g. every source file represents a resource, record, image, or something unique). Or it just 50K disparate code files?
Most of your compile time will not be based on the size of each source file. It will be based on the amount of header files (and the headers they include) that will be brought in with each cpp file. Headers, while not usually containing implementations, just declarations, have to go through a compile process. And redundant headers across the code base can slow your build time down.
Large projects at that kind of scale use precompiled headers. You can include all the commonly used header files in one header file (common.h) and build common.h. Then all the other source files just include "common.h". The compiler can be configured to automatically use the compiled header file when it sees the #include "common.h" for each source.
(i) There are way too many factors involved in determining this, even an approximation is impossible. Compilation can be memory, cpu or hard drive bound. The complexity of the files matter (from your description, your complexity is low).
(ii) The typical way of doing this is to make a library and let the system figure out linking or loading. You can choose static or dynamic linking.
static linking
Assuming you are using gcc, this would look like this:
g++ -c file1.cpp -o file1.o
g++ -c file2.cpp -o file2.o
...
g++ -c filen.cpp -o filen.o
ar -rc libvector.a file1.o file2.o ... filen.o
Then, when you build your own code, your final link looks like this:
g++ myfile.cpp libvector.a -o mytask
dynamic linking
Again, assuming you are using gcc, this would look like this:
g++ -c file1.cpp -fPIC -o file1.o
g++ -c file2.cpp -fPIC -o file2.o
...
g++ -c filen.cpp -fPIC -o filen.o
ld -G file1.o file2.o ... filen.o -o libvector.so
Then, when you build your own code, your final link looks like this:
g++ myfile.cpp libvector.so -o mytask
You will need libvector.so to be in the loader's path for your executable to work.
In any case, as long as the 50,000 files don't change, you will only need to do the last command (which will be much faster).
You can build each object file from a '.cpp' with having the '.h' file having lots (and I MEAN LOTS) of forward declarations - so when you change a .h file it does not need to recompile the rest of the program. Usually a function/method needs the name of the object in its parmaters or what it is returing. If it needs other details - yes it needs to be included.
Please get a book by Scott Myers - Will help you a lot.
Oh - When trying to eat a big cake - divied it up. The slices are more manageable.
We can't really say the time it will take to compile, but what you should do is compile each .cpp/.h pair into a .o file:
$ g++ -c -o test.o test.cpp ...
Once you have all of these, you compile the main program as so:
$ g++ -c -o main.o main.cpp
$ g++ -o main main.o test.o blah.o otherThings.o foo.o bar.o baz.o etc...
Your idea of using .sos is pretty much asking "how quickly can I crash the program and possibly the OS?". Shared libraries are ment for large libraries in small numbers, not 50,000 .sos linked to a binary (especially if you load them dynamicly...that would be BAD).