# Why is manual copying of .dll needed when linking library?

**URL:** <https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971>\
**Category:** Code\
**Tags:** os:windows\
**Created:** [November 28, 2022, 4:07pm UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971 "2022-11-28T16:07:59Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![willem](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/w/898d66/32.png) [@willem](https://discourse.cmake.org/u/willem)\
**Post date:** [November 28, 2022, 4:07pm UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/1 "2022-11-28T16:07:59Z")

</div>

I am trying to figure out how CMake is supposed to work for shared libraries. I create a shared library like so:

(in /mdp\_opt/CMakeLists.txt:)

add\_library (mdp\_opt SHARED librarycomponent.cpp)

Now, a test executable uses this:  
(/test/CMakeLists.txt:)  
add\_executable (test test.cpp)

target\_link\_libraries(test PRIVATE mdp\_opt)

This works fine if the library is marked STATIC (instead of SHARED as above). When it is marked SHARED (as in above), I need to add:

set(CMAKE\_WINDOWS\_EXPORT\_ALL\_SYMBOLS ON)

I halfway understand why, but let’s forget that. What is more important is that with this change, it only works if I copy the file mdp\_opt.dll from build/x64-debug/mdp\_opt to build/x64-debug/test. I can do that - it is not a problem - but I don’t understand why?

In the book “professional CMake”, I read ( **emphasis** mine):

LINK\_LIBRARIES  
This target property holds a list of all libraries the target should link to directly. It is initially  
empty when the target is created and it supports generator expressions. An associated interface  
property INTERFACE\_LINK\_LIBRARIES is supported. Each library listed can be one of the following:  
• A path to a library, usually specified as an absolute path.  
• Just the library name without a path, usually also without any platform-specific file name  
prefix (e.g. lib) or suffix (e.g. .a, .so, .dll).  
• The name of a CMake library target. **CMake will convert this to a path to the built library**  
**when generating the linker command, including supplying any prefix or suffix to the file**  
**name as appropriate for the platform.** Because CMake handles all the various platform  
differences and paths on the project’s behalf, using a CMake target name is generally the  
preferred method.

So didn’t I just state with:

target\_link\_libraries(test PRIVATE mdp\_opt)

that I intend to link the output associated with the target mdp\_opt with the test executable? Also, in my reading of the above resource, my understanding is that the executable will convert to a path? Anyhow?

So if the answer is that this somehow does not work and that some manual copying is needed (e.g. post-build), what is the preferred way to deal with this in a cross-platform way?

---

<div class="post-metadata">

**Author:** ![imikejackson](https://discourse.cmake.org/user_avatar/discourse.cmake.org/imikejackson/32/301_2.png) [@imikejackson](https://discourse.cmake.org/u/imikejackson)\
**Post date:** [November 30, 2022, 2:15pm UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/2 "2022-11-30T14:15:37Z")

</div>

```cmake
# ---------- Setup output Directories -------------------------
if(NOT DEFINED CMAKE_LIBRARY_OUTPUT_DIRECTORY)
  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
    ${${PROJECT_NAME} _BINARY_DIR}/Bin
    CACHE PATH
    "Single Directory for all Libraries"
    )
endif()

# --------- Setup the Executable output Directory -------------
if(NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
    ${${PROJECT_NAME} _BINARY_DIR}/Bin
    CACHE PATH
    "Single Directory for all Executables."
    )
endif()

# --------- Setup the Executable output Directory -------------
if(NOT DEFINED CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
  set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
    ${${PROJECT_NAME} _BINARY_DIR}/Bin
    CACHE PATH
    "Single Directory for all static libraries."
    )
endif()

```

This will make sure all libraries and executables are placed into the same directory. This is one way to solve the issue.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [November 30, 2022, 7:45pm UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/3 "2022-11-30T19:45:43Z")

</div>

This is essentially because Windows lacks an “rpath” mechanism where a library can contain a set of directories for the runtime loader to look at. On Windows, there is just `PATH` and various special flags one can pass to `LoadLibrary` (which is outside of your control).

---

<div class="post-metadata">

**Author:** ![willem](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/w/898d66/32.png) [@willem](https://discourse.cmake.org/u/willem)\
**Post date:** [December 1, 2022, 7:52am UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/4 "2022-12-01T07:52:04Z")

</div>

Thanks, that is very helpful; I think I understand now why all this fuss is needed. It would help if documentation (like the quoted book) would mention these limitations on windows; I found the statements a bit misleading.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [June 10, 2023, 2:41am UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/5 "2023-06-10T02:41:53Z")

</div>

> [@willem](#):
>
> I halfway understand why, but let’s forget that. What is more important is that with this change, it only works if I copy the file mdp\_opt.dll from build/x64-debug/mdp\_opt to build/x64-debug/test.

Sorry it has taken me so long to reply here, but are you talking about building or running your executable here? Building it shouldn’t require you to force the DLL for `mdp_opt` to be in the same directory as the `test` executable. When _running_ the executable, that’s a different story. Either the DLL has to be in the same directory as the executable, or it has to be found in one of the directories specified by the `PATH` environment variable. How you run things is something CMake can’t control, so it’s up to you to get that right. Many projects dump all DLLs and executables in the same output directory so that their users don’t have to deal with it. That may be feasible for smaller projects, but for large projects with many executables (including test executables), that may not be appropriate.

I should also mention that you should not call any targets you define “test”. That target name is reserved for CMake’s own use. The `enable_testing()` command will cause a global `test` target to be defined, which would then clash with the one you’ve tried to define in the `add_executable()` call.

---

<div class="post-metadata">

**Author:** ![willem](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/w/898d66/32.png) [@willem](https://discourse.cmake.org/u/willem)\
**Post date:** [June 12, 2023, 6:42am UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/6 "2023-06-12T06:42:13Z")

</div>

Thanks, that makes things clear; e.g. the distinction between building and running.

Still, in your book, a newbie to cmake like me might feel confused when they link a library with target\_link\_libraries, and then find that the executable won’t run because it cannot find the dll. A remark somewhere would help the learning curve.

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [June 17, 2023, 9:59pm UTC](https://discourse.cmake.org/t/why-is-manual-copying-of-dll-needed-when-linking-library/6971/7 "2023-06-17T21:59:41Z")

</div>

Note that the reason for the split is for cross compilation where the paths on the build machine don’t necessary match what the deployment will see. `DESTDIR`-mediated installs is another complication here. For example, a “sysroot” might live on the build machine at `/usr/sysroots/aarch64-linux-gnu` while it is `/usr` on the deployment machine. CMake doesn’t have a model for deployment layouts to warn when things don’t match (in general or for the common case of “like the build machine”).
