What is Include(CheckIPOSupported), and how to use it in CMake?

The Include(CheckIPOSupported) command checks if the compiler supports interprocedural optimization (IPO), a compiler technique that optimizes multiple source files and function boundaries to enhance performance.

IPO example

The include(CheckIPOSupported) command includes a CMake module, which provides functions and macros for checking IPO support in the current compiler. Here's an example of how to use it in a CMakeLists.txt file:

cmake_minimum_required(VERSION 3.25.1)
project(MyProject)
# including CheckIPOSupported libarary
include(CheckIPOSupported)
# check if IPO is supported
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_OUTPUT)
if(IPO_SUPPORTED)
message(STATUS "IPO is supported: ${IPO_OUTPUT}")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
message(STATUS "IPO is not supported: ${IPO_OUTPUT}")
endif()
# including directories
include_directories(include)
set(SOURCES
src/main.cpp
src/foo.cpp
src/bar.cpp
)
# enabling private compiler options
add_executable(MyExecutable ${SOURCES})
target_compile_options(MyExecutable PRIVATE -Wall -Wextra)

Lines 1–2: Set the minimum required version of CMake to 3.25.1 and declare a CMake project named MyProject.

Line 5: Includes a module named CheckIPOSupported, which is used in a CMake script to determine if the compiler supports IPO to allow enhanced program optimization across multiple translation units during compilation.

Line 8: Calls the check_ipo_supported function with four arguments: RESULT, IPO_SUPPORTED, OUTPUT, and IPO_OUTPUT, which checks for IPO support and stores the result and associated output in the specified variables.

Lines 9–14: Check if IPO is supported. If it is, then enable it and display a related message. Otherwise, display a message indicating that IPO is not supported.

Lines 17–22: Include header files from the include directory and define the main.cpp, foo.cpp, and bar.cpp source files located in the src directory.

Line 25: CMake script compiles source files defined by ${SOURCES} into an executable named MyExecutable.

Line 26: Enables private compiler options for it to enforce stricter warnings using -Wall and -Wextra.

Here's an implementation of the main.cpp file:

#include <iostream>
#include "foo.h"
#include "bar.h"
// main function
int main() {
Foo foo;
Bar bar;
foo.doSomething();
bar.doSomethingElse();
std::cout << "Program executed successfully!" << std::endl;
return 0;
}

Lines 1–3: Include necessary header files, namely iostream, foo.h, and bar.h. Allow access to input/output streams and declarations from foo.h and bar.h for further code implementation.

Lines 6–16: Define a main function that creates instances of the Foo and Bar classes. Call the doSomething method on the foo object and the doSomethingElse method on the bar object. Then, output "Program executed successfully!" to the console to indicate a successful program execution.

Here's an example implementation of the foo.h header files:

#ifndef FOO_H
#define FOO_H
// declaring class
class Foo {
public:
void doSomething();
};
#endif

Lines 1–10: Define the foo.h header file that guards against multiple inclusion and declares the Foo class with a doSomething() public member function.

Here's an example implementation of the bar.h header files:

#ifndef BAR_H
#define BAR_H
// declaring class
class Bar {
public:
void doSomethingElse();
};
#endif

Lines 1–10: Define the bar.h header file that guards against multiple inclusion and declares the Bar class with a doSomethingElse() public member function.

Here's an implementation of the foo.cpp file:

#include <iostream>
#include "foo.h"
// function body
void Foo::doSomething() {
std::cout << "Doing something in Foo." << std::endl;
}

Lines 1–2: Include the standard input/output stream header and a custom header, foo.h, for potential further code dependencies.

Lines 4–6: Define the doSomething member function within the Foo class, which outputs the text “Doing something in Foo” to the standard output stream, followed by a new line.

Here's an example implementation of the bar.cpp file:

#include <iostream>
#include "bar.h"
// function body
void Bar::doSomethingElse() {
std::cout << "Doing something else in Bar." << std::endl;
}

Lines 1–2: Include the standard input/output stream header and the bar.h custom header for potential further code dependencies.

Lines 4–6: Define the doSomethingElse member function within the Foo class, which outputs the text, “Doing something else in Bar”, to the standard output stream, followed by a new line.

In this example, foo.h defines the Foo class with a single-member function, doSomething(). Similarly, bar.h defines the Bar class with a single-member function, doSomethingElse(). Both header files are protected with the included guards (#ifndef and #define directives) to prevent multiple inclusion and potential symbol redefinition issues. These header files can also be included in the corresponding source files (main.cpp, foo.cpp, bar.cpp) to provide the necessary declarations and definitions for the classes and their member functions.

Try it yourself

We need to run the following commands to run the CMake program.

Here is the command to compile and link the program:

cmake -B buildtree

Here is the command to build the program:

cmake --build buildtree/

Here is the command to execute the program:

./buildtree/MyExecutable

Now, let's practice the above commands and see the CMake output by clicking the “Run” button.

#ifndef BAR_H
#define BAR_H

class Bar {
public:
    void doSomethingElse();
};

#endif  // BAR_H
Playground for Include(CheckIPOSupported)

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved