You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The implementation for Runtime.InitializePlatformData just have some limitations.
The platform.py would import subprocess, but not all release binaries have it.
Need a another genernal way to get the architecture type.
defarchitecture(executable=sys.executable, bits='', linkage=''):
""" Queries the given executable (defaults to the Python interpreter binary) for various architecture information. Returns a tuple (bits, linkage) which contains information about the bit architecture and the linkage format used for the executable. Both values are returned as strings. Values that cannot be determined are returned as given by the parameter presets. If bits is given as '', the sizeof(pointer) (or sizeof(long) on Python version < 1.5.2) is used as indicator for the supported pointer size. The function relies on the system's "file" command to do the actual work. This is available on most if not all Unix platforms. On some non-Unix platforms where the "file" command does not exist and the executable is set to the Python interpreter binary defaults from _default_architecture are used. """# Use the sizeof(pointer) as default number of bits if nothing# else is given as default.ifnotbits:
importstructsize=struct.calcsize('P')
bits=str(size*8) +'bit'# Get data from the 'file' system commandifexecutable:
fileout=_syscmd_file(executable, '')
else:
fileout=''ifnotfileoutand \
executable==sys.executable:
# "file" command did not return anything; we'll try to provide# some sensible defaults then...ifsys.platformin_default_architecture:
b, l=_default_architecture[sys.platform]
ifb:
bits=bifl:
linkage=lreturnbits, linkageif'executable'notinfileoutand'shared object'notinfileout:
# Format not supportedreturnbits, linkage# Bitsif'32-bit'infileout:
bits='32bit'elif'N32'infileout:
# On Irix onlybits='n32bit'elif'64-bit'infileout:
bits='64bit'# Linkageif'ELF'infileout:
linkage='ELF'elif'PE'infileout:
# E.g. Windows uses this formatif'Windows'infileout:
linkage='WindowsPE'else:
linkage='PE'elif'COFF'infileout:
linkage='COFF'elif'MS-DOS'infileout:
linkage='MSDOS'else:
# XXX the A.OUT format also falls under this class...passreturnbits, linkage
See #897, if we drop support for .NET<4.7.1 we can use the respective .NET standard functions for this, which means we wouldn't even need to have Python loaded already to do the right thing. This would also be beneficial to @lostmsu's idea to use GetProcAddress instead of P/Invoke to get the API functions.
For Python3.8, this issue seems to be a blocker for embedding in dotnetcore on Linux. The import _posixsubprocess that InitializePlatformData causes fails with this kind of error:
because the code in runtime.cs that loads the Python shared object library (which would prevent this error) requires InitializePlatformData to set OperatingSystem.
InitializePlatformData();
IntPtr dllLocal = IntPtr.Zero;
var loader = LibraryLoader.Get(OperatingSystem);
The change in Python3.8 to start using the subprocess module was a breaking change for this pythonnet code.
@Jeff17RobbinsRuntime.InitializePlatformData can be remove in the future.
But your error is wired, why it tried to get PyTuple_Type from _posixsubprocess.so.
I'm further assuming that since [DllImport] does NOT use the RTLD_GLOBAL flag on its dlopen() call, that the Linux loader can't resolve PyTuple_Type from the already loaded python .so?
I'm also assuming that this lack of RTLD_GLOBAL is why pythonnet goes to all this trouble to load
python explicitly in the first place?
InitializePlatformData();
IntPtr dllLocal = IntPtr.Zero;
var loader = LibraryLoader.Get(OperatingSystem);
if (_PythonDll != "__Internal")
{
dllLocal = loader.Load(_PythonDll);
}
But I don't know the history of the project, and don't know specifically why we need this loader.Load(_PythonDll) other than my assumption about the lack of RTLD_GLOBAL in the implementation of [DllImport].
I would appreciate any info anyone has as to the rationale for all this startup code, or a pointer to any work going on to simplify it, at least for the dotnet core 3.x case.
The symbol should in python's ELF or .so, _posixsubprocess.so just import from python runtime, so the symbol should be find.
You can use ldd to check is all the dependencies exist. Or you can try add the python's parent directory into LD_LIBRARY_PATH and run again.
The loader code you specified can be remove, see #880
I apologize in advance for being a somewhat ignorant newbie wrt Linux. But the scenario I am testing, I am embedding C Python into a dotnet core 3 C# app using pythonnet.
pythonnet uses [DllImport] in runtime.cs to bootstrap loading libpython3.8.so so it can call, e.g., Py_InitializeEx.
nm -D libpython3.8.so does indeed show that the python runtime symbols are exported, e.g.
0000000000353b20 D PyTuple_Type
But since [DllImport] does NOT set the RTLD_GLOBAL flag when it loads libpython3.8.so, my understanding is that subsequently loaded shared objects, like the C extension that subprocess.py imports (_posixsubprocess.cpython-38-x86_64-linux-gnu.so), those shared object libraries do not "see" the symbols from libpython3.8.so.
When I run ldd -d on _posixsubprocess...so I don't see it showing its dependence on libpython. But of course a builtin Python C extension (ships with Python) presumably "knows" what it is doing, or at least has an expectation that the "parent" libpython3.8.so is loaded.
And I assume that this expectation includes being loaded with the aforementioned RTLD_GLOBAL flag?
Or why is pythonnet taking all this trouble to explicitly load libpython3.8.so in the first place?
On some Linux distributions, notably Debian, the .so files of CPython C extension modules may be compiled without saying that they depend on libpythonX.Y.so. This makes such Python systems unsuitable for embedding if the embedder uses dlopen(..., RTLD_LOCAL). You get an undefined symbol error. See issue #264. A workaround is to first call dlopen("libpythonX.Y.so", RTLD_LAZY|RTLD_GLOBAL), which will force libpythonX.Y.so to be loaded first.
Activity
amos402 commentedon Jun 21, 2019
cpython3.7.1


@benoithudson
_posixsubprocessorselectare not the essential components for python corebenoithudson commentedon Jun 21, 2019
I import platform for two pieces of info.
Py_GetPlatform() gives the OS type. We should probably use that.
I didn't see a C API for the architecture; do you know of one?
amos402 commentedon Jun 22, 2019
Me too, it may also not provided by any c# runtimes.
If there is no general API to do that, we can only use a native API by per system......
Cronan commentedon Jun 26, 2019
Architecture does this - worth replicating?
filmor commentedon Jun 26, 2019
See #897, if we drop support for .NET<4.7.1 we can use the respective .NET standard functions for this, which means we wouldn't even need to have Python loaded already to do the right thing. This would also be beneficial to @lostmsu's idea to use
GetProcAddressinstead of P/Invoke to get the API functions.Jeff17Robbins commentedon Dec 13, 2019
For Python3.8, this issue seems to be a blocker for embedding in dotnetcore on Linux. The
import _posixsubprocessthatInitializePlatformDatacauses fails with this kind of error:because the code in
runtime.csthat loads the Python shared object library (which would prevent this error) requiresInitializePlatformDatato setOperatingSystem.The change in Python3.8 to start using the
subprocessmodule was a breaking change for this pythonnet code.amos402 commentedon Dec 14, 2019
@Jeff17Robbins
Runtime.InitializePlatformDatacan be remove in the future.But your error is wired, why it tried to get
PyTuple_Typefrom_posixsubprocess.so.Jeff17Robbins commentedon Dec 14, 2019
I'm assuming because this code in
_posixsubprocess.crefers to that symbol in this code?I'm further assuming that since
[DllImport]does NOT use theRTLD_GLOBALflag on itsdlopen()call, that the Linux loader can't resolvePyTuple_Typefrom the already loaded python.so?I'm also assuming that this lack of
RTLD_GLOBALis whypythonnetgoes to all this trouble to loadpython explicitly in the first place?
But I don't know the history of the project, and don't know specifically why we need this
loader.Load(_PythonDll)other than my assumption about the lack ofRTLD_GLOBALin the implementation of[DllImport].I would appreciate any info anyone has as to the rationale for all this startup code, or a pointer to any work going on to simplify it, at least for the dotnet core 3.x case.
amos402 commentedon Dec 14, 2019
The symbol should in python's ELF or .so,
_posixsubprocess.sojust import from python runtime, so the symbol should be find.You can use
lddto check is all the dependencies exist. Or you can try add the python's parent directory intoLD_LIBRARY_PATHand run again.The loader code you specified can be remove, see #880
Jeff17Robbins commentedon Dec 14, 2019
I apologize in advance for being a somewhat ignorant newbie wrt Linux. But the scenario I am testing, I am embedding C Python into a dotnet core 3 C# app using pythonnet.
pythonnet uses
[DllImport]inruntime.csto bootstrap loadinglibpython3.8.soso it can call, e.g.,Py_InitializeEx.nm -D libpython3.8.sodoes indeed show that the python runtime symbols are exported, e.g.But since
[DllImport]does NOT set theRTLD_GLOBALflag when it loadslibpython3.8.so, my understanding is that subsequently loaded shared objects, like the C extension that subprocess.py imports (_posixsubprocess.cpython-38-x86_64-linux-gnu.so), those shared object libraries do not "see" the symbols fromlibpython3.8.so.When I run
ldd -don_posixsubprocess...soI don't see it showing its dependence on libpython. But of course a builtin Python C extension (ships with Python) presumably "knows" what it is doing, or at least has an expectation that the "parent"libpython3.8.sois loaded.And I assume that this expectation includes being loaded with the aforementioned
RTLD_GLOBALflag?Or why is pythonnet taking all this trouble to explicitly load
libpython3.8.soin the first place?[EDIT] @amos402 , why do you believe
I think this will break the embedding scenario on Linux dotnet core. Some code has to load
libpython.sowithRTLD_GLOBAL, doesn't it?Jeff17Robbins commentedon Dec 14, 2019
I've been reading more about this issue and found this bit of folklore
cffi link
This led me to an official-looking Debian statement
I don't see how to support Pythonnet Embedding on Debian unless someone calls
dlopenwith theRTLD_GLOBALflag...Jeff17Robbins commentedon Dec 14, 2019
This issue is not restricted to Pythonnet, even regular C embedding of Python on certain Linux distributions face the same
RTLD_GLOBALissue:https://bugs.python.org/issue21536#msg340817
Get platform information without import `platform`. pythonnet#891
Remove dependency on importing `platform`. pythonnet#891
lostmsu commentedon Feb 21, 2021
InitializePlatformDatais gone. To solve the problem with embedding DLL one must setRuntime.PythonDLLbefore making any other calls.