arvidn / libtorrent

an efficient feature complete C++ bittorrent implementation
http://libtorrent.org
Other
5.21k stars 993 forks source link

Python binding fails to build: can't create dynamic relocation R_X86_64_32 against local symbol in readonly segment #6890

Closed yurivict closed 1 year ago

yurivict commented 2 years ago
d: error: can't create dynamic relocation R_X86_64_32 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in ../../deps/try_signal/bin/clang-linux-12/release/address-model-64/cxxstd-14-iso/link-static/threading-multi/visibility-hidden/libtry_signal.a(signal_error_code.o)
>>> referenced by signal_error_code.cpp
>>>               signal_error_code.o:(sig::errors::make_error_code(sig::errors::error_code_enum)) in archive ../../deps/try_signal/bin/clang-linux-12/release/address-model-64/cxxstd-14-iso/link-static/threading-multi/visibility-hidden/libtry_signal.a

Revision: 2.0.6-27-g34c75eb5f clang-13.3 FreeBSD 13.1

userdocs commented 2 years ago

I think this is the problem.

recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output

https://www.libtorrent.org/building.html#build-features

With b2 you would use fpic=on when compiling libtorrent.

yurivict commented 2 years ago

Shouldn't this be a default in the project?

userdocs commented 2 years ago

I don't know about that that but if you used the flag when building it's in the build path like /cxxstd-14-iso/fpic/link-static/

Try it and see if it works.

yurivict commented 2 years ago

With b2 you would use fpic=on when compiling libtorrent.

I use setup.py to build, How do I pass fpic=on to setup.py? Both --b2-args fpic=on and --b2-args=fpic=on as suggested in setup.py don't work.

userdocs commented 2 years ago

According to the docs here https://www.libtorrent.org/python_binding.html

I think it's like this, maybe @AllSeeingEyeTolledEweSew can confirm, since I only build it using b2

python setup.py build_ext --b2-args="fpic=on"

yurivict commented 2 years ago

Adding fpic=on like is described above doesn't solve the problem. b2 fails the same way with this argument.

yurivict commented 2 years ago
ld: error: relocation R_X86_64_PC32 cannot be used against symbol __stack_chk_guard; recompile with -fPIC
>>> defined in /lib/libc.so.7
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::index(boost::python::api::object const&) const) in archive /usr/local/lib/libboost_python38.a

ld: error: can't create dynamic relocation R_X86_64_32S against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in /usr/local/lib/libboost_python38.a(list.o)
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::index(boost::python::api::object const&) const) in archive /usr/local/lib/libboost_python38.a

ld: error: relocation R_X86_64_PC32 cannot be used against symbol __stack_chk_guard; recompile with -fPIC
>>> defined in /lib/libc.so.7
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::index(boost::python::api::object const&) const) in archive /usr/local/lib/libboost_python38.a

ld: error: relocation R_X86_64_PC32 cannot be used against symbol __stack_chk_guard; recompile with -fPIC
>>> defined in /lib/libc.so.7
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::insert(long, boost::python::api::object const&)) in archive /usr/local/lib/libboost_python38.a

ld: error: can't create dynamic relocation R_X86_64_32S against symbol: PyList_Type in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/session.o
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::insert(long, boost::python::api::object const&)) in archive /usr/local/lib/libboost_python38.a

ld: error: can't create dynamic relocation R_X86_64_32S against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in /usr/local/lib/libboost_python38.a(list.o)
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::insert(long, boost::python::api::object const&)) in archive /usr/local/lib/libboost_python38.a

ld: error: can't create dynamic relocation R_X86_64_32 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in /usr/local/lib/libboost_python38.a(list.o)
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::insert(long, boost::python::api::object const&)) in archive /usr/local/lib/libboost_python38.a

ld: error: relocation R_X86_64_PC32 cannot be used against symbol __stack_chk_guard; recompile with -fPIC
>>> defined in /lib/libc.so.7
>>> referenced by list.cpp
>>>               list.o:(boost::python::detail::list_base::insert(long, boost::python::api::object const&)) in archive /usr/local/lib/libboost_python38.a

ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

    "clang++"  -o "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/libtorrent.cpython-38.so"  -Wl,-soname -Wl,libtorrent.cpython-38.so -shared -Wl,--start-group "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/module.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/sha1_hash.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/sha256_hash.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/info_hash.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/converters.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/create_torrent.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/fingerprint.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/utility.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/session.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/entry.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/torrent_info.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/string.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/torrent_handle.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/torrent_status.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/session_settings.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/version.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/alert.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/datetime.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/peer_info.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/ip_filter.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/magnet_uri.o" "bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/src/error_code.o" "../../bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/link-static/threading-multi/visibility-hidden/libtorrent-rasterbar.a" "../../deps/try_signal/bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/link-static/threading-multi/visibility-hidden/libtry_signal.a"  -Wl,-Bstatic -lboost_python38 -lboost_system -lssl -lcrypto -Wl,-Bdynamic -lpthread -lssl -lcrypto -Wl,--end-group -fPIC -std=c++14  /usr/local/lib/libboost_python38.so /usr/local/lib/libiconv.so -fstack-protector-strong -L/usr/local/lib 

