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:
- https://stackoverflow.com/a/11448878/2137996
- https://stackoverflow.com/a/10635366/2137996
- https://stackoverflow.com/a/68866472/2137996
- https://stackoverflow.com/a/67435497/2137996
- 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
What Is the Idiomatic Way in Cmake to Add the -Fpic Compiler Option
Automatic Perspective Correction Opencv
C++ Getters/Setters Coding Style
Vector or Map, Which One to Use
Dead Code Detection in Legacy C/C++ Project
What Do C and Assembler Actually Compile To
M_Pi Works with Math.H But Not with Cmath in Visual Studio
How to Scale Down Numbers from Rand()
What Happens to Global Variables Declared in a Dll
How to Create a Pause/Wait Function Using Qt
Is There a Good Python Library That Can Parse C++
What Is the Correct Way of Reading from a Tcp Socket in C/C++
Mingw .Exe Requires a Few Gcc Dll's Regardless of the Code
Does Boost Have a Datatype for Set Operations That Is Simpler Than the Stl
How to Call a Function by Its Name (Std::String) in C++