从看到这个问题的那一刻起我就想说未定义的行为 (UB). Python带有它的C运行 (UCRTLib),同时Cygwin .dll有它自己的。混合编译器和C进程中的运行时间通常会导致灾难。
我找到了官方的说法[赛格温]:6.15.我可以同时链接 MSVCRT*.DLL 和 cygwin1.dll 吗? https://cygwin.com/faq/faq.html#faq.programming.msvcrt-and-cygwin (emphasis是我的):
不,您必须使用其中之一,它们是互斥的.
Check [SO]:如何规避 Windows 通用 CRT 标头对 vcruntime.h 的依赖(@CristiFati 的回答) https://stackoverflow.com/questions/45340527/how-to-circumvent-windows-universal-crt-headers-dependency-on-vcruntime-h/50838055#50838055欲了解更多详细信息MSVCRT*.DLL
现在,美丽UB是它描述了一种看似随机的行为。
我准备了一个全面的示例(稍微修改您的代码)。
isengrad.c:
#if defined(_WIN32)
# define ISENGRAD_EXPORT_API __declspec(dllexport)
#else
# define ISENGRAD_EXPORT_API
#endif
ISENGRAD_EXPORT_API int isengrad(int hobbit) {
return hobbit / 2;
}
脚本0.py:
#!/usr/bin/env python3
import sys
import ctypes
dll_name = "./lib/isengrad_{0:s}_{1:03d}.dll".format(sys.argv[1][:3] if sys.argv else sys.platform[:3].lower(), ctypes.sizeof(ctypes.c_void_p) * 8)
print("Attempting to load: {0:s}".format(dll_name))
isengrad_dll = ctypes.CDLL(dll_name)
print("DLL Loaded")
def main():
isengrad_func = isengrad_dll.isengrad
isengrad_func.argtypes = [ctypes.c_int]
isengrad_func.restype = ctypes.c_int
res = isengrad_func(46)
print("{0:s} returned {1:}".format(isengrad_func.__name__, res))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
脚本1.py:
#!/usr/bin/env python3
import sys
import script0
def main():
pass
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
Outputs:
- I'll be using 3 windows:
-
cmd - Win (32bit and 64bit)
-
Cygwin's Mintty:
- 请注意,即使我将每个内容粘贴到一个块中(以避免分散它们),我也会在运行命令时在它们之间切换
-
Cygwin 32bit:
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q056855348]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
[032bit prompt]> gcc -shared -fPIC -o lib/isengrad_cyg_032.dll isengrad.c
[032bit prompt]> ls lib/*.dll
lib/isengrad_cyg_032.dll lib/isengrad_cyg_064.dll lib/isengrad_win_032.dll lib/isengrad_win_064.dll
[032bit prompt]>
[032bit prompt]> python3 script0.py cyg
Attempting to load: ./lib/isengrad_cyg_032.dll
DLL Loaded
Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] 32bit on cygwin
isengrad returned 23
Done.
[032bit prompt]>
[032bit prompt]> python3 script1.py cyg
Attempting to load: ./lib/isengrad_cyg_032.dll
DLL Loaded
Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] 32bit on cygwin
Done.
[032bit prompt]>
[032bit prompt]> python3 script0.py win
Attempting to load: ./lib/isengrad_win_032.dll
DLL Loaded
Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] 32bit on cygwin
isengrad returned 23
Done.
[032bit prompt]>
[032bit prompt]> python3 script1.py win
Attempting to load: ./lib/isengrad_win_032.dll
DLL Loaded
Python 3.6.4 (default, Jan 7 2018, 17:45:56) [GCC 6.4.0] 32bit on cygwin
Done.
-
Cygwin 64bit:
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q056855348]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
[064bit prompt]> gcc -shared -fPIC -o lib/isengrad_cyg_064.dll isengrad.c
[064bit prompt]> ls lib/*.dll
lib/isengrad_cyg_032.dll lib/isengrad_cyg_064.dll lib/isengrad_win_032.dll lib/isengrad_win_064.dll
[064bit prompt]>
[064bit prompt]> python3 script0.py cyg
Attempting to load: ./lib/isengrad_cyg_064.dll
DLL Loaded
Python 3.6.8 (default, Feb 14 2019, 22:09:48) [GCC 7.4.0] 64bit on cygwin
isengrad returned 23
Done.
[064bit prompt]>
[064bit prompt]> python3 script1.py cyg
Attempting to load: ./lib/isengrad_cyg_064.dll
DLL Loaded
Python 3.6.8 (default, Feb 14 2019, 22:09:48) [GCC 7.4.0] 64bit on cygwin
Done.
[064bit prompt]>
[064bit prompt]> python3 script0.py win
Attempting to load: ./lib/isengrad_win_064.dll
DLL Loaded
Python 3.6.8 (default, Feb 14 2019, 22:09:48) [GCC 7.4.0] 64bit on cygwin
isengrad returned 23
Done.
[064bit prompt]>
[064bit prompt]> python3 script1.py win
Attempting to load: ./lib/isengrad_win_064.dll
DLL Loaded
Python 3.6.8 (default, Feb 14 2019, 22:09:48) [GCC 7.4.0] 64bit on cygwin
Done.
-
cmd:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056855348]> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
[prompt]> dir /b lib
[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.14
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
[prompt]> cl /nologo /DDLL isengrad.c /link /NOLOGO /DLL /OUT:lib\isengrad_win_064.dll
isengrad.c
Creating library lib\isengrad_win_064.lib and object lib\isengrad_win_064.exp
[prompt]>
[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x86
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.14
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x86'
[prompt]> cl /nologo /DDLL isengrad.c /link /NOLOGO /DLL /OUT:lib\isengrad_win_032.dll
isengrad.c
Creating library lib\isengrad_win_032.lib and object lib\isengrad_win_032.exp
[prompt]> dir /b lib\*.dll
isengrad_cyg_032.dll
isengrad_cyg_064.dll
isengrad_win_032.dll
isengrad_win_064.dll
[prompt]> set _PATH=%PATH%
[prompt]> :: Python 32bit
[prompt]> set PATH=%_PATH%;e:\Install\x86\Cygwin\Cygwin\Version\bin
[prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py win
Attempting to load: ./lib/isengrad_win_032.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32
isengrad returned 23
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script1.py win
Attempting to load: ./lib/isengrad_win_032.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script0.py cyg
Attempting to load: ./lib/isengrad_cyg_032.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32
isengrad returned 23
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_032_03.07.03_test0\Scripts\python.exe" script1.py cyg
Attempting to load: ./lib/isengrad_cyg_032.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 21:26:53) [MSC v.1916 32 bit (Intel)] 32bit on win32
Done.
[prompt]> :: Python 64bit
[prompt]> set PATH=%_PATH%;c:\Install\x64\Cygwin\Cygwin\AllVers\bin
[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script0.py win
Attempting to load: ./lib/isengrad_win_064.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
isengrad returned 23
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script1.py win
Attempting to load: ./lib/isengrad_win_064.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script0.py cyg
Attempting to load: ./lib/isengrad_cyg_064.dll
DLL Loaded
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
isengrad returned 23
Done.
[prompt]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" script1.py cyg
Attempting to load: ./lib/isengrad_cyg_064.dll
[prompt]>
[prompt]> echo %errorlevel%
-1073741819
可以看出,交叉编译器.exe - .dll在 7 个(共 8 个)案例中工作(崩溃于64bit Win Python with 脚本1.py),而同一个编译器在所有 8 个中都工作。
因此,我建议在使用此类环境时,尝试保留用于构建各个部分的编译器持续的 (or 兼容的至少)。
Update #0
我只是想到了事情可能出错的一个原因64bit: sizeof(long)
通常有所不同(以下大小以字节为单位):
-
4 on Win
-
8 on Cygwin (on Nix, 一般来说)
同样的事情sizeof(long double)
(这是2 * sizeof(long)
).
所以,如果Cygwin .dll暴露一些long值大于2 ** 64 (1 ),它将被截断Win进程,在这种情况下可能会发生崩溃。理论上,这种情况应该也会影响相反的情况,但事实并非如此。
还有其他因素可能导致此行为,例如默认内存对齐等等。