Skip to content

bpo-35257: Avoid leaking the linker flags into distutils. #10900

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

Merged
merged 4 commits into from
Dec 19, 2018

Conversation

stratakis
Copy link
Contributor

@stratakis stratakis commented Dec 4, 2018

This is the first draft of the PR addressing the propagation of LDFLAGS to C extensions built by distutils.
The work is based on acb8c52 where CFLAGS_NODIST was added for compiler flags aimed to be used only by the interpreter and the stdlib modules but not by 3rd party C extensions. This PR expands that to the linker flags.

While LDFLAGS are not leaked into python-config as CFLAGS are, this can be checked by compiling a simple C extension (e.g. psycopg2).

https://bugs.python.org/issue35257

@stratakis stratakis changed the title [WIP] bpo-35257: Add LDFLAGS_NODIST for stdlib c extensions [WIP] bpo-35257: Add LDFLAGS_NODIST for stdlib C extensions Dec 4, 2018
@stratakis stratakis changed the title [WIP] bpo-35257: Add LDFLAGS_NODIST for stdlib C extensions bpo-35257: Avoid leaking the linker flags into distutils. Dec 5, 2018
Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something is wrong in this change, but I don't know what: "git clean -fdx; ./configure CC=clang --with-lto && make" fails with this PR, whereas it pass in the master branch. Failure:

clang -pthread   -Xlinker -export-dynamic -o Programs/_testembed Programs/_testembed.o libpython3.8m.a -lpthread -ldl  -lutil -lm   -lm 
Programs/python.oPrograms/_testembed.o: file not recognized: : file not recognized: file format not recognizedfile format not recognized

clang-7: error: linker command failed with exit code 1 (use -v to see invocation)clang-7: 
error: linker command failed with exit code 1 (use -v to see invocation)

@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@stratakis stratakis requested a review from a team as a code owner December 6, 2018 16:39
@stratakis
Copy link
Contributor Author

Updates based on some discussion with Victor.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments. I didn't test your updated PR yet.

Makefile.pre.in Outdated
@@ -85,6 +85,10 @@ CONFIGURE_CFLAGS= @CFLAGS@
# Use it when a compiler flag should _not_ be part of the distutils CFLAGS
# once Python is installed (Issue #21121).
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 (Issue #35257)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: "bpo-35257" syntax is now preferred.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, will update.

@@ -147,7 +154,7 @@ CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(LDVERSION)
SHLIB_SUFFIX= @SHLIB_SUFFIX@
EXT_SUFFIX= @EXT_SUFFIX@
LDSHARED= @LDSHARED@ $(PY_LDFLAGS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would mind to add a comment explaining why PY_LDFLAGS (and not PY_LDFLAGS_NODIST) is used for LDSHARED?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to dig in a bit more into the buildsystem to figure out how they are used as my approach was a bit of trial and error for LDSHARED and BLDSHARED. Will try to offer a more comprehensive explanation.

Makefile.pre.in Outdated
@@ -497,7 +504,7 @@ profile-run-stamp:
touch $@

build_all_generate_profile:
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_GEN_FLAG)" LDFLAGS="$(LDFLAGS) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_GEN_FLAG)" LDFLAGS_NODIST="$(LDFLAGS) $(PGO_PROF_GEN_FLAG)" LIBS="$(LIBS)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why $CFLAGS is passed as CFLAGS_NODIST :-(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the target for created the binary using profile guided optimizations, thus I followed the same pattern for ldflags as with the cflags.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it's a bug: https://bugs.python.org/issue35499 and that you should write: LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wrote PR #11219 to avoid modifying LDFLAGS here: https://bugs.python.org/issue35499#msg332079

Makefile.pre.in Outdated
@@ -511,7 +518,7 @@ build_all_merge_profile:
profile-opt: profile-run-stamp
@echo "Rebuilding with profile guided optimizations:"
-rm -f profile-clean-stamp
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_USE_FLAG)" LDFLAGS="$(LDFLAGS)"
$(MAKE) @DEF_MAKE_RULE@ CFLAGS_NODIST="$(CFLAGS) $(PGO_PROF_USE_FLAG)" LDFLAGS_NODIST="$(LDFLAGS)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why $CFLAGS is passed as CFLAGS_NODIST :-(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto: https://bugs.python.org/issue35499 write: LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)".

@@ -0,0 +1,2 @@
Avoid leaking the linker flags into distutils when compiling
C extensions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should mention LTO compilation with clang. Maybe: "Avoid leaking Link Time Optimization (LTO) flags in linker flags into distutils when compiling C extensions."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, will do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LTO is targeted now as the one that shouldn't propagate to C extensions, however that should target the all the flags that are not intended for propagation to C extensions, so shouldn't we have a more generic description of it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so shouldn't we have a more generic description of it?

Keep the generic description, but add a sentence to explain in which case the bug was the most visible. For example:

"Avoid leaking the linker flags into distutils when compiling C extensions, especially Link Time Optimization (LTO) flags."

From what I see in this PR, LDFLAGS="$LDFLAGS $LTOFLAGS" replaced with LDFLAGS_NODIST="$LDFLAGS_NODIST $LTOFLAGS" is the major change of this PR. I don't see other linker flags only passed to LDFLAGS_NODIST. Maybe during the temporary profiling step for PGO? But that's not visible for users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed.

setup.py Outdated
# modules (Issue #35257).
ldflags = sysconfig.get_config_var('LDFLAGS')
py_ldflags_nodist = sysconfig.get_config_var('PY_LDFLAGS_NODIST')
sysconfig.get_config_vars()['LDFLAGS'] = ldflags + ' ' + py_ldflags_nodist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dislike putting more and more code at the module level :-( Would you mind to move these code (from clfags to sysconfig.get_config_vars()['LDFLAGS']) into a new subfunction (ex: "set_compiler_flags()") which does update sysconfig?

setup.py Outdated
@@ -24,6 +24,12 @@
py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST')
sysconfig.get_config_vars()['CFLAGS'] = cflags + ' ' + py_cflags_nodist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why CFLAGS is used instead of PY_CFLAGS here? I would expect that setup.py would use the same CFLAGS than Makefile, something like $(PY_STDMODULE_CFLAGS).

Module/makesetup uses $(PY_BUILTIN_MODULE_CFLAGS).

setup.py Outdated
@@ -24,6 +24,12 @@
py_cflags_nodist = sysconfig.get_config_var('PY_CFLAGS_NODIST')
sysconfig.get_config_vars()['CFLAGS'] = cflags + ' ' + py_cflags_nodist

# Add special LDFLAGS reserved for building the interpreter and the stdlib
# modules (Issue #35257).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto: bpo-35257

Copy link
Member

@ned-deily ned-deily left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_osx_support change LGTM

@stratakis
Copy link
Contributor Author

@vstinner I believe I addressed the current issues, didn't have time today to dig more to LDSHARED and BLDSHARED though. It works through all the configs I tested (--with-lto, --with-shared, using clang and more) and the flags do not propagate to distutils. I'd like to have it in 3.6 but maybe it can be added downstream only.

Also @skrah is the author of the original code that added cflags_nodist, maybe you could take a look?

@vstinner vstinner requested a review from Yhg1s December 12, 2018 15:15
@vstinner
Copy link
Member

cc @serge-sans-paille

@stratakis
Copy link
Contributor Author

By the way the issue first appeared due to https://bugs.python.org/issue31354 when 3.7 was the master branch. However I requested it to be backported to 3.6 which made this bug propagate to 3.6 as well. I realized it when working on backporting some lto+clang related fixes from master.

@serge-sans-paille
Copy link
Contributor

@vstinner tested locally and this now builds fine with

../configure '--with-lto' 'CC=clang' 'CXX=clang++'

and

% sh python-config --libs --ldflags
-lpython3.8m -lpthread -ldl  -lutil -lm -lm 
-L/home/sguelton/sources/cpython/lib/python3.8/config-3.8m-x86_64-linux-gnu -L/home/sguelton/sources/cpython/lib -lpython3.8m -lpthread -ldl  -lutil -lm -lm  -Xlinker -export-dynamic

which looks file to me

@vstinner
Copy link
Member

Can you please merge master into your PR, to retrieve PR #11164 changes? And can you modify build_all_generate_profile: and profile-opt: to use LDFLAGS_NODIST="$(LDFLAGS_NODIST) $(PGO_PROF_GEN_FLAG)"?

@stratakis
Copy link
Contributor Author

Rebased on top of master. Didn't have time yet to test the changes though.

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.
@miss-islington
Copy link
Contributor

Thanks @stratakis for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.7.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @stratakis and @vstinner, I could not cleanly backport this to 3.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker cf10a750f4b50b6775719cfb17bee00bc3a9c60b 3.7

@bedevere-bot
Copy link

GH-11264 is a backport of this pull request to the 3.7 branch.

vstinner added a commit that referenced this pull request Dec 20, 2018
…H-11264)

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.

(cherry picked from commit cf10a75)
ned-deily pushed a commit that referenced this pull request Dec 20, 2018
) (GH-11265)

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.

(cherry picked from commit cf10a75)
ned-deily pushed a commit to ned-deily/cpython that referenced this pull request Dec 23, 2018
) (pythonGH-11264)

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.

(cherry picked from commit cf10a75)
@stratakis stratakis deleted the ldflags_nodist branch January 3, 2020 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants