krames
krames

Reputation: 589

Why is my shared library not linking correctly when using CMake?

This is a very trivial problem and may be due to my inexperience with CMake. I have followed the tutorial at http://fabzter.com/blog/cmake-tutorial-1 and am having issues with linking.

Basically I have a library MathFuncs and an executable that uses MathFuncs. The CMakeLists for MathFuncs is:

cmake_minimum_required(VERSION 2.8)
project(MathFuncs)

include_directories(${PROJECT_SOURCE_DIR})

SET (HEADER_FILES mysqrt.hpp)
add_library(MathFuncs SHARED mysqrt.cpp ${HEADER_FILES})

and the executable CMakeLists is:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)

set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
set (Tutorial_VERSION_BUGFIX 0)

#configure header file to pass some of the CMake settings 
#to the source code
configure_file(
    "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
    "${PROJECT_BINARY_DIR}/TutorialConfig.h"
) 

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")

# add the include directories necessary to build library
include_directories("${PROJECT_SOURCE_DIR}/MathFuncs}")
add_subdirectory(MathFuncs)

SET (MATHFUNCTIONS_DIR ${PROJECT_SOURCE_DIR}/MathFuncs)
add_executable(tutorial tutorial.cpp ${MATHFUNCTIONS_DIR}/mysqrt.hpp)

target_link_libraries(tutorial MathFuncs)

CMake runs fine. However when I try to compile with Visual Studio, I get a linker error stating that it cannot open MathFuncs.lib. When I remove the 'SHARED' option from the MathFuncs CMakeList it runs since it is building a static library, however for my application I want a shared library DLL.

How do I make CMake set the library reference as shared?

Thank you,

Upvotes: 4

Views: 6045

Answers (1)

Fraser
Fraser

Reputation: 78270

It looks like you're not exporting the classes/functions from your DLL properly. See this article for a detailed description.

This isn't entirely straightforward, but fortunately CMake can offer some help here. You can use the GenerateExportHeader module to auto-generate a header with all the preprocessor definitions you should need to properly export your library's public functions.

Here's an example of how I'd change your files. Each is hopefully commented enough to let you understand what's going on. If not, add a comment and I'll expand.

Top-level CMakeLists.txt:

cmake_minimum_required (VERSION 3.0)
project(Tutorial)

add_subdirectory(MathFuncs)

set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)
set(Tutorial_VERSION_BUGFIX 0)

# Configure header file to pass some of the CMake settings to the source code.
set(TutorialConfigHeader "${PROJECT_BINARY_DIR}/TutorialConfig.h")
configure_file(TutorialConfig.h.in "${TutorialConfigHeader}")

# Include the output file of 'configure_file' to ensure it gets configured.
add_executable(tutorial tutorial.cpp "${TutorialConfigHeader}")

# Add TutorialConfig.h's path to include dirs for 'tutorial'.
target_include_directories(tutorial PRIVATE "${PROJECT_BINARY_DIR}")

target_link_libraries(tutorial MathFuncs)

# If 'MathFuncs' is a shared lib, copy it to 'tutorial's bin dir so
# it can be found at runtime.
get_target_property(MathFuncsType MathFuncs TYPE)
if(MathFuncsType STREQUAL "SHARED_LIBRARY")
  add_custom_command(TARGET tutorial POST_BUILD
                     COMMAND ${CMAKE_COMMAND} -E copy_if_different
                         $<TARGET_FILE:MathFuncs> $<TARGET_FILE_DIR:tutorial>
                     COMMENT "Copying MathFuncs shared lib alongside tutorial."
                     VERBATIM)
endif()


MathFuncs/CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
project(MathFuncs)

add_library(MathFuncs SHARED
            mysqrt.cpp
            mysqrt.hpp
            "${PROJECT_BINARY_DIR}/mathfuncs_export.h")

# Write appropriate export PP definitions in a file called
# 'mathfuncs_export.h' in the current binary dir
include(GenerateExportHeader)
generate_export_header(MathFuncs)

# Add the current source dir as a PUBLIC include dir
# (to allow mysqrt.hpp to be found by dependent targets)
# Add the current binary dir as a PUBLIC include dir
# (to allow mathfuncs_export.h to be found by dependent targets)
target_include_directories(MathFuncs PUBLIC
                           ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})


Then to use the generated export header, you just need to have mysqrt.hpp contain something like:

#ifndef MYSQRT_HPP_
#define MYSQRT_HPP_

#include "mathfuncs_export.h"

double MATHFUNCS_EXPORT MySqrt(double input);

#endif  // MYSQRT_HPP_


This should now cause VS to create an export library ${CMAKE_BINARY_DIR}/MathFuncs/Debug/MathFuncs.lib (fixing the linker issue) and the actual DLL ${CMAKE_BINARY_DIR}/MathFuncs/Debug/MathFuncs.dll.

Upvotes: 6

Related Questions