Building Shared or Static Libraries with CMake's TARGET_SUPPORTS_SHARED_LIBS


TARGET_SUPPORTS_SHARED_LIBS

  • Impact
    The value of TARGET_SUPPORTS_SHARED_LIBS influences how CMake generates build rules. If it's TRUE (the default for most platforms), CMake will attempt to create shared libraries for targets. If it's FALSE, CMake will focus on generating static libraries or executables, as shared libraries might not be supported.
  • Default Value
    By default, CMake assumes most general-purpose operating systems support shared libraries. However, this can be overridden based on platform detection or specific toolchain configurations.
  • Purpose
    This boolean property in CMake indicates whether the target platform supports creating shared libraries (.so on Linux, .dll on Windows, etc.).

Understanding Properties of Global Scope

  • Properties can be used to control various aspects of the build process, including:
    • Build flags (e.g., compiler optimization settings)
    • Dependencies
    • Visibility of targets
    • And more
  • Global properties, like TARGET_SUPPORTS_SHARED_LIBS, have project-wide scope. They can be set once and affect all targets within the project unless overridden for specific targets.
  • Properties are attributes associated with targets, sources, files, and other entities in a CMake project.

How TARGET_SUPPORTS_SHARED_LIBS is Used

  • You can also explicitly set it in your CMakeLists.txt file using the set_target_properties command:
  • CMake automatically sets this property based on platform detection during project configuration.
set_target_properties(my_target PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)

This would instruct CMake to generate a static library (or executable) for the target my_target even if the platform generally supports shared libraries.

Common Scenarios for Overriding TARGET_SUPPORTS_SHARED_LIBS

  • Custom Toolchains
    If you're using a custom toolchain that doesn't support shared libraries, you'd set this property to FALSE for all targets within that toolchain.
  • Embedded Systems
    Some embedded systems might have limited memory or lack support for dynamic linking, making shared libraries unsuitable. In such cases, you'd set TARGET_SUPPORTS_SHARED_LIBS to FALSE to ensure static libraries are generated.


Example 1: Platform-Specific Shared Library Behavior

cmake_minimum_required(VERSION 3.10)

project(my_project)

# Detect the platform
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
  # Shared libraries are likely supported on Linux
  set(TARGET_SUPPORTS_SHARED_LIBS TRUE)
elseif(CMAKE_SYSTEM_NAME MATCHES "Windows")
  # Shared libraries are also supported on Windows
  set(TARGET_SUPPORTS_SHARED_LIBS TRUE)
else()
  # Assume other platforms might not support shared libraries
  set(TARGET_SUPPORTS_SHARED_LIBS FALSE)
  message(WARNING "Platform '${CMAKE_SYSTEM_NAME}' may not support shared libraries. Building static libraries by default.")
endif()

# Create a library (type will be determined based on TARGET_SUPPORTS_SHARED_LIBS)
add_library(my_lib my_lib.cpp)

In this example, CMake checks the operating system name and sets TARGET_SUPPORTS_SHARED_LIBS accordingly. The library my_lib will be built as a shared library on Linux and Windows, but as a static library on other platforms.

Example 2: Explicitly Forcing Static Library

cmake_minimum_required(VERSION 3.5)

project(my_project)

# Create a library and explicitly force it to be static
add_library(my_lib STATIC my_lib.cpp)

# Even if the platform supports shared libraries, this one will be static
set_target_properties(my_lib PROPERTIES TARGET_SUPPORTS_SHARED_LIBS FALSE)

Here, regardless of the platform, my_lib will be built as a static library because TARGET_SUPPORTS_SHARED_LIBS is set to FALSE explicitly.

cmake_minimum_required(VERSION 3.15)

project(my_project)

option(BUILD_SHARED_LIBS "Build shared libraries (default: ON)" ON)

# Set TARGET_SUPPORTS_SHARED_LIBS based on the user's choice
set(TARGET_SUPPORTS_SHARED_LIBS ${BUILD_SHARED_LIBS})

add_library(my_lib my_lib.cpp)

if(TARGET_SUPPORTS_SHARED_LIBS)
  message(STATUS "Building my_lib as a shared library.")
else()
  message(STATUS "Building my_lib as a static library.")
endif()


    • Use CMAKE_SYSTEM_NAME or other platform detection methods to check the operating system.
    • Based on the platform, use if statements to explicitly specify the library type in add_library:
    if(CMAKE_SYSTEM_NAME MATCHES "Linux")
      add_library(my_lib SHARED my_lib.cpp)
    else()
      add_library(my_lib STATIC my_lib.cpp)
    endif()
    
  1. BUILD_SHARED_LIBS Variable

    • CMake provides the BUILD_SHARED_LIBS boolean variable. Projects often use option to create a user-controllable option with this variable:
    option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
    
    add_library(my_lib ${sources})
    
    if(BUILD_SHARED_LIBS)
      set_target_properties(my_lib PROPERTIES LIBRARY_SHARED TRUE)
    else()
      set_target_properties(my_lib PROPERTIES LIBRARY_SHARED FALSE)
    endif()
    

    Here, add_library doesn't specify the type. Based on the BUILD_SHARED_LIBS value, the library type is set using set_target_properties.

  2. External Toolchains

    • If you have custom toolchains that don't support shared libraries, consider setting BUILD_SHARED_LIBS to OFF for targets built with that toolchain.

Choosing the Best Approach

  • For managing custom toolchains, consider a combination of BUILD_SHARED_LIBS and toolchain-specific configurations.
  • If you want user control over library type, the BUILD_SHARED_LIBS option is a good choice.
  • For simple platform-specific behavior, conditional logic with if and else might be sufficient.