Same source, all that, just want a static and shared version both. Easy to do?
-
8All the answers to this question are wrong or incomplete. I wrote a [blog post about this here](https://alexreinking.com/blog/building-a-dual-shared-and-static-library-with-cmake.html). Thanks to PIC (among other things), the best thing to do is just create _one_ target and build twice. – Alex Reinking Mar 10 '21 at 09:14
5 Answers
Yes, it's moderately easy. Just use two "add_library" commands:
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Even if you have many source files, you can place the list of sources in a Cmake
variable, so it's still easy to do.
On Windows you should probably give each library a different name, since there is a ".lib" file for both shared and static. But on Linux and Mac you can even give both libraries the same name (e.g. libMyLib.a
and libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
But I don't recommend giving both the static and dynamic versions of the library the same name. I prefer to use different names because that makes it easier to choose static vs. dynamic linkage on the compile line for tools that link to the library. Usually I choose names like libMyLib.so
(shared) and libMyLib_static.a
(static). (Those would be the names on linux.)

- 2,963
- 11
- 33

- 9,160
- 7
- 46
- 61
-
Was hoping for them to have the same name, but oh well. Another question: Can you tell CMake to link static libraries into the shared library when possible? – gct Jan 28 '10 at 04:24
-
More about "same name": If you are on Windows and want the same name for both libraries and you don't need the shared .lib file, it is possible to create a static .lib and a shared .dll. But you need that shared .lib file if you are using your library for ordinary compile time linking. – Christopher Bruns Jan 28 '10 at 04:29
-
1I'm not sure I understand your question about linking static libraries into the shared library. – Christopher Bruns Jan 28 '10 at 04:30
-
Example: I have libsomelib that libmylib.so depends on, I'd like it to use libsomelib.a and merge it into libmylib.so where possible... – gct Jan 28 '10 at 04:51
-
Either you link libmylib.so with libsomelib.a, in which case libmylib.so will include libsomelib.a, or you don't. There is no "where possible". (Remember that static libraries are just collections of object files.) – JesperE Jan 28 '10 at 08:45
-
8**Note** that this is not the suggested way to do it anymore. For non-trivially sized projects (ones that take minutes, not seconds to compile), avoiding doubling the compile time is wondrous. See user465139 answer below for Object Library usage or the docs: https://cmake.org/cmake/help/v3.8/command/add_library.html#object-libraries – KymikoLoco Jun 05 '17 at 21:01
-
4@KymikoLoco: The Object Library approach does indeed reduce compilation time by half, but it requires static libraries be built as Position Independent Code (i.e. with `-fPIC`), which adds a small amount of runtime overhead when those static libraries are used. So for maximum performance, this answer is still the best. – John Zwinck Jul 24 '17 at 09:54
-
@JohnZwinck That's a good point, but doesn't that only apply to Unix? – KymikoLoco Jul 24 '17 at 15:13
-
But these two calls to `add_library` cause two different targets in Visual Studio: ${libname}-shared and ${libname}-static. Any way to avoid this? – Oct 08 '19 at 09:23
-
Please be aware that this solution won't work with `MSVC`, I've added additional answer with `ARCHIVE_OUTPUT_DIRECTORY` usage. – puchu Apr 09 '21 at 19:47
Since CMake version 2.8.8, you can use "object libraries" to avoid the duplicated compilation of the object files. Using Christopher Bruns' example of a library with two source files:
# list of source files
set(libsrc source1.c source2.c)
# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})
# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)
From the CMake docs:
An object library compiles source files but does not archive or link their object files into a library. Instead other targets created by
add_library()
oradd_executable()
may reference the objects using an expression of the form$<TARGET_OBJECTS:objlib>
as a source, where objlib is the object library name.
Simply put, the add_library(objlib OBJECT ${libsrc})
command instructs CMake to compile the source files to *.o
object files. This collection of *.o
files is then referred to as $<TARGET_OBJECT:objlib>
in the two add_library(...)
commands that invoke the appropriate library creation commands that build the shared and static libraries from the same set of object files. If you have lots of source files, then compiling the *.o
files can take quite long; with object libraries you compile them only once.
The price you pay is that the object files must be built as position-independent code because shared libraries need this (static libs don't care). Note that position-independent code may be less efficient, so if you aim for maximal performance then you'd go for static libraries. Furthermore, it is easier to distribute statically linked executables.

- 20,030
- 7
- 43
- 238

- 8,948
- 5
- 48
- 51
-
3This worked like a charm for me – the only caveat was subsequent `target_link_libraries()` calls that depend on your library can’t use the “object library” to link against; those must target the new shared or static libraries (and might be duplicated). But contrary to the first commenters’ experience this was quite useful, and allowed me to remove all the duplicated targets and cut all my `CMakeLists.txt` files by close to half. – fish2000 May 24 '16 at 01:35
-
1Do you need to "escape" the obblib when setting the target properties? i.e. set_property(TARGET ${objlib} PROPERTY ...) vs set_property(TARGET objlib PROPERTY ...) – gnac Sep 08 '16 at 21:56
-
1@user465139 Perhaps you should explain why it should work to re-use object files for both static and shared target. Especially, general knowledge in SO is still very confusing about it, old/archives don't help to clarify it either, eg. https://cmake.org/pipermail/cmake/2008-March/020315.html A solid explanation of the status quo is needed. p.s. It wasn't me who downvoted – mloskot Mar 27 '17 at 13:58
-
1@mloskot Thank you, I added an extra paragraph trying to explain the idea a bit better, and also included a quote from the CMake docs. – András Aszódi Mar 28 '17 at 11:40
-
2@gnac I cannot confirm this. In my case, the `set_property` only worked when I used `objlib` and not when using `${objlib}`. So maybe this answer could be corrected? – josch May 12 '17 at 09:24
-
2
-
1@mkaptur: The object files are compiled only _once_ and they will be used both for the static and the shared libraries and that's why they have to be compiled with the PIC property because that's needed by the shared library objects. Static libraries don't care, that's correct. – András Aszódi Oct 04 '17 at 11:54
-
Since CMake version 3.0.2 [POSITION_INDEPENDENT_CODE ](https://cmake.org/cmake/help/v3.0/prop_tgt/POSITION_INDEPENDENT_CODE.html) is True by default for shared library thus it is not necessary to be set explicitly. – Jónás Balázs Jul 20 '18 at 14:34
-
@JónásBalázs yes, but I believe you have to specify PIC anyway because you are building a shared _and_a_static_ library from the same object files. PIC is not default for static libraries. – András Aszódi Aug 02 '18 at 14:44
-
@LaryxDecidua At the time I wrote the comment I used MinGW and fPIC is unused for Windows. According to this it is not necessar on Windows. Discussed [here](https://stackoverflow.com/questions/5674613/compiling-a-dynamically-linked-library) – Jónás Balázs Aug 03 '18 at 08:08
-
1Unfortunately object libraries are not supported by CUDA_ADD_LIBRARY as of cmake 3.12... https://cmake.org/pipermail/cmake/2015-June/060937.html – Jakub Klinkovský Sep 09 '18 at 18:33
-
Do you know if there is also some way to share the include directories? – Arwed Mett Mar 24 '19 at 11:38
-
@ArwedMett : just define them as usual, there's no need to do anything special. NB I am not sure I understood your question correctly. – András Aszódi Mar 29 '19 at 09:30
-
@LaryxDecidua I meant the target_include_directories command. In the given example you would have to do it for each target (objlib, Mylib_shared, Mylib_static), which is kind of cumbersome. – Arwed Mett Mar 29 '19 at 10:00
-
After doing this, there's no `.a` found, finally I added the target to the `build.gradle` and it works. ``` android { defaultConfig { externalNativeBuild{ cmake { targets "MyLib_static" // see https://stackoverflow.com/a/52966824/1632448 } } } } ``` – fantouch Jun 04 '19 at 09:07
-
1Keep in mind that PIC comes with a performance hit. It's mild on x64, but can be significant on other architectures. If you optimize for performance, sacrifice some build time, go with the default flow and compile twice. Another PIC alternative in 64-bit code is full-size non-IP-relative relocations, enabled in gcc with `-fpic -mcmodel=large` (lowercase `-fpic`, not `-fPIC`), but they trade indirection for code size. Benchmark all 3 options for static libs (default `-fno-pic`, `-fpic -mcmodel=large` and `-fPIC`) before taking the decision to go with same objects for both libraries. – kkm inactive - support strike Jan 06 '21 at 22:37
-
@kkm The last paragraph of my answer does warn about the performance hit but I didn't go into the `gcc` specifics which is a valuable addition to the topic, thanks a lot! – András Aszódi Jan 11 '21 at 16:47
-
1@LaryxDecidua, you're welcome. By the way, compared to 32-bit x86 architecture, PIC relocations have much less impact on performance on x64--I presume, lessons have been learned, and both linkers and CPUs became smarter. :) – kkm inactive - support strike Feb 28 '21 at 17:56
-
This is a fundamentally flawed approach because of 1) the `-fPIC` issue, and even in case you disregard 1), then 2) https://stackoverflow.com/questions/76587329/how-to-correctly-use-object-libraries-to-build-both-static-and-shared-libraries – Ton van den Heuvel Jun 30 '23 at 08:41
-
@TonvandenHeuvel I respectfully disagree. If this approach is "fundamentally flawed" then the CMake docs are also flawed. That's where the idea comes from namely, as explained above. As regards the PIC issue, see some of the comments above, it's not as important nowadays as compilers got better. I also explicitly warn about the possible performance penalty. In any case, "premature optimisation is the root of all evil". Do timings first: if `-fPIC` makes a difference, then don't use this approach. You always have to consider what's more valuable: your time or the runtime. – András Aszódi Jun 30 '23 at 14:54
-
@AndrásAszódi, as I mentioned, I can understand people are willing to step over the `-fPIC` thing, but what do you think about the exposure of all of the object libraries' private dependencies using this approach? Also, I could not find any mention in the CMake documentation where they advice to use object libraries to prevent having to build object files for a static and shared library twice, maybe I missed it. The CMake documentation advices to use `BUILD_SHARED_LIBS` for this as far as I can see. – Ton van den Heuvel Jul 03 '23 at 06:04
-
@AndrásAszódi, essentially the way the private object library dependencies are handled may result in overlinking of the resulting shared library which is bad. – Ton van den Heuvel Jul 03 '23 at 13:13
There is generally no need to duplicate ADD_LIBRARY
calls for your purpose. Just make use of
$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$'
BUILD_SHARED_LIBS
Global flag to cause add_library to create shared libraries if on.
If present and true, this will cause all libraries to be built shared unless the library was
explicitly added as a static library. This variable is often added to projects as an OPTION
so that each user of a project can decide if they want to build the project using shared or
static libraries.
while building, first (in one out-of-source directory) with -DBUILD_SHARED_LIBS:BOOL=ON
, and with OFF
in the other.

- 16,549
- 8
- 60
- 74

- 889
- 6
- 9
-
63This doesn't seem to build BOTH static and shared versions, which I think is what this question is getting at. – Nick Desaulniers Jul 07 '15 at 19:17
-
1To clarify: The project is built twice, once with static and once with shared libraries. This a solution, if it is the exception to need both cases. But it works for all CMake projects without adaptation is the most "natural" or "CMake" way. – usr1234567 Sep 17 '20 at 15:59
Please be aware that previous answers won't work with MSVC
:
add_library(test SHARED ${SOURCES})
add_library(testStatic STATIC ${SOURCES})
set_target_properties(testStatic PROPERTIES OUTPUT_NAME test)
CMake will create test.dll
together with test.lib
and test.exp
for shared
target. Than it will create test.lib
in the same directory for static
target and replace previous one. If you will try to link some executable with shared
target it will fail with error like:
error LNK2001: unresolved external symbol __impl_*.`.
Please use ARCHIVE_OUTPUT_DIRECTORY
and use some unique output directory for static
target:
add_library(test SHARED ${SOURCES})
add_library(testStatic STATIC ${SOURCES})
set_target_properties(
testStatic PROPERTIES
OUTPUT_NAME test
ARCHIVE_OUTPUT_DIRECTORY testStatic
)
test.lib
will be created in testStatic
directory and won't override test.lib
from test
target. It works perfect with MSVC
.

- 3,294
- 6
- 38
- 62
-
-
`dll` will be created in current directory for libraries, static will be created in `testStatic` subdirectory. – puchu May 28 '23 at 23:18
It's possible to pack eveything in the same compilation breath, as suggested in the previous answers, but I would advise against it, because in the end it's a hack that works only for simple projects. For example, you may need at some point different flags for different versions of the library (esp. on Windows where flags are typically used to switch between exporting symbols or not). Or as mentionned above, you may want to put .lib
files into different directories depending on whether they correspond to static or shared libraries. Each of those hurdles will require a new hack.
It may be obvious, but one alternative that has not been mentionned previously is to make the type of the library a parameter:
set( ${PROJECT_NAME}_LIBTYPE CACHE STRING "library type" )
set_property( CACHE ${PROJECT_NAME}_LIBTYPE PROPERTY STRINGS "SHARED;STATIC" )
add_library( ${PROJECT_NAME} ${PROJECT_NAME}_LIBTYPE ${SOURCE_FILES} )
Having shared and static versions of the library in two different binary trees makes it easier to handle different compilation options. I don't see any serious drawback in keeping compilation trees distinct, especially if your compilations are automated.
Note that even if you intend to mutualize compilations using an intermediate OBJECT
library (with the caveats mentionned above, so you need a compelling reason to do so), you could still have end libraries put in two different projects.

- 23,115
- 9
- 87
- 104