-
-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrect copied shared library name in filesystem relative resource policy #284
Comments
A similar issue occurs when trying to install Likewise, fixing the output directory layout to match the wheel (and also adding |
This seems like a legitimate bug report. Thank you for filing. Would you be willing to try reproducing this using the latest code in the I'm making a hard push in 0.8 for better compatibility with extension modules. And I'm very interest in fixing problems like this. |
I tried with main but was hitting #254 and haven't used the workaround there yet. I'll have another look later. Should you want to try also: the numpy example is pretty easy to replicate, just create a new config project and change those two lines. When running the executable in |
I've made a lot of progress towards better support for extension modules and shared library dependencies in the past few weeks. However, numpy is special and triggers a currently unhandled corner case. What's happening is that numpy installs some shared libraries in unconventional locations on the filesystem. This confuses PyOxidizer's parser for discovering resources. In some cases, numpy's shared libraries are improperly being detected as Python extension modules. In other cases, they aren't being detected at all because they are inside a While this is a corner case, the expectation is for PyOxidizer to just work. So I'll need to teach PyOxidizer to handle this scenario. This will require:
Please let me know the current state of matters with the latest commit in the |
Ok, excellent. I couldn't get main to work for other reasons when I tried last time, but I'm probably missing something obvious and will try again. PySide2 was the other example you can look at to see if they're doing anything in common with numpy. |
PyOxidizer 0.9 has a new files mode which can be leveraged to enable PyOxidizer to work with complex packages like NumPy. See https://pyoxidizer.readthedocs.io/en/v0.9.0/packaging_additional_files.html#installing-unclassified-files-on-the-filesystem for an example of how to get NumPy working with PyOxidizer. |
Would the new "files mode" help fix the issue @aaliddell had with PySide2? |
I can now get numpy and PySide2 to work on 0.10.3, after following similar steps to what's in that guide. With regard to resolving the classification failure: am I correct in believing that from Python's perspective, a .so file can be either a python extension or just a normal shared library?
As a quick check, I tried the following with the numpy files:
Another observation is that python extension shared libraries don't follow the
Other heuristics could be the presence of extra Obviously if symbol scanning is fast enough, you wouldn't bother with these heuristics and instead just always scan a .so file. |
Here's an example of some code that attempts to classify the .so files based on the presence of the relevant import pathlib
import elftools
def is_python_extension(file_path):
# Get init hook symbol name, as per https://www.python.org/dev/peps/pep-0489/#export-hook-name
expected_modulename = pathlib.Path(file_path).name.partition('.')[0]
if expected_modulename.isascii():
expected_symbol_name = 'PyInit_' + expected_modulename
else:
expected_symbol_name = 'PyInitU_' + expected_modulename.encode('punycode').replace(b'-', b'_').decode('ascii')
# Search for symbol in dynamic segment
is_python_ext = False
with file_path.open('rb') as f:
ef = elftools.elf.elffile.ELFFile(f)
for seg in ef.iter_segments():
if isinstance(seg, elftools.elf.dynamic.DynamicSegment):
for sym in seg.iter_symbols():
if sym.name == expected_symbol_name:
is_python_ext = True
break
# Don't bother scanning any more segments if we've already found PyInit
if is_python_ext:
break
return is_python_ext Running this against the .so files from numpy, gets:
This appears to be classifying correctly in this particular case and I have also checked against PySide2/shiboken2. It is not particularly fast, but it's not attempting to use any of the above heuristics and is only in Python. I unfortunately don't know enough Rust to be helpful with a PR 😕 I may also have completely missed the point here 🙄 |
Thank you for all the investigations here. If PyOxidizer moves forward with extension module file detection, the code will be implemented in pure Rust using a symbol name sniffing strategy similar to what people in this issue have implemented. |
When trying to use 0.7.0 to build a basic app with only numpy added, the new
prefer-in-memory-fallback-filesystem-relative
resource policy can be used. This almost works, but one of the shared libraries is copied into the incorrect location in the specified folder.The
pyoxidizer.bzl
file is effectively the default generated file from the getting started guide, but with the following lines:resources_policy='prefer-in-memory-fallback-filesystem-relative:lib',
exe.add_filesystem_relative_python_resources('lib', dist.pip_install(['numpy']))
When running the binary, then doing
import numpy
, the following (trimmed) error occurs:Original error was: libopenblasp-r0-ae94cfde.3.9.dev.so: cannot open shared object file: No such file or directory
When looking at the file tree alongside the binary, there is the file at
build/x86_64-unknown-linux-gnu/debug/install/lib/numpy/libs/libopenblasp-r0-ae94cfde/3/9/dev.so
, which should instead be atbuild/x86_64-unknown-linux-gnu/debug/install/lib/numpy.libs/libopenblasp-r0-ae94cfde.3.9.dev.so
It appears
.
in the file name (libopenblasp-r0-ae94cfde.3.9.dev.so
) and folder name (numpy.libs
) have been converted to/
. If you look in the numpy wheel, you can see the expected file tree structure. Having a vague dig through the PyOxidizer code, I can't see why this one file is getting mis-copied, particularly when there are three other shared libraries in that folder which are copied correctly. The only difference is the order of the version numbers around the.so
. Is the shared lib path perhaps getting interpretted as a python module name?If I manually move that file to the
numpy.libs
folder, numpy now imports correctly and works for the few things I've tested. If this can be resolved, numpy will effectively work out-of-the-box and resolve #65 .The text was updated successfully, but these errors were encountered: