1. 程式人生 > 其它 >一次小折騰:PyCharm 呼叫 Cygwin Python 找不到 time、sys 等內建模組

一次小折騰:PyCharm 呼叫 Cygwin Python 找不到 time、sys 等內建模組

1、需求背景

為什麼要這樣幹呢?因為 Python 雖然號稱跨平臺,但是一些和作業系統相關的函式 API,windows 下也還是隻能幹瞪眼用不了,比如 import  fcntl 這在 windows 下是沒法用的,這就給開發測試帶來了不便,在兩個異構系統上,沒法無縫切換 work。因此,能想到的就是利用 windows 上的 Cygwin 模擬 linux,然後 Pycharm 去呼叫 Cygwin 下的 Python 即可。

2、配置環境變數以及 PyCharm 引數

2.1 環境變數

CYGWIN_HOME=D:Cygwin_64bit

Path=C:ProgramDataOracleJavajavapath;%SystemRoot%system32;%SystemRoot%;%SystemRoot%System32Wbem;%SYSTEMROOT%System32WindowsPowerShellv1.0;f:OpenV**bin;%JAVA_HOME%bin;%SCALA_HOME%bin;%CYGWIN_HOME%lib;%CYGWIN_HOME%bin;%CYGWIN_HOME%usrsbin;%CYGWIN_HOME%libpython2.7;%CYGWIN_HOME%usrincludepython2.7;%CYGWIN_HOME%usrinclude;D:phantomjs-2.0.0-windowsbin;%MINGW_HOME%mingw32bin;D:Kerberosbin;C:Program FilesMITKerberosbin;F:SCRT

PYTHONPATH=%CYGWIN_HOME%lib;%CYGWIN_HOME%bin;%CYGWIN_HOME%usrsbin;%CYGWIN_HOME%libpython2.7;%CYGWIN_HOME%usrincludepython2.7;%PYTHONPATH%

# 以下3個和本文主題無關,備份之用
LIBRARY_PATH=%CYGWIN_HOME%lib
MINGW_HOME=D:C-Free5mingw
C_INCLUDE_PATH=%CYGWIN_HOME%libgccx86_64-pc-cygwin5.3.0;%CYGWIN_HOME%libgccx86_64-pc-cygwin5.3.0includec++;%CYGWIN_HOME%libgccmingw323.4.5include

2.2 設定 pycharm 直譯器路徑

2.3 測試程式碼

程式碼請使用《300行python程式碼的輕量級HTTPServer實現檔案上傳下載》來測試,這份的程式碼的特點是在 windows 下會報錯,linux 正常,因為使用了 linux 下特有的模組:fcntl

然而我們卻在 IDE 裡看到語法報錯了:

這是為毛?

sys 和 time 模組居然會找不到???

然後小心翼翼的先 alt + shift + x  執行試試,居然 working 正常!

3、如何解決這個問題

由於想到 sys 和 time 都屬於內建模組,可能和 python.exe 這個可執行檔案有關,於是先 copy 了一個 windows 版的 python.exe 過去試試,重新載入就沒有語法報錯的問題了。

但是上面的疑問還是沒解決:為什麼 time 和 sys 模組找不到居然還能執行成功呢?

第一反應就是找找看 time 在哪裡。搜尋了 python 安裝目錄,發現根本就找不到 time.py 或者 time.pyc,然後繼續檢視系統環境:

import sys
# for i in sys.modules.keys():
#     print i

# print sys.path

import time
# print time.__file__


import imp
# print imp.find_module('time')
# print help(imp)

# import datetime
# print datetime.__file__

# D:Cygwin_64bitbinpython2.7.exe F:/sourceDemo/flask/study/flumeFileMonitor/t1.py
# /usr/lib/python2.7/lib-dynload/datetime.dll

import fcntl

print fcntl.__file__

當 直譯器是 windows 版本時,time.__file__ 會拋異常,根本就找不到 time 模組路徑,是不是很奇怪,那平時咱們 import time 是怎麼執行成功的呢?

搜了下 SF 發現了答案:

原來 windows 下的這些內建模組都是 C 寫的,是沒有 time.__file__ 屬性,也就是看不到原始碼的,而在linux下則會指向一個 .so 檔案。

當直譯器是 Cygwin 版本時,time.__file__ 結果是:/usr/lib/python2.7/lib-dynload/time.dll

  • 也就是說雖然 Pycharm 中載入 windows 版本直譯器語法提示不報錯,但是 time.__file__ 會拋異常,但這又是正常的,因為內建模組存在只是沒有提供這個屬性而已。
  • 然而 Pycharm 中載入 Cygwin 版本直譯器雖然報錯提示找不到模組,但是真正執行的時候是沒有問題的,因為相應的模組都以 .dll 形式提供了,只是 Pycharm 無法直接靜態分析該版本的 python.exe,而導致“看起來找不到內建模組”,因此才會出現了 IDE 靜態分析提示錯誤,但是能執行成功的現象。
  • 而且這兩個版本的直譯器對呼叫執行基礎的模組、函式 都是沒有問題的。

