I'm wandering which is the right way to compile static library on Linux with GCC in such way that when link time optimizations (LTO) be applied to the executable the library to be consumable and possibly to be achieved optimal performance.
When library is compiled only with -flto
the executable cannot be linked to it no matter whether it uses -flto
or not. The error is:
undefined reference to `hello'
where hello
is function defined in the library.
According to the answer to this Stack Overflow question one possible solution is the following:
set(CMAKE_AR gcc-ar)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH true)
Then the library can be linked to the executable both with -flto
and without -flto
passed to the linker flags.
But according to the answer to this Stack Overflow question if we want static library to be compiled in such way to be usable with and without LTO than we have to use -ffat-lto-objects
. If we add this flag to the library compilation flags again the library can be linked to executables both with -flto
and without -flto
passed to the linker flags.
My questions are:
- What is the exact meaning of the first solution with
gcc-ar
? What is the difference between different working variants when library is compiled with
-flto
.2.1 Executable without
-flto
.- Library is using only
gcc-ar
. - Library is using only
-ffat-lto-objects
. - Library is using both
gcc-ar
and-ffat-lto-objects
2.2 Executable with
-flto
and the same 3 variants for the library.- Library is using only
Here is Minimal, Complete, and Verifiable example with my test project which is modified version of the example from this Stack Overflow question. I'm using GCC version 7.2.0
.
CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(lto)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -g -O3")
add_subdirectory(lib)
add_subdirectory(exe)
exe/CMakeLists.txt
set(TARGET_NAME exe)
add_executable(${TARGET_NAME} src/main.c)
target_link_libraries(${TARGET_NAME} lib)
option(EXE_LTO "Use link time optimizations for the executable." OFF)
if(${EXE_LTO})
target_compile_options(${TARGET_NAME} PRIVATE "-flto")
endif()
exe/src/main.c
extern void hello();
int main()
{
hello();
return 0;
}
lib/CMakeLists.txt
set(TARGET_NAME lib)
add_library(${TARGET_NAME} STATIC src/lib.c)
option(LIB_LTO "Use link time optimizations for the library." OFF)
option(LIB_FAT_LTO "Create fat LTO objects for library files." OFF)
option(LIB_USE_LTO_AR "Use another AR program for LTO objects." OFF)
if(${LIB_LTO})
target_compile_options(${TARGET_NAME} PRIVATE -flto)
endif()
if(${LIB_FAT_LTO})
target_compile_options(${TARGET_NAME} PRIVATE -ffat-lto-objects)
endif()
if(${LIB_USE_LTO_AR})
set(CMAKE_AR gcc-ar)
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_FINISH true)
endif()
lib/src/lib.c
#include <stdio.h>
void hello()
{
puts("Hello");
}