CMake BUILD_SHARED_LIBS: A Guide to Building Shared and Static Libraries
Purpose
- Determines whether libraries are built as shared libraries (
.so
or.dll
on Unix-like systems,.dll
on Windows) or static libraries (.a
on all platforms). - Controls the default behavior of the
add_library()
command in CMake.
How it Works
- You can set
BUILD_SHARED_LIBS
at the beginning of your top-levelCMakeLists.txt
file using theoption()
command: - If
BUILD_SHARED_LIBS
is set toOFF
,add_library()
creates static libraries by default. - When
BUILD_SHARED_LIBS
is set toON
(the default),add_library()
creates shared libraries by default if no explicit library type is specified.
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
This allows users to choose between shared and static libraries when building your project.
Key Points
- Default Behavior
WithBUILD_SHARED_LIBS
on,add_library()
creates shared libraries unless you explicitly specifySTATIC
:
add_library(mylibrary mylibrary.cpp) # Creates a shared library (default)
add_library(mystaticlib STATIC mystaticlib.cpp) # Creates a static library
- Overriding
You can override the default behavior for individual libraries:
set(BUILD_SHARED_LIBS OFF) # All libraries will be static by default now
add_library(mysharedlib SHARED mysharedlib.cpp) # Explicitly create a shared library
Benefits of Shared Libraries
- Dynamic Linking
Programs link to shared libraries at runtime, allowing for updates without recompiling the entire program. - Code Reusability
Shared libraries can be used by multiple programs, reducing code duplication and saving disk space.
Benefits of Static Libraries
- No Dependencies
Executables don't rely on the presence of shared libraries to run. - Smaller Executables
Static libraries are embedded directly into the executable file, resulting in smaller executables.
Choosing Between Shared and Static Libraries
- Consider factors like code reusability, dependency management, and deployment complexity when making a decision.
- Building shared libraries might require additional configuration on some platforms.
- Shared libraries often require setting linker flags to ensure proper linking.
Example 1: Building Shared and Static Libraries (User Choice)
This example allows users to choose between building shared and static libraries using the option()
command:
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
# Library with default behavior (shared if BUILD_SHARED_LIBS is ON)
add_library(mylibrary mylibrary.cpp)
# Library explicitly built as static
add_library(mystaticlib STATIC mystaticlib.cpp)
# Optionally build a shared library even if BUILD_SHARED_LIBS is OFF
if(NOT BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON CACHE INTERNAL "" FORCE) # Force shared library
add_library(forcesharedlib SHARED forcesharedlib.cpp)
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "" FORCE) # Restore original value
endif()
Example 2: Building Shared Library by Default
This example builds a shared library by default, overriding the default behavior for this specific library:
set(BUILD_SHARED_LIBS OFF) # All libraries will be static by default
# Explicitly build a shared library
add_library(mysharedlib SHARED mysharedlib.cpp)
# Other libraries will be static unless explicitly specified as shared
add_library(myotherlib myotherlib.cpp) # Static library (default)
Example 3: Conditional Compilation Based on Library Type
This example demonstrates how you can conditionally compile code based on whether a shared or static library is being built:
# Assuming BUILD_SHARED_LIBS is set
if(BUILD_SHARED_LIBS)
add_definitions(-DPIC) # Add -fPIC flag for shared library (Position-Independent Code)
endif()
add_library(mylibrary mylibrary.cpp)
Custom CMake Options
Instead of relying on the global BUILD_SHARED_LIBS
variable, you can define custom options for each library target:
option(MYLIB_BUILD_SHARED "Build mylibrary as a shared library" ON)
add_library(mylibrary mylibrary.cpp)
if(MYLIB_BUILD_SHARED)
set_target_properties(mylibrary PROPERTIES POSITION_INDEPENDENT_CODE ON) # For shared libs
endif()
This approach offers more granular control for individual libraries and avoids potential conflicts with other projects using the same top-level CMakeLists.txt
.
Preprocessor Macros
While not as common, you can use preprocessor macros like BUILD_SHARED
or BUILD_STATIC
defined during the build process. However, this requires modifying source code and can be less flexible compared to CMake options:
# Define macros based on build type (e.g., using CMAKE_BUILD_TYPE)
# In source code
#ifdef BUILD_SHARED
# // Code specific to shared libraries
#endif
#ifdef BUILD_STATIC
# // Code specific to static libraries
#endif
This method adds complexity to the code and might not be suitable for large projects.
- Avoid using preprocessor macros unless absolutely necessary due to potential maintenance issues.
- For complex projects with multiple libraries and requirements
Custom CMake options provide better control. - For simple projects with clear shared/static preferences
BUILD_SHARED_LIBS
is often sufficient.