bpo-35257: Avoid leaking LTO linker flags into distutils (GH-10900)

When compiling 3rd party C extensions, the linker flags used by the
compiler for the interpreter and the stdlib modules, will get
leaked into distutils. In order to avoid that, the PY_CORE_LDFLAGS
and PY_LDFLAGS_NODIST are introduced to keep those flags separated.
This commit is contained in:
stratakis 2018-12-19 18:19:01 +01:00 committed by Victor Stinner
parent 55cc34500e
commit cf10a750f4
8 changed files with 38 additions and 18 deletions

View File

@ -17,7 +17,7 @@ __all__ = [
_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS', _UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
'BLDSHARED', 'LDSHARED', 'CC', 'CXX', 'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
'PY_CORE_CFLAGS') 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
# configuration variables that may contain compiler calls # configuration variables that may contain compiler calls
_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX') _COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')

View File

@ -411,7 +411,10 @@ def collect_sysconfig(info_add):
'OPT', 'OPT',
'PY_CFLAGS', 'PY_CFLAGS',
'PY_CFLAGS_NODIST', 'PY_CFLAGS_NODIST',
'PY_CORE_LDFLAGS',
'PY_LDFLAGS', 'PY_LDFLAGS',
'PY_LDFLAGS_NODIST',
'PY_STDMODULE_CFLAGS',
'Py_DEBUG', 'Py_DEBUG',
'Py_ENABLE_SHARED', 'Py_ENABLE_SHARED',
'SHELL', 'SHELL',

View File

@ -24,7 +24,7 @@ class Test_OSXSupport(unittest.TestCase):
for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS',
'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC', 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
'PY_CORE_CFLAGS'): 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'):
if cv in self.env: if cv in self.env:
self.env.unset(cv) self.env.unset(cv)

View File

@ -84,6 +84,10 @@ CONFIGURE_CFLAGS= @CFLAGS@
# Use it when a compiler flag should _not_ be part of the distutils CFLAGS # Use it when a compiler flag should _not_ be part of the distutils CFLAGS
# once Python is installed (Issue #21121). # once Python is installed (Issue #21121).
CONFIGURE_CFLAGS_NODIST=@CFLAGS_NODIST@ CONFIGURE_CFLAGS_NODIST=@CFLAGS_NODIST@
# LDFLAGS_NODIST is used in the same manner as CFLAGS_NODIST.
# Use it when a linker flag should _not_ be part of the distutils LDFLAGS
# once Python is installed (bpo-35257)
CONFIGURE_LDFLAGS_NODIST=@LDFLAGS_NODIST@
CONFIGURE_CPPFLAGS= @CPPFLAGS@ CONFIGURE_CPPFLAGS= @CPPFLAGS@
CONFIGURE_LDFLAGS= @LDFLAGS@ CONFIGURE_LDFLAGS= @LDFLAGS@
# Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the # Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the
@ -96,6 +100,7 @@ PY_CFLAGS_NODIST=$(CONFIGURE_CFLAGS_NODIST) $(CFLAGS_NODIST) -I$(srcdir)/Include
# environment variables # environment variables
PY_CPPFLAGS= $(BASECPPFLAGS) -I. -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS) PY_CPPFLAGS= $(BASECPPFLAGS) -I. -I$(srcdir)/Include $(CONFIGURE_CPPFLAGS) $(CPPFLAGS)
PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS) PY_LDFLAGS= $(CONFIGURE_LDFLAGS) $(LDFLAGS)
PY_LDFLAGS_NODIST=$(CONFIGURE_LDFLAGS_NODIST) $(LDFLAGS_NODIST)
NO_AS_NEEDED= @NO_AS_NEEDED@ NO_AS_NEEDED= @NO_AS_NEEDED@
SGI_ABI= @SGI_ABI@ SGI_ABI= @SGI_ABI@
CCSHARED= @CCSHARED@ CCSHARED= @CCSHARED@
@ -107,6 +112,8 @@ CFLAGSFORSHARED=@CFLAGSFORSHARED@
PY_STDMODULE_CFLAGS= $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFORSHARED) PY_STDMODULE_CFLAGS= $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFORSHARED)
PY_BUILTIN_MODULE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE_BUILTIN PY_BUILTIN_MODULE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE_BUILTIN
PY_CORE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE PY_CORE_CFLAGS= $(PY_STDMODULE_CFLAGS) -DPy_BUILD_CORE
# Linker flags used for building the interpreter object files
PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST)
# Strict or non-strict aliasing flags used to compile dtoa.c, see above # Strict or non-strict aliasing flags used to compile dtoa.c, see above
CFLAGS_ALIASING=@CFLAGS_ALIASING@ CFLAGS_ALIASING=@CFLAGS_ALIASING@
@ -146,7 +153,7 @@ CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(LDVERSION)
SHLIB_SUFFIX= @SHLIB_SUFFIX@ SHLIB_SUFFIX= @SHLIB_SUFFIX@
EXT_SUFFIX= @EXT_SUFFIX@ EXT_SUFFIX= @EXT_SUFFIX@
LDSHARED= @LDSHARED@ $(PY_LDFLAGS) LDSHARED= @LDSHARED@ $(PY_LDFLAGS)
BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS) BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS_NODIST)
LDCXXSHARED= @LDCXXSHARED@ LDCXXSHARED= @LDCXXSHARED@
DESTSHARED= $(BINLIBDEST)/lib-dynload DESTSHARED= $(BINLIBDEST)/lib-dynload
@ -496,7 +503,7 @@ profile-run-stamp:
touch $@ touch $@
build_all_generate_profile: build_all_generate_profile:
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS="$(LDFLAGS) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)" $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
run_profile_task: run_profile_task:
@ # FIXME: can't run for a cross build @ # FIXME: can't run for a cross build
@ -510,7 +517,7 @@ build_all_merge_profile:
profile-opt: profile-run-stamp profile-opt: profile-run-stamp
@echo "Rebuilding with profile guided optimizations:" @echo "Rebuilding with profile guided optimizations:"
-rm -f profile-clean-stamp -rm -f profile-clean-stamp
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS="$(LDFLAGS)" $(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS_NODIST) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS_NODIST)"
# Compile and run with gcov # Compile and run with gcov
.PHONY=coverage coverage-lcov coverage-report .PHONY=coverage coverage-lcov coverage-report
@ -567,7 +574,7 @@ clinic: check-clean-src $(srcdir)/Modules/_blake2/blake2s_impl.c
# Build the interpreter # Build the interpreter
$(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) $(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS)
platform: $(BUILDPYTHON) pybuilddir.txt platform: $(BUILDPYTHON) pybuilddir.txt
$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform
@ -632,7 +639,7 @@ libpython3.so: libpython$(LDVERSION).so
$(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^
libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) libpython$(LDVERSION).dylib: $(LIBRARY_OBJS)
$(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \
libpython$(VERSION).sl: $(LIBRARY_OBJS) libpython$(VERSION).sl: $(LIBRARY_OBJS)
@ -657,7 +664,7 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \
$(LIBRARY) \ $(LIBRARY) \
$(RESSRCDIR)/Info.plist $(RESSRCDIR)/Info.plist
$(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION) $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)
$(CC) -o $(LDLIBRARY) $(PY_LDFLAGS) -dynamiclib \ $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
-all_load $(LIBRARY) -Wl,-single_module \ -all_load $(LIBRARY) -Wl,-single_module \
-install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \ -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \
-compatibility_version $(VERSION) \ -compatibility_version $(VERSION) \
@ -698,7 +705,7 @@ Makefile Modules/config.c: Makefile.pre \
Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
$(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LINKCC) $(PY_CORE_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/_testembed.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS)
############################################################################ ############################################################################
# Importlib # Importlib
@ -706,7 +713,7 @@ Programs/_testembed: Programs/_testembed.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY)
Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile Programs/_freeze_importlib.o: Programs/_freeze_importlib.c Makefile
Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_freeze_importlib: Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN)
$(LINKCC) $(PY_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LINKCC) $(PY_CORE_LDFLAGS) -o $@ Programs/_freeze_importlib.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS)
.PHONY: regen-importlib .PHONY: regen-importlib
regen-importlib: Programs/_freeze_importlib regen-importlib: Programs/_freeze_importlib
@ -794,7 +801,7 @@ Python/sysmodule.o: $(srcdir)/Python/sysmodule.c Makefile
$(IO_OBJS): $(IO_H) $(IO_OBJS): $(IO_H)
$(PGEN): $(PGENOBJS) $(PGEN): $(PGENOBJS)
$(CC) $(OPT) $(PY_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) $(CC) $(OPT) $(PY_CORE_LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
.PHONY: regen-grammar .PHONY: regen-grammar
regen-grammar: $(PGEN) regen-grammar: $(PGEN)

View File

@ -0,0 +1,2 @@
Avoid leaking the linker flags from Link Time Optimizations (LTO)
into distutils when compiling C extensions.

4
configure vendored
View File

@ -666,6 +666,7 @@ SHLIB_SUFFIX
LIBTOOL_CRUFT LIBTOOL_CRUFT
OTHER_LIBTOOL_OPT OTHER_LIBTOOL_OPT
UNIVERSAL_ARCH_FLAGS UNIVERSAL_ARCH_FLAGS
LDFLAGS_NODIST
CFLAGS_NODIST CFLAGS_NODIST
BASECFLAGS BASECFLAGS
CFLAGS_ALIASING CFLAGS_ALIASING
@ -6627,7 +6628,7 @@ $as_echo "$as_me: llvm-ar found via xcrun: ${LLVM_AR}" >&6;}
fi fi
CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS" CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
LDFLAGS="$LDFLAGS $LTOFLAGS" LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
fi fi
# Enable PGO flags. # Enable PGO flags.
@ -6879,6 +6880,7 @@ fi
# The -arch flags for universal builds on OSX # The -arch flags for universal builds on OSX
UNIVERSAL_ARCH_FLAGS= UNIVERSAL_ARCH_FLAGS=

View File

@ -1358,7 +1358,7 @@ if test "$Py_LTO" = 'true' ; then
fi fi
CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS" CFLAGS_NODIST="$CFLAGS_NODIST $LTOFLAGS"
LDFLAGS="$LDFLAGS $LTOFLAGS" LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS"
fi fi
# Enable PGO flags. # Enable PGO flags.
@ -1518,6 +1518,7 @@ fi
AC_SUBST(BASECFLAGS) AC_SUBST(BASECFLAGS)
AC_SUBST(CFLAGS_NODIST) AC_SUBST(CFLAGS_NODIST)
AC_SUBST(LDFLAGS_NODIST)
# The -arch flags for universal builds on OSX # The -arch flags for universal builds on OSX
UNIVERSAL_ARCH_FLAGS= UNIVERSAL_ARCH_FLAGS=

View File

@ -18,11 +18,16 @@ from distutils.spawn import find_executable
cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ cross_compiling = "_PYTHON_HOST_PLATFORM" in os.environ
# Add special CFLAGS reserved for building the interpreter and the stdlib # Set common compiler and linker flags derived from the Makefile,
# modules (Issue #21121). # reserved for building the interpreter and the stdlib modules.
cflags = sysconfig.get_config_var('CFLAGS') # See bpo-21121 and bpo-35257
py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST') def set_compiler_flags(compiler_flags, compiler_py_flags_nodist):
sysconfig.get_config_vars()['CFLAGS'] = cflags + ' ' + py_cflags_nodist flags = sysconfig.get_config_var(compiler_flags)
py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist)
sysconfig.get_config_vars()[compiler_flags] = flags + ' ' + py_flags_nodist
set_compiler_flags('CFLAGS', 'PY_CFLAGS_NODIST')
set_compiler_flags('LDFLAGS', 'PY_LDFLAGS_NODIST')
class Dummy: class Dummy:
"""Hack for parallel build""" """Hack for parallel build"""