libcalamares: create Python module libcalamares by hand

From inside Calamares, register libcalamares to the
interpreter by hand; from external Python processes
the regular extension library hooks are called.

Tested by running ./build/localmodule dummypython
(which means that the shared library is not present
in the current directory, so then `import libcalamares`
fails if the module is not already registered --
a test scenario that previous attempt at module
import missed).
This commit is contained in:
Adriaan de Groot 2023-11-07 21:33:18 +01:00
parent a629e2650a
commit 1051033324

View File

@ -22,6 +22,9 @@
namespace py = pybind11; namespace py = pybind11;
// Forward-declare function generated by PYBIND11_MODULE
static void pybind11_init_libcalamares( ::pybind11::module_& variable );
namespace namespace
{ {
@ -242,7 +245,38 @@ Job::exec()
// Import, but do not keep the handle lying around // Import, but do not keep the handle lying around
try try
{ {
auto calamaresModule = py::module_::import( "libcalamares" ); // import() only works if the library can be found through
// normal Python import mechanisms -- and after installation,
// libcalamares can not be found. An alternative, like using
// PYBIND11_EMBEDDED_MODULE, falls foul of not being able
// to `import libcalamares` from external Python scripts,
// which are used in tests.
//
// auto calamaresModule = py::module_::import( "libcalamares" );
//
// Using the constructor directly generates compiler warnings
// because this is deprecated.
//
// auto calamaresModule = py::module_("libcalamares");
//
// So create it by hand, using code cribbed from pybind11/embed.h
// to register an extension module. This does not make it
// available to the current interpreter.
//
static ::pybind11::module_::module_def libcalamares_def;
auto calamaresModule = py::module_::create_extension_module( "libcalamares", nullptr, &libcalamares_def );
pybind11_init_libcalamares( calamaresModule );
// Add libcalamares to the main namespace (as if it has already
// been imported) and also to sys.modules under its own name.
// Now `import libcalamares` in modules will find the already-
// loaded module.
auto scope = py::module_::import( "__main__" ).attr( "__dict__" );
scope["libcalamares"] = calamaresModule;
auto sys = scope["sys"].attr("modules");
sys["libcalamares"] = calamaresModule;
calamaresModule.attr( "job" ) = Calamares::Python::JobProxy( this ); calamaresModule.attr( "job" ) = Calamares::Python::JobProxy( this );
calamaresModule.attr( "globalstorage" ) calamaresModule.attr( "globalstorage" )
= Calamares::Python::GlobalStorageProxy( JobQueue::instance()->globalStorage() ); = Calamares::Python::GlobalStorageProxy( JobQueue::instance()->globalStorage() );