至此,我們能看到這兩個版本的 python.exe 各有優劣:

  • Cygwin 版本可以利用 linux 特性,但是會影響 Pycharm 靜態分析功能導致內建模組看起來缺失,和相應的程式碼提示功能不可用。
  • Windows 版本下,Pycharm 的靜態分析功能可以給使用者提供強大的語法檢查和智慧程式碼提示。

但是我們沒有辦法可以讓 Pycharm 既能支援 linux 特性也能擁有內建模組語法檢查與程式碼提示功能。說到底這是一個熊掌與魚不可兼得的問題。

最後要說下,我還嘗試了另一個方案:自己在 Cygwin 下編譯 Linux 版 Python 原始碼,但是和 Cygwin 自帶 Python 一樣,存在同樣的問題。而且編譯過程當中還遇到報錯了:

  File "./setup.py", line 2041, in configure_ctypes
    exec f in fficonfig
  File "build/temp.cygwin-2.4.1-x86_64-2.7/libffi/fficonfig.py", line 33, in <mo                                                                 dule>
    ffi_sources += ffi_platforms['X86_WIN64']
KeyError: 'X86_WIN64'
Makefile:513: recipe for target 'sharedmods' failed
make: *** [sharedmods] Error 1

解決方案是將第 33 行的 X86_WIN64 改成 X86_64 即可通過編譯。

ffi_sources = """
src/prep_cif.c
src/closures.c
""".split()

ffi_platforms = {
    'MIPS_IRIX': ['src/mips/ffi.c', 'src/mips/o32.S', 'src/mips/n32.S'],
    'MIPS_LINUX': ['src/mips/ffi.c', 'src/mips/o32.S'],
    'X86': ['src/x86/ffi.c', 'src/x86/sysv.S', 'src/x86/win32.S'],
    'X86_FREEBSD': ['src/x86/ffi.c', 'src/x86/freebsd.S'],
    'X86_WIN32': ['src/x86/ffi.c', 'src/x86/win32.S'],
    'SPARC': ['src/sparc/ffi.c', 'src/sparc/v8.S', 'src/sparc/v9.S'],
    'ALPHA': ['src/alpha/ffi.c', 'src/alpha/osf.S'],
    'IA64': ['src/ia64/ffi.c', 'src/ia64/unix.S'],
    'M32R': ['src/m32r/sysv.S', 'src/m32r/ffi.c'],
    'M68K': ['src/m68k/ffi.c', 'src/m68k/sysv.S'],
    'POWERPC': ['src/powerpc/ffi.c', 'src/powerpc/ffi_sysv.c', 'src/powerpc/ffi_linux64.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S', 'src/powerpc/linux64.S', 'src/powerpc/linux64_closure.S'],
    'POWERPC_AIX': ['src/powerpc/ffi_darwin.c', 'src/powerpc/aix.S', 'src/powerpc/aix_closure.S'],
    'POWERPC_FREEBSD': ['src/powerpc/ffi.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S'],
    'AARCH64': ['src/aarch64/sysv.S', 'src/aarch64/ffi.c'],
    'ARM': ['src/arm/sysv.S', 'src/arm/ffi.c'],
    'LIBFFI_CRIS': ['src/cris/sysv.S', 'src/cris/ffi.c'],
    'FRV': ['src/frv/eabi.S', 'src/frv/ffi.c'],
    'S390': ['src/s390/sysv.S', 'src/s390/ffi.c'],
    'X86_64': ['src/x86/ffi64.c', 'src/x86/unix64.S', 'src/x86/ffi.c', 'src/x86/sysv.S'],
    'SH': ['src/sh/sysv.S', 'src/sh/ffi.c'],
    'SH64': ['src/sh64/sysv.S', 'src/sh64/ffi.c'],
    'PA': ['src/pa/linux.S', 'src/pa/ffi.c'],
    'PA_LINUX': ['src/pa/linux.S', 'src/pa/ffi.c'],
    'PA_HPUX': ['src/pa/hpux32.S', 'src/pa/ffi.c'],
}

ffi_sources += ffi_platforms['X86_64']

ffi_cflags = ' -Wall -fexceptions'

說到底文章開頭的想法最終也沒能行得通,也罷,windows Pycharm 下還是老老實實的用 windows 版 Python 吧,Cygwin 下用 vim 湊合得了~

Refer:

[1] How do I find the location of Python module sources?

http://stackoverflow.com/questions/269795/how-do-i-find-the-location-of-python-module-sources

[2] Error with libffi while installing Python 2.7.5 on Cygwin 64

https://github.com/yyuu/pyenv/issues/61

[3] Re: Unable to compile python 3.3 [Was: Re: Python 3.3 coming soon?]

http://bit.ly/1TdHAcs