The Conditional Variable Assignment Operator in a Makefile

Last updated: March 18, 2024

makefile conditional assignment

It's finally here:

>> The Road to Membership and Baeldung Pro .

Going into ads, no-ads reading , and bit about how Baeldung works if you're curious :)

We’ve started a new DevOps area on the site. If you’re interested in writing about DevOps, check out the Contribution Guidelines .

1. Overview

Make is a de-facto tool for building and running software projects. In this article, we’ll learn about the conditional variable assignment operator ( ?= ) using a simple use case .

Let’s start by writing a simple Makefile and adding a target called greet :

Now, let’s use the make command to execute the greet target:

We should note that we used the @ prefix before the target definition. That instructs the Make tool to suppress the command definition while showing the output and limiting the output to the result of the executed command.

Great! We’ve got a basic setup ready with us. We’ll extend this Makefile in the next section by using variable definitions.

3. Variables in a Makefile

So far, the greeting shown to the user by our Makefile is a static text, so all users get the same greeting message. To make it dynamic, let’s include the login username in the message so that the greeting is more personalized for each user.

Let’s define a user variable and initialize it with the output of the whoami command by using the assignment ( = ) operator:

We should note that we followed a standard naming convention of using lowercase letters in the variable name because the variable’s scope is limited to the Makefile .

Further, let’s now use this variable in the greet target by referencing this variable using the $() operator :

Next, let’s see the revised greeting in action by executing the greet target again:

It looks like we’ve got it right!

4. Using the Conditional Variable Assignment Operator ( ?= )

Now that we understand the basics of using a variable in a Makefile , we’ll be more comfortable understanding the ?= operator, which is used for conditional variable assignment in a Makefile .

To that end, let’s extend our Makefile by allowing the user to specify the username to be mentioned in the greeting  instead of using the login name. However, we want to keep this optional, so if the user doesn’t specify the value, we still resort to the default behavior of using the login name.

As part of the refactoring exercise, we need to use the ?= operator in place of the = operator so that we don’t override the value if the variable already holds a value. Secondly, we’ll now use uppercase letters in the variable name because we’re extending its scope by letting the user define it from the outside:

Next, let’s see the two scenarios in action:

In the first scenario, we must note that we passed the USER variable’s value as an argument to the make command to get a custom username. On the other hand, in the second scenario, we didn’t pass the value of the USER variable, so we got the default login name in the greeting message.

Fairly straightforward, right? That’s all we need to know for using the conditional operator to create an effective Makefile for our projects.

5. Conclusion

In this tutorial, we took a step-by-step approach to learn about the conditional variable assignment in a Makefile . We first understood the basics of using variables in a Makefile , followed by using the ?= operator for a more advanced use case.

Understanding and Using Makefile Variables

Table of contents

What are make variables, how to use make variables, recursive and simple assignment, immediate assignment, conditional assignment, shell assignment, variables with spaces, target-specific variables, pattern-specific variables, environment variables, command-line arguments, how to append to a variable, automatic variables, implicit variables.

  • ‣ Makefile Examples
  • ‣ Makefile Wildcards
  • ‣ G++ Makefile

Learn More About Earthly

Earthly makes builds super simple. Learn More

Understanding and Using Makefile Variables

Aniket Bhattacharyea %

In this Series

Table of Contents

The article explains the intricacies of Makefile variables. Earthly improves on Makefile performance by introducing sophisticated caching and concurrent execution. Learn more about Earthly .

Since its appearance in 1976, Make has been helping developers automate complex processes for compiling code, building executables, and generating documentation.

Like other programming languages, Make lets you define and use variables that facilitate reusability of values.

Have you found yourself using the same value in multiple places? This is both repetitive and prone to errors. If you’d like to change this value, you’ll have to change it everywhere. This process is tedious, but it can be solved with variables, and Make offers powerful variable manipulation techniques that can make your life easier.

In this article, you’ll learn all about make variables and how to use them.

A variable is a named construct that can hold a value that can be reused in the program. It is defined by writing a name followed by = , := , or ::= , and then a value. The name of a variable can be any sequence of characters except “:”, “#”, “=”, or white space. In addition, variable names in Make are case sensitive, like many other programming languages.

The following is an example of a variable definition:

Any white space before the variable’s value is stripped away, but white spaces at the end are preserved. Using a $ inside the value of the variable is permitted, but make will assume that a string starting with the $ sign is referring to another variable and will substitute the variable’s value:

As you’ll soon learn, make assumes that $t refers to another variable named t and substitutes it. Since t doesn’t exist, it’s empty, and therefore, foo becomes onewo . If you want to include a $ verbatim, you must escape it with another $ :

Once defined, a variable can be used in any target, prerequisite, or recipe. To substitute a variable’s value, you need to use a dollar sign ( $ ) followed by the variable’s name in parentheses or curly braces. For instance, you can refer to the foo variable using both ${foo} and $(foo) .

Here’s an example of a variable reference in a recipe:

Running make with the earlier makefile will print “Hello, World!”.

Another common example of variable usage is in compiling a C program where you can define an objects variable to hold the list of all object files:

Here, the objects variable has been used in a target, prerequisite, and recipe.

Unlike many other programming languages, using a variable that you have not set explicitly will not result in an error; rather, the variable will have an empty string as its default value. However, some special variables have built-in non-empty values, and several other variables have different default values set for each different rule (more on this later).

How to Set Variables

How to Set Variables

Setting a variable refers to defining a variable with an initial value as well as changing its value later in the program. You can either set a value explicitly in the makefile or pass it as an environment variable or a command-line argument.

Variables in the Makefile

There are four different ways you can define a variable in the Makefile:

  • Recursive assignment
  • Simple assignment
  • Immediate assignment
  • Conditional assignment

As you may remember, you can define a variable with = , := , and ::= . There’s a subtle difference in how variables are expanded based on what operator is used to define them.

  • The variables defined using = are called recursively expanded variables , and
  • Those defined with := and ::= are called simply expanded variables .

When a recursively expanded variable is expanded, its value is substituted verbatim. If the substituted text contains references to other variables, they are also substituted until no further variable reference is encountered. Consider the following example where foo expands to Hello $(bar) :

Since foo is a recursively expanded variable, $(bar) is also expanded, and “Hello World” is printed. This recursive expansion process is performed every time the variable is expanded, using the current values of any referenced variables:

The biggest advantage of recursively expanded variables is that they make it easy to construct new variables piecewise: you can define separate pieces of the variable and string them together. You can define more granular variables and join them together, which gives you finer control over how make is executed.

For example, consider the following snippet that is often used in compiling C programs:

Here, ALL_CFLAGS is a recursively expanded variable that expands to include the contents of CFLAGS along with the -I. option. This lets you override the CFLAGS variable if you wish to pass other options while retaining the mandatory -I. option:

A disadvantage of recursively expanded variables is that it’s not possible to append something to the end of the variable:

To overcome this issue, GNU Make supports another flavor of variable known as simply expanded variables , which are defined with := or ::= . A simply expanded variable, when defined, is scanned for further variable references, and they are substituted once and for all.

Unlike recursively expanded variables, where referenced variables are expanded to their current values, in a simply expanded variable, referenced variables are expanded to their values at the time the variable is defined:

With a simply expanded variable, the following is possible:

GNU Make supports simply and recursively expanded variables. However, other versions of make usually only support recursively expanded variables. The support for simply expanded variables was added to the Portable Operating System Interface (POSIX) standard in 2012 with only the ::= operator.

A variable defined with :::= is called an immediately expanded variable . Like a simply expanded variable, its value is expanded immediately when it’s defined. But like a recursively expanded variable, it will be re-expanded every time it’s used. After the value is immediately expanded, it will automatically be quoted, and all instances of $ in the value after expansion will be converted into $$ .

In the following code, the immediately expanded variable foo behaves similarly to a simply expanded variable:

However, if there are references to other variables, things get interesting:

Here, OUT will have the value one$$two . This is because $(var) is immediately expanded to one$two , which is quoted to get one$$two . But OUT is a recursive variable, so when it’s used, $two will be expanded:

The :::= operator is supported in POSIX Make, but GNU Make includes this operator from version 4.4 onward.

The conditional assignment operator ?= can be used to set a variable only if it hasn’t already been defined:

An equivalent way of defining variables conditionally is to use the origin function :

These four types of assignments can be used in some specific situations:

You may sometimes need to run a shell command and assign its output to a variable. You can do that with the shell function:

A shorthand for this is the shell assignment operator != . With this operator, the right-hand side must be the shell command whose result will be assigned to the left-hand side:

Trailing spaces at the end of a variable definition are preserved in the variable value, but spaces at the beginning are stripped away:

It’s possible to preserve spaces at the beginning by using a second variable to store the space character:

It’s possible to limit the scope of a variable to specific targets only. The syntax for this is as follows:

Here’s an example:

Here, the variable foo will have different values based on which target make is currently evaluating:

Pattern-Specific Variables

Pattern-specific variables make it possible to limit the scope of a variable to targets that match a particular pattern . The syntax is similar to target-specific variables:

For example, the following line sets the variable foo to World for any target that ends in .c :

Pattern-specific variables are commonly used when you want to set the variable for multiple targets that share a common pattern , such as setting the same compiler options for all C files.

The real power of make variables starts to show when you pair them with environment variables . When make is run in a shell, any environment variable present in the shell is transformed into a make variable with the same name and value. This means you don’t have to set them in the makefile explicitly:

When you run the earlier makefile , it should print your username since the USER environment variable is present in the shell.

This feature is most commonly used with flags . For example, if you set the CFLAGS environment variable with your preferred C compiler options, they will be used by most makefiles to compile C code since, conventionally, the CFLAGS variable is only used for this purpose. However, this is only sometimes guaranteed, as you’ll see next.

If there’s an explicit assignment in the makefile to a variable, it overrides any environment variable with the same name:

The earlier makefile will always print Bob since the assignment overrides the $USER environment variable. You can pass the -e flag to make so environment variables override assignments instead, but this is not recommended, as it can lead to unexpected results.

You can pass variable values to the make command as command-line variables. Unlike environment variables, command-line arguments will always override assignments in the makefile unless the override directive is used:

You can simply run make , and the default values will be used:

You can pass a new value for BAR by passing it as a command-line argument:

However, since the override directive is used with FOO , it cannot be changed via command-line arguments:

This feature is handy since it lets you change a variable’s value without editing the makefile . This is most commonly used to pass configuration options that may vary from system to system or used to customize the software. As a practical example, Vim uses command-line arguments to override configuration options , like the runtime directory and location of the default configuration.

How to Append to a Variable

You can use the previous value of a simply expanded variable to add more text to it:

As mentioned before, this syntax will produce an infinite recursion error with a recursively expanded variable. In this case, you can use the += operator, which appends text to a variable, and it can be used for both recursively expanded and simply expanded variables:

However, there’s a subtle difference in the way it works for the two different flavors of variables, which you can read about in the docs .

How To Use Special Variables

In Make, any variable that is not defined is assigned an empty string as the default value. There are, however, a few special variables that are exceptions:

Automatic variables are special variables whose value is set up automatically per rule based on the target and prerequisites of that particular rule. The following are several commonly used automatic variables:

  • $@ is the file name of the target of the rule.
  • $< is the name of the first prerequisite.
  • $? is the name of all the prerequisites that are newer than the target, with spaces between them. If the target does not exist, all prerequisites will be included.
  • $^ is the name of all the prerequisites, with spaces between them.

Here’s an example that shows automatic variables in action:

Running make with the earlier makefile prints the following:

If you run touch one to modify one and run make again, you’ll get a different output:

Since one is newer than the target hello , $? contains only one .

There exist variants of these automatic variables that can extract the directory and file-within-directory name from the matched expression. You can find a list of all automatic variables in the official docs .

Automatic variables are often used where the target and prerequisite names dictate how the recipe executes . A very common practical example is the following rule that compiles a C file of the form x.c into x.o :

Make ships with certain predefined rules for some commonly performed operations. These rules include the following:

  • Compiling x.c to x.o with a rule of the form $(CC) -c $(CPPFLAGS) $(CFLAGS) $^ -o $@
  • Compiling x.cc or x.cpp with a rule of the form $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
  • Linking a static object file x.o to create x with a rule of the form $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
  • And many more

These implicit rules make use of certain predefined variables known as implicit variables. Some of these are as follows:

  • CC is a program for compiling C programs. The default is cc .
  • CXX is a program for compiling C++ programs. The default is g++ .
  • CPP is a program for running the C preprocessor. The default is $(CC) -E .
  • LEX is a program to compile Lex grammars into source code. The default is lex .
  • YACC is a program to compile Yacc grammars into source code. The default is yacc .

You can find the full list of implicit variables in GNU Make’s docs .

Just like standard variables, you can explicitly define an implicit variable:

Or you can define them with command line arguments:

Flags are special variables commonly used to pass options to various command-line tools, like compilers or preprocessors. Compilers and preprocessors are implicitly defined variables for some commonly used tools, including the following:

  • CFLAGS is passed to CC for compiling C.
  • CPPFLAGS is passed to CPP for preprocessing C programs.
  • CXXFLAGS is passed to CXX for compiling C++.

Learn more about Makefile flags .

Make variables are akin to variables in other languages with unique features that make them effective yet somewhat complex. Learning them can be a handy addition to your programming toolkit. If you’ve enjoyed diving into the intricacies of Makefile variables, you might want to explore Earthly for a fresh take on builds!

Bala Priya C %

Bala is a technical writer who enjoys creating long-form content. Her areas of interest include math and programming. She shares her learning with the developer community by authoring tutorials, how-to guides, and more.

makefile conditional assignment

12 minute read

Learn how to automate the software building process using `make`, a powerful tool that saves time and resources. This article covers the basics of writing a ...

makefile conditional assignment

8 minute read

Learn how to use wildcards in Makefiles to create flexible and automated build processes. This tutorial provides examples and explanations of common wildcard...

  • Getting started with makefile
  • .PHONY target
  • Advanced Makefile
  • GNU Pattern Rules
  • Appending Text To an Existing Variable
  • Automatic Variables
  • Conditional Variable Assignment
  • Recursively-Expanded Variables
  • Referencing a Variable
  • Simply-Expanded Variables

makefile Variables Conditional Variable Assignment

Fastest entity framework extensions.

The ?= operator is an extension that behaves like = , except that the assignment only occurs if the variable is not already set.

Got any makefile Question?

pdf

  • Advertise with us
  • Cookie Policy
  • Privacy Policy

Get monthly updates about new articles, cheatsheets, and tricks.

Next: Functions , Previous: Using Variables , Up: Top   [ Contents ][ Index ]

7 Conditional Parts of Makefiles

A conditional directive causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. Conditionals control what make actually “sees” in the makefile, so they cannot be used to control recipes at the time of execution.

  Example of a conditional
  The syntax of conditionals.
  Conditionals that test flags.

Next: Conditional Syntax , Previous: Conditionals , Up: Conditionals   [ Contents ][ Index ]

7.1 Example of a Conditional

The following example of a conditional tells make to use one set of libraries if the CC variable is ‘ gcc ’, and a different set of libraries otherwise. It works by controlling which of two recipe lines will be used for the rule. The result is that ‘ CC=gcc ’ as an argument to make changes not only which compiler is used but also which libraries are linked.

This conditional uses three directives: one ifeq , one else and one endif .

The ifeq directive begins the conditional, and specifies the condition. It contains two arguments, separated by a comma and surrounded by parentheses. Variable substitution is performed on both arguments and then they are compared. The lines of the makefile following the ifeq are obeyed if the two arguments match; otherwise they are ignored.

The else directive causes the following lines to be obeyed if the previous conditional failed. In the example above, this means that the second alternative linking command is used whenever the first alternative is not used. It is optional to have an else in a conditional.

The endif directive ends the conditional. Every conditional must end with an endif . Unconditional makefile text follows.

As this example illustrates, conditionals work at the textual level: the lines of the conditional are treated as part of the makefile, or ignored, according to the condition. This is why the larger syntactic units of the makefile, such as rules, may cross the beginning or the end of the conditional.

When the variable CC has the value ‘ gcc ’, the above example has this effect:

When the variable CC has any other value, the effect is this:

Equivalent results can be obtained in another way by conditionalizing a variable assignment and then using the variable unconditionally:

Next: Testing Flags , Previous: Conditional Example , Up: Conditionals   [ Contents ][ Index ]

7.2 Syntax of Conditionals

The syntax of a simple conditional with no else is as follows:

The text-if-true may be any lines of text, to be considered as part of the makefile if the condition is true. If the condition is false, no text is used instead.

The syntax of a complex conditional is as follows:

There can be as many “ else conditional-directive ” clauses as necessary. Once a given condition is true, text-if-true is used and no other clause is used; if no condition is true then text-if-false is used. The text-if-true and text-if-false can be any number of lines of text.

The syntax of the conditional-directive is the same whether the conditional is simple or complex; after an else or not. There are four different directives that test different conditions. Here is a table of them:

Expand all variable references in arg1 and arg2 and compare them. If they are identical, the text-if-true is effective; otherwise, the text-if-false , if any, is effective.

Often you want to test if a variable has a non-empty value. When the value results from complex expansions of variables and functions, expansions you would consider empty may actually contain whitespace characters and thus are not seen as empty. However, you can use the strip function (see Text Functions ) to avoid interpreting whitespace as a non-empty value. For example:

will evaluate text-if-empty even if the expansion of $(foo) contains whitespace characters.

Expand all variable references in arg1 and arg2 and compare them. If they are different, the text-if-true is effective; otherwise, the text-if-false , if any, is effective.

The ifdef form takes the name of a variable as its argument, not a reference to a variable. If the value of that variable has a non-empty value, the text-if-true is effective; otherwise, the text-if-false , if any, is effective. Variables that have never been defined have an empty value. The text variable-name is expanded, so it could be a variable or function that expands to the name of a variable. For example:

The variable reference $(foo) is expanded, yielding bar , which is considered to be the name of a variable. The variable bar is not expanded, but its value is examined to determine if it is non-empty.

