Compiling a Static Executable with Cmake

Compiling a static executable with CMake

As global CMake settings, add these lines before add_executable, valid for gcc/clang:

set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_EXE_LINKER_FLAGS "-static")

On Modern CMake (3.x+ - target_link_libraries doc), you can apply the flag to specific targets, in this way:

target_link_libraries(your_target_name -static)

If you're using MSVC, you have to set the compiler and linker flags:

set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
target_compile_options(your_target_name [PUBLIC|PRIVATE] /MT)
target_link_options(your_target_name [PUBLIC|PRIVATE] /INCREMENTAL:NO /NODEFAULTLIB:MSVCRT)

or alternatively also:

set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

and if you are using MFC, you need to specify the flag to 1 see here:

set(CMAKE_MFC_FLAG 1) 

Generate Static Executable with CMake

Long story short: You need to tell CMake that you prefer static linking with the libraries.
This is done by setting property LINK_SEARCH_START_STATIC. Also you need to tell CMake to not reset static linkage at the end of the libraries list.
This is done by setting property LINK_SEARCH_END_STATIC:

set_target_properties(main-static PROPERTIES
LINK_SEARCH_START_STATIC ON
LINK_SEARCH_END_STATIC ON
)

See also that question: CMake and Static Linking.

What is going on

Actually, the linker option -static not only disables PIE, but also affects on further libraries listed in the command... unless -dynamic is specified.

CMake has a notion about "default linking type", which is applied for every library (uuid in your case) for which CMake cannot deduce its type. Moreover, CMake maintains that default linking type after each library it adds into the linker's command line. And CMake expects the same behavior from the user, who manually adds linker flags.

Your first example is wrong, but suddenly works:

You add -static which turns current linkage type to static. And thus you break CMake expectations about current linkage type.

When produce the linker option for link with uuid, CMake expects that current linkage is dynamic. So, CMake doesn't add -dynamic linker switch.

That time CMake expectations doesn't correspond to the reality, which in turn corresponds to your expectations: uuid is linked statically.

But the second example reveals the problem:

When linking with libtestlib.a library, CMake is perfectly aware that this is a static library, and thus adds Wl,-Bstatic option before that library. But CMake need to maintain default linkage after every option, so it adds -Wl,-Bdynamic after the library:

-Wl,-Bstatic -ltestlib -Wl,-Bdynamic

With such options CMake expectations about default dynamic linking corresponds to the reality: uuid is linked dynamically. But now that reality doesn't correspond to yours expectations.

How to create a static library (not executable) in CMake?

add_library can be used by itself, without using add_executable at all. Simply remove line 2 to get rid of the executable. The error is most likely caused by line 3, which needs myexe to function. Line 3 should also be removed, because you are only building the library and not linking it.

Need help understanding linking with cmake

I had a basic understanding that libraries were a collection of objects/symbols, so I had assumed that by linking foo to bar, bar would also have those objects/symbols, but that is not the case, so I am wondering if I am missing something or if I am doing something wrong.

Indeed this is not quite the case. The C/C++ language standards do not define the contents of static libraries, but on most platforms they are archives containing specific object files. If those object files collectively depend on external symbols, then that static library depends on some other library or object file and all must be linked into the final executable.

"Linking" one static library to another in CMake merely declares the dependency between them. There is no platform-independent mechanism for merging them nor, within CMake, is there a pressing need to do so.

I do not want to use SHARED libraries, I would prefer to stay with STATIC libraries, how can I have my libraries keep all the objects/symbols? Am I forced to link both bar and foo?

There are many questions and answers on StackOverflow detailing how to use OBJECT libraries to accomplish this. Here's, say, five:

  1. https://stackoverflow.com/a/11448878/2137996
  2. https://stackoverflow.com/a/10635366/2137996
  3. https://stackoverflow.com/a/68866472/2137996
  4. https://stackoverflow.com/a/67435497/2137996
  5. https://stackoverflow.com/a/68406028/2137996

Yet, I would say that all of these questions are misguided. CMake handles linking library dependencies just fine.



Related Topics



Leave a reply



Submit