【问题标题】:Building of executable and shared library with cmake, runtimelinker does not find dll用cmake构建可执行和共享库,runtimelinker找不到dll
【发布时间】:2014-06-12 23:24:47
【问题描述】:

我正在使用 gcc(cygwin)、gnu make、windows 7 和 cmake。

我的 cmake testprojekt 具有以下结构

rootdir
|-- App
|   |-- app.cpp
|   +-- CMakeLists.txt
|-- Lib
|   |-- lib.cpp
|   |-- CMakeLists.txt
|-- MakeFileProject
+ CMakeLists.txt

rootdir/App/app.cpp:

#include<string>
void printThemMessageToScreen(std::string input);//prototype
int main(int argc,char **argv){
 printThemMessageToScreen("this will be displayed by our lib");
 return 0;
}

rootdir/Lib/lib.cpp:

#include<iostream>
#include<string>

void printThemMessageToScreen(std::string input){
 std::cout<<input;
}

rootdir/CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)
project(TestProject)

add_subdirectory(App)
add_subdirectory(Lib)

rootdir/Lib/CMakeLists.txt:

add_library(Lib SHARED lib.cpp)

rootdir/App/CMakeLists.txt:

# Make sure the compiler can find include files from our Lib library. 
include_directories (${LIB_SOURCE_DIR}/Lib) 

# Make sure the linker can find the Lib library once it is built. 
link_directories (${LIB_BINARY_DIR}/Lib) 

# Add executable called "TestProjectExecutable" that is built from the source files 
add_executable (TestProjectExecutable app.cpp) 

# Link the executable to the lib library. 
target_link_libraries (TestProjectExecutable Lib) 

现在,当我运行 cmake 和 make 时,所有内容都将生成并构建,没有错误,但是当我尝试执行二进制文件时,它将失败,因为找不到生成的库。

但是:当我将 lib dll 复制到与应用程序 exe 相同的目录中时,它将被执行!

另外:如果我将库配置为静态,它也会执行。

如何告诉运行时链接器在哪里寻找我的 dll?

更新:

根据用户Vorren提出的方法解决:

我打开注册表编辑器,并导航到以下键:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths

,我在这里创建了一个名为我的应用程序的新密钥:

在这种情况下:TestProjectExecutable.exe

之后,(默认)值设置为 TestProjectExecutable.exe 的完整路径,包括文件名和扩展名。然后我创建了另一个名为“Path”的字符串值,并将值设置为 dll 所在的文件夹:

【问题讨论】:

  • dll 是和可执行文件在同一个文件夹中还是在你的路径中?
  • 不,我希望 dll 位于不同的目录中,但是如果我将 dll 复制到与 exe 相同的目录中,程序将执行得很好。
  • 那么您很可能必须将包含 dll 的文件夹添加到您的 PATH 变量中。这确实不是 cmake 或 cygwin 特定的问题,而是 Windows 问题。请参阅此处了解 windows 如何查找 dll:msdn.microsoft.com/en-us/library/7d83bc18.aspx
  • 最简单的方法是将dll和exe放在同一个文件夹中。我给你的链接显示了 5 种可能的方法来做到这一点,微软认为所有这些方法都很好。尽管使用 UAC 触摸系统文件夹将需要提升权限和权限。
  • 顺便说一句,使用 cmake 您可以轻松设置输出文件夹,以便将 .dll 与 exe 放在同一文件夹中:stackoverflow.com/questions/6594796/… 我在所有基于 cmake 的项目中都使用此方法。跨度>

标签: c++ windows dll makefile cmake


【解决方案1】:

您的问题不在于链接器或编译器,而在于 Windows 搜索 DLL 的方式。

操作系统将使用以下算法来定位所需的 DLL:

看看:

  1. 应用程序特定路径注册表项中列出的目录;
  2. 当前进程的可执行模块所在目录;
  3. 当前目录;
  4. Windows 系统目录;
  5. Windows 目录;
  6. PATH 环境变量中列出的目录;

因此,如果您不想将操作系统目录与应用特定的 dll 混淆,那么您有两个合理的选择:

  1. 创建一个特定于应用程序的路径注册表项(我会选择此选项);
  2. 将您的 DLL 与您的 EXE 放在同一文件夹中;
  3. 修改 PATH 变量(但是,如果您可以使用选项 1,为什么要这样做?)

【讨论】:

  • 所以当我想使用选项 1 时,可交付应用程序需要像 wix 或 nullsoft 安装程序这样的安装程序来为我的 dll 创建注册表项,对吗?
  • 要么,要么你需要弄清楚如何从你的应用程序代码中修改注册表。查看此链接:msdn.microsoft.com/en-us/library/windows/desktop/…
  • 好的,在我完成今天的工作后,我会调查并尝试您的第一个选项。
  • 是的,你的方法很有效!我将详细说明我的问题,关于如何让它与注册表应用程序路径一起工作
  • 有没有办法让 cmake 编辑特定于应用程序的路径注册表?
【解决方案2】:

我更喜欢的一个没有真正提到的解决方案是将您的共享库构建到与可执行文件相同的目录中。这往往是一个更简单的解决方案。

使用 cmake 的一种方法是

设置(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

或者您也可以根据构建风格设置输出目录。

how do I make cmake output into a 'bin' dir?

【讨论】:

  • 我的回答中的第二个选项并且在问题的 cmets 中被提及;)
  • 工作中出现问题。如果我想更改 dll 的输出目录,我需要说服其他人他需要更改 dll 的输出目录。我希望通过为我的测试 exe 更改本地 CMakeLists 文件中的某些内容来避免这种情况。
  • 对我来说这也是最明智的选择。
  • @Knitschi 您不必说服他们,因为您可以制作自己的 CMakeLists.txt(Visual Studio 解决方案)来设置这个美妙的变量并包含他们的 CMakeLists 文件
  • @Liviu 我认为问题在于我们的项目有一个用于一些插件 dll 的额外文件夹和另一个用于可执行文件的文件夹。生产代码使用正确的路径手动加载插件。当我为插件代码编写测试时,可执行文件最终位于 exe 文件夹中,我想避免在测试中手动加载插件 dll。但我现在在另一家公司,所以不用担心;-)
【解决方案3】:

我发现(我相信是)一种很好的处理方式。它遵循将 .dll 添加到与 .exe 相同的目录的方法。你可以在 CMake 中这样做:

if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
    TARGET <app-target> POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    $<TARGET_FILE_DIR:<lib-target>>
    $<TARGET_FILE_DIR:<app-target>)
endif()

其中app-target 是您正在构建的应用程序或库的名称(通过add_executableadd_library 创建),lib-target 是通过find_package 引入的导入库。

# full example
cmake_minimum_required(VERSION 3.14)

project(my-app-project VERSION 0.0.1 LANGUAGES CXX)

find_package(useful-library REQUIRED)

add_executable(my-application main.cpp)

target_link_libraries(my-application PUBLIC useful-library::useful-library)

if (WIN32)
# copy the .dll file to the same folder as the executable
add_custom_command(
    TARGET my-application POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
    $<TARGET_FILE_DIR:useful-library::useful-library>
    $<TARGET_FILE_DIR:my-application>)
endif()

【讨论】:

    【解决方案4】:

    我从接受的答案(通过 pdeschain)中尝试了选项 1。 我什至创建了一个 cmake 钩子来自动注册链接库的路径

    function (xtarget_link_libraries target libs) # same as target_link_libraries but with additional improvements to allow windows find the library at runtime
    LIST(REMOVE_AT ARGV 0)
    SET(LIBS ${ARGV}) # this is to pass list into this function
    target_link_libraries(${target} ${LIBS}) # call standard routine
    
    if(WIN32)
        set(TFILE ".")
        get_property(slibs TARGET ${target} PROPERTY all_libs) # recall libs linked before
        set(LIBS ${slibs};${LIBS})
        set_property(TARGET ${target} PROPERTY all_libs ${LIBS}) # save all libs
        FOREACH(lib ${LIBS}) # compose a list of paths
            set(TFILE "${TFILE};$<TARGET_LINKER_FILE_DIR:${lib}>")
        ENDFOREACH()
        #add reg key
        add_custom_command(TARGET ${target} POST_BUILD COMMAND  reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /v "Path" /d "${TFILE}" /f )
    endif()
    endfunction()
    

    可以用作xtarget_link_libraries(test lib1 lib2)。应用程序将能够在其绝对路径中找到动态库。

    但是,这有一个大问题,App Paths 机制https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx#appPaths

    不允许有不同的条目来表示“Debug/test.exe”和“Release/test.exe”。所以对我来说这是一个糟糕的选择。

    您可以添加以下行来填充 Default 键作为帖子中建议的程序路径。

    add_custom_command(TARGET ${target} POST_BUILD COMMAND reg add "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${target}.exe" /ve /d "$&lt;TARGET_FILE:${target}&gt;" /f )

    现在您可以在系统的任何位置享受运行 test.exe 的乐趣...我想我的下一个尝试将是选项

    1. 使用 cmake 创建指向 dll 的符号链接。

    【讨论】:

      猜你喜欢
      • 2021-07-17
      • 2021-10-25
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多