Re: Build and run-time triplets

2022-06-09 Thread Julian Gilbey
On Thu, Jun 09, 2022 at 11:23:26AM +0500, Andrey Rahmatullin wrote:
> On Wed, Jun 08, 2022 at 10:43:57PM +0100, Julian Gilbey wrote:
> > I'd like to ask for some help.  I'm working on packaging pydevd, which
> > builds a private .so library.  Ordinary extensions built using cython
> > or similar end up being called "foo.cpython-310-x86_64-linux-gnu.so",
> > but this library, which is not dependent on the Python version, should
> > presumably be called "bar.x86_64-linux-gnu.so".
> If it's just a private library and not a Python module it should be called
> bar.so.
> 
> > Question 1: How do I determine (within Python) the triplet to use when
> > building the library?
> You don't.
> 
> > Question 2: How do I determine (within Python) the triplet to use when
> > loading the library at runtime?
> You don't, but also how are you actually loading it?

Well, the upstream wanted to compile two versions of the library, one
for 64 bit architectures and one for 32 bit architectures.  I don't
really want to build two different arch libraries in a single build,
because that seems very contrary to the way the Debian architectures
work, and would also limit it to the amd64/i386 architectures for no
obviously good reason.  I had imagined that if there is some sort of
multiarch setup, one might have the amd64 and i386 packages installed
simultaneously, hence the need for different names.  But I've never
done that myself, so I've no idea if it's even meaningful to do this.

The library is loaded into gdb using this code:

cmd.extend([
"--eval-command='call (void*)dlopen(\"%s\", 2)'" % target_dll,
"--eval-command='sharedlibrary %s'" % target_dll_name,
"--eval-command='call (int)DoAttach(%s, \"%s\", %s)'" % (
is_debug, python_code, show_debug_info)
])

where cmd is a list containing the gdb call, and target_dll and
target_dll_name point to the shared library.

Best wishes,

   Julian



Re: Build and run-time triplets

2022-06-09 Thread Andrey Rahmatullin
On Thu, Jun 09, 2022 at 08:42:28AM +0100, Julian Gilbey wrote:
> > > I'd like to ask for some help.  I'm working on packaging pydevd, which
> > > builds a private .so library.  Ordinary extensions built using cython
> > > or similar end up being called "foo.cpython-310-x86_64-linux-gnu.so",
> > > but this library, which is not dependent on the Python version, should
> > > presumably be called "bar.x86_64-linux-gnu.so".
> > If it's just a private library and not a Python module it should be called
> > bar.so.
> > 
> > > Question 1: How do I determine (within Python) the triplet to use when
> > > building the library?
> > You don't.
> > 
> > > Question 2: How do I determine (within Python) the triplet to use when
> > > loading the library at runtime?
> > You don't, but also how are you actually loading it?
> 
> Well, the upstream wanted to compile two versions of the library, one
> for 64 bit architectures and one for 32 bit architectures.  I don't
> really want to build two different arch libraries in a single build,
> because that seems very contrary to the way the Debian architectures
> work, and would also limit it to the amd64/i386 architectures for no
> obviously good reason.  I had imagined that if there is some sort of
> multiarch setup, one might have the amd64 and i386 packages installed
> simultaneously, hence the need for different names.
The normal way for this is putting it into
/usr/lib//pkgname/foo.so, and according to the code below you'll
need the full path at the run time so you indeed need the triplet at both
build and run time. You can get the triplet in d/rules, not sure how
should you pass it to the build system as that depends on the build system
used. For the run time, https://wiki.debian.org/Python/MultiArch suggests
sys.implementation._multiarch (note that you cannot use it during the
build as that would break cross-compilation etc.), not sure if there are
better ways. 

-- 
WBR, wRAR


signature.asc
Description: PGP signature


Re: Build and run-time triplets

2022-06-09 Thread Julian Gilbey
On Thu, Jun 09, 2022 at 01:03:25PM +0500, Andrey Rahmatullin wrote:
> [...]
> > Well, the upstream wanted to compile two versions of the library, one
> > for 64 bit architectures and one for 32 bit architectures.  I don't
> > really want to build two different arch libraries in a single build,
> > because that seems very contrary to the way the Debian architectures
> > work, and would also limit it to the amd64/i386 architectures for no
> > obviously good reason.  I had imagined that if there is some sort of
> > multiarch setup, one might have the amd64 and i386 packages installed
> > simultaneously, hence the need for different names.
> The normal way for this is putting it into
> /usr/lib//pkgname/foo.so, and according to the code below you'll
> need the full path at the run time so you indeed need the triplet at both
> build and run time. You can get the triplet in d/rules, not sure how
> should you pass it to the build system as that depends on the build system
> used. For the run time, https://wiki.debian.org/Python/MultiArch suggests
> sys.implementation._multiarch (note that you cannot use it during the
> build as that would break cross-compilation etc.), not sure if there are
> better ways. 

Thanks for your help!

OK (and yes, it does require the full path at runtime).  What triplet
do I use in d/rules?  dpkg-architecture offers 6 different ones:
DEB_{BUILD,HOST,TARGET}_{GNU_TYPE,MULTIARCH}?  I'm guessing
DEB_TARGET_MULTIARCH, but I'm really not certain, so it would be great
to confirm that.

About the location, though: why do compiled Python libraries live in
/usr/lib/python3/dist-packages/ and not
/usr/lib//?  And is there a good reason not to do
the same with this Python-package-specific library?  It's not for
general use, so I can't see why I shouldn't put it in the python3
directory with the other compiled Python module libraries.

Best wishes,

   Julian



Re: Build and run-time triplets

2022-06-09 Thread Simon McVittie
On Thu, 09 Jun 2022 at 13:03:25 +0500, Andrey Rahmatullin wrote:
> The normal way for this is putting it into
> /usr/lib//pkgname/foo.so, and according to the code below you'll
> need the full path at the run time so you indeed need the triplet at both
> build and run time.

You can do something like

 handle = dlopen("/usr/${LIB}/pkgname/foo.so", flags);

(that's a literal string passed to dlopen!) and ld.so/libdl will expand
${LIB} at runtime to the token that was configured into our glibc, which
in Debian's case is "lib/x86_64-linux-gnu" or similar. On non-Debian
distributions, ${LIB} typically expands to "lib64" or "lib32" or "lib"
instead, whichever one is most appropriate for the architecture and the
distro's layout.

Then you'd install the private library into what Autotools would refer to
as ${libdir}/pkgname/foo.so (adjust as necessary for other build systems)
and it will usually end up in the correct place. This assumes that
${libdir} is configured to something like
${exec_prefix}/lib/x86_64-linux-gnu or ${exec_prefix}/lib64 as appropriate
for the distribution, but that's normally true anyway, and in particular
should be true in debhelper.

Replace /usr with the ${exec_prefix} determined at compile-time if you
want to send code upstream that supports custom installation prefixes.

(Historical note: this is broken on ancient/EOL versions of Debian and
maybe some of the Extended Security Maintenance versions of Ubuntu,
where ${LIB} mistakenly expanded to the multiarch tuple without the
"lib/" prefix. Non-FHS distributions like Exherbo and NixOS might also
need to adjust it a bit, but they have to adjust everything else anyway,
so they should be used to that...)

smcv



Re: Build and run-time triplets

2022-06-09 Thread Julian Gilbey
On Thu, Jun 09, 2022 at 10:26:13AM +0100, Simon McVittie wrote:
> On Thu, 09 Jun 2022 at 13:03:25 +0500, Andrey Rahmatullin wrote:
> > The normal way for this is putting it into
> > /usr/lib//pkgname/foo.so, and according to the code below you'll
> > need the full path at the run time so you indeed need the triplet at both
> > build and run time.
> 
> You can do something like
> 
>  handle = dlopen("/usr/${LIB}/pkgname/foo.so", flags);
> [...]
> 
> Then you'd install the private library into what Autotools would refer to
> as ${libdir}/pkgname/foo.so (adjust as necessary for other build systems)
> and it will usually end up in the correct place. This assumes that
> ${libdir} is configured to something like
> ${exec_prefix}/lib/x86_64-linux-gnu or ${exec_prefix}/lib64 as appropriate
> for the distribution, but that's normally true anyway, and in particular
> should be true in debhelper.

Thanks Simon!

The build system here is the standard Python setup.py, except for this
library.  That is built by the following script:

---
g++ -m64 -shared -o attach_linux_amd64.so -fPIC -nostartfiles attach.cpp
mv attach_linux_amd64.so ../attach_linux_amd64.so
echo Compiled amd64
---

There's not even an attempt at working out ${libdir} or so on.  It
seems like overkill to set up a whole Autotools environment for this
one file :-(

I'm still unsure why I shouldn't just put it in the Python package
area near the cython files such as
/usr/lib/python3/dist-packages/_pydevd_bundle/pydevd_cython.cpython-310-x86_64-linux-gnu.so

Best wishes,

   Julian



Re: Build and run-time triplets

2022-06-09 Thread Andrey Rahmatullin
On Thu, Jun 09, 2022 at 09:56:42AM +0100, Julian Gilbey wrote:
> > [...]
> > > Well, the upstream wanted to compile two versions of the library, one
> > > for 64 bit architectures and one for 32 bit architectures.  I don't
> > > really want to build two different arch libraries in a single build,
> > > because that seems very contrary to the way the Debian architectures
> > > work, and would also limit it to the amd64/i386 architectures for no
> > > obviously good reason.  I had imagined that if there is some sort of
> > > multiarch setup, one might have the amd64 and i386 packages installed
> > > simultaneously, hence the need for different names.
> > The normal way for this is putting it into
> > /usr/lib//pkgname/foo.so, and according to the code below you'll
> > need the full path at the run time so you indeed need the triplet at both
> > build and run time. You can get the triplet in d/rules, not sure how
> > should you pass it to the build system as that depends on the build system
> > used. For the run time, https://wiki.debian.org/Python/MultiArch suggests
> > sys.implementation._multiarch (note that you cannot use it during the
> > build as that would break cross-compilation etc.), not sure if there are
> > better ways. 
> 
> Thanks for your help!
> 
> OK (and yes, it does require the full path at runtime).  What triplet
> do I use in d/rules?  dpkg-architecture offers 6 different ones:
> DEB_{BUILD,HOST,TARGET}_{GNU_TYPE,MULTIARCH}?  I'm guessing
> DEB_TARGET_MULTIARCH, but I'm really not certain, so it would be great
> to confirm that.
It's always DEB_HOST_MULTIARCH. *_TARGET_* are for Canadian cross. See
TERMS in dpkg-architecture(1).

> About the location, though: why do compiled Python libraries live in
> /usr/lib/python3/dist-packages/ and not
> /usr/lib//? 
That's where the import machinery expects them. They also have special
names.

> And is there a good reason not to do the same with this
> Python-package-specific library?
Yes, it's not Python-related.

> It's not for general use, so I can't see why I shouldn't put it in the
> python3 directory with the other compiled Python module libraries.
It's not a module.

-- 
WBR, wRAR


signature.asc
Description: PGP signature


Re: Build and run-time triplets

2022-06-09 Thread Andrey Rahmatullin
On Thu, Jun 09, 2022 at 10:43:01AM +0100, Julian Gilbey wrote:
> > > The normal way for this is putting it into
> > > /usr/lib//pkgname/foo.so, and according to the code below you'll
> > > need the full path at the run time so you indeed need the triplet at both
> > > build and run time.
> > 
> > You can do something like
> > 
> >  handle = dlopen("/usr/${LIB}/pkgname/foo.so", flags);
> > [...]
> > 
> > Then you'd install the private library into what Autotools would refer to
> > as ${libdir}/pkgname/foo.so (adjust as necessary for other build systems)
> > and it will usually end up in the correct place. This assumes that
> > ${libdir} is configured to something like
> > ${exec_prefix}/lib/x86_64-linux-gnu or ${exec_prefix}/lib64 as appropriate
> > for the distribution, but that's normally true anyway, and in particular
> > should be true in debhelper.
> 
> Thanks Simon!
> 
> The build system here is the standard Python setup.py, except for this
> library.  That is built by the following script:
> 
> ---
> g++ -m64 -shared -o attach_linux_amd64.so -fPIC -nostartfiles attach.cpp
> mv attach_linux_amd64.so ../attach_linux_amd64.so
> echo Compiled amd64
> ---
> 
> There's not even an attempt at working out ${libdir} or so on.
Sure, it's not necessary to know the installation path at the compile and
link time. It's only needed at the install time.


-- 
WBR, wRAR


signature.asc
Description: PGP signature


Re: Build and run-time triplets

2022-06-09 Thread Simon McVittie
On Thu, 09 Jun 2022 at 09:56:42 +0100, Julian Gilbey wrote:
> OK (and yes, it does require the full path at runtime).  What triplet
> do I use in d/rules?  dpkg-architecture offers 6 different ones:
> DEB_{BUILD,HOST,TARGET}_{GNU_TYPE,MULTIARCH}?  I'm guessing
> DEB_TARGET_MULTIARCH, but I'm really not certain, so it would be great
> to confirm that.

You'd want DEB_HOST_MULTIARCH here (or use ${LIB} as I mentioned in a
previous message to this thread).

DEB_BUILD_* is the architecture you are building *on*. For example,
if you cross-build ARM packages on an x86 machine, DEB_BUILD_* is x86.
Only use this rarely, for instance if you are compiling a program that
you will run during the build but not install into the package. If you
don't know that this is the correct choice then it probably isn't.

DEB_HOST_* is the architecture you will run the built code on. For example,
if you cross-build ARM packages on an x86 machine, DEB_HOST_* is ARM.
This is usually the interesting one in practice.

DEB_TARGET_* is almost never relevant: it only matters if you are
compiling a compiler.

*_MULTIARCH is the normalized multiarch tuple, for example i386-linux-gnu
on the i386 architecture.

*_GNU_TYPE is the GNU tuple to be used by Autotools build systems and
to choose a cross-compiler, for example i686-linux-gnu on the i386
architecture.

> About the location, though: why do compiled Python libraries live in
> /usr/lib/python3/dist-packages/ and not
> /usr/lib//?

The Python jargon for a native C/C++ library that can be loaded to
provide a Python module is an *extension*.

If a program will load a shared object as a plugin, then the shared object
needs to be installed into whatever directory the program has chosen as
the location where it looks for plugins, otherwise the program will not
find it: it is the program's choice, not the plugin's choice.

Python extensions are like plugins for Python, and Python has chosen
/usr/lib/python3/dist-packages as one of several locations where it looks
for extensions (specifically, extensions that come from a package other
than Python itself), so that is where you have to put them. If the extension
that implements the "foo" module is somewhere else, then Python code that
does "import foo" won't find it.

(Analogous: if a package wants to provide a plugin for GStreamer, it has
to put it in /usr/lib//gstreamer-1.0. If it puts the plugin
anywhere else, GStreamer will not find it and the plugin will be useless.)

The shared object also needs to follow the naming convention and API that
the program that will load it has chosen. The naming convention that Python
has chosen is that if you will load the module with "import foo", then
the filename is something like "foo.cpython-310-x86_64-linux-gnu.so" or
"foo.abi3.so", and it must export a symbol named "PyInit_foo" with a
particular signature.

Something that might be confusing you is that for a lot of Python modules
that are implemented in C, the thing that API users are meant to import
directly is Python code, and the Python code internally imports an
extension with a different name. For instance, to use python3-dbus,
you "import dbus", but the lower-level C code that implements that is
actually in a private extension named "_dbus_bindings" (so the filename is
_dbus_bindings.cpython-310-x86_64-linux-gnu.so). As an API user, you are
not meant to "import _dbus_bindings", but the Python code in python3-dbus
needs to be able to do that in order to do its job.

> And is there a good reason not to do
> the same with this Python-package-specific library?

If it isn't a Python extension (cannot be loaded into Python with
"import foo" to provide a module API to Python code) then it would seem
inappropriate to put it in the directory that is reserved for Python
extensions.

> It's not for
> general use, so I can't see why I shouldn't put it in the python3
> directory with the other compiled Python module libraries.

Because it isn't a Python extension (what you are calling a "compiled
Python module library"), but instead some other sort of library with a
different purpose (from your other messages, it seems like it's being
injected into a program that is being debugged with gdb).

smcv



Re: Build and run-time triplets

2022-06-09 Thread Julian Gilbey
On Thu, Jun 09, 2022 at 11:00:28AM +0100, Simon McVittie wrote:
> On Thu, 09 Jun 2022 at 09:56:42 +0100, Julian Gilbey wrote:
> > OK (and yes, it does require the full path at runtime).  What triplet
> > do I use in d/rules?  dpkg-architecture offers 6 different ones:
> > DEB_{BUILD,HOST,TARGET}_{GNU_TYPE,MULTIARCH}?  I'm guessing
> > DEB_TARGET_MULTIARCH, but I'm really not certain, so it would be great
> > to confirm that.
> 
> You'd want DEB_HOST_MULTIARCH here (or use ${LIB} as I mentioned in a
> previous message to this thread).
> [...]

Thanks for this great explanation - I'm learning so much in this
thread!

> > About the location, though: why do compiled Python libraries live in
> > /usr/lib/python3/dist-packages/ and not
> > /usr/lib//?
> 
> The Python jargon for a native C/C++ library that can be loaded to
> provide a Python module is an *extension*.
> [...]

> > And is there a good reason not to do
> > the same with this Python-package-specific library?
> 
> If it isn't a Python extension (cannot be loaded into Python with
> "import foo" to provide a module API to Python code) then it would seem
> inappropriate to put it in the directory that is reserved for Python
> extensions.

I hear this argument, though we do find data files and other sorts of
things other than Python files and compiled extensions that are needed
by Python modules in that same directory ("data_files" in setup.py);
for example numpy has dozens of other files in
/usr/lib/python3/dist-packages/numpy.

I think the counter-argument is exactly what you said: as long as the
shared library is in a place where the code that uses it knows where
to locate it, all will work fine.  The Python code as-written expects
the library to be in the same directory as the Python code.

Best wishes,

   Julian



Re: Build and run-time triplets

2022-06-09 Thread Julian Gilbey
On Thu, Jun 09, 2022 at 03:00:24PM +0500, Andrey Rahmatullin wrote:
> > The build system here is the standard Python setup.py, except for this
> > library.  That is built by the following script:
> > 
> > ---
> > g++ -m64 -shared -o attach_linux_amd64.so -fPIC -nostartfiles attach.cpp
> > mv attach_linux_amd64.so ../attach_linux_amd64.so
> > echo Compiled amd64
> > ---
> > 
> > There's not even an attempt at working out ${libdir} or so on.
> Sure, it's not necessary to know the installation path at the compile and
> link time. It's only needed at the install time.

Ah, to clarify: this script compiles the library and sticks it into
the parent directory.  It is then installed with the rest of the
Python module via setup.py into /usr/lib/python3/dist-packages/...
So if I want to install it somewhere else, I will have to handle that
manually.

Best wishes,

   Julian