Simple Makefile Example

Versión en español de esta publicación.
This article tries to explain how to make a simple makefile to run a simple class that will display the text “hello world” to console,

First, we start by defining a new main file that will contain the main function logic to start our program here is the code for main.cpp

Main.cpp

#include "Hello.hpp"
 
int main() {
    phoxonics::samples::Hello hello;
    hello.say_hello_world();
    return 0;
}

The first line includes our Hello.hpp class header that will be used to create our object instance, this instance will be used to access the encapsulated object logic, then we have the main function which has the object creation and after that we have the function call to display our hello world message, lets get into the object class definition, here is the code for “Hello.hpp”.

Hello.hpp

#ifndef HELLO_HPP_
#define HELLO_HPP_
 
#include <string>
#include <iostream>
 
namespace phoxonics {
namespace samples {
 
class Hello {
public:
    Hello(); // constructor
    virtual ~Hello(); // destructor
 
    void say_hello_world();
     
    std::string hello();
    std::string world();
 
    void hello(std::string message);
    void world(std::string message);
 
private:
    std::string hello_ { "" };
    std::string world_ { "" };
};
 
}
}
 
#endif

The first two lines of code are code guards which prevents that multiple inclusion of the header file occur, then we have the include directives that define the libraries that we are going to use in our class logic, usually this includes may refer to objects of the STL library, next to that we have the namespace definition which is a container that prevents naming collisions between library functions, next to that we have the constructor and destructor class functions which are the responsible for the initialization of our class object and the clean logic respectively, remember that these functions are only class definitions functions this means that there is no code in the functions and the code is defined in the class implementation the “.cpp” file that corresponds to this header, the next lines of code refers to the public functions which are accessible from any scope, we also have members functions that are the responsible to get the internal data of an object, remember that the data is encapsulated in the object itself to this functions are needed to access that data, and at the end of the class we have our private section of the class that holds all the private data that the class will use internally to perform some action, this data is called class members or properties and it has a type related to it, lets get to the class implementation, here is the “Hello.cpp” code:

Hello.cpp

#include "Hello.hpp"
 
namespace phoxonics {
namespace samples {
 
// constructor
Hello::Hello() {
    this->hello("hello");
    this->world("world");
}
 
// destructor
Hello::~Hello() { }
 
void Hello::say_hello_world() {
    std::cout << this->hello() << " " << this->world() << std::endl; 
}
 
std::string Hello::hello() {
    return this->hello_; 
}
 
std::string Hello::world() {
    return this->world_;
}
 
void Hello::hello(std::string message) {
    this->hello_ = message; 
}
 
void Hello::world(std::string message) {
    this->world_ = message; 
}
 
}
}

The very first line defines the header of this class where all functions and members are defined, in case we need to add a new function that function needs to be defined first in the header file and then implemented in this file, next to that we have the namespace definition that is needed to encapsulate our functions in a container like item, next to that we have the constructor and destructor implementation functions, in the constructor we are using our member functions to initialize the state of our object that is: we set the member variables hello_ and world_ to the strings “hello” and “world” respectively trough our public member functions hello(str) and world(str), note that we also have use the this keyword which allow us to access the object instance itself and all the object functions and properties, next to that we have the implementation for the say_hello_world() function, the only purpose of this function is to display the data contained in our object private variables using the object public member functions to access the data, and at the end of the implementation class we have the member functions, this functions serve as a gateway to access the private data variables. We now proceed to the makefile and the compilation for this code, here is the code for the simple makefile:

makefile

all: hello
 
hello: main.o Hello.o
    g++ -Wall main.o Hello.o -o hello -std=c++0x
 
main.o: main.cpp
    g++ -Wall -c main.cpp -std=c++0x
 
hello.o: Hello.cpp Hello.hpp
    g++ -Wall -c Hello.cpp -std=c++0x
 
clean:
    rm -f *.o hello
     
run:
    ./hello

The makefile standard is a clean way to define how the program will be compiled and all the steps to transform source code into binaries, there are lots of possibilities that can be used to define the steps to package our source code in this standards, this is a minimal example just to show how it works, at the very top of the file we have “all:” this is called a target and is the default target that is called when we type $ make at the command prompt in a folder that contains a makefile, if we want to run the logic for other targets lets say “clean:” then what we need to do is to type $ make clean at the command prompt and that is the way it works for running targets, the “all:” target defines that we need two objects that our program needs to run, the first one is “main.o” and is the main file that contains our main logic, and the second one is “Hello.o” which is the class definition that is used by the main program to display a message into console, this objects are also targets which define how to construct that object by compiling the code, the first target “main.o” definition states that we are compiling main.cpp it defines the compiler to use, the source code files and the flags to use when compiling, then we have the other target called “hello.o” this target specifies that it needs two source files to produce the “Hello.o” object which are the class header and the class definition that we saw above, it also defines the compiler to use, the source files and the compiler flags, at the end we have the clean and run targets which are used to remove binary generated objects and to run the program respectively, in order to compile the program we need to run this in a console:

make

Don’t forget that the default target for the above command is “all:” so the above command will run the “all:” target, once compiled we proceed to run the program by running the “run:” target

make run

This will run the program and a “hello world message” will be displayed in our console, and finally to clean the binary generated objects we need to run the “clean:” taget.

make clean

You can download the source code files here.

Enjoy! 🙂
-Yohan

Share This:

Leave a Reply

Your email address will not be published. Required fields are marked *