...failed clang-linux.link.dll bin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8/libtorrent.cpython-38.so...
...skipped <p/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8>libtorrent.cpython-38.so for lack of <pbin/clang-linux-13/release/address-model-64/cxxstd-14-iso/fpic-on/python-3.8>libtorrent.cpython-38.so...
...failed updating 1 target...
...skipped 1 target...
...updated 222 targets...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "setup.py", line 449, in <module>
    setuptools.setup(
  File "/usr/local/lib/python3.8/site-packages/setuptools/__init__.py", line 153, in setup
    return distutils.core.setup(**attrs)
  File "/usr/local/lib/python3.8/distutils/core.py", line 148, in setup
    dist.run_commands()
  File "/usr/local/lib/python3.8/distutils/dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "/usr/local/lib/python3.8/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "setup.py", line 328, in run
    self._build_extension_with_b2()
  File "setup.py", line 347, in _build_extension_with_b2
    subprocess.run(command, cwd=python_binding_dir, check=True)
  File "/usr/local/lib/python3.8/subprocess.py", line 516, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['b2', 'fpic=on', 'boost-link=static', 'libtorrent-link=static', 'crypto=openssl', 'deprecated-functions=on', 'variant=release', 'address-model=64', 'python=3.8', 'libtorrent-python=on', 'python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8', 'install_module', '--project-config=/tmp/tmpdfp_8ze0']' returned non-zero exit status 1.
*** Error code 1
AllSeeingEyeTolledEweSew commented 2 years ago

arvid added the feature libtorrent-python-pic in bindings/python/Jamfile, presumably so that the python bindings and the main library can be built with independent choices of -fPIC.

It conditionally defaults on:

https://github.com/arvidn/libtorrent/blob/34c75eb5f3e68896532838b9d408ccdc11b900ef/bindings/python/Jamfile#L157-L162

If the defaults aren't working on FreeBSD, I believe this block should probably be updated. @arvidn?

In the meantime, try

python setup.py build_ext --b2-args=libtorrent-python-pic=on
yurivict commented 2 years ago

Same with libtorrent-python-pic=on.

arvidn commented 2 years ago

there's already a fpic=on build feature.

python setup.py build_ext --b2-args=fpic=on
yurivict commented 2 years ago

there's already a fpic=on build feature.

But it doesn't solve the problem.

AllSeeingEyeTolledEweSew commented 2 years ago

Same with libtorrent-python-pic=on.

libtorrent-python-pic=on isn't producing -fPIC? That's surprising; it's a very straightforward application in the Jamfile. Could you add some more b2 debug flags to --b2-args, to verify the compilation command being produced? I'm not sure which are needed.

userdocs commented 2 years ago

If the Op has already built libtorrent.so and installed it to a system path will it need to be rebuilt with fpic for this to work when creating the binding?

Or will that lib have no effect on the outcome of the binding?

I'm not sure how the python build works to be honest and I only build it using b2 + boost source in docker and using fpic just works.

yurivict commented 2 years ago

If the Op has already built libtorrent.so and installed it to a system path will it need to be rebuilt with fpic for this to work when creating the binding?

Shared libraries can only be built with fpic option.

userdocs commented 2 years ago

Then maybe do this and use the debug to see if there is more helpful info?

Same with libtorrent-python-pic=on.

libtorrent-python-pic=on isn't producing -fPIC? That's surprising; it's a very straightforward application in the Jamfile. Could you add some more b2 debug flags to --b2-args, to verify the compilation command being produced? I'm not sure which are needed.

I think using b2 will work

https://www.mankier.com/1/b2

-dx
Set the debug level to x (0-9)

To be honest I can't test anything on that OS as i only used Debian based or Alpine.

arvidn commented 2 years ago

passing -n to b2 will make it print the command lines. Although, it should be printing the command lines that fail already.

AllSeeingEyeTolledEweSew commented 2 years ago

The link command is what's failing, but we need to know what's passed to clang. It should be passing -fPIC but isn't.

(or something else is going on, like build artifacts are staying around when they should be rebuilt)

yurivict commented 2 years ago

Here is a log with -n.

arvidn commented 2 years ago

the command line I see in that log does not have -n in it:

b2 fpic=on boost-link=static libtorrent-link=static crypto=openssl deprecated-functions=on variant=release address-model=64 python=3.8 libtorrent-python=on python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8 install_module --project-config=/tmp/tmphtrr1cxx
yurivict commented 2 years ago

Sorry, this was due to a typo. I updated the file.

arvidn commented 2 years ago

it looks like the extension is built twice:

The first time:

b2 fpic=on -n boost-link=static libtorrent-link=static crypto=openssl deprecated-functions=on variant=release address-model=64 python=3.8 libtorrent-python=on python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8 install_module --project-config=/tmp/tmpmpdrl48c

That does the tight thing. In fact -fPIC is mentioned twice on the command line because boost-build knows to add it as well as the fpic=on feature.

However, that invocation won't produce a binary, it just prints the command lines that would have run.

The second time:

b2 boost-link=static libtorrent-link=static crypto=openssl deprecated-functions=on variant=release address-model=64 python=3.8 libtorrent-python=on python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8 install_module --project-config=/tmp/tmp84e5zdkr

This is the one that fails. Note how it does not have -n nor fpic=on. The reason boost-build doesn't add -fPIC is because it's linked statically, so those static libraries need to know that they are linked into a shared library when they are built, and apparently they don't (or the python extension rule in boost-build doesn't indicate to dependencies that it's a shared library).

Where does this second invocation come from?

perhaps the python stack trace at the bottom is a clue:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "setup.py", line 449, in <module>
    setuptools.setup(
  File "/usr/local/lib/python3.8/site-packages/setuptools/__init__.py", line 153, in setup
    return distutils.core.setup(**attrs)
  File "/usr/local/lib/python3.8/distutils/core.py", line 148, in setup
    dist.run_commands()
  File "/usr/local/lib/python3.8/distutils/dist.py", line 966, in run_commands
    self.run_command(cmd)
  File "/usr/local/lib/python3.8/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "/usr/local/lib/python3.8/site-packages/setuptools/command/install.py", line 61, in run
    return orig.install.run(self)
  File "/usr/local/lib/python3.8/distutils/command/install.py", line 545, in run
    self.run_command('build')
  File "/usr/local/lib/python3.8/distutils/cmd.py", line 313, in run_command
    self.distribution.run_command(command)
  File "/usr/local/lib/python3.8/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "/usr/local/lib/python3.8/distutils/command/build.py", line 135, in run
    self.run_command(cmd_name)
  File "/usr/local/lib/python3.8/distutils/cmd.py", line 313, in run_command
    self.distribution.run_command(command)
  File "/usr/local/lib/python3.8/distutils/dist.py", line 985, in run_command
    cmd_obj.run()
  File "setup.py", line 328, in run
    self._build_extension_with_b2()
  File "setup.py", line 347, in _build_extension_with_b2
    subprocess.run(command, cwd=python_binding_dir, check=True)
  File "/usr/local/lib/python3.8/subprocess.py", line 516, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['b2', 'boost-link=static', 'libtorrent-link=static', 'crypto=openssl', 'deprecated-functions=on', 'variant=release', 'address-model=64', 'python=3.8', 'libtorrent-python=on', 'python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8', 'install_module', '--project-config=/tmp/tmp84e5zdkr']' returned non-zero exit status 1.
*** Error code 1
mexicarne commented 2 years ago

Hello, are there any news on setup.py build?

yozart commented 1 year ago

No fix since the 28th of May ? what shall we do to install Deluge then ?

yurivict commented 1 year ago

For Python bindings pybind11 is really great.

Yesterday I created a binding for an unrelated project and it was a breeze. It only requires 1 C++ source file and 1 cmake script.

Why can't this project use pybind11?

AllSeeingEyeTolledEweSew commented 1 year ago

Here is a log with -n.

I'm not sure what the underlying script is doing, but it looks like it's invoking setup.py twice: once with --b2-args=fpic=on and once without.

...
===>  Building for py38-libtorrent-rasterbar-2.0.6.27,1
running build_ext
b2 fpic=on -n boost-link=static libtorrent-link=static crypto=openssl deprecated-functions=on variant=release address-model=64 python=3.8 libtorrent-python=on python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8 install_module --project-config=/tmp/tmpmpdrl48c
...
===>   Generating temporary packing list
running install
running build
running build_ext
...
b2 boost-link=static libtorrent-link=static crypto=openssl deprecated-functions=on variant=release address-model=64 python=3.8 libtorrent-python=on python-install-path=/disk-samsung/freebsd-ports/net-p2p/py-libtorrent-rasterbar/work-py38/libtorrent-2.0.6-27-g34c75eb5f/bindings/python/build/lib.freebsd-13.1-STABLE-amd64-3.8 install_module --project-config=/tmp/tmp84e5zdkr

Looks like it may be doing setup.py build_ext --b2-args=... followed by setup.py install (which implicitly invokes build_ext again)

It's important to note that b2 has some impedence mismatch with distutils/setuptools. Normally build_ext --some-args is assumed to build artifacts with the given args, then a later build_ext recognizes the built artifacts, and does nothing. But b2 always checks that artifacts match its given args. If you want a second run of b2 to be a no-op, you need to run it with the same args you used previously.

TL;DR I think the script should be doing setup.py build_ext --b2-args=fpic=on setup.py build_ext --b2-args=fpic=on install (or just the second one)

Since this looks like a distro build script though, you might also want to build the python bindings with dynamic linking. By default, they statically link libtorrent.

You'd need something like: setup.py build_ext --b2-args="fpic=on libtorrent-link=shared boost-link=shared" install

For Python bindings pybind11 is really great.

Yesterday I created a binding for an unrelated project and it was a breeze. It only requires 1 C++ source file and 1 cmake script.

Why can't this project use pybind11?

I haven't used pybind11, but I've looked at it, and I like it MUCH more than boost.python. It's on my long-term list to convert the python bindings to pybind11. But libtorrent's API surface is huge (much more than "only 1 source file"), and we really need to backport our test suite from master before making a big shift like this, to make sure the API stays stable. This backport is next on my list.

This issue isn't about boost.python though. It's about the build system. Arvid supports b2 as the primary build system of libtorrent, for better or worse.

AllSeeingEyeTolledEweSew commented 1 year ago

@arvidn fpic=on still shouldn't be required here, right? I think the fpic feature logic in Jamfile is only effective for gcc today, should it cover clang too?

AllSeeingEyeTolledEweSew commented 1 year ago

@yurivict

or maybe you want setup.py build_ext --b2-args="fpic=on libtorrent-link=prebuilt boost-link=default depending on the build environment

yozart commented 1 year ago

It's beyond my knowledges and understanding here. I tried the setup.py b2 commands but ... If anyone can help me to complete the script I made in following topic I would be very thankfull !

https://www.truenas.com/community/threads/issues-with-deluge-on-truenas-12-u2.92105/post-720208

AllSeeingEyeTolledEweSew commented 1 year ago

@yozart I tried sorting through those scripts but it's a bunch of freebsd-specific stuff, some of it declarative. I don't know anything about freebsd. Can you point me to the thing that tries to build libtorrent?

sporkman commented 1 year ago

@AllSeeingEyeTolledEweSew - TL;DR is that the key is downgrading the "py39-libtorrent-rasterbar" package/port to an older version pre-dating this bug (version 1.2.16). This was enough for me to get deluge working.

If anyone working on this from the project needs a) a FreeBSD VM and b) a quick conversation to get the basics of the FreeBSD ports/packages systems down I can provide that.

bergman commented 1 year ago

I have been working on this a bit on the FreeBSD ports side and got things to build and run at least but it is a bit hacky since I am not proficient at writing ports or configuring boost/Jamfile things. I would gladly take any help on this.

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=264970 (patch also updates deluge but you can ignore that part)

Direct link to diff/patch in question (up to date as of right now but may break if/when further patches are pushed) https://bugs.freebsd.org/bugzilla/attachment.cgi?id=238177&action=diff

The problems I couldn't really solve in a nice way:

  1. The python bindings were trying to find a file named libtorrent-rasterbar.so.10.0.0 but in the default build it seems to be named libtorrent-rasterbar.so.1.2.18 (with a symlink libtorrent-rasterbar.so.10 pointing to it) so I had to construct an additional symlink in the last stages of the build. It would be nice if this could be configured to either create the symlink through the Jamfile or to have the python binding look for one of the existing names.

  2. The python binding seems to go in a subdirectory in site-packages which seems to not be supported out of the box with FreeBSD ports system python utils. I am not sure which way is more correct in python/general but in ports I had to disable the automatic file detection and explicitly add ${PYTHON_SITELIBDIR}/${PYDISTUTILS_PKGNAME}/__init__${PYTHON_EXT_SUFFIX}.so. The old way of keeping the .so file right in the site-packages directory seemed to work automatically.

Thanks to everyone in the thread for pointers and especially @AllSeeingEyeTolledEweSew for your comment, that helped a lot https://github.com/arvidn/libtorrent/issues/6890#issuecomment-1281460362 👍

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.