diff --git a/tests/slic3rutils/CMakeLists.txt b/tests/slic3rutils/CMakeLists.txt index a055d9d937..20c317cb0e 100644 --- a/tests/slic3rutils/CMakeLists.txt +++ b/tests/slic3rutils/CMakeLists.txt @@ -30,6 +30,19 @@ if (WIN32) COMMENT "Copying Python runtime for slic3rutils plugin host API tests" VERBATIM ) +elseif (APPLE) + target_link_options(${_TEST_NAME}_tests PRIVATE + "LINKER:-rpath,@executable_path/python/lib") + + add_custom_command(TARGET ${_TEST_NAME}_tests POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rm -rf + "$/python" + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_PREFIX_PATH}/libpython" + "$/python" + COMMENT "Copying Python runtime for macOS plugin host API tests" + VERBATIM + ) endif() orcaslicer_discover_tests(${_TEST_NAME}_tests) diff --git a/tests/slic3rutils/python_test_support.hpp b/tests/slic3rutils/python_test_support.hpp index 1920b2ce2a..ab66f05887 100644 --- a/tests/slic3rutils/python_test_support.hpp +++ b/tests/slic3rutils/python_test_support.hpp @@ -2,7 +2,10 @@ // Shared embedded-interpreter bootstrap for slic3rutils tests that need a live Python // interpreter (test_plugin_host_api.cpp, test_slicing_pipeline_bindings.cpp, ...). - +#include +#include +#include +#include #include #include @@ -12,17 +15,29 @@ namespace { void ensure_python_initialized() { - // Deliberately a bare scoped_interpreter rather than Slic3r::PythonInterpreter: - // `orca` is a PYBIND11_EMBEDDED_MODULE compiled into this test binary, so importing - // it needs no bundled stdlib/sys.path, and the deterministic assertions are - // independent of the host's Python. PythonInterpreter::initialize() expects the - // bundled Python home laid out next to the app bundle (lib/python3.12/encodings), - // which is not deployed beside the test binary, so using it here would fail to find - // a home on macOS/Linux. The optional numpy-backed assertions are guarded at runtime. - if (!Py_IsInitialized()) { - static pybind11::scoped_interpreter interpreter; - (void) interpreter; + if (Py_IsInitialized()) + return; + + static std::unique_ptr interpreter; + + PyConfig config; + PyConfig_InitPythonConfig(&config); + config.parse_argv = 0; + + const auto python_home = boost::dll::program_location().parent_path() / "python"; + + if (boost::filesystem::exists(python_home)) { + const std::string home = python_home.string(); + const PyStatus status = PyConfig_SetBytesString(&config, &config.home, home.c_str()); + + if (PyStatus_Exception(status)) { + const char* message = status.err_msg ? status.err_msg : "Failed to set Python home"; + PyConfig_Clear(&config); + throw std::runtime_error(message); + } } + + interpreter = std::make_unique(&config); } pybind11::module_ import_orca_module()