Skip to content

Commit d823ea8

Browse files
committed
Add test illustrating crash when PythonQt is initialized in dynamically loaded lib
1 parent 9d8e809 commit d823ea8

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

CMakeLists.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,5 +302,37 @@ if(BUILD_TESTING)
302302
NAME tests_PythonQtTestMain
303303
COMMAND ${Slicer_LAUNCH_COMMAND} $<TARGET_FILE:PythonQtCppTests> tests/PythonQtTestMain
304304
)
305+
306+
#
307+
# tests_PythonQtDynamicLoading: This test checks that a dynamically loaded library (itself linked against
308+
# PythonQt) properly initializes PythonQt.
309+
#
310+
311+
add_library(PythonQtDynamicLoaderSharedLibrary SHARED tests/PythonQtDynamicLoaderSharedLibrary.cpp)
312+
target_link_libraries(PythonQtDynamicLoaderSharedLibrary PythonQt)
313+
314+
add_executable(PythonQtDynamicLoader tests/PythonQtDynamicLoader.cpp)
315+
target_link_libraries(PythonQtDynamicLoader ${QT_LIBRARIES})
316+
317+
# Since setting the ENVIRONMENT property value with semicolon (e.g. PATH) is not supported, we
318+
# generate a wrapper script to update PATH and LD_LIBRARY_PATH.
319+
set(test_wrapper "${CMAKE_CURRENT_BINARY_DIR}/test_wrapper.cmake")
320+
file(WRITE ${test_wrapper} "
321+
if(UNIX)
322+
set(ENV{LD_LIBRARY_PATH} \"\$ENV{LD_LIBRARY_PATH}:.\")
323+
else()
324+
set(ENV{PATH} \"\$ENV{PATH};.\")
325+
endif()
326+
execute_process(COMMAND \${TARGET_FILE} RESULT_VARIABLE result)
327+
if(NOT result EQUAL 0)
328+
message(FATAL_ERROR \"test failed ! [result: \${result}]\")
329+
endif()
330+
")
331+
332+
add_test(
333+
NAME tests_PythonQtDynamicLoading
334+
COMMAND ${CMAKE_COMMAND} -DTARGET_FILE=$<TARGET_FILE:PythonQtDynamicLoader> -P ${test_wrapper}
335+
)
336+
305337
endif()
306338

tests/PythonQtDynamicLoader.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
#include <QApplication>
3+
#include <QLibrary>
4+
#include <QtGlobal>
5+
6+
#include <cstdlib>
7+
#include <iostream>
8+
9+
int main(int argc, char* argv[])
10+
{
11+
QApplication qapp(argc, argv);
12+
13+
#ifdef Q_OS_WIN32
14+
std::cout << "PATH [" << qPrintable(qgetenv("PATH")) << "]" << std::endl;
15+
#else
16+
std::cout << "LD_LIBRARY_PATH [" << qPrintable(qgetenv("LD_LIBRARY_PATH")) << "]" << std::endl;
17+
#endif
18+
19+
20+
QLibrary library("PythonQtDynamicLoaderSharedLibrary");
21+
if (!library.load())
22+
{
23+
std::cerr << "Failed to load 'PythonQtDynamicLoaderSharedLibrary': "
24+
<< qPrintable(library.errorString()) << std::endl;
25+
return EXIT_FAILURE;
26+
}
27+
28+
//
29+
// Resolve and invoke 'this_function_returns_42' function.
30+
//
31+
typedef int (*FUNC_RETURNS_INT_TYPE)();
32+
FUNC_RETURNS_INT_TYPE func = (FUNC_RETURNS_INT_TYPE) library.resolve("this_function_returns_42");
33+
if (!func)
34+
{
35+
std::cerr << "Failed to resolve symbol 'this_function_returns_42'" << std::endl;
36+
return EXIT_FAILURE;
37+
}
38+
int result = func();
39+
int expected = 42;
40+
if (result != expected)
41+
{
42+
std::cerr << "Problem with function 'this_function_returns_42':\n"
43+
<< "\tresult: " << result << "\n"
44+
<< "\texpected: " << expected
45+
<< std::endl;
46+
return EXIT_FAILURE;
47+
}
48+
return EXIT_SUCCESS;
49+
}
50+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
3+
#include "PythonQt.h"
4+
5+
#ifdef Q_OS_WIN
6+
#define MY_EXPORT __declspec(dllexport)
7+
#else
8+
#define MY_EXPORT
9+
#endif
10+
11+
extern "C"
12+
{
13+
14+
int MY_EXPORT this_function_returns_42()
15+
{
16+
return 42;
17+
}
18+
19+
}
20+
21+
struct StaticInitializer
22+
{
23+
StaticInitializer()
24+
{
25+
std::cout << "PythonQtDynamicLoaderSharedLibrary::StaticInitializer" << std::endl;
26+
PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);
27+
}
28+
};
29+
30+
31+
StaticInitializer staticInitializer;
32+

0 commit comments

Comments
 (0)