| # 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 <iostream> |
| #include "MathFunctions.h" |
| |
| // include the generated table |
| #include "Table.h" |
| |
| #include <cmath> |
| |
| 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? |