1

In my project, static library is created using cmake. But now i wanted to change it to create and support both static and shared libraries.

Could someone please help me how to proceed with that?

Below is my existing script for the static library:

include(bundle_static_library.cmake)

set(BINARY camsdk)

set(CMAKE_VERBOSE_MAKEFILE ON)

include_directories("../../OpenSource/boost_1_75_0")
if(CMAKE_HOST_WIN32)
add_definitions(-DBOOST_DATE_TIME_NO_LIB)
endif()
include_directories(Include)
include_directories("../Dependencies/CamSupport/h")

file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp)
set(SOURCES 
    ${SOURCES}
    ${CMAKE_CURRENT_LIST_DIR}/../CamVisionLibrary/Source/VisionClient.cpp)

if(CMAKE_HOST_UNIX)
    add_compile_options(-fpic -Wall -Werror)
    add_definitions(-DBOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX)
elseif(CMAKE_HOST_WIN32)
    # all warnings as errors
    add_compile_options(/W4 /WX)
    add_definitions(-D_UNICODE -DUNICODE)
endif ()

if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
    set(BUILD_TYPE "debug")
else()
    set(BUILD_TYPE "release")
endif() 

if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
    set(PLATFORM "macos")
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
    set(PLATFORM "windows")
else()
    set(PLATFORM "linux")
endif()

# We depend on another static library EMR
add_library(EMR STATIC IMPORTED)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
    if(NOT CMAKE_CL_64)
        message(STATUS "Architecture: x86")
        set_property(TARGET EMR PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/Library/emr/lib/${PLATFORM}-x86-${BUILD_TYPE}-static/testemr-cc.lib)
    else()
        message(STATUS "Architecture: x64")
        set_property(TARGET EMR PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/Library/emr/lib/${PLATFORM}-x64-${BUILD_TYPE}-static/testemr-cc.lib)
    endif()
else()
    set_property(TARGET EMR PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/Library/emr/lib/${PLATFORM}-x64-${BUILD_TYPE}-static/libtestemr-cc.a)
endif()

# First build a temporary library
set(TMP_BINARY camsdk-tmp)
add_library(${TMP_BINARY} STATIC ${SOURCES})
target_link_libraries(${TMP_BINARY} PUBLIC EMR)

bundle_static_library(${TMP_BINARY} ${BINARY})
sas
  • 89
  • 8
  • Should this be configuration option when cmake is run for first time or you need both targets for every build? – Marek R Jun 28 '21 at 12:27
  • Hi @Marek R, we need both the targets with every build. – sas Jun 28 '21 at 12:38
  • Just create **another library target**, which will be shared one. E.g. `add_library(${TMP_BINARY}-shared SHARED ${SOURCES})`. You need to link this library as usual. – Tsyvarev Jun 28 '21 at 13:23
  • Thank you @Tsyvarev for your suggestion. I will create library target and link the library like below. But after that how to bundle it with shared library like we are using bundle_static_library for static library. add_library(${TMP_BINARY}-shared SHARED ${SOURCES}) target_link_libraries(${TMP_BINARY} PUBLIC EMR) – sas Jun 28 '21 at 14:06
  • "But after that how to bundle it ..." - What do you mean by "bundle"? E.g. that [bundle_static_library.cmake](https://gist.github.com/cristianadam/ef920342939a89fae3e8a85ca9459b49) **merges** static libraries into the single static library. This procedure has no sense for the shared libraries. – Tsyvarev Jun 28 '21 at 14:55
  • ok, understood. Then i will try to run with the library target and target_link_libraries. – sas Jun 28 '21 at 15:04
  • [I wrote a long article about why you actually don't want to do this what you should do instead.](https://alexreinking.com/blog/building-a-dual-shared-and-static-library-with-cmake.html) – Alex Reinking Jun 28 '21 at 16:33
  • Hi @AlexReinking, I have gone through your article. But it is bit confusing for me. Could you please help me how can i change my script based on your approach. – sas Jun 28 '21 at 16:55
  • There is already an extensive example in that article and a [GitHub repo](https://github.com/alexreinking/SharedStaticStarter/) people can use as a starting point. Without the ability to test proposed changes to your build, I cannot offer concrete suggestions. – Alex Reinking Jun 28 '21 at 16:57
  • Could someone help me how to merge the static libraries (testemr.lib) that i am using to the shared library (camsdk.dll) that i am creating. – sas Jun 28 '21 at 17:34

1 Answers1

2

As I recall, the best way to handle this is with CMake Object libraries. An object library contains the compiled objects, which you can then wrap with shared and static versions. This avoids the need to compile twice. For example:

add_library(something OBJECT lib/something.cpp)
target_include_directories(something PUBLIC lib)

add_library(something_shared SHARED)
target_link_libraries(something_shared PUBLIC something)

add_library(something_static STATIC)
target_link_libraries(something_static PUBLIC something)

In this example, you compile the .cpp once, then you wrap that library with a shared and static version that you can link to.

bremen_matt
  • 6,902
  • 7
  • 42
  • 90
  • Worth noting this doesn't work properly for xcode builds in CMake prior to 3.25 due to this: https://gitlab.kitware.com/cmake/cmake/-/issues/23734 – Kamil Kisiel Nov 03 '22 at 23:07