lld runs LTO even if -fno-lto is passed

2.4k views Asked by At

I have a CMake project with several subprojects that create static libraries built with -flto=thin.

The project has a lot of tests that are linked against the aforementioned libraries. With LTO it takes a lot of time to build tests, therefore I have disabled LTO for tests using -fno-lto.

What I noticed though, is that lld performs LTO on tests even with -fno-lto. If I run the linker with --time-trace I can see that the majority of the time is spent on LTO.

My questions are:

  1. Is this expected? If so I can assume that lld performs LTO whenever it finds the LTO info in the object it links.
  2. If not, is there a way to disable this behavior? Adding -fno-lto to the compiler does not seem to work, and lld does not have a param to explicitly disable LTO.
  3. If not, is this a bug?

Update 1:

This is how I handle lto in CMake:

# Enable Thin LTO only on non-test targets.
if(ENABLE_LTO)
  if (IS_TEST)
    target_compile_options(${TARGET} PRIVATE -fno-lto)
    # Probably pointless.
    target_link_options(${TARGET} PRIVATE -fno-lto)
  else()
    message(STATUS "ENABLE_LTO on target ${TARGET})")
    target_compile_options(${TARGET} PRIVATE -flto=thin)
    target_link_options(${TARGET} PRIVATE -flto=thin -Wl,--thinlto-cache-dir=${CMAKE_BINARY_DIR}/lto.cache)
  endif()
endif()
1

There are 1 answers

2
Goswin von Brederlow On BEST ANSWER

If you compile the libraries with -flto then, at least for gcc, the object files will only contain the intermediate language and no binary code.

That means when you link them into your test cases compiled with -fno-lto there is no binary code to link to. The linker has no choice but to first compile the intermediate language into binary for each needed function, which you would see as an LTO phase.

In gcc there is an option -ffat-lto-objects that tells gcc to include both the intermediate language as well as binary code in the object files. They can then be used for linking with LTO or without. The drawback is that this takes a bit longer to compile and produces larger object files.

You have to check if clang has the same option, they are usually pretty compatible with options.