| by Arround The Web | No comments

Enhancing Your Makefile: Using Include, Vpath, and Other Directive Commands

Although makefiles are said to be a group of different rules, we have to utilize different variables and directives to make them more advanced and functional. Using different directives and commands, you can increase its functionality and make your project more efficient without going through the whole project. This guide discusses the different makefile illustrations to use like “include”, “vpath”, and other directives to get a more advanced version of a makefile.

Include Directive

The “include” directive in makefiles is employed to add the data of one makefile or document to the one that is currently used. This can be helpful to organize your code into modules and make it simpler to reuse it. Also, it’s helpful to incorporate the parameters and guidelines that are unique to a selected target or collection of targets. Consider the following C++ code to use in the makefile as a source file:

#include <iostream>

using namespace std;

int main(){

  char v[20];

  cout << "Enter Name: ";

  cin >> v;

  cout<<"\nHello "<<v << "!"<<endl;

  return 0;

}

We utilize two makefiles from the same working directory to elaborate on using the “include” directive. The very first makefile includes the other makefile named “config” with the help of the “include” directive. This makefile defines the default “all” target that depends on the “target” and “greeting” targets. These targets are not defined here; they must be defined in the other “config” makefile. The clean target is defined here to clean the “target” after the execution of a makefile.

include config

all: target greeting

clean:

rm -f target

The “config” makefile starts with the declaration of some variables like CXX to set the compiler for C++ and the CXXFLAGS variables to set the compiler flags. The “target” rule uses the “name.cpp” file to create an executable using the CXX and CXXFLAGS variables.

Now, we utilize the “define” custom directive here to create a “Hello” function. This function employs the echo statement to display a welcome message on the console. At the end, the “greeting” target calls the “Hello” custom function with the “John” argument to print the welcome message.

CXX = g++

CXXFLAGS := -std=c++11 -Wall

target: name.cpp

  $(CXX) $(CXXFLAGS) -o $@ $<

define Hello
 
  @echo Welcome, $(1)!

endef

greeting:

  $(call Hello, John)

Now that both makefiles are interlinked via the “include” directive, we can use the “make” instruction to build the target executable. The target is generated and we successfully executed it as depicted in the following image:

  • Ls
  • Make
  • target

Vpath Directive

A list of folders that “make” ought to look in for prerequisite documents is specified by the VPATH make variable. It may be utilized to look for utility files and object files alongside the usual purpose of searching for source files. To maintain several folders for your source documents without declaring each file’s location in your makefile specifically, assume that we have a structure like the following for our current project:

  • Tree /f

The makefile in the root directory is all set to create a target executable for the C++ file that is located in the “src” folder; the “src” folder is also located in the root directory. The path to the “utils” folder is defined in the UTILS variable. The SRCS variable gets the C++ code files from the “src” and “utils” folders via wildcards; “utils” is the subfolder of the “src” folder.

Here, the VPATH directive is used to search and interlink the path for the C++ files that are located at two different locations. The default “all” target depends on the TARGET variable which is a target that is responsible for creating an executable file.

CXX = g++

CXXFLAGS := -std=c++11 -Wall

SDIR = src

UTILS = src/utils

SRCS = $(wildcard $(SDIR)/*.cpp) $(wildcard $(UTILS)/*.cpp)

TARGET = test

VPATH = $(SDIR) $(UTILS)

all: $(TARGET)

$(TARGET): $(SRCS)

  $(CXX) $(CXXFLAGS) -o $@ $^

clean:

  rm -f $(TARGET)

.PHONY: all clean

The “name.cpp” file includes the usual main() function to get the input from a user and display it. Along with that, it contains a function call to the “show” method that is implemented in the other C++ file “test.cpp” which is located in the “utils” folder. The header to include the “test.h” file in this C++ file is a must.

#include <iostream>

#include "utils/test.h"

using namespace std;

int main() {

  char v[20];

  cout << "Enter Name: ";

  cin >> v;

  cout << "\nHello " << v << "!" << endl;

  show();

  return 0;

}

The “test.cpp” file implements the show() function and it should include the header to the “test.h” file that contains the declaration of the show() method.

#include <iostream>

#include "test.h"

using namespace std;

void show() {

  cout << "\nHello World! " << endl;

}

The show() function is declared in the “test.h” file as shown in the following:

void show();

Running the makefile that successfully interlinked the C++ files that are located at different locations is responsible to successfully display the messages in the main() and show() functions.

  • Ls
  • Make
  • test

Ifeq Directive

In makefiles, the “ifeq” command is employed to contrast two values and run an entire section of code in a specific way depending on the comparison outcome. The makefile starts with declaring the CXX and CXXFLAGS variables. Declare the C++ compiler and its flags.

The SRC variable sets the name of the “name.cpp” source file and the TARGET variable specifies the name of an executable file to be built using the source file. The DEBUG variable that is responsible for debugging the program code is set to 1.

Here, the “ifeq” conditional directive comes into use to check if the value of the DEBUG variable is 1 or not. If it is 1, the CXXFLAGS value is overridden by “-g -DDEBUG”. The program is compiled in a debug mode. Otherwise, the program is compiled for ideal performance.

At the end of “ifeq”, we create the default “target” that uses the TARGET variable to create a makefile rule that is responsible for generating an executable file via the CXX and CXXFLAGS variables. In the end, the “clean” target cleans the “build” target.

CXX = g++

  CXXFLAGS := -std=c++11 -Wall

SRC = name.cpp

TARGET = test

DEBUG = 1

ifeq ($(DEBUG), 1)

  CXXFLAGS += -g -DDEBUG

else

  CXXFLAGS += -O2

endif

all: $(TARGET)

$(TARGET): $(SRC)

   $(CXX) $(CXXFLAGS) -o $@ $^

clean:

   rm -f $(TARGET)

The “name.cpp” C++ file that is used as the source code file in the makefile is displayed in the following. This file only inputs the string value from a user and displays that value on the console:

#include <iostream>

using namespace std;

int main() {

  char v[20];

  cout << "Enter Name: ";

  cin >> v;

  cout << "\nHello " << v << "!" << endl;

  return 0;

}

Now, running the default “all” target creates the test that is executable after debugging the program code. The “test” executable asks for an input and display after getting it.

  • Ls
  • Make all
  • test

Conclusion

This guide elaborates on the different directives that are used in makefile to enhance its working and performance. The examples depict the use of the “include” directive, “Vpath” directive, and “ifeq” conditional directive. There are other directive commands available on the web that you can look for.

Share Button

Source: linuxhint.com

Leave a Reply