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\lib
在 PATH
中,因此 DLL 在 cmake --install
之后找到。然而,这不是我们想要的:ctest
应始终使用当前版本的新 DLL,而不是已安装的版本。
在Linux下,一切正常。为什么不用于 Windows 和 MinGW?这是 CMake 中的错误吗?我们如何解决这个问题,以便 ctest
在所有平台上正确执行?
您的问题似乎是当您的 Demo
可执行文件被 ctest
运行 时,Windows DLL 搜索程序未能找到 mylib.dll
。 Windows DLL 搜索顺序指定为 here:
- The directory from which the application loaded.
- The system directory. Use the
GetSystemDirectory
function to get the path of this directory.
- The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
- The Windows directory. Use the
GetWindowsDirectory
function to get the path of this directory.
- The current directory.
- 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)
顶层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\lib
在 PATH
中,因此 DLL 在 cmake --install
之后找到。然而,这不是我们想要的:ctest
应始终使用当前版本的新 DLL,而不是已安装的版本。
在Linux下,一切正常。为什么不用于 Windows 和 MinGW?这是 CMake 中的错误吗?我们如何解决这个问题,以便 ctest
在所有平台上正确执行?
您的问题似乎是当您的 Demo
可执行文件被 ctest
运行 时,Windows DLL 搜索程序未能找到 mylib.dll
。 Windows DLL 搜索顺序指定为 here:
- The directory from which the application loaded.
- The system directory. Use the
GetSystemDirectory
function to get the path of this directory.- The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
- The Windows directory. Use the
GetWindowsDirectory
function to get the path of this directory.- The current directory.
- The directories that are listed in the
PATH
environment variable. Note that this does not include the per-application path specified by theApp Paths
registry key. TheApp 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
:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
另一种选择:
add_test(NAME Demo COMMAND Demo WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib)