Ayumu Kasugano
Ayumu Kasugano

Reputation: 440

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?

Upvotes: 1

Views: 258

Answers (1)

tadman
tadman

Reputation: 211580

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.

Upvotes: 2

Related Questions