Search code examples
c++cmakefile

Enabling link time optimization via makefile


In trying to follow the official GNU documents for enabling link time optimization for some of my C and C++ code, I am running into some confusion.

Official documentation, here suggests to include all flags used in compilation also in linking. The example they provide is rather simple. In my makefile, the compile options are quite large and detailed like so:

CXXFLAGS=-m64 -fno-common -fPIC -fno-strict-aliasing -fexceptions -fopenmp -Wall -Wextra -DVSCODE

The actual compile command for building a target from a single source file is like so:

$(COMPILE.cc) -O2 -DNDEBUG -DBOOST_DISABLE_ASSERTS -flto -std=c++17 -MMD -MP -MF "[email protected]" -o ${OBJECTDIR}/_ext/0/main.o ../code/main.cpp

So, following the documentation, should I be including all of the above flags again while linking?

Currently, my linking command is concise and just:

${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/linux ${OBJECTFILES} ${LDLIBSOPTIONS} -lm -lpthread -ldl -lboost_timer

Should I now be modifying this to the rather longish:

${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/linux -flto -O2 -DNDEBUG -DBOOST_DISABLE_ASSERTS -std=c++17 -MMD -MP -MF "[email protected]" ${CXXFLAGS} ${OBJECTFILES} ${LDLIBSOPTIONS} -lm -lpthread -ldl -lboost_timer

thereby repeating inside of the linking command all of the compile command flags as well? This seems rather complicated and error prone (if I forget to update the linker command but add a few flags for the compiler) and hence the query in this thread. Not specified above, my compile flags also contain some include directories for header files via -I /path/to/header. Should they be put inside the linker command also?

Can all compile flags be put as linker flags also? Are some flags common between the linker and the compiler, while others are exclusively for the compiler and still others exclusively for the linker?

This is a crosspost from /r/cpp_questions here as I could not obtain any response there.


Solution

  • Official documentation, here suggests to include all flags used in compilation also in linking.

    No, it doesn't. It says:

    -flto and optimization options should be specified at compile time and during the final link.

    (Emphasis added.) That is the context in which the next sentence, ...

    It is recommended that you compile all the files participating in the same link with the same options and also specify those options at link time.

    ... should be understood. For LTO purposes, it is only optimization options, including -flto, that need to be used uniformly for linking and all contributing compilations.

    The only optimization option in the CXXFLAGS you present is -fno-strict-aliasing. Your single-source compile command includes -O2 -flto, which are optimization options too, and of course -flto is the specific one you're asking about in the first place. Of the options you show in various places, it is those three alone that need to be used both at compile time and link time to support link-time optimization. (There might be other options required in both places for different reasons.)


    Side note: since you present a single-source build rule, I feel compelled to observe that link-time optimization gains you nothing in single-source builds.


    Currently, my linking command is concise and just [does not appear to provide for configurable non-library link options].

    Should I now be modifying this to the rather longish [...] thereby repeating inside of the linking command all of the compile command flags as well? This seems rather complicated and error prone

    I would advise factoring out the optimization flags:

    OPT_FLAGS = -O2 -fno-strict-aliasing -flto
    
    CXXFLAGS = $(OPT_FLAGS) ...
    LDFLAGS = $(OPT_FLAGS) ...
    

    ... and expanding LDFLAGS into your link command:

    ${LINK.cc} $(LDFLAGS) -o ...
    

    You will then have to maintain some discipline in deciding to which variable to add specific options, but you will not need to duplicate any, and you will not be at risk of optimization-flag inconsistencies between the compile and link stages.

    my compile flags also contain some include directories for header files via -I /path/to/header. Should they be put inside the linker command also?

    No. That's not an optimization option. Strictly speaking, it's not even a compile option, but rather a preprocessor option, though it will be used during compilation.

    Can all compile flags be put as linker flags also?

    That depends on your compiler, your linker, and how you invoke them. In the GCC system, it is usual to invoke both C++ compiler and linker via the g++ front end. This front end does recognize all the options for all the stages, and it will pass on only relevant ones to the compiler and linker back ends, as appropriate.

    Are some flags common between the linker and the compiler, while others are exclusively for the compiler and still others exclusively for the linker?

    The compiler and linker do different jobs, though LTO blurs the lines there. They each have their own options, with comparatively little overlap, though that's obscured when they are accessed through a common front end.

    It is notable here that although the g++ and gcc front ends expose many of the linker's options, they don't expose all linker options directly. Accordingly, they provide means to pass arbitrary options directly through to the linker (-Xlinker, -Wl).