# Mixing Static and Shared # In this section we will show how by using the BUILD_SHARED_LIBS variable we can control the default behavior of add_library, and allow control over how libraries without an explicit type ( STATIC/SHARED/MODULE/OBJECT ) are built. To accomplish this we need to add BUILD_SHARED_LIBS to the top level CMakeLists.txt. We use the option command as it allows users to optionally select if the value should be On or Off. Next we are going to refactor MathFunctions to become a real library that encapsulates using mysqrt or sqrt, instead of requiring the calling code to do this logic. This will also mean that USE_MYMATH will not control building MathFuctions, but instead will control the behavior of this library. The first step is to update the starting section of the top level CMakeLists.txt to look like: cmake_minimum_required(VERSION 3.3) project(Tutorial) # control where the static and shared libraries are built so that on windows # we don't need to tinker with the path to run the executable set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) option(BUILD_SHARED_LIBS "Build using shared libraries" ON) # the version number. set(Tutorial_VERSION_MAJOR 1) set(Tutorial_VERSION_MINOR 0) # configure a header file to pass the version number only configure_file( "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in" "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # add the MathFunctions library add_subdirectory(MathFunctions) # add the executable add_executable(Tutorial tutorial.cxx) target_link_libraries(Tutorial PUBLIC MathFunctions) Now that we have made MathFunctions always be used, we will need to update the logic of that library. So, in MathFunctions/CMakeLists.txt we need to create a SqrtLibrary that will conditionally be built when USE_MYMATH is enabled. Now, since this is a tutorial, we are going to explicitly require that SqrtLibrary is built statically. The end result is that MathFunctions/CMakeLists.txt should look like: # add the library that runs add_library(MathFunctions MathFunctions.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) if(USE_MYMATH) # does this system provide the log and exp functions? include(CheckSymbolExists) set(CMAKE_REQUIRED_LIBRARIES "m") check_symbol_exists(log "math.h" HAVE_LOG) check_symbol_exists(exp "math.h" HAVE_EXP) # first we add the executable that generates the table add_executable(MakeTable MakeTable.cxx) # add the command to generate the source code add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h DEPENDS MakeTable ) # library that just does sqrt add_library(SqrtLibrary STATIC mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h ) # state that we depend on our binary dir to find Table.h target_include_directories(SqrtLibrary PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") if(HAVE_LOG AND HAVE_EXP) target_compile_definitions(SqrtLibrary PRIVATE "HAVE_LOG" "HAVE_EXP") endif() target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif() # define the symbol stating we are using the declspec(dllexport) when # building on windows target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") install(TARGETS MathFunctions DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) Next, update MathFunctions/mysqrt.cxx to use the mathfunctions and detail namespaces: #include #include "MathFunctions.h" // include the generated table #include "Table.h" #include namespace mathfunctions { namespace detail { // a hack square root calculation using simple operations double mysqrt(double x) { ... return result; } } } We also need to make some changes in tutorial.cxx, so that it no longer uses USE_MYMATH: 1. Always include MathFunctions.h 2. Always use mathfunctions::sqrt Finally, update MathFunctions/MathFunctions.h to use dll export defines: #if defined(_WIN32) #if defined(EXPORTING_MYMATH) #define DECLSPEC __declspec(dllexport) #else #define DECLSPEC __declspec(dllimport) #endif #else //non windows #define DECLSPEC #endif namespace mathfunctions { double DECLSPEC sqrt(double x); } At this point, if you build everything, you will notice that linking fails as we are combining a static library without position enabled code with a library that has position enabled code. This solution to this is to explicitly set the POSITION_INDEPENDENT_CODE target property of SqrtLibrary to be True no matter the build type. Exercise: We modified MathFunctions.h to use dll export defines. Using CMake documentation can you find a helper module to simplify this? Exercise: Determine what command is enabling PIC for SqrtLibrary. What happens if we remove said command?