|
7 | 7 | from __future__ import division
|
8 | 8 | from __future__ import absolute_import
|
9 | 9 |
|
| 10 | +from shutil import rmtree |
| 11 | +from tempfile import mkdtemp |
| 12 | +import errno |
| 13 | +import re |
| 14 | +import multiprocessing |
10 | 15 | import os
|
11 |
| -import subprocess |
12 | 16 | import os.path as p
|
13 |
| -import sys |
| 17 | +import platform |
14 | 18 | import shlex
|
15 |
| -import errno |
| 19 | +import subprocess |
| 20 | +import sys |
16 | 21 |
|
17 | 22 | PY_MAJOR, PY_MINOR = sys.version_info[ 0 : 2 ]
|
18 | 23 | if not ( ( PY_MAJOR == 2 and PY_MINOR >= 6 ) or
|
|
33 | 38 |
|
34 | 39 | sys.path.insert( 1, p.abspath( p.join( DIR_OF_THIRD_PARTY, 'argparse' ) ) )
|
35 | 40 |
|
36 |
| -from tempfile import mkdtemp |
37 |
| -from shutil import rmtree |
38 |
| -import platform |
39 | 41 | import argparse
|
40 |
| -import multiprocessing |
| 42 | + |
| 43 | +NO_DYNAMIC_PYTHON_ERROR = ( |
| 44 | + 'ERROR: found static Python library ({library}) but a dynamic one is ' |
| 45 | + 'required. You must use a Python compiled with the {flag} flag. ' |
| 46 | + 'If using pyenv, you need to run the command:\n' |
| 47 | + ' export PYTHON_CONFIGURE_OPTS="{flag}"\n' |
| 48 | + 'before installing a Python version.' ) |
| 49 | +NO_PYTHON_LIBRARY_ERROR = 'ERROR: unable to find an appropriate Python library.' |
| 50 | + |
| 51 | +LIBRARY_LDCONFIG_REGEX = re.compile( |
| 52 | + '(?P<library>\S+) \(.*\) => (?P<path>\S+)' ) |
| 53 | + |
| 54 | + |
| 55 | +def OnLinux(): |
| 56 | + return platform.system() == 'Linux' |
41 | 57 |
|
42 | 58 |
|
43 | 59 | def OnMac():
|
@@ -120,82 +136,125 @@ def CheckOutput( *popen_args, **kwargs ):
|
120 | 136 | return output
|
121 | 137 |
|
122 | 138 |
|
| 139 | +def GetPythonNameOnUnix(): |
| 140 | + python_name = 'python' + str( PY_MAJOR ) + '.' + str( PY_MINOR ) |
| 141 | + # Python 3 has an 'm' suffix on Unix platforms, for instance libpython3.3m.so. |
| 142 | + if PY_MAJOR == 3: |
| 143 | + python_name += 'm' |
| 144 | + return python_name |
| 145 | + |
| 146 | + |
| 147 | +def GetStandardPythonLocationsOnUnix( prefix, name ): |
| 148 | + return ( '{0}/lib/lib{1}'.format( prefix, name ), |
| 149 | + '{0}/include/{1}'.format( prefix, name ) ) |
| 150 | + |
| 151 | + |
| 152 | +def FindPythonLibrariesOnLinux(): |
| 153 | + python_name = GetPythonNameOnUnix() |
| 154 | + python_library_root, python_include = GetStandardPythonLocationsOnUnix( |
| 155 | + sys.exec_prefix, python_name ) |
| 156 | + |
| 157 | + python_library = python_library_root + '.so' |
| 158 | + if p.isfile( python_library ): |
| 159 | + return python_library, python_include |
| 160 | + |
| 161 | + python_library = python_library_root + '.a' |
| 162 | + if p.isfile( python_library ): |
| 163 | + sys.exit( NO_DYNAMIC_PYTHON_ERROR.format( library = python_library, |
| 164 | + flag = '--enable-shared' ) ) |
| 165 | + |
| 166 | + # On some distributions (Ubuntu for instance), the Python system library is |
| 167 | + # not installed in its default path: /usr/lib. We use the ldconfig tool to |
| 168 | + # find it. |
| 169 | + python_library = 'lib' + python_name + '.so' |
| 170 | + ldconfig_output = CheckOutput( [ 'ldconfig', '-p' ] ).strip().decode( 'utf8' ) |
| 171 | + for line in ldconfig_output.splitlines(): |
| 172 | + match = LIBRARY_LDCONFIG_REGEX.search( line ) |
| 173 | + if match and match.group( 'library' ) == python_library: |
| 174 | + return match.group( 'path' ), python_include |
| 175 | + |
| 176 | + sys.exit( NO_PYTHON_LIBRARY_ERROR ) |
| 177 | + |
| 178 | + |
| 179 | +def FindPythonLibrariesOnMac(): |
| 180 | + python_prefix = sys.exec_prefix |
| 181 | + |
| 182 | + python_library = p.join( python_prefix, 'Python' ) |
| 183 | + if p.isfile( python_library ): |
| 184 | + return python_library, p.join( python_prefix, 'Headers' ) |
| 185 | + |
| 186 | + python_name = GetPythonNameOnUnix() |
| 187 | + python_library_root, python_include = GetStandardPythonLocationsOnUnix( |
| 188 | + python_prefix, python_name ) |
| 189 | + |
| 190 | + # On MacOS, ycmd does not work with statically linked python library. |
| 191 | + # It typically manifests with the following error when there is a |
| 192 | + # self-compiled python without --enable-framework (or, technically |
| 193 | + # --enable-shared): |
| 194 | + # |
| 195 | + # Fatal Python error: PyThreadState_Get: no current thread |
| 196 | + # |
| 197 | + # The most likely explanation for this is that both the ycm_core.so and the |
| 198 | + # python binary include copies of libpython.a (or whatever included |
| 199 | + # objects). When the python interpreter starts it initializes only the |
| 200 | + # globals within its copy, so when ycm_core.so's copy starts executing, it |
| 201 | + # points at its own copy which is uninitialized. |
| 202 | + # |
| 203 | + # Some platforms' dynamic linkers (ld.so) are able to resolve this when |
| 204 | + # loading shared libraries at runtime[citation needed], but OSX seemingly |
| 205 | + # cannot. |
| 206 | + # |
| 207 | + # So we do 2 things special on OS X: |
| 208 | + # - look for a .dylib first |
| 209 | + # - if we find a .a, raise an error. |
| 210 | + python_library = python_library_root + '.dylib' |
| 211 | + if p.isfile( python_library ): |
| 212 | + return python_library, python_include |
| 213 | + |
| 214 | + python_library = python_library_root + '.a' |
| 215 | + if p.isfile( python_library ): |
| 216 | + sys.exit( NO_DYNAMIC_PYTHON_ERROR.format( library = python_library, |
| 217 | + flag = '--enable-framework' ) ) |
| 218 | + |
| 219 | + sys.exit( NO_PYTHON_LIBRARY_ERROR ) |
| 220 | + |
| 221 | + |
| 222 | +def FindPythonLibrariesOnWindows(): |
| 223 | + python_prefix = sys.exec_prefix |
| 224 | + python_name = 'python' + str( PY_MAJOR ) + str( PY_MINOR ) |
| 225 | + |
| 226 | + python_library = p.join( python_prefix, 'libs', python_name + '.lib' ) |
| 227 | + if p.isfile( python_library ): |
| 228 | + return python_library, p.join( python_prefix, 'include' ) |
| 229 | + |
| 230 | + sys.exit( NO_PYTHON_LIBRARY_ERROR ) |
| 231 | + |
| 232 | + |
| 233 | +def FindPythonLibraries(): |
| 234 | + if OnLinux(): |
| 235 | + return FindPythonLibrariesOnLinux() |
| 236 | + |
| 237 | + if OnMac(): |
| 238 | + return FindPythonLibrariesOnMac() |
| 239 | + |
| 240 | + if OnWindows(): |
| 241 | + return FindPythonLibrariesOnWindows() |
| 242 | + |
| 243 | + sys.exit( 'ERROR: your platform is not supported by this script. Follow the ' |
| 244 | + 'Full Installation Guide instructions in the documentation.' ) |
| 245 | + |
| 246 | + |
123 | 247 | def CustomPythonCmakeArgs():
|
124 | 248 | # The CMake 'FindPythonLibs' Module does not work properly.
|
125 | 249 | # So we are forced to do its job for it.
|
| 250 | + print( 'Searching Python {major}.{minor} libraries...'.format( |
| 251 | + major = PY_MAJOR, minor = PY_MINOR ) ) |
126 | 252 |
|
127 |
| - print( 'Searching for python libraries...' ) |
128 |
| - |
129 |
| - python_prefix = CheckOutput( [ |
130 |
| - 'python-config', |
131 |
| - '--prefix' |
132 |
| - ] ).strip().decode( 'utf8' ) |
133 |
| - |
134 |
| - if p.isfile( p.join( python_prefix, '/Python' ) ): |
135 |
| - python_library = p.join( python_prefix, '/Python' ) |
136 |
| - python_include = p.join( python_prefix, '/Headers' ) |
137 |
| - print( 'Using OSX-style libs from {0}'.format( python_prefix ) ) |
138 |
| - else: |
139 |
| - major_minor = CheckOutput( [ |
140 |
| - 'python', |
141 |
| - '-c', |
142 |
| - 'import sys;i=sys.version_info;print( "%d.%d" % (i[0], i[1]) )' |
143 |
| - ] ).strip().decode( 'utf8' ) |
144 |
| - which_python = 'python' + major_minor |
145 |
| - |
146 |
| - # Python 3 has an 'm' suffix, for instance libpython3.3m.a |
147 |
| - if major_minor.startswith( '3' ): |
148 |
| - which_python += 'm' |
149 |
| - |
150 |
| - lib_python = '{0}/lib/lib{1}'.format( python_prefix, which_python ).strip() |
151 |
| - |
152 |
| - print( 'Searching for python with prefix: {0} and lib {1}:'.format( |
153 |
| - python_prefix, which_python ) ) |
154 |
| - |
155 |
| - # On MacOS, ycmd does not work with statically linked python library. |
156 |
| - # It typically manifests with the following error when there is a |
157 |
| - # self-compiled python without --enable-framework (or, technically |
158 |
| - # --enable-shared): |
159 |
| - # |
160 |
| - # Fatal Python error: PyThreadState_Get: no current thread |
161 |
| - # |
162 |
| - # The most likely explanation for this is that both the ycm_core.so and the |
163 |
| - # python binary include copies of libpython.a (or whatever included |
164 |
| - # objects). When the python interpreter starts it initializes only the |
165 |
| - # globals within its copy, so when ycm_core.so's copy starts executing, it |
166 |
| - # points at its own copy which is uninitialized. |
167 |
| - # |
168 |
| - # Some platforms' dynamic linkers (ld.so) are able to resolve this when |
169 |
| - # loading shared libraries at runtime[citation needed], but OSX seemingly |
170 |
| - # cannot. |
171 |
| - # |
172 |
| - # So we do 2 things special on OS X: |
173 |
| - # - look for a .dylib first |
174 |
| - # - if we find a .a, raise an error. |
175 |
| - |
176 |
| - if p.isfile( '{0}.dylib'.format( lib_python ) ): |
177 |
| - python_library = '{0}.dylib'.format( lib_python ) |
178 |
| - elif p.isfile( '/usr/lib/lib{0}.dylib'.format( which_python ) ): |
179 |
| - # For no clear reason, python2.6 only exists in /usr/lib on OS X and |
180 |
| - # not in the python prefix location |
181 |
| - python_library = '/usr/lib/lib{0}.dylib'.format( which_python ) |
182 |
| - elif p.isfile( '{0}.a'.format( lib_python ) ): |
183 |
| - if OnMac(): |
184 |
| - sys.exit( 'ERROR: You must use a python compiled with ' |
185 |
| - '--enable-shared or --enable-framework (and thus a {0}.dylib ' |
186 |
| - 'library) on OS X'.format( lib_python ) ) |
187 |
| - |
188 |
| - python_library = '{0}.a'.format( lib_python ) |
189 |
| - # This check is for CYGWIN |
190 |
| - elif p.isfile( '{0}.dll.a'.format( lib_python ) ): |
191 |
| - python_library = '{0}.dll.a'.format( lib_python ) |
192 |
| - else: |
193 |
| - sys.exit( 'ERROR: Unable to find an appropriate python library' ) |
| 253 | + python_library, python_include = FindPythonLibraries() |
194 | 254 |
|
195 |
| - python_include = '{0}/include/{1}'.format( python_prefix, which_python ) |
| 255 | + print( 'Found Python library: {0}'.format( python_library ) ) |
| 256 | + print( 'Found Python headers folder: {0}'.format( python_include ) ) |
196 | 257 |
|
197 |
| - print( 'Using PYTHON_LIBRARY={0} PYTHON_INCLUDE_DIR={1}'.format( |
198 |
| - python_library, python_include ) ) |
199 | 258 | return [
|
200 | 259 | '-DPYTHON_LIBRARY={0}'.format( python_library ),
|
201 | 260 | '-DPYTHON_INCLUDE_DIR={0}'.format( python_include )
|
@@ -322,8 +381,7 @@ def BuildYcmdLib( args ):
|
322 | 381 |
|
323 | 382 | try:
|
324 | 383 | full_cmake_args = [ '-G', GetGenerator( args ) ]
|
325 |
| - if OnMac(): |
326 |
| - full_cmake_args.extend( CustomPythonCmakeArgs() ) |
| 384 | + full_cmake_args.extend( CustomPythonCmakeArgs() ) |
327 | 385 | full_cmake_args.extend( GetCmakeArgs( args ) )
|
328 | 386 | full_cmake_args.append( p.join( DIR_OF_THIS_SCRIPT, 'cpp' ) )
|
329 | 387 |
|
|
0 commit comments