8

I have a simple project structure derived from the amazing tutorial

https://rix0r.nl/blog/2015/08/13/cmake-guide/

It looks as follows:

- src
  - CMakeLists.txt
  - mylib
    - include/mylib/mylibclass.h
    - src/mylibclass.cpp
    - CMakeLists.txt
  - myapp
    - src/myapp.cpp
    - CMakeLists.txt

The top level CMakeLists.txt contains:

cmake_minimum_required( VERSION 3.6 )
project( sample_project VERSION 0.1 LANGUAGES CXX )

set( BUILD_SHARED_LIBS ON CACHE BOOL "" )

add_subdirectory( mylib )
add_subdirectory( myapp )

The CMakeLists.txt in the mylib folder contains:

add_library( mylib src/mylibclass.cpp include/mylib/mylibclass.h )
set_target_properties( mylib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_include_directories( mylib
    PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> PRIVATE src )  

And the one in the myapp folder contains:

add_executable( myapp src/myapp.cpp )
target_link_libraries( myapp mylib )

I want to use this structure to develop both mylib (as a shared or static library as determined by BUILD_SHARED_LIBS) and myapp. For this, I want to set myapp as my startup project in Visual Studio and compile and run in the MSVC debugger. This is not possible for the shared library case without extra CMake code, as the myapp.exe doesn't know where to find the mylib.dll.

What is best CMake practice to tell the program where to find the dll?

Edit:

Based on the suggestions by @Andre, I've added the following lines to the top level CMakeLists.txt:

set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "" )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "" )
DrPepperJo
  • 632
  • 1
  • 5
  • 19

1 Answers1

11

The problem occurs, because your mylib.dll is not in the same folder as your myapp.exe nor is it in the %PATH% environment variable when Visual Studio tries to start your myapp.exe

The obvious solution is to make sure both dll and exe are in the same folder. There are several ways to do this:

  1. Put both exe and dll into a single "output" directory by setting the RUNTIME_OUTPUT_DIRECTORY and the LIBRARY_OUTPUT_DIRECTORY properties on your targets:

    set_target_properties( myapp PROPERTIES RUNTIME_OUTPUT_DIRECTORY 
       ${sample_project_BINARY_DIR}/build_results/bin )
    set_target_properties( mylib PROPERTIES LIBRARY_OUTPUT_DIRECTORY
       ${sample_project_BINARY_DIR}/build_results/bin )
    

This will produce the myapp.exe and mylib.dll into a single build_results/bin folder in your top-level build folder.

  1. Or by setting the the global CMAKE_RUNTIME_OUTPUT_DIRECTORY and CMAKE_LIBRARY_OUTPUT_DIRECTORY variables which will do this for all targets in your sample_project.

  2. Copy the dll to the exe location after building, e.g. with

    add_custom_command(TARGET mylib
      POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy mylib.dll ${myapp_BINARY_DIR}/.
    )
    
O'Neil
  • 3,790
  • 4
  • 16
  • 30
André
  • 18,348
  • 6
  • 60
  • 74
  • Thanks for your answer. Which of your solutions would you say is best practice? Concerning answer 1, is this something that should be determined in the app or on top level? – DrPepperJo Oct 01 '16 at 14:46
  • 2
    I prefer option 2, which I can put in my top-level CMakeLists.txt. Only in rare cases is it undesirable to put all dlls/exes in the same bin folder. Note that this is something I use only in a build-environment as a developer. For "real" deployment I will use the [install](https://cmake.org/cmake/help/v3.4/command/install.html) mechanisms of CMake. – André Oct 01 '16 at 14:51
  • Say I have a number of prebuilt external libraries and I need those dlls as well and I don't want to set any additional runtime paths. Would option 3 be the only way to facilitate the copying of dll files or is there some kind of option to copy all dlls associated with linked to stub files? – DrPepperJo Dec 10 '16 at 13:06
  • 3
    Options 1 and 2 would require you to build your own binaries in the installation folders of the 3rdparty binaries, which is really, really awkward. That leaves only option 3. Alternatively, you could set the PATH environment variable (or LD_LIBRARY_PATH on linux), see http://stackoverflow.com/q/28533012/417197 – André Dec 13 '16 at 13:24
  • Thanks, all your answers were incredibely useful! – DrPepperJo Dec 13 '16 at 13:27