| by Arround The Web | No comments

Advanced Makefile Features: Functions, Eval, and Subst Explained

You may create more effective and dependable makefiles using extended makefile capabilities. Using such features, the interdependencies among the files in your project may be dynamically tracked by Make. You may create custom functions that can be utilized to carry out challenging tasks. Just like that, we have the eval and subst features in makefile that can make our makefile more reusable and understandable as a result. Therefore, we will depict several illustrations of custom functions, eval, and subs.

Define the Custom Functions in Makefile

A designated section of text that is utilized to carry out a challenging task is known as a custom function. Custom functions can call additional specialized functions and accept parameters. The syntax of defining the custom functions in a makefile is depicted as follows:

Let’s start with a makefile example to elaborate on using the custom functions. For this depiction, we require the following C++ code:

#include <iostream>

using namespace std;

int main(){

int v;

cout << "Enter Age: ";

cin >> v;

cout<<"\nAge: "<<v <<endl;

return 0; }

Here is a simple Makefile that defines a custom function and uses it to print a greeting. The first line defines the CXX variable to be the g++ compiler. The second line defines the CXXFLAGS variable that contains the flags for C++. We define a default target that depends on the other two targets which are “target” and “greeting”. This means that when the user runs the “make all” command, the makefile builds both the “target” and “greeting” targets.

Here comes the makefile rule that uses “test.cpp” as the dependency of a target named “target”. Makefile compiles the “test.cpp” file into an executable file called “target” using the CXX and CXXFLAGS variables in the “rule” command. The “$@” and “$<” are special variables that refer to the target and dependency file names, respectively. In line 7, we define a custom function called “Welcome”. This function takes one argument, “$(1)”, which is the name of the person to be greeted.

The function then prints a greeting to that person via the @echo command. The “endef” marks the end of the “Welcome” function definition. The “greeting” target with no dependencies is then defined. The “call” command of this target calls the “Welcome” function with the “Queen” argument. It is responsible for the execution of a “Welcome” function which eventually displays the greeting to a person.

CXX := g++

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

all: target greeting

target: test.cpp

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

# Define a custom function

define Welcome

  @echo Welcome, $(1)!

endef

# using a custom function

greeting:

     $(call Welcome, Queen)

Using the “make all” instruction, we execute the default “all” target of our makefile that builds the “target” target file within the current working directory and runs the greeting target. The output displays the “Welcome, Queen” greeting message on the console. Along with that, the target executable of the C++ file can also be utilized to input at run time and display the values, i.e. age = 77.

Make all

Eval Function in Makefile

You can build the makefile elements dynamically using the extremely potent “eval” method in makefiles. It accepts a string as an input and analyzes it just like a makefile. This implies that you may declare fresh parameters, targets, rules, etc. using the “eval” method. To demonstrate the “eval” function usage in makefile, we use the following C++ file:

#include <iostream>

using namespace std;

int main(){

  char v[20];

  cout << "Enter Name: ";

  cin >> v;

  cout<<"\nName: "<<v <<endl;

return 0;

}

The following provided makefile is a good example of generating dynamic rules to build the object files using the “eval” function. The CXX and CXXFLAGS variables hold the compiler and compiler flags to use when constructing the project. The user’s “make” command builds the “all” target since it is the default target. The “all” target depends on the “target” and “print” targets. The names of all the project’s source documents may be found in the SOURCES variable.

With the help of the “$(SOURCES:.cpp=.o)” expression, the OBJECTS variable is created. The “.o” extension is added to every file in the SOURCES variable in place of the “.cpp” extension. This generates a list of all the project’s object file names. The object files in the OBJECTS variable are built using the dynamic rules that are generated by the code at line 8. The foreach loop produces a rule for each source file while iterating through the SOURCES variable.

The “.cpp” extension of the source file name is replaced with the “.o” extension using the “src:.cpp=.o” expression. The name of the object file is the outcome of this. The “(eval)” function evaluates the rule content which generates a makefile rule that creates the object file. Makefile also defines a rule to build the target executable and a rule to print the value of the OBJECTS variable.

CXX := g++

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

all: target print

SOURCES := name.cpp

# Generate object file names from source files

OBJECTS := $(SOURCES:.cpp=.o)

# Generate dynamic rules to build object files

$(foreach src,$(SOURCES),$(eval $(src:.cpp=.o): $(src)))

# Rule to build the target executable

target: $(OBJECTS)

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

# Rule to print the value of OBJECTS

print:

  @echo Name of the object file: $(OBJECTS)

Upon running the “make” instruction with the “all” target, the target executable and object file are created in the same directory. Along with that, it displays the name of the object file.

Make all

Subst Function in Makefile

The “subst” text manipulation method in makefiles replaces a specified pattern in a string with another. The string is returned after the “subst” function has performed a change. The “subst” function takes three arguments:

  • a string to replace
  • a string to replace with
  • a string to search within

The following makefile is the illustration of the “subst” function usage in the simplest way possible. In this makefile, we define a default “all target that depends on another target named “print”.

After this, two variables, “S1” and “S2”, are defined. The “S1” variable holds the name of a file as its value, while the “S2” variable holds the whole sentence string as its value. We try the “subst” function on the “S1” variable to replace the “name” string with “fame”, and on the “S2” variable to replace a “stones” string with “waves”. New values are saved to the NEW_S1 and NEW_S2 variables, respectively. The print target uses the @echo command to display both variables’ original and new values on a console.

all: print

S1 := name.cpp

S2 := Crossing the river by feeling the stones

# Use subst to replace "name" with "fame"

NEW_S1 := $(subst name, fame, $(S1))

# Use subst to replace "stones" with "waves"

NEW_S2 := $(subst stones, waves, $(S2))

print:

  @echo Original S1 = $(S1)

  @echo New S1 = $(NEW_S1)

  @echo Original S2 = $(S2)

  @echo New S2 = $(NEW_S2)

Upon running the makefile with the “all” default target, we get the original values as well as the new updated values of the displayed variables.

Conclusion

This guide is utilized to discuss the advanced makefile features and their usage. The illustrations include the use of the custom functions to perform different tasks, the “eval” function to build the dynamic makefile components, and the “subst” function to modify the strings.

Share Button

Source: linuxhint.com

Leave a Reply