From 79d6727077c78e5f2dbb7c9dd85ccbc81ad40b6c Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 2 Feb 2025 20:11:32 +0100 Subject: [PATCH] Move MAIN_DIR initialization code from interrogate to panda3d Using the new -init flag, see panda3d/interrogate#3 --- cmake/macros/Interrogate.cmake | 8 +- dtool/Config.cmake | 2 +- dtool/src/dtoolutil/CMakeLists.txt | 2 + .../dtoolutil/p3dtoolutil_ext_composite.cxx | 1 + dtool/src/dtoolutil/pyenv_init.cxx | 80 +++++++++++++++++++ dtool/src/dtoolutil/pyenv_init.h | 14 ++++ makepanda/makepanda.py | 5 +- makepanda/makepandacore.py | 4 +- panda/CMakeLists.txt | 2 +- 9 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 dtool/src/dtoolutil/pyenv_init.cxx create mode 100644 dtool/src/dtoolutil/pyenv_init.h diff --git a/cmake/macros/Interrogate.cmake b/cmake/macros/Interrogate.cmake index 5f26cebbe9..7533be7564 100644 --- a/cmake/macros/Interrogate.cmake +++ b/cmake/macros/Interrogate.cmake @@ -283,7 +283,7 @@ endfunction(interrogate_sources) # # Function: add_python_module(module [lib1 [lib2 ...]] [LINK lib1 ...] -# [IMPORT mod1 ...]) +# [IMPORT mod1 ...] [INIT func1 ...]) # Uses interrogate to create a Python module. If the LINK keyword is specified, # the Python module is linked against the specified libraries instead of those # listed before. The IMPORT keyword makes the output module import another @@ -305,7 +305,7 @@ function(add_python_module module) set(keyword) foreach(arg ${ARGN}) - if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "COMPONENT") + if(arg STREQUAL "LINK" OR arg STREQUAL "IMPORT" OR arg STREQUAL "INIT" OR arg STREQUAL "COMPONENT") set(keyword "${arg}") elseif(keyword STREQUAL "LINK") @@ -316,6 +316,10 @@ function(add_python_module module) list(APPEND import_flags "-import" "${arg}") set(keyword) + elseif(keyword STREQUAL "INIT") + list(APPEND import_flags "-init" "${arg}") + set(keyword) + elseif(keyword STREQUAL "COMPONENT") set(component "${arg}") set(keyword) diff --git a/dtool/Config.cmake b/dtool/Config.cmake index f3063d86ad..67ea64c9ce 100644 --- a/dtool/Config.cmake +++ b/dtool/Config.cmake @@ -265,7 +265,7 @@ if(BUILD_INTERROGATE) panda3d-interrogate GIT_REPOSITORY https://github.com/panda3d/interrogate.git - GIT_TAG 03418d6d7ddda7fb99abf27230aa42d1d8bd607e + GIT_TAG d2844d994fcc465a4e22b10001d3ac5c4012b814 PREFIX ${_interrogate_dir} CMAKE_ARGS diff --git a/dtool/src/dtoolutil/CMakeLists.txt b/dtool/src/dtoolutil/CMakeLists.txt index 5885534178..fdab210e14 100644 --- a/dtool/src/dtoolutil/CMakeLists.txt +++ b/dtool/src/dtoolutil/CMakeLists.txt @@ -69,6 +69,8 @@ set(P3DTOOLUTIL_IGATEEXT globPattern_ext.h iostream_ext.cxx iostream_ext.h + pyenv_init.cxx + pyenv_init.h textEncoder_ext.cxx textEncoder_ext.h ) diff --git a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx index ceb2f01bf1..3a8de69d4d 100644 --- a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx +++ b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx @@ -1,4 +1,5 @@ #include "filename_ext.cxx" #include "globPattern_ext.cxx" #include "iostream_ext.cxx" +#include "pyenv_init.cxx" #include "textEncoder_ext.cxx" diff --git a/dtool/src/dtoolutil/pyenv_init.cxx b/dtool/src/dtoolutil/pyenv_init.cxx new file mode 100644 index 0000000000..d806a8ef7c --- /dev/null +++ b/dtool/src/dtoolutil/pyenv_init.cxx @@ -0,0 +1,80 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file pyenv_init.cxx + * @author rdb + * @date 2025-02-02 + */ + +#include "pyenv_init.h" +#include "py_panda.h" +#include "executionEnvironment.h" + +/** + * Called when panda3d.core is initialized, does some initialization specific + * to the Python environment. + */ +void +pyenv_init() { + // MAIN_DIR needs to be set very early; this seems like a convenient place + // to do that. Perhaps we'll find a better place for this in the future. + static bool initialized_main_dir = false; + if (!initialized_main_dir) { + /*if (interrogatedb_cat.is_debug()) { + // Good opportunity to print this out once, at startup. + interrogatedb_cat.debug() + << "Python " << version << "\n"; + }*/ + + if (!ExecutionEnvironment::has_environment_variable("MAIN_DIR")) { + // Grab the __main__ module and extract its __file__ attribute. + Filename main_dir; + PyObject *main_module = PyImport_ImportModule("__main__"); + PyObject *file_attr = nullptr; + if (main_module != nullptr) { + file_attr = PyObject_GetAttrString(main_module, "__file__"); + } else { + std::cerr << "Warning: unable to import __main__\n"; + } + if (file_attr == nullptr) { + // Must be running in the interactive interpreter. Use the CWD. + main_dir = ExecutionEnvironment::get_cwd(); + } else { +#if PY_MAJOR_VERSION >= 3 + Py_ssize_t length; + wchar_t *buffer = PyUnicode_AsWideCharString(file_attr, &length); + if (buffer != nullptr) { + main_dir = Filename::from_os_specific_w(std::wstring(buffer, length)); + main_dir.make_absolute(); + main_dir = main_dir.get_dirname(); + PyMem_Free(buffer); + } +#else + char *buffer; + Py_ssize_t length; + if (PyString_AsStringAndSize(file_attr, &buffer, &length) != -1) { + main_dir = Filename::from_os_specific(std::string(buffer, length)); + main_dir.make_absolute(); + main_dir = main_dir.get_dirname(); + } +#endif + else { + std::cerr << "Invalid string for __main__.__file__\n"; + } + } + ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific()); + PyErr_Clear(); + } + initialized_main_dir = true; + } + + // Also, while we are at it, initialize the thread swap hook. +#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + global_thread_state_swap = PyThreadState_Swap; +#endif +} diff --git a/dtool/src/dtoolutil/pyenv_init.h b/dtool/src/dtoolutil/pyenv_init.h new file mode 100644 index 0000000000..2369ca1871 --- /dev/null +++ b/dtool/src/dtoolutil/pyenv_init.h @@ -0,0 +1,14 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file pyenv_init.h + * @author rdb + * @date 2025-02-02 + */ + +extern "C" void pyenv_init(); diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index f04bb08f1c..3e27dd19fb 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1651,6 +1651,9 @@ def CompileImod(wobj, wsrc, opts): importmod = GetValueOption(opts, "IMPORT:") if importmod: cmd += ' -import ' + importmod + initfunc = GetValueOption(opts, "INIT:") + if initfunc: + cmd += ' -init ' + initfunc for x in wsrc: cmd += ' ' + BracketNameWithQuotes(x) oscmd(cmd) CompileCxx(wobj,woutc,opts) @@ -4168,7 +4171,7 @@ if GetTarget() != "emscripten": if PkgSkip("FREETYPE")==0: PyTargetAdd('core_module.obj', input='libp3pnmtext.in') -PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core']) +PyTargetAdd('core_module.obj', opts=['IMOD:panda3d.core', 'ILIB:core', 'INIT:pyenv_init']) PyTargetAdd('core.pyd', input='libp3dtoolbase_igate.obj') PyTargetAdd('core.pyd', input='p3dtoolbase_typeHandle_ext.obj') diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 49d2034dbd..c3c101486d 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -589,8 +589,8 @@ def GetInterrogateDir(): return INTERROGATE_DIR dir = os.path.join(GetOutputDir(), "tmp", "interrogate") - if not os.path.isdir(os.path.join(dir, "panda3d_interrogate-0.4.0.dist-info")): - oscmd("\"%s\" -m pip install --force-reinstall --upgrade -t \"%s\" panda3d-interrogate==0.4.0" % (sys.executable, dir)) + if not os.path.isdir(os.path.join(dir, "panda3d_interrogate-0.5.0.dist-info")): + oscmd("\"%s\" -m pip install --force-reinstall --upgrade -t \"%s\" panda3d-interrogate==0.5.0" % (sys.executable, dir)) INTERROGATE_DIR = dir diff --git a/panda/CMakeLists.txt b/panda/CMakeLists.txt index cb33932d9c..e118a8a5b9 100644 --- a/panda/CMakeLists.txt +++ b/panda/CMakeLists.txt @@ -107,7 +107,7 @@ if(HAVE_FREETYPE) endif() if(INTERROGATE_PYTHON_INTERFACE) - add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda) + add_python_module(panda3d.core ${CORE_MODULE_COMPONENTS} LINK panda INIT pyenv_init) # Generate our __init__.py if(WIN32)