Note that ifdef only tests whether a variable has a value. It does not expand the variable to see if that value is nonempty. Consequently, tests using ifdef return true for all definitions except those like foo = . To test for an empty value, use ifeq ($(foo),) . For example,

sets ‘ frobozz ’ to ‘ yes ’, while:

sets ‘ frobozz ’ to ‘ no ’.

If the variable variable-name has an empty value, the text-if-true is effective; otherwise, the text-if-false , if any, is effective. The rules for expansion and testing of variable-name are identical to the ifdef directive.

Extra spaces are allowed and ignored at the beginning of the conditional directive line, but a tab is not allowed. (If the line begins with a tab, it will be considered part of a recipe for a rule.) Aside from this, extra spaces or tabs may be inserted with no effect anywhere except within the directive name or within an argument. A comment starting with ‘ # ’ may appear at the end of the line.

The other two directives that play a part in a conditional are else and endif . Each of these directives is written as one word, with no arguments. Extra spaces are allowed and ignored at the beginning of the line, and spaces or tabs at the end. A comment starting with ‘ # ’ may appear at the end of the line.

Conditionals affect which lines of the makefile make uses. If the condition is true, make reads the lines of the text-if-true as part of the makefile; if the condition is false, make ignores those lines completely. It follows that syntactic units of the makefile, such as rules, may safely be split across the beginning or the end of the conditional.

make evaluates conditionals when it reads a makefile. Consequently, you cannot use automatic variables in the tests of conditionals because they are not defined until recipes are run (see Automatic Variables ).

To prevent intolerable confusion, it is not permitted to start a conditional in one makefile and end it in another. However, you may write an include directive within a conditional, provided you do not attempt to terminate the conditional inside the included file.

Previous: Conditional Syntax , Up: Conditionals   [ Contents ][ Index ]

7.3 Conditionals that Test Flags

You can write a conditional that tests make command flags such as ‘ -t ’ by using the variable MAKEFLAGS together with the findstring function (see Functions for String Substitution and Analysis ). This is useful when touch is not enough to make a file appear up to date.

The findstring function determines whether one string appears as a substring of another. If you want to test for the ‘ -t ’ flag, use ‘ t ’ as the first string and the value of MAKEFLAGS as the other.

For example, here is how to arrange to use ‘ ranlib -t ’ to finish marking an archive file up to date:

The ‘ + ’ prefix marks those recipe lines as “recursive” so that they will be executed despite use of the ‘ -t ’ flag. See Recursive Use of make .

Makefile: Target-Specific Variables and Conditional Assignments

Understanding Makefile Target-Specific Variables and Ignoring Other Conditional Assignments

Abstract: In this article, we will discuss how to use target-specific variables in Makefiles and how to ignore other conditional assignments.

Understanding Makefile Target-Specific Variables and Ignoring Conditional Assignments

In this article, we will discuss Makefile target-specific variables and how to ignore conditional assignments. Makefiles are used to automate the build process in Unix-based operating systems. They are written in the Makefile language and contain rules and variables that define how to build software.

Target-Specific Variables

Target-specific variables are variables that are only defined for a specific target. They override the global variables for that target. This is useful when you want to define different variables for different targets.

For example, consider the following Makefile:

In this Makefile, there are three targets: plus , cond , and set . The plus target exports the FOO variable with the value plus added to it. The cond target exports the FOO variable with the value cond if it is not already defined. The set target exports the FOO variable with the value set .

When we run the make plus command, we get the following output:

This is because the plus target exports the FOO variable with the value plus added to it. When we run the make cond command, we get the following output:

This is because the cond target exports the FOO variable with the value cond if it is not already defined. Since the FOO variable is not defined in the global scope, the cond value is used.

When we run the make set command, we get the following output:

This is because the set target exports the FOO variable with the value set . Since the FOO variable is already defined in the global scope, the set value is used.

Ignoring Conditional Assignments

Conditional assignments are assignments that are only made if a certain condition is true. In Makefiles, conditional assignments are made using the ?= operator. If the variable is already defined, the conditional assignment is ignored.

In this Makefile, the cond target has a conditional assignment for the FOO variable. If the FOO variable is not already defined, it is assigned the value cond . If the FOO variable is already defined, the conditional assignment is ignored.

This is because the cond target has a conditional assignment for the FOO variable. Since the FOO variable is not defined in the global scope, the cond value is used.

  • Target-specific variables are variables that are only defined for a specific target. They override the global variables for that target.
  • Conditional assignments are assignments that are only made if a certain condition is true. In Makefiles, conditional assignments are made using the ?= operator.
  • If the variable is already defined, the conditional assignment is ignored.
  • Target-specific Variables
  • Conditional Variables

Tags: :  Makefile Variables Conditional Assignments

Latest news

  • Code Hook System Call: Resolving Issues with 5.15.0-113 and 5.15.0-119 Kernels
  • Effectively Loading Images in Spring Boot: A Comprehensive Guide
  • Mailcatcher and Codeception in Github Actions: Setting Up Mailcatcher with Install Command
  • Programmatically Sending Key Combinations: Ctrl+Alt+Shift+Right Arrow
  • Decimal Error in Excel: Writing SQL Query Results
  • Applying Pulse Effect to 3D Extruded Polygon Meshes in Three.js
  • Deploying a Vue.js Project with Nuxt.js and Netlify: A Troubleshooting Guide
  • Handling 404 Errors in Next.js API Routes for GET Requests Only
  • XeLaTeX not finding font path for QTLinostroke.otf with TexLive-Fonts-Extra on Ubuntu
  • Running Sequelize Query with Fetch Row Associated Model
  • Managing Custom Size Variants and Inputs for Size Selection in Shopify
  • Azure Devops YAML Pipeline: Condition Variable Not Working - A Fix
  • Gracefully Stopping Spring Batch Jobs After App Crash and DB Restart in Spring Boot
  • Installing Tkinter with a Specific Python Version: A Common Issue
  • Integrating Metal Price API Data into MySQL Localhost Database
  • Exploring BUPA R Process Mining with R: An Event Log Analysis
  • Triggering Container Image Build with GitLab-CI: Branch-Specific Image (imagetag=branchslug)
  • Adding Webpage Screenshot Functionality to CentOS Server
  • Chrome Devtools Still Doesn't Allow Putting Breakpoint Inside Async Function
  • Fixing Trade Entries in a Pine Script Asian Strategy
  • Unresolved Issue: Closed Workbooks in VBA Editor Persist
  • Creating a Controller with OpenAPI Generator in Java 21 and Spring Boot 3.3: Handling Default Response Entities
  • Zephyr RF52840 DK: Logging RSSI Every Second with Zephyr-Issue-create-thread-MPUFAULT
  • Using Form Data with Two Data Sources: A Practical Approach
  • Manually Controlling a Humanoid Character with Waypoint Bone in Script
  • Call Button Not Working in Flutter? Here's How to Make It Functional
  • Preventing Position Items from Being Removed in SwiftUI ScrollView
  • Adding a Certificate to Fiddler HTTP Request
  • Taking Screenshots with Python and libPNG: Error Solution
  • Unable to Validate Leave Request in Inactive Analytic Account in Odoo 15
  • Understanding the Foundry Slate Textbox Layout: Display Function and Default Values
  • Creating a 'Generate Scripts' Unity Menu Item: A Step-by-Step Guide
  • iPadOS 17: Expected popoverview, found null - Swift Error Explanation
  • Checking Criteria: Meeting the Patch Count for Given Machine IDs
  • Resetting Angular Template Reference Variables: A Comprehensive Guide
