Skip to content

IPO+PIE: Inconsistency between compilation and linking

Inconsistent use of -fPIE and -fPIC in compile and linker arguments leads to code generation error with INTERPROCEDURAL_OPTIMIZATION enabled.

Using CMake 3.22.2, gcc 12.2.1, and Qt 5.15.6 on Fedora 36 the following options:

include(CheckPIESupported)
check_pie_supported()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)

...triggers the following code to be compiled and linked incorrectly:

#include <iostream>
#include <QCoreApplication>
#include <QString>

int main(int argc, char **argv)
{
    QCoreApplication app(argc, argv);
    {
        auto foo = qEnvironmentVariable("an_env_var_that_is_not_set");
        std::cout << "1: isNull(): " << foo.isNull() << "\n";
    }

    {
        auto foo = qEnvironmentVariable("an_env_var_that_is_not_set", QString());
        std::cout << "2: isNull(): " << foo.isNull() << "\n";
    }
}

When compiled correctly the output of this program will be:

1: isNull(): 1
2: isNull(): 1

With the flags above the output is instead:

1: isNull(): 0
2: isNull(): 1

The full repro case can be found in example.zip

I have also reproduced the issue with CMake 3.20.2, gcc/g++ 11.2.1, and Qt 5.15.6 on RHEL 9.

With the flags above the compile and link steps executed are these:

[1/2] /usr/bin/c++ -DQT_CORE_LIB -DQT_NO_DEBUG -isystem /home/ts/src/qtbase-build/install/include -isystem /home/ts/src/qtbase-build/install/include/QtCore -isystem /home/ts/src/qtbase-build/install/./mkspecs/linux-g++ -O2 -g -DNDEBUG -flto -fno-fat-lto-objects -fPIE -fPIC -MD -MT CMakeFiles/example.dir/example.cc.o -MF CMakeFiles/example.dir/example.cc.o.d -o CMakeFiles/example.dir/example.cc.o -c /home/ts/src/easyviz-3/example/example.cc
[2/2] : && /usr/bin/c++ -O2 -g -DNDEBUG -flto -fno-fat-lto-objects -fPIE -pie CMakeFiles/example.dir/example.cc.o -o example  -Wl,-rpath,/home/ts/src/qtbase-build/install/lib  /home/ts/src/qtbase-build/install/lib/libQt5Core.so.5.15.6 && :

Notice that the compile step passes -fPIE -fPIC, whereas the link step only passes -fPIE. If I manually amend the link step to pass -fPIE -fPIC it solves the problem. Note here that the order matters - passing -fPIE -fPIC fixes the problem, but -fPIC -fPIE does not.

This issue does not reproduce with the distro-provided versions of Qt, and I have no idea why. The attached example.zip contains full instructions for also building Qt 5.15.6 - on a reasonably modern computer the whole repro case can be executed in 5-10 minutes of setup and build time.

I am opening a bug here, rather than with Qt or gcc, because I think it is a bug that CMake doesn't pass consistent flags to the compiler and the linker when INTERPROCEDURAL_OPTIMIZATION is enabled.

Edited by Brad King
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information