Opened 6 years ago

Closed 6 years ago

#2087 closed defect (fixed)

Problem with distutils-generated loader flags

Reported by: tic20@… Owned by: Conrad Huang
Priority: normal Milestone:
Component: Tool Shed Version:
Keywords: Cc:
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

The following bug report has been submitted:
Platform:        Linux-3.10.0-957.12.2.el7.x86_64-x86_64-with-centos-7.6.1810-Core
ChimeraX Version: 0.9 (2019-06-06)
Description
This is perhaps more of a DistUtils bug than a ChimeraX one, but I run into it afresh whenever I try to install into ChimeraX any package that requires compiling and linking. If you look in ChimeraX/lib/python3.7/distutils/unixccompiler.py, at line 212 you'll find the following method:

{{{
    def runtime_library_dir_option(self, dir):
        # XXX Hackish, at the very least.  See Python bug #445902:
        # http://sourceforge.net/tracker/index.php
        #   ?func=detail&aid=445902&group_id=5470&atid=105470
        # 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 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
        # we use this hack.
        compiler = os.path.basename(sysconfig.get_config_var("CC"))
        if sys.platform[:6] == "darwin":
            # MacOSX's linker doesn't understand the -R flag at all
            return "-L" + dir
        elif sys.platform[:7] == "freebsd":
            return "-Wl,-rpath=" + dir
        elif sys.platform[:5] == "hp-ux":
            if self._is_gcc(compiler):
                return ["-Wl,+s", "-L" + dir]
            return ["+s", "-L" + dir]
        else:
            if self._is_gcc(compiler):
                # 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
}}}

The problem here is that if I run `sysconfig.get_config_var('CC')` from within ChimeraX, I get:

'gcc -pipe -fPIC -std=gnu99 -fdebug-prefix-map=/tmp/chx-v0.9.pFsGzN/build=. -fstack-protector-strong  -I/tmp/chx-v0.9.pFsGzN/build/include -L/tmp/chx-v0.9.pFsGzN/build/lib -DUSE_DYLD_GLOBAL_NAMESPACE -pthread'

... which the call to os.path.basename makes a mess of parsing, so the compiler variable ends up with the value:

'lib -DUSE_DYLD_GLOBAL_NAMESPACE -pthread'

... causing the method to default to the final "No idea how..." option and return "-R" + dir, which in turn causes GCC to crash at the linking stage.

At the moment I just work around it by replacing that branch with the correct return string for my system (-Wl,--enable-new-dtags,-R). 

Same bug is discussed at https://github.com/ContinuumIO/anaconda-issues/issues/6340. Seems if you can strip the -fdebug-prefix-map, -I and -L arguments out (which shouldn't be a problem - looks like these are only relevant to your original build) then it should be fine - it's only the arguments with a "/" in them that confuse basename().

Log:
UCSF ChimeraX version: 0.9 (2019-06-06)  
© 2016-2019 Regents of the University of California. All rights reserved.  
How to cite UCSF ChimeraX  

> toolshed show Shell

/opt/UCSF/ChimeraX/lib/python3.7/site-packages/IPython/core/history.py:226:
UserWarning: IPython History requires SQLite, your history will not be saved  
warn("IPython History requires SQLite, your history will not be saved")  




OpenGL version: 3.3.0 NVIDIA 415.27
OpenGL renderer: TITAN Xp/PCIe/SSE2
OpenGL vendor: NVIDIA Corporation

Change History (13)

comment:1 by Eric Pettersen, 6 years ago

Component: UnassignedTool Shed
Owner: set to Conrad Huang
Platform: all
Project: ChimeraX
Status: newassigned
Summary: ChimeraX bug report submissionProblem with distutils-generated loader flags

comment:2 by Conrad Huang, 6 years ago

Status: assignedfeedback

I've added a hack (5cc957203) to remove -fdebug-map-prefix, -I and -L from CC on Linux. Can you give that a try? Does the same need to be done for MacOS? I know it is not needed for Windows.

in reply to:  3 ; comment:3 by tic20@…, 6 years ago

I'm planning on waiting another week or so before catching up to the 
daily builds. Partly in case there's some disaster in the ISOLDE release 
requiring an urgent patch (fingers crossed!), partly because I have a 
few other things I need to focus on for a while. Will make sure to test 
this once I'm caught up.

On 2019-06-20 03:02, ChimeraX wrote:

comment:4 by Conrad Huang, 6 years ago

In case it might help, here's the one-chunk hack I added to src/apps/ChimeraX:

diff --git a/src/apps/ChimeraX/ChimeraX_main.py b/src/apps/ChimeraX/ChimeraX_main.py
index 4b48f745c..ed9788dd8 100644
--- a/src/apps/ChimeraX/ChimeraX_main.py
+++ b/src/apps/ChimeraX/ChimeraX_main.py
@@ -471,6 +471,23 @@ def init(argv, event_loop=True):
         from distutils import sysconfig
         site.USER_SITE = sysconfig.get_python_lib()

+    # Hack Linux CC to remove compiler arguments inserted for building
+    # Python.  These args contain '/', which confuses
+    # sysconfig.get_config_var() when used by bundle_builder
+    if sys.platform.startswith("linux"):
+        def _clean(cc):
+            parts = cc.split()
+            def ignore(arg):
+                return (arg.startswith("-fdebug-prefix-map") or
+                        arg.startswith("-I") or
+                        arg.startswith("-L"))
+            keep = [arg for arg in parts if not ignore(arg)]
+            return ' '.join(keep)
+        import sysconfig
+        cvars = sysconfig.get_config_vars()
+        cvars["CC"] = _clean(cvars["CC"])
+        del cvars
+
     # Find the location of "share" directory so that we can inform
     # the C++ layer.  Assume it's a sibling of the directory that
     # the executable is in.

comment:5 by Conrad Huang, 6 years ago

TODO: The "right" way to solve this is to run a Python script after Python is built (on Linux and Mac) to strip the flags from CC in lib/python*/config*/Makefile. Then no hack would be required at run time. And the additional script is appropriate since it is only associated with the build environment for Python.

comment:6 by Conrad Huang, 6 years ago

Should be fixed in 73e6661. Waiting for a successful daily build before closing ticket.

comment:7 by Tristan Croll, 6 years ago

Still not working, I'm afraid. From within the Jupyter shell, sysconfig reports the right result:

import sysconfig
sysconfig.get_config_var('CC')
  
  'gcc -pipe -fPIC -std=gnu99 -fstack-protector-strong -DUSE_DYLD_GLOBAL_NAMESPACE -pthread'

... but somehow distutils still sees the problematic flags. If I hack distutils.unixccompiler.UnixCCompiler.runtime_library_dir_option() to report the result of sysconfig.get_config_var('CC'):

from distutils.unixccompiler import UnixCCompiler
ucc = UnixCCompiler()
ucc.runtime_library_dir_option('test')

  gcc -pipe -fPIC -std=gnu99 -fdebug-prefix-map=/tmp/chx-develop.3kdcy2/build=. -fstack-protector-strong  -I/tmp/chx-develop.3kdcy2/build/include -L/tmp/chx-develop.3kdcy2/build/lib -DUSE_DYLD_GLOBAL_NAMESPACE -pthread

  '-Rtest'

comment:8 by Conrad Huang, 6 years ago

This should be fixed by cleaning the Makefile when the app is built. Unfortunately, the daily build failed due to my other change, so it's not ready for testing yet. Hopefully tomorrow.

comment:9 by Conrad Huang, 6 years ago

The new fix (73e6661) is in and the old hack (5cc957203) is out. And there has been one successful daily build. Can you please try your test again?

comment:10 by Tristan Croll, 6 years ago

Still broken. Doing a bit of digging, the sysconfig variables for distutils are set in distutils.sysconfig._init_posix(), which (in the CentOS build of ChimeraX) loads them from /opt/UCSF/ChimeraX-daily/lib/python3.7/_sysconfigdata_m_linux_x86_64-linux-gnu.py. Next question would be to work out what writes that file (or you could simply strip the problem parts from there).

comment:11 by Tristan Croll, 6 years ago

Confirmed that editing out directory arguments from 'CC' and 'CONFIG_ARGS' (not sure if the latter is required) in /opt/UCSF/ChimeraX-daily/lib/python3.7/_sysconfigdata_m_linux_x86_64-linux-gnu.py leads to successful compilation.

comment:12 by Conrad Huang, 6 years ago

The previous fix cleaned up Makefile but not the generated module. eed5c3b should do that. The rebuilt Python sysconfig returns a CC without the offending flags. Hopefully, this is the right fix.

comment:13 by Greg Couch, 6 years ago

Resolution: fixed
Status: feedbackclosed
Note: See TracTickets for help on using tickets.