Skip to content

Commit c86bd14

Browse files
committed
🏁 Fix Windows-related errors with DLLs
Signed-off-by: burgholzer <burgholzer@me.com>
1 parent 9918078 commit c86bd14

8 files changed

Lines changed: 149 additions & 6 deletions

File tree

src/qdmi/driver/CMakeLists.txt

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,27 @@ if(NOT TARGET ${TARGET_NAME})
3030
target_compile_definitions(
3131
${TARGET_NAME}
3232
PRIVATE
33-
"DYN_DEV_LIBS=std::array{ std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMINaDevice>\", \"MQT_NA\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMIScDevice>\", \"MQT_SC\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMI_DDSIM_Device>\", \"MQT_DDSIM\"} }"
33+
"DYN_DEV_LIBS=std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMINaDevice>\", \"MQT_NA\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMIScDevice>\", \"MQT_SC\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMI_DDSIM_Device>\", \"MQT_DDSIM\"}"
3434
)
3535

3636
# Ensure the driver can find the device libraries at runtime
3737
if(WIN32)
38-
# On Windows, ensure the driver depends on the device libraries so they are found when loading
39-
# the driver DLL.
40-
target_link_libraries(${TARGET_NAME} PRIVATE MQT::CoreQDMINaDevice MQT::CoreQDMIScDevice
41-
MQT::CoreQDMI_DDSIM_Device)
38+
# On Windows, we need to copy the device DLLs to the library directory
39+
add_custom_command(
40+
TARGET ${TARGET_NAME}
41+
PRE_BUILD
42+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMIScDevice>
43+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
44+
add_custom_command(
45+
TARGET ${TARGET_NAME}
46+
PRE_BUILD
47+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMINaDevice>
48+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
49+
add_custom_command(
50+
TARGET ${TARGET_NAME}
51+
PRE_BUILD
52+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMI_DDSIM_Device>
53+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
4254
else()
4355
target_link_options(
4456
${TARGET_NAME}

src/qdmi/driver/Driver.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <qdmi/device.h>
1717
#include <spdlog/spdlog.h>
1818

19+
#include <array>
1920
#include <cassert>
2021
#include <cstddef>
2122
#include <cstring>
@@ -31,13 +32,59 @@
3132

3233
#ifdef _WIN32
3334
#include <windows.h>
35+
36+
#include <filesystem>
3437
#else
3538
#include <dlfcn.h>
3639
#endif // _WIN32
3740

3841
namespace qdmi {
3942
#ifdef _WIN32
40-
#define DL_OPEN(lib) LoadLibraryA((lib))
43+
namespace {
44+
/// Returns the directory of the currently loaded driver library.
45+
[[nodiscard]] auto getDriverDirectory() -> std::filesystem::path {
46+
HMODULE module = nullptr;
47+
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
48+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
49+
reinterpret_cast<LPCWSTR>(&getDriverDirectory),
50+
&module) == 0) {
51+
return {};
52+
}
53+
54+
std::wstring buffer(MAX_PATH, L'\0');
55+
DWORD size = 0;
56+
while (true) {
57+
size = GetModuleFileNameW(module, buffer.data(),
58+
static_cast<DWORD>(buffer.size()));
59+
if (size == 0) {
60+
return {};
61+
}
62+
if (size < buffer.size()) {
63+
buffer.resize(size);
64+
break;
65+
}
66+
buffer.resize(buffer.size() * 2);
67+
}
68+
69+
return std::filesystem::path(buffer).parent_path();
70+
}
71+
72+
/// Loads the device library with the given name, searching in the driver
73+
/// directory if no path is specified.
74+
[[nodiscard]] auto loadDeviceLibrary(const std::string& libName) -> HMODULE {
75+
const auto requested = std::filesystem::path(libName);
76+
77+
const std::filesystem::path path = requested.has_parent_path()
78+
? requested
79+
: getDriverDirectory() / requested;
80+
81+
return LoadLibraryExW(path.wstring().c_str(), nullptr,
82+
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
83+
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
84+
}
85+
} // namespace
86+
87+
#define DL_OPEN(lib) loadDeviceLibrary((lib))
4188
#define DL_SYM(lib, sym) \
4289
reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>((lib)), (sym)))
4390
#define DL_CLOSE(lib) FreeLibrary(static_cast<HMODULE>((lib)))

test/fomac/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,23 @@ set(TARGET_NAME mqt-core-fomac-test)
1010

1111
if(TARGET MQT::CoreFoMaC)
1212
package_add_test(${TARGET_NAME} MQT::CoreFoMaC test_fomac.cpp)
13+
14+
if(WIN32)
15+
# On Windows, we need to copy the device DLLs to the test directory
16+
add_custom_command(
17+
TARGET ${TARGET_NAME}
18+
PRE_BUILD
19+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMIScDevice>
20+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
21+
add_custom_command(
22+
TARGET ${TARGET_NAME}
23+
PRE_BUILD
24+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMINaDevice>
25+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
26+
add_custom_command(
27+
TARGET ${TARGET_NAME}
28+
PRE_BUILD
29+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMI_DDSIM_Device>
30+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
31+
endif()
1332
endif()

test/na/fomac/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,23 @@ if(TARGET MQT::CoreNAFoMaC)
1414
# Set the device json path
1515
target_compile_definitions(${TARGET_NAME}
1616
PRIVATE NA_DEVICE_JSON="${PROJECT_SOURCE_DIR}/json/na/device.json")
17+
18+
if(WIN32)
19+
# On Windows, we need to copy the device DLLs to the test directory
20+
add_custom_command(
21+
TARGET ${TARGET_NAME}
22+
PRE_BUILD
23+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMIScDevice>
24+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
25+
add_custom_command(
26+
TARGET ${TARGET_NAME}
27+
PRE_BUILD
28+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMINaDevice>
29+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
30+
add_custom_command(
31+
TARGET ${TARGET_NAME}
32+
PRE_BUILD
33+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMI_DDSIM_Device>
34+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
35+
endif()
1736
endif()

test/qdmi/devices/dd/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,13 @@ if(TARGET MQT::CoreQDMI_DDSIM_Device)
3232
# Set the executable path and version information
3333
target_compile_definitions(${TARGET_NAME} PRIVATE MQT_CORE_VERSION="${MQT_CORE_VERSION}")
3434
target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
35+
36+
# On Windows, we need to copy the DLL to the test executable directory
37+
if(WIN32)
38+
add_custom_command(
39+
TARGET ${TARGET_NAME}
40+
PRE_BUILD
41+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMI_DDSIM_Device>
42+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
43+
endif()
3544
endif()

test/qdmi/devices/na/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,13 @@ if(TARGET MQT::CoreQDMINaDeviceGen
2828
PRIVATE EXECUTABLE_PATH="$<TARGET_FILE:MQT::CoreQDMINaDeviceGenerator>"
2929
MQT_CORE_VERSION="${MQT_CORE_VERSION}"
3030
NA_DEVICE_JSON="${PROJECT_SOURCE_DIR}/json/na/device.json")
31+
32+
# On Windows, we need to copy the DLL to the test executable directory
33+
if(WIN32)
34+
add_custom_command(
35+
TARGET ${TARGET_NAME}
36+
PRE_BUILD
37+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMINaDevice>
38+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
39+
endif()
3140
endif()

test/qdmi/devices/sc/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,13 @@ if(TARGET MQT::CoreQDMIScDeviceGen
2828
PRIVATE EXECUTABLE_PATH="$<TARGET_FILE:MQT::CoreQDMIScDeviceGenerator>"
2929
MQT_CORE_VERSION="${MQT_CORE_VERSION}"
3030
SC_DEVICE_JSON="${PROJECT_SOURCE_DIR}/json/sc/device.json")
31+
32+
# On Windows, we need to copy the DLL to the test executable directory
33+
if(WIN32)
34+
add_custom_command(
35+
TARGET ${TARGET_NAME}
36+
PRE_BUILD
37+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMIScDevice>
38+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
39+
endif()
3140
endif()

test/qdmi/driver/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,23 @@ if(TARGET MQT::CoreQDMIDriver)
1515
PRIVATE
1616
"DYN_DEV_LIBS=std::array{ std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMINaDevice>\", \"MQT_NA\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMIScDevice>\", \"MQT_SC\"}, std::pair{\"$<TARGET_FILE_NAME:MQT::CoreQDMI_DDSIM_Device>\", \"MQT_DDSIM\"} }"
1717
)
18+
19+
if(WIN32)
20+
# On Windows, we need to copy the device DLLs to the test directory
21+
add_custom_command(
22+
TARGET ${TARGET_NAME}
23+
PRE_BUILD
24+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMIScDevice>
25+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
26+
add_custom_command(
27+
TARGET ${TARGET_NAME}
28+
PRE_BUILD
29+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMINaDevice>
30+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
31+
add_custom_command(
32+
TARGET ${TARGET_NAME}
33+
PRE_BUILD
34+
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MQT::CoreQDMI_DDSIM_Device>
35+
$<TARGET_FILE_DIR:${TARGET_NAME}>)
36+
endif()
1837
endif()

0 commit comments

Comments
 (0)