[ ] [ ]   [ ] [ ] [ ]         [ ] [ ] [ ] [ ]

7. Conditional Parts of Makefiles

A conditional causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. Conditionals control what make actually “sees” in the makefile, so they cannot be used to control shell commands at the time of execution.

   Example of a conditional
   The syntax of conditionals.
   Conditionals that test flags.

7.1 Example of a Conditional

The following example of a conditional tells make to use one set of libraries if the CC variable is ‘ gcc ’, and a different set of libraries otherwise. It works by controlling which of two command lines will be used as the command for a rule. The result is that ‘ CC=gcc ’ as an argument to make changes not only which compiler is used but also which libraries are linked.

 

This conditional uses three directives: one ifeq , one else and one endif .

The ifeq directive begins the conditional, and specifies the condition. It contains two arguments, separated by a comma and surrounded by parentheses. Variable substitution is performed on both arguments and then they are compared. The lines of the makefile following the ifeq are obeyed if the two arguments match; otherwise they are ignored.

The else directive causes the following lines to be obeyed if the previous conditional failed. In the example above, this means that the second alternative linking command is used whenever the first alternative is not used. It is optional to have an else in a conditional.

The endif directive ends the conditional. Every conditional must end with an endif . Unconditional makefile text follows.

As this example illustrates, conditionals work at the textual level: the lines of the conditional are treated as part of the makefile, or ignored, according to the condition. This is why the larger syntactic units of the makefile, such as rules, may cross the beginning or the end of the conditional.

When the variable CC has the value ‘ gcc ’, the above example has this effect:

When the variable CC has any other value, the effect is this:

Equivalent results can be obtained in another way by conditionalizing a variable assignment and then using the variable unconditionally:

7.2 Syntax of Conditionals

The syntax of a simple conditional with no else is as follows:

  endif

The text-if-true may be any lines of text, to be considered as part of the makefile if the condition is true. If the condition is false, no text is used instead.

The syntax of a complex conditional is as follows:

  else endif
  else else endif

There can be as many “ else conditional-directive ” clauses as necessary. Once a given condition is true, text-if-true is used and no other clause is used; if no condition is true then text-if-false is used. The text-if-true and text-if-false can be any number of lines of text.

The syntax of the conditional-directive is the same whether the conditional is simple or complex; after an else or not. There are four different directives that test different conditions. Here is a table of them:

Expand all variable references in arg1 and arg2 and compare them. If they are identical, the text-if-true is effective; otherwise, the text-if-false , if any, is effective.

Often you want to test if a variable has a non-empty value. When the value results from complex expansions of variables and functions, expansions you would consider empty may actually contain whitespace characters and thus are not seen as empty. However, you can use the strip function (see section Functions for String Substitution and Analysis ) to avoid interpreting whitespace as a non-empty value. For example:

will evaluate text-if-empty even if the expansion of $(foo) contains whitespace characters.

Expand all variable references in arg1 and arg2 and compare them. If they are different, the text-if-true is effective; otherwise, the text-if-false , if any, is effective.

The ifdef form takes the name of a variable as its argument, not a reference to a variable. The value of that variable has a non-empty value, the text-if-true is effective; otherwise, the text-if-false , if any, is effective. Variables that have never been defined have an empty value. The text variable-name is expanded, so it could be a variable or function that expands to the name of a variable. For example:

The variable reference $(foo) is expanded, yielding bar , which is considered to be the name of a variable. The variable bar is not expanded, but its value is examined to determine if it is non-empty.

Note that ifdef only tests whether a variable has a value. It does not expand the variable to see if that value is nonempty. Consequently, tests using ifdef return true for all definitions except those like foo = . To test for an empty value, use ifeq ($(foo),) . For example,

sets ‘ frobozz ’ to ‘ yes ’, while:

sets ‘ frobozz ’ to ‘ no ’.

If the variable variable-name has an empty value, the text-if-true is effective; otherwise, the text-if-false , if any, is effective. The rules for expansion and testing of variable-name are identical to the ifdef directive.

Extra spaces are allowed and ignored at the beginning of the conditional directive line, but a tab is not allowed. (If the line begins with a tab, it will be considered a command for a rule.) Aside from this, extra spaces or tabs may be inserted with no effect anywhere except within the directive name or within an argument. A comment starting with ‘ # ’ may appear at the end of the line.

The other two directives that play a part in a conditional are else and endif . Each of these directives is written as one word, with no arguments. Extra spaces are allowed and ignored at the beginning of the line, and spaces or tabs at the end. A comment starting with ‘ # ’ may appear at the end of the line.

Conditionals affect which lines of the makefile make uses. If the condition is true, make reads the lines of the text-if-true as part of the makefile; if the condition is false, make ignores those lines completely. It follows that syntactic units of the makefile, such as rules, may safely be split across the beginning or the end of the conditional.

make evaluates conditionals when it reads a makefile. Consequently, you cannot use automatic variables in the tests of conditionals because they are not defined until commands are run (see section Automatic Variables ).

To prevent intolerable confusion, it is not permitted to start a conditional in one makefile and end it in another. However, you may write an include directive within a conditional, provided you do not attempt to terminate the conditional inside the included file.

7.3 Conditionals that Test Flags

You can write a conditional that tests make command flags such as ‘ -t ’ by using the variable MAKEFLAGS together with the findstring function (see section Functions for String Substitution and Analysis ). This is useful when touch is not enough to make a file appear up to date.

The findstring function determines whether one string appears as a substring of another. If you want to test for the ‘ -t ’ flag, use ‘ t ’ as the first string and the value of MAKEFLAGS as the other.

For example, here is how to arrange to use ‘ ranlib -t ’ to finish marking an archive file up to date:

The ‘ + ’ prefix marks those command lines as “recursive” so that they will be executed despite use of the ‘ -t ’ flag. See section Recursive Use of make .

[ ] [ ]           [ ] [ ] [ ] [ ]

This document was generated on October 20, 2021 using texi2html 1.82 .

  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Advertising & Talent Reach devs & technologists worldwide about your product, service or employer brand
  • OverflowAI GenAI features for Teams
  • OverflowAPI Train & fine-tune LLMs
  • Labs The future of collective knowledge sharing
  • About the company Visit the blog

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

How to assign the output of a command to a Makefile variable

I need to execute some make rules conditionally, only if the Python installed is greater than a certain version (say 2.5).

I thought I could do something like executing:

and then using the output ('1' if ok, '0' otherwise) in a ifeq make statement.

In a simple bash shell script it's just:

but that doesn't work in a Makefile.

Any suggestions? I could use any other sensible workaround to achieve this.

tshepang's user avatar

  • Strange back ticks around the command work for executing other scripts for me in a Makefile. Might be something else. –  leif.gruenwoldt Commented Jan 13, 2014 at 15:50
  • @LeifGruenwoldt that's likely a coincidence. Make is copying your backticks to your shell and your shell is interpreting them - see stackoverflow.com/questions/60628832/… That works often but is dangerous because if you use the variable inside a shell quoted environment it may not get executed. Use the answer from below in preference. –  Michael Commented Oct 14, 2022 at 14:47
  • MY_VAR != python3 -c "print('hi')" . In GNU Make at least –  Neil McGuigan Commented Nov 8, 2022 at 23:57

8 Answers 8

Use the Make shell builtin like in MY_VAR=$(shell echo whatever)

OneCricketeer's user avatar

  • 49 shell is not a standard Make builtin command. This is a GNU Make builtin. –  Dereckson Commented Feb 18, 2014 at 20:17
  • 21 stackoverflow.com/a/2373111/12916 adds an important note about escaping $ . –  Jesse Glick Commented Aug 25, 2014 at 22:27
  • 10 This simple example works. It also works with shell commands pipeline. But it is essential that you should use $$ to represent $ in the shell command –  Sergey P. aka azure Commented Oct 7, 2014 at 9:12
  • 42 While question is mildly old, it's best to do MY_VAR := $(shell ...), otherwise every time MY_VAR is evaluated, it'll execute $(shell ...) again. –  Russ Schultz Commented Aug 25, 2015 at 15:57
  • 4 Replace shell echo whatever with python -c 'import sys; print int(sys.version_info >= (2,5))' . You get "syntax error near unexpected token". I can't understand how anyone thought this answered the question. Can anyone please explain what I'm missing? –  AlanSE Commented Oct 23, 2017 at 16:10

Beware of recipes like this

It does two things wrong. The first line in the recipe is executed in a separate shell instance from the second line. The variable is lost in the meantime. Second thing wrong is that the $ is not escaped.

Both problems have been fixed and the variable is useable. The backslash combines both lines to run in one single shell, hence the setting of the variable and the reading of the variable afterwords, works.

One final improvement, if the consumer expects an "environment variable" to be set, then you have to export it.

would need this in the makefile

In general, one should avoid doing any real work outside of recipes, because if someone use the makefile with '--dry-run' option, to only SEE what it will do, it won't have any undesirable side effects. Every $(shell) call is evaluated at compile time and some real work could accidentally be done. Better to leave the real work to the inside of the recipes when possible.

Juraj's user avatar

With GNU Make, you can use shell and eval to store, run, and assign output from arbitrary command line invocations. The difference between the example below and those which use := is the := assignment happens once (when it is encountered) and for all. Recursively expanded variables set with = are a bit more "lazy"; references to other variables remain until the variable itself is referenced, and the subsequent recursive expansion takes place each time the variable is referenced , which is desirable for making "consistent, callable, snippets". See the manual on setting variables for more info.

Mitchell Tracy's user avatar

  • You have the first nice explanation I've every come across. Thank you. Though one thing to add is that if $(SET_ID) lives inside of an if clause that is false then it is still called . –  Roman Commented Nov 20, 2019 at 3:06
  • 2 It is still called because the if stmts are evaluated at makefile compile-time not at run-time. For run-time specific instructions, put them in recipes. If they are conditional, add if stmts, written in bash / shell, as part of the recipe. –  Juraj Commented Dec 5, 2019 at 20:50
  • 3 +100 for a simple, to the point explanation –  Prakash P Commented Dec 23, 2021 at 13:12

Wrapping the assignment in an eval is working for me.

Victor Sergienko's user avatar

  • 9 "Note: The @true here prevents Make from thinking there's nothing to be done." Um, that's what .PHONY always make these targets is for. –  underscore_d Commented Oct 23, 2016 at 14:19
  • Thank you! This helps me bypass "weird bash" in makefile –  Nam G VU Commented Oct 31, 2017 at 7:52
  • I thought .PHONY is supposed to be used the other way around: gnu.org/software/make/manual/html_node/Phony-Targets.html –  Ciprian Tomoiagă Commented Dec 30, 2022 at 14:27

Here's a bit more complicated example with piping and variable assignment inside recipe:

Francesco Casula's user avatar

  • 3 In case it ever comes handy I am using a bit similar approach to get PODNAME by deployment name: $(eval PODNAME=$(shell sh -c "kubectl get pod -l app=sqlproxy -o jsonpath='{.items[0].metadata.name}'")) –  Jan Richter Commented Aug 26, 2018 at 19:22
  • 2 The syntax confused me for a second until I realized you were using both the shell builtin eval (on the docker-env line) and the make function eval (on the next line). –  Rag Commented May 17, 2020 at 4:42
  • Can you explain why this syntax is needed? –  Edmondo Commented Dec 28, 2021 at 19:20

I'm writing an answer to increase visibility to the actual syntax that solves the problem. Unfortunately, what someone might see as trivial can become a very significant headache to someone looking for a simple answer to a reasonable question.

Put the following into the file "Makefile".

The behavior you would like to see is the following (assuming you have recent python installed).

If you copy and paste the above text into the Makefile, will you get this? Probably not. You will probably get an error like what is reported here:

makefile:4: *** missing separator. Stop

Why: Because although I personally used a genuine tab, Stack Overflow (attempting to be helpful) converts my tab into a number of spaces. You, frustrated internet citizen, now copy this, thinking that you now have the same text that I used. The make command, now reads the spaces and finds that the "all" command is incorrectly formatted. So copy the above text, paste it, and then convert the whitespace before "@echo" to a tab, and this example should, at last, hopefully, work for you.

AlanSE's user avatar

  • Depends on what editor you are pasting into. I just copied and pasted into an Eclipse Makefile editor, and got a leading tab (as required). –  Technophile Commented Jun 6, 2018 at 20:12
  • Oh I did not think of that. Atom here. –  AlanSE Commented Jun 6, 2018 at 20:35
  • 2 That's then because Eclipse converts these spaces into a tab, by recognizing the makefile syntax. In the SO web page, it's definitely spaces. –  Gerhard Commented Aug 3, 2020 at 17:09

In the below example, I have stored the Makefile folder path to LOCAL_PKG_DIR and then use LOCAL_PKG_DIR variable in targets.

Terminal output:

Amritpal Singh's user avatar

From the make manual

The shell assignment operator ‘!=’ can be used to execute a shell script and set a >variable to its output. This operator first evaluates the right-hand side, then passes >that result to the shell for execution. If the result of the execution ends in a >newline, that one newline is removed; all other newlines are replaced by spaces. The >resulting string is then placed into the named recursively-expanded variable. For >example: hash != printf '\043' file_list != find . -name '*.c'

Poniros's user avatar

  • not for target –  Belegnar Commented Jun 14 at 9:02
  • works on Linux, but does not work on my Mac M3 using GNU Make 3.81 –  Alex F Commented Jun 17 at 10:30

Your Answer

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Not the answer you're looking for? Browse other questions tagged shell makefile or ask your own question .

  • The Overflow Blog
  • At scale, anything that could fail definitely will
  • Featured on Meta
  • Announcing a change to the data-dump process
  • Bringing clarity to status tag usage on meta sites
  • What does a new user need in a homepage experience on Stack Overflow?
  • Feedback requested: How do you use tag hover descriptions for curating and do...
  • Staging Ground Reviewer Motivation

Hot Network Questions

  • Word for when someone tries to make others hate each other
  • Do I need to validate a Genoa MET daily ticket every time?
  • Invest smaller lump sum vs investing (larger) monthly amount
  • Velocity dispersion of stars in galaxies
  • Can it be acceptable to take over CTRL + F shortcut in web app
  • In roulette, is the frequency of getting long sequences of reds lower than that of shorter sequences?
  • Why is the wiper fluid hose on the Mk7 Golf covered in cloth tape?
  • Hip pain when cycling (experienced cyclist)
  • Whats the safest way to store a password in database?
  • How should I secure ceiling drywall with no edge backing?
  • How to survive 40c while golfing
  • Strange variable scope behavior when calling function recursivly
  • Is consciousness a prerequisite for knowledge?
  • figuring out the speed controller of a cassette tape motor
  • What happens to entropy during compression?
  • In Lord Rosse's 1845 drawing of M51, was the galaxy depicted in white or black?
  • Marie-Sklodowska-Curie actions: publish a part of the proposal just after the deadline?
  • Why is the stall speed of an aircraft a specific speed?
  • How To "Fly" A Special Call Sign
  • How do I keep my tikz drawing on the page?
  • Can a quadrilateral polygon have 3 obtuse angles?
  • Proof of the principle of explosion
  • Nearly stalled on takeoff after just 3 hours training on a PPL. Is this normal?
  • If a Palestinian converts to Judaism, can they get Israeli citizenship?

makefile conditional assignment

Next: Conditional Parts of Makefiles , Previous: Writing Recipes in Rules , Up: GNU make   [ Contents ][ Index ]

6 How to Use Variables

A variable is a name defined in a makefile to represent a string of text, called the variable’s value . These values are substituted by explicit request into targets, prerequisites, recipes, and other parts of the makefile. (In some other versions of make , variables are called macros .)

Variables and functions in all parts of a makefile are expanded when read, except for in recipes, the right-hand sides of variable definitions using ‘ = ’, and the bodies of variable definitions using the define directive. The value a variable expands to is that of its most recent definition at the time of expansion. In other words, variables are dynamically scoped.

Variables can represent lists of file names, options to pass to compilers, programs to run, directories to look in for source files, directories to write output in, or anything else you can imagine.

A variable name may be any sequence of characters not containing ‘ : ’, ‘ # ’, ‘ = ’, or whitespace. However, variable names containing characters other than letters, numbers, and underscores should be considered carefully, as in some shells they cannot be passed through the environment to a sub- make (see Communicating Variables to a Sub- make ). Variable names beginning with ‘ . ’ and an uppercase letter may be given special meaning in future versions of make .

Variable names are case-sensitive. The names ‘ foo ’, ‘ FOO ’, and ‘ Foo ’ all refer to different variables.

It is traditional to use upper case letters in variable names, but we recommend using lower case letters for variable names that serve internal purposes in the makefile, and reserving upper case for parameters that control implicit rules or for parameters that the user should override with command options (see Overriding Variables ).

A few variables have names that are a single punctuation character or just a few characters. These are the automatic variables , and they have particular specialized uses. See Automatic Variables .

  • Basics of Variable References
  • The Two Flavors of Variables
  • Advanced Features for Reference to Variables
  • How Variables Get Their Values
  • Setting Variables
  • Appending More Text to Variables
  • The override Directive
  • Defining Multi-Line Variables
  • Undefining Variables
  • Variables from the Environment
  • Target-specific Variable Values
  • Pattern-specific Variable Values
  • Suppressing Inheritance
  • Other Special Variables

IMAGES

  1. How to Write a Makefile with Ease

    makefile conditional assignment

  2. make and Makefiles

    makefile conditional assignment

  3. Makefile--conditional statement

    makefile conditional assignment

  4. How to Write a Makefile with Ease

    makefile conditional assignment

  5. Creating a makefile

    makefile conditional assignment

  6. Makefiles to Improve Your Life

    makefile conditional assignment

VIDEO

  1. Conditional and selected signal assignment statements

  2. C Language Tutorial for Beginners Part2 || Operators

  3. Operators in C

  4. Could not Compile Conditional Assignment in Rust #10

  5. Unreal Engine QUICKTIP

  6. Top 40 Javascript One Liners

COMMENTS

  1. Conditional Assignment (GNU make)

    6.2.4 Conditional Variable Assignment. There is another assignment operator for variables, ...

  2. The Conditional Variable Assignment Operator in a Makefile

    Let's define a user variable and initialize it with the output of the whoami command by using the assignment (=) operator: user= $(shell whoami) We should note that we followed a standard naming convention of using lowercase letters in the variable name because the variable's scope is limited to the Makefile.

  3. Using conditional rules in a makefile

    The correct usage of the Makefile is one of the below. make CATEGORY=parser TEST=basic. make ALL. If a user gives "JUST" the commands as indicated below, it should print a message saying "CATEGORY defined TEST undefined" and vice-versa. make CATEGORY=parser.

  4. Conditional Syntax (GNU make)

    7.2 Syntax of Conditionals. The syntax of a simple conditional with no else is as follows: conditional-directive text-if-true. endif. The text-if-true may be any lines of text, to be considered as part of the makefile if the condition is true. If the condition is false, no text is used instead. The syntax of a complex conditional is as follows ...

  5. Conditionals (GNU make)

    A conditional directive causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. Conditionals control what make actually "sees" in the makefile, so they cannot be used to control recipes at the time ...

  6. GNU Make

    Conditional Parts of Makefiles. A conditional causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. Conditionals control what make actually "sees" in the makefile, so they cannot be used to control ...

  7. Using Variables (GNU make)

    A variable is a name defined in a makefile to represent a string of text, called the variable's value. These values are substituted by explicit request into targets, prerequisites, recipes, and other parts of the makefile. (In some other versions of make, variables are called macros.) Variables and functions in all parts of a makefile are ...

  8. GNU make

    How to Use Variables. A variable is a name defined in a makefile to represent a string of text, called the variable's value. These values are substituted by explicit request into targets, prerequisites, commands, and other parts of the makefile. (In some other versions of make, variables are called macros.) Variables and functions in all parts ...

  9. Conditional Example (GNU make)

    Unconditional makefile text follows. As this example illustrates, conditionals work at the textual level: the lines of the conditional are treated as part of the makefile, or ignored, according to the condition. This is why the larger syntactic units of the makefile, such as rules, may cross the beginning or the end of the conditional.

  10. Understanding and Using Makefile Variables

    There are four different ways you can define a variable in the Makefile: Recursive assignment; Simple assignment; Immediate assignment; Conditional assignment; Recursive and Simple Assignment. As you may remember, you can define a variable with =, :=, and ::=. There's a subtle difference in how variables are expanded based on what operator is ...

  11. makefile Tutorial => Conditional Variable Assignment

    Learn makefile - Conditional Variable Assignment. Learn makefile - Conditional Variable Assignment. RIP Tutorial. Tags; Topics; Examples; eBooks; Download makefile (PDF) ... Conditional Variable Assignment. Fastest Entity Framework Extensions . Bulk Insert . Bulk Delete . Bulk Update . Bulk Merge .

  12. Conditionals (GNU make)

    7 Conditional Parts of Makefiles. A conditional directive causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. Conditionals control what make actually "sees" in the makefile, so they cannot be ...

  13. Understanding Makefile Target-Specific Variables and Ignoring Other

    In this article, we will discuss Makefile target-specific variables and how to ignore conditional assignments. Makefiles are used to automate the build process in Unix-based operating systems. They are written in the Makefile language and contain rules and variables that define how to build software.

  14. GNU Make

    Deciding (based on the values of variables) whether to use or ignore a part of the makefile (see section Conditional Parts of Makefiles). Defining a variable from a verbatim string containing multiple lines (see section Defining Variables Verbatim). `#' in a line of a makefile starts a comment. It and the rest of the line are ignored, except ...

  15. GNU make: 7. Conditional Parts of Makefiles

    A conditional causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string. ... Equivalent results can be obtained in another way by conditionalizing a variable assignment and then using the variable ...

  16. Quick Reference (GNU make)

    Conditionally evaluate part of the makefile. See Conditional Parts of Makefiles. include file-include file sinclude file. Include another makefile. See Including Other Makefiles. override variable-assignment. Define a variable, overriding any previous definition, even one from the command line. See The override Directive. export

  17. makefile

    I am trying to write a make function to touch/create an empty file and/or set the permissions, user and group, where possible, or warn if not. However, every conditional check within my function seems to evaluate to true. The essentials of my Makefile are

  18. How to assign the output of a command to a Makefile variable

    With GNU Make, you can use shell and eval to store, run, and assign output from arbitrary command line invocations. The difference between the example below and those which use := is the := assignment happens once (when it is encountered) and for all. Recursively expanded variables set with = are a bit more "lazy"; references to other variables remain until the variable itself is referenced ...

  19. Using Variables (GNU make)

    A variable is a name defined in a makefile to represent a string of text, called the variable's value. These values are substituted by explicit request into targets, prerequisites, recipes, and other parts of the makefile. (In some other versions of make , variables are called macros .) Variables and functions in all parts of a makefile are ...