When using LTO, we should repeat the compiler flags when linking. LTO basically recompiles by taking IR generated from all object files that will be part of the executable. Since it knows all the code that is going into the executable, it can do more optimisations.

Now since it does the whole IR assembly code generation again at link time, the compile options at that time are important.

Impact Example

extern int x;
void foo() { x++; }
 
int main() {}

The simple program above compiles when compiled with

gcc lto-test.c -ffunction-sections -c 
gcc lto-test.o -Wl,--gc-sections

This is because foo() is not referenced anywhere and due to it being present in a different section which is unused, it gets removed from the executable. So, there’s no undefined reference to x error.

If we add -flto only to the compilation command, the link command gives the error:

/usr/bin/ld: /tmp/cclh6LYv.ltrans0.ltrans.o: in function `foo()':
<artificial>:(.text+0x7): undefined reference to `x'

This is because the linker command doesn’t know to put functions in different sections. Adding -ffunction-sections to the link command fixes the error.

NOTE: Using CMake and enabling CMAKE_INTERPROCEDURAL_OPTIMIZATION doesn’t copy compiler options either as we would expect.