CTest、CMake 和 MinGW:可执行文件构建,但未能 运行,因为未找到新的 DLL

CTest, CMake & MinGW: Executables build, but fail to run, because fresh DLL is not found

顶层CMakeLists.txt包含:

include(CTest)
add_subdirectory(lib)
add_subdirectory(demo)
add_subdirectory(test)

lib/CMakeLists.txt 本质上是:

add_library(MyLib <sources>)

demo/CMakeLists.txt 本质上是:

add_executable(Demo demo.c)
target_link_libraries(Demo MyLib)

test/CMakeLists.txt 就是:

add_test(NAME Demo COMMAND Demo)

从 gitlab-runner,我们执行:

cmake -G "Ninja" -DCMAKE_INSTALL_PREFIX=C:\opt\x64 -B. ..
cmake --build
ctest --output-on-failure

前两步成功;第三个失败:

Start 1: Demo
1/1 Test #1: Demo .......................Exit code 0xc0000135
***Exception:   0.03 sec

如果我重试:

cmake --install
ctest

那么测试成功。所以唯一的问题就是在运行ctest的时候找不到build/lib/mylib.dll。而 C:\opt\x64\libPATH 中,因此 DLL 在 cmake --install 之后找到。然而,这不是我们想要的:ctest 应始终使用当前版本的新 DLL,而不是已安装的版本。

在Linux下,一切正常。为什么不用于 Windows 和 MinGW?这是 CMake 中的错误吗?我们如何解决这个问题,以便 ctest 在所有平台上正确执行?

您的问题似乎是当您的 Demo 可执行文件被 ctest 运行 时,Windows DLL 搜索程序未能找到 mylib.dll。 Windows DLL 搜索顺序指定为 here:

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

因此,您可以将 PATH 环境变量修改为 同时 包括当前构建中的新 DLL 的位置。

更好、更不容易出错的解决方案可能是将 DLL 放在与 Demo 可执行文件相同的目录中。您可以通过修改顶级 CMake 文件强制 CMake 为 DLL 和可执行文件使用相同的 binary 目录:

include(CTest)
add_subdirectory(lib ${CMAKE_BINARY_DIR}/demo)
add_subdirectory(demo ${CMAKE_BINARY_DIR}/demo)
add_subdirectory(test)

或者,作为一种本地化程度较低的方法,您可以通过设置 CMAKE_RUNTIME_OUTPUT_DIRECTORY:

将 DLL 放在与可执行文件相同的目录中
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

另一种选择:

add_test(NAME Demo COMMAND Demo WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib)