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.