From e2be83def891db39fd4b7b707247740bd28cd811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarek=20Ziad=C3=A9?= Date: Sat, 9 May 2009 08:28:53 +0000 Subject: [PATCH] Fixed Issue 5900: distutils.command.build_ext - Ensure RUNPATH is added to extension modules with RPATH if GNU ld is used --- Lib/distutils/tests/test_build_ext.py | 3 +- Lib/distutils/tests/test_unixccompiler.py | 93 +++++++++++++++++++++++ Lib/distutils/unixccompiler.py | 24 ++++-- Makefile.pre.in | 2 + Misc/NEWS | 3 + configure | 27 ++++++- configure.in | 19 +++++ 7 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 Lib/distutils/tests/test_unixccompiler.py diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py index 9097bee2e45..141c2869b59 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py @@ -125,7 +125,7 @@ class BuildExtTestCase(support.TempdirManager, dist = Distribution({'name': 'xx'}) cmd = build_ext(dist) - # making sure the suer option is there + # making sure the user option is there options = [name for name, short, lable in cmd.user_options] self.assert_('user' in options) @@ -145,6 +145,7 @@ class BuildExtTestCase(support.TempdirManager, # see if include_dirs and library_dirs # were set self.assert_(lib in cmd.library_dirs) + self.assert_(lib in cmd.rpath) self.assert_(incl in cmd.include_dirs) def test_optional_extension(self): diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py new file mode 100644 index 00000000000..94e9edfc094 --- /dev/null +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -0,0 +1,93 @@ +"""Tests for distutils.unixccompiler.""" +import sys +import unittest + +from distutils import sysconfig +from distutils.unixccompiler import UnixCCompiler + +class UnixCCompilerTestCase(unittest.TestCase): + + def setUp(self): + self._backup_platform = sys.platform + self._backup_get_config_var = sysconfig.get_config_var + class CompilerWrapper(UnixCCompiler): + def rpath_foo(self): + return self.runtime_library_dir_option('/foo') + self.cc = CompilerWrapper() + + def tearDown(self): + sys.platform = self._backup_platform + sysconfig.get_config_var = self._backup_get_config_var + + def test_runtime_libdir_option(self): + + # not tested under windows + if sys.platform == 'win32': + return + + # Issue#5900 + # + # Ensure RUNPATH is added to extension modules with RPATH if + # GNU ld is used + + # darwin + sys.platform = 'darwin' + self.assertEqual(self.cc.rpath_foo(), '-L/foo') + + # hp-ux + sys.platform = 'hp-ux' + self.assertEqual(self.cc.rpath_foo(), '+s -L/foo') + + # irix646 + sys.platform = 'irix646' + self.assertEqual(self.cc.rpath_foo(), ['-rpath', '/foo']) + + # osf1V5 + sys.platform = 'osf1V5' + self.assertEqual(self.cc.rpath_foo(), ['-rpath', '/foo']) + + # GCC GNULD + sys.platform = 'bar' + def gcv(v): + if v == 'CC': + return 'gcc' + elif v == 'GNULD': + return 'yes' + sysconfig.get_config_var = gcv + self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') + + # GCC non-GNULD + sys.platform = 'bar' + def gcv(v): + if v == 'CC': + return 'gcc' + elif v == 'GNULD': + return 'no' + sysconfig.get_config_var = gcv + self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo') + + # non-GCC GNULD + sys.platform = 'bar' + def gcv(v): + if v == 'CC': + return 'cc' + elif v == 'GNULD': + return 'yes' + sysconfig.get_config_var = gcv + self.assertEqual(self.cc.rpath_foo(), '-R/foo') + + # non-GCC non-GNULD + sys.platform = 'bar' + def gcv(v): + if v == 'CC': + return 'cc' + elif v == 'GNULD': + return 'no' + sysconfig.get_config_var = gcv + self.assertEqual(self.cc.rpath_foo(), '-R/foo') + +def test_suite(): + return unittest.makeSuite(UnixCCompilerTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 045368a925d..0b1dc4af7d3 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -273,8 +273,9 @@ class UnixCCompiler(CCompiler): # Linkers on different platforms need different options to # specify that directories need to be added to the list of # directories searched for dependencies when a dynamic library - # is sought. GCC has to be told to pass the -R option through - # to the linker, whereas other compilers just know this. + # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to + # be told to pass the -R option through to the linker, whereas + # other compilers and gcc on other systems just know this. # Other compilers may need something slightly different. At # this time, there's no way to determine this information from # the configuration data stored in the Python installation, so @@ -287,10 +288,23 @@ class UnixCCompiler(CCompiler): return "+s -L" + dir elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5": return ["-rpath", dir] - elif compiler[:3] == "gcc" or compiler[:3] == "g++": - return "-Wl,-R" + dir else: - return "-R" + dir + if compiler[:3] == "gcc" or compiler[:3] == "g++": + # gcc on non-GNU systems does not need -Wl, but can + # use it anyway. Since distutils has always passed in + # -Wl whenever gcc was used in the past it is probably + # safest to keep doing so. + if sysconfig.get_config_var("GNULD") == "yes": + # GNU ld needs an extra option to get a RUNPATH + # instead of just an RPATH. + return "-Wl,--enable-new-dtags,-R" + dir + else: + return "-Wl,-R" + dir + else: + # No idea how --enable-new-dtags would be passed on to + # ld if this system was using GNU ld. Don't know if a + # system like this even exists. + return "-R" + dir def library_option(self, lib): return "-l" + lib diff --git a/Makefile.pre.in b/Makefile.pre.in index 88512164215..8f91f88485b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -36,6 +36,8 @@ AR= @AR@ RANLIB= @RANLIB@ SVNVERSION= @SVNVERSION@ +GNULD= @GNULD@ + # Shell used by make (some versions default to the login shell, which is bad) SHELL= /bin/sh diff --git a/Misc/NEWS b/Misc/NEWS index fa362fd929b..485920a5c43 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -285,6 +285,9 @@ Core and Builtins Library ------- +- Issue #5900: Ensure RUNPATH is added to extension modules with RPATH if GNU + ld is used. Original patch by Floris Bruynooghe. + - Issue #5941: Distutils build_clib command was not working anymore because of an incomplete costumization of the archiver command. Added ARFLAGS in the Makefile besides AR and make Distutils use it. Original patch by David diff --git a/configure b/configure index 0379997ca97..910542ae679 100755 --- a/configure +++ b/configure @@ -695,6 +695,7 @@ LDLIBRARYDIR INSTSONAME RUNSHARED LINKCC +GNULD RANLIB AR ARFLAGS @@ -3998,6 +3999,27 @@ fi { echo "$as_me:$LINENO: result: $LINKCC" >&5 echo "${ECHO_T}$LINKCC" >&6; } +# GNULD is set to "yes" if the GNU linker is used. If this goes wrong +# make sure we default having it set to "no": this is used by +# distutils.unixccompiler to know if it should add --enable-new-dtags +# to linker command lines, and failing to detect GNU ld simply results +# in the same bahaviour as before. + +{ echo "$as_me:$LINENO: checking for GNU ld" >&5 +echo $ECHO_N "checking for GNU ld... $ECHO_C" >&6; } +ac_prog=ld +if test "$GCC" = yes; then + ac_prog=`$CC -print-prog-name=ld` +fi +case `"$ac_prog" -V 2>&1 < /dev/null` in + *GNU*) + GNULD=yes;; + *) + GNULD=no;; +esac +{ echo "$as_me:$LINENO: result: $GNULD" >&5 +echo "${ECHO_T}$GNULD" >&6; } + { echo "$as_me:$LINENO: checking for --enable-shared" >&5 echo $ECHO_N "checking for --enable-shared... $ECHO_C" >&6; } # Check whether --enable-shared was given. @@ -26042,6 +26064,7 @@ LDLIBRARYDIR!$LDLIBRARYDIR$ac_delim INSTSONAME!$INSTSONAME$ac_delim RUNSHARED!$RUNSHARED$ac_delim LINKCC!$LINKCC$ac_delim +GNULD!$GNULD$ac_delim RANLIB!$RANLIB$ac_delim AR!$AR$ac_delim ARFLAGS!$ARFLAGS$ac_delim @@ -26059,7 +26082,6 @@ SO!$SO$ac_delim LDSHARED!$LDSHARED$ac_delim BLDSHARED!$BLDSHARED$ac_delim CCSHARED!$CCSHARED$ac_delim -LINKFORSHARED!$LINKFORSHARED$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -26101,6 +26123,7 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +LINKFORSHARED!$LINKFORSHARED$ac_delim CFLAGSFORSHARED!$CFLAGSFORSHARED$ac_delim SHLIBS!$SHLIBS$ac_delim USE_SIGNAL_MODULE!$USE_SIGNAL_MODULE$ac_delim @@ -26126,7 +26149,7 @@ SRCDIRS!$SRCDIRS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 23; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 24; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 diff --git a/configure.in b/configure.in index 1491417ea01..d2c41a9141e 100644 --- a/configure.in +++ b/configure.in @@ -647,6 +647,25 @@ then fi AC_MSG_RESULT($LINKCC) +# GNULD is set to "yes" if the GNU linker is used. If this goes wrong +# make sure we default having it set to "no": this is used by +# distutils.unixccompiler to know if it should add --enable-new-dtags +# to linker command lines, and failing to detect GNU ld simply results +# in the same bahaviour as before. +AC_SUBST(GNULD) +AC_MSG_CHECKING(for GNU ld) +ac_prog=ld +if test "$GCC" = yes; then + ac_prog=`$CC -print-prog-name=ld` +fi +case `"$ac_prog" -V 2>&1 < /dev/null` in + *GNU*) + GNULD=yes;; + *) + GNULD=no;; +esac +AC_MSG_RESULT($GNULD) + AC_MSG_CHECKING(for --enable-shared) AC_ARG_ENABLE(shared, AC_HELP_STRING(--enable-shared, disable/enable building shared python library))