From Fedora Project Wiki
(Metadata)
(Description (incomplete))
Line 68: Line 68:


<!-- Expand on the summary, if appropriate.  A couple sentences suffices to explain the goal, but the more details you can provide the better. -->
<!-- Expand on the summary, if appropriate.  A couple sentences suffices to explain the goal, but the more details you can provide the better. -->
=== The Problem ===
When Python is built, it saves the flags (<code>CFLAGS</code>, <code>CXXFLAGS</code> and <code>LDFLAGS</code>) for further use when building extension modules into a designated <code>Makefile</code>. The distutils module (a component responsible for building Python packages and extension modules) then reads the file and applies the flags. You can see the file at <code>/usr/lib64/python3.7/config-3.7m-x86_64-linux-gnu/Makefile</code> in {{package|python3-libs}}. This is mostly done to make user-built extension modules binary compatible with the Python interpreter they are being built for.
Traditionally (=before this change), the {{package|python3}} package was created in a way that it simply saved the same set of flags used for building itself.
This proved problematic as the flags used to build Fedora packages grew specific things (not actually needed for binary compatibility of the extension modules) and several workarounds needed to be made, most specifically the {{package|python3-devel}}  package got a runtime dependency on {{package|redhat-rpm-config}}:
* https://bugzilla.redhat.com/show_bug.cgi?id=1217376
* https://bugzilla.redhat.com/show_bug.cgi?id=1496757
* https://bugzilla.redhat.com/show_bug.cgi?id=1218294
The problematic flags are GCC plugins (such as annobin) and GCC spec files (<code>-specs=</code> arguments).
Example: Any Python developer using Fedora automatically builds Python extension modules with annobin and hardening flags by default even if they don't need that. They might build the extension on Fedora, test it and later ship it and build it on a CI that is not based on Fedora and get a different results.
=== The solution ===
The solution is not to save the problematic flags, but only the flags needed. Until recently, this would be hackish, but [https://src.fedoraproject.org/rpms/redhat-rpm-config/blob/master/f/buildflags.md#support-for-extension-builders a designated set of flags] was created in Fedora 30, supposed to be used by extension builders (such as the Python's distutil module): <code>%{extension_cflags}</code>, <code>%{extension_cxxflags}</code> and <code>%{extension_ldflags}</code>.
The [https://src.fedoraproject.org/rpms/redhat-rpm-config/blob/master/f/buildflags.md#support-for-extension-builders documentation for the flags] currently reads:
<blockquote>
The current set of differences are:
* No GCC plugins (such as annobin) are activated.
* No GCC spec files (<code>-specs=</code> arguments) are used.
Additional flags may be removed in the future if they prove to be incompatible with alternative toolchains.
</blockquote>
Python already had (an incomplete) ability to specify a different set of flags for itself and for the extensions. In Python 3.7.2 and 3.6.8 the ability was completed by providing a way to do this for the <code>LDFAGS</code> (this was actually driven by Fedora's needs). Currently we are able to set a different set of flags for building Python and for building user extension modules. The code to do this can be inspected at the Fedora [https://src.fedoraproject.org/rpms/python3/pull-request/75 pull request implementing this change].
=== Impact on users building extension modules ===
When an user compiles a Python extension module and does not specify any flags explicitly, this is what they used to had:
$ python3 setup.py build
running build
running build_ext
building 'demo' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python3.7m -c demo.c -o build/temp.linux-x86_64-3.7/demo.o
creating build/lib.linux-x86_64-3.7
gcc -pthread -shared -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -g build/temp.linux-x86_64-3.7/demo.o -L/usr/lib64 -lpython3.7m -o build/lib.linux-x86_64-3.7/demo.cpython-37m-x86_64-linux-gnu.so
After the change, they will get:
$ python3 setup.py build
running build
running build_ext
building 'demo' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python3.7m -c demo.c -o build/temp.linux-x86_64-3.7/demo.o
creating build/lib.linux-x86_64-3.7
gcc -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.7/demo.o -L/usr/lib64 -lpython3.7m -o build/lib.linux-x86_64-3.7/demo.cpython-37m-x86_64-linux-gnu.so
Users are able to provide their own flags by setting the <code>CFLAGS</code>, <code>CXXFLAGS</code> and <code>LDFLAGS</code> environment variables. They can for example opt-in for annobin if they wish to do so.


== Benefit to Fedora ==
== Benefit to Fedora ==

Revision as of 10:31, 4 January 2019


Python distutils to use build flags for extension builders (XXX better name?)

Summary

The build flags (CFLAGS, CXXFLAGS and LDFLAGS) saved in the Python's distutils module for building extension modules are switched from %{build_cflags}, %{build_cxxflags} and %{build_ldflags} to %{extension_cflags}, %{extension_cxxflags} and %{extension_ldflags}.

This currently means no GCC plugins (such as annobin) are activated and no GCC spec files (-specs= arguments) are used by default when building Python extension modules (e.g. with python3 setup.py build). That also means the Package-x-generic-16.pngpython3-devel package can loose a runtime dependency on Package-x-generic-16.pngredhat-rpm-config.

The change mostly affects building extension modules by users, outside of RPM environment. The Python standard library and Fedora's Python 3 RPM packages are still built with the "traditional" set of flags (%{build_cflags} and friends), unless the package uses nonstandard methods to build the extensions.

Only Python 3.7 (Package-x-generic-16.pngpython3) and 3.6 (Package-x-generic-16.pngpython36) will be changed.

Owner

Current status

  • Targeted release: Fedora 30
  • Last updated: 2019-01-04
  • Tracker bug: <will be assigned by the Wrangler>

Detailed Description

The Problem

When Python is built, it saves the flags (CFLAGS, CXXFLAGS and LDFLAGS) for further use when building extension modules into a designated Makefile. The distutils module (a component responsible for building Python packages and extension modules) then reads the file and applies the flags. You can see the file at /usr/lib64/python3.7/config-3.7m-x86_64-linux-gnu/Makefile in Package-x-generic-16.pngpython3-libs. This is mostly done to make user-built extension modules binary compatible with the Python interpreter they are being built for.

Traditionally (=before this change), the Package-x-generic-16.pngpython3 package was created in a way that it simply saved the same set of flags used for building itself. This proved problematic as the flags used to build Fedora packages grew specific things (not actually needed for binary compatibility of the extension modules) and several workarounds needed to be made, most specifically the Package-x-generic-16.pngpython3-devel package got a runtime dependency on Package-x-generic-16.pngredhat-rpm-config:

The problematic flags are GCC plugins (such as annobin) and GCC spec files (-specs= arguments).

Example: Any Python developer using Fedora automatically builds Python extension modules with annobin and hardening flags by default even if they don't need that. They might build the extension on Fedora, test it and later ship it and build it on a CI that is not based on Fedora and get a different results.

The solution

The solution is not to save the problematic flags, but only the flags needed. Until recently, this would be hackish, but a designated set of flags was created in Fedora 30, supposed to be used by extension builders (such as the Python's distutil module): %{extension_cflags}, %{extension_cxxflags} and %{extension_ldflags}.

The documentation for the flags currently reads:

The current set of differences are:

  • No GCC plugins (such as annobin) are activated.
  • No GCC spec files (-specs= arguments) are used.

Additional flags may be removed in the future if they prove to be incompatible with alternative toolchains.

Python already had (an incomplete) ability to specify a different set of flags for itself and for the extensions. In Python 3.7.2 and 3.6.8 the ability was completed by providing a way to do this for the LDFAGS (this was actually driven by Fedora's needs). Currently we are able to set a different set of flags for building Python and for building user extension modules. The code to do this can be inspected at the Fedora pull request implementing this change.

Impact on users building extension modules

When an user compiles a Python extension module and does not specify any flags explicitly, this is what they used to had:

$ python3 setup.py build
running build
running build_ext
building 'demo' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python3.7m -c demo.c -o build/temp.linux-x86_64-3.7/demo.o
creating build/lib.linux-x86_64-3.7
gcc -pthread -shared -Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -g build/temp.linux-x86_64-3.7/demo.o -L/usr/lib64 -lpython3.7m -o build/lib.linux-x86_64-3.7/demo.cpython-37m-x86_64-linux-gnu.so

After the change, they will get:

$ python3 setup.py build
running build
running build_ext
building 'demo' extension
creating build
creating build/temp.linux-x86_64-3.7
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/usr/include/python3.7m -c demo.c -o build/temp.linux-x86_64-3.7/demo.o
creating build/lib.linux-x86_64-3.7
gcc -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.7/demo.o -L/usr/lib64 -lpython3.7m -o build/lib.linux-x86_64-3.7/demo.cpython-37m-x86_64-linux-gnu.so

Users are able to provide their own flags by setting the CFLAGS, CXXFLAGS and LDFLAGS environment variables. They can for example opt-in for annobin if they wish to do so.

Benefit to Fedora

Scope

  • Proposal owners:
  • Other developers: N/A (not a System Wide Change)
  • Policies and guidelines: N/A (not a System Wide Change)
  • Trademark approval: N/A (not needed for this Change)

Upgrade/compatibility impact

N/A (not a System Wide Change)

How To Test

N/A (not a System Wide Change)

User Experience

Dependencies

N/A (not a System Wide Change)

Contingency Plan

  • Contingency mechanism: (What to do? Who will do it?) N/A (not a System Wide Change)
  • Contingency deadline: N/A (not a System Wide Change)
  • Blocks release? N/A (not a System Wide Change), Yes/No
  • Blocks product? product

Documentation

N/A (not a System Wide Change)

Release Notes