Each of these directives requires one or two parameters according to the kind of test that is being run. Although various conditional directives are available in a makefile, we will discuss the use and examples of “ifelse”, “ifdef”, and “ifndef” in this guide.
Ifdef Directive
As the name suggests, the makefile’s “ifdef” directive checks whether a variable is defined in a makefile or not, i.e. has been assigned with a value. The lines of the makefile that follow the “ifdef” directive are performed if the value of the variable is defined. If not, those lines are omitted.
To elaborate on the use of the “ifdef” directive in a makefile, we use the following makefile code. We define the “S” variable that contains a string and the NEW variable that uses a “subst” function to get an updated version of the “S” variable, i.e. by replacing “stones” with “waves”.
The default “all” target is defined along with PHONY targets to clean the build. The “print” target uses the @echo command to display the value of both variables that are defined in the previous lines.
It’s time to make use of the “ifdef” directive to apply a condition on both variables. The “S” or “NEW” label of the variable that is being tested is the only input that is accepted by the “ifdef” directive. Parentheses can be used to enclose the variable name, but they are not necessary. If the variable is already defined in the file, the first “echo” command is executed to display “Yes, ‘S’/’new’ is defined”. Otherwise, the “else” part of the directive is executed to display the contrary message which is “No, ‘variable-label’ is not defined”.
You can just skip the “else” part if you want to. In this case, we utilize a lowercase label for the second variable, “new”, which is not defined. Therefore, the “else” part should be executed after the make build. The “ifdef” directive ends with the “endif” keyword as depicted in the following:
NEW := $(subst stones, waves, $(S))
.PHONY: all print
all: print
print:
@echo S = $(S)
@echo New = $(NEW)
ifdef S
@echo Yes, 'S' is defined
else
@echo No, 'S' is not defined
endif
ifdef new
@echo Yes, 'new' is defined
else
@echo No, 'new' is not defined
endif
Let’s run the makefile via the “make” instruction in the CMD. First, it displays the values of both variables using the “echo” command. After that, it displays that the “S” variable is defined and “new” is not defined.
make
Ifndef Directive
The “ifndef” directive of makefile works exactly the opposite of the “ifdef” directive which confirms that a variable is not defined in a makefile as its name suggests. The “n” part of the “ifndef” directive represents “not”.
If required, you can also utilize the “else” part of the directive. To elaborate on the use of the “ifndef” directive, we employed the same makefile that we used for the “ifdef” directive with a little update. Nothing has been changed except that the “ifdef” keyword is replaced with the “ifndef” keyword for both the conditions at lines 9 and 15. The “ifndef” directive should display “defined” in the case of the “S” variable and “not defined” in the case of the “new” variable. But, we can expect the opposite because the execution lines of the code are the same as we used in the case of the “ifdef” directive.
NEW := $(subst stones, waves, $(S))
.PHONY: all print
all: print
print:
@echo S = $(S)
@echo New = $(NEW)
ifndef S
@echo Yes, 'S' is defined
else
@echo No, 'S' is not defined
endif
ifndef new
@echo Yes, 'new' is defined
else
@echo No, 'new' is not defined
endif
Running this makefile displays the variable values but also displays the wrong output in case of each variable, i.e. “S” is defined and “new” is not defined in the file.
make
It’s time to correct the makefile to output the logically correct statements on the execution of the “ifndef” directive. Therefore, we switch the placement of echo statements in both the conditions at lines 9 and 15. The @echo command at line 10 is switched with the @echo command at line 12 in case of the “S” variable, while the @echo command at line 16 is switched with the @echo command of line 18 in case of a “new” variable.
NEW := $(subst stones, waves, $(S))
.PHONY: all print
all: print
print:
@echo S = $(S)
@echo New = $(NEW)
ifndef S
@echo No, 'S' is not defined
else
@echo 'S' is defined
endif
ifndef new
@echo No, 'new' is not defined
else
@echo 'new' is defined
endif
Now, running the “make” instruction displays the logically correct output on our command screen: the “S” variable is defined, and “new” is not defined in the makefile.
make
Ifelse Directive
In a makefile, the “ifelse” statement is a conditional directive that accepts two inputs. The condition that is put to the test is the first input. The code that runs if the condition is met is the second parameter. The code that runs if the criteria is false is the last parameter.
To elaborate on the “ifelse” directive of a makefile, we create a new makefile illustration that is shown in the following code. After declaring the C++ compiler and its flags through variables, we define the SRC variable which contains the “name.cpp” filename as its value. The TARGET variable utilizes the “ifelse” directive to get its value. The “ifelse” uses the SRC variable as its first argument to be checked if it exists or not. If it exists, the target file name should be “name”. Otherwise, it will be “test” as per the second and third arguments of the “ifelse” directive.
The default “all” target depends on the “TARGET” variable that is used to define the makefile rule. The makefile rule at line 6 defines the “TARGET” target which depends on the SRC variable and uses the C++ compiler and its flags to create an executable file. The last line defines the “clean” target that can be utilized to remove the build files from the directory.
CXXFLAGS = -std=c++11 -Wall
SRC = name.cpp
TARGET := $(if $(SRC), name, test)
all: $(TARGET)
$(TARGET): $(SRC)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(SRC)
clean:
rm -f new
When the condition in the “ifelse” directive is true, the executable named “name” is generated in the same working directory.
make
Let’s replace the SRC variable with “S” in the “ifelse” directive; no variable is defined with the name “S”.
CXXFLAGS = -std=c++11 -Wall
SRC = name.cpp
TARGET := $(if $(S), name, test)
all: $(TARGET)
$(TARGET): $(SRC)
$(CXX) $(CXXFLAGS) -o $(TARGET) $(SRC)
clean:
rm -f new
The target executable “test” is generated since the “S” variable is missing in the makefile.
Conclusion
This guide is all about the use of conditional directives in makefiles to create a robust structure. We elaborated the easy-to-learn examples of “ifelse”, “ifdef”, and “ifndef” conditional directives with the help of variables.