Add Cygwin support.
Add Cygwin support.
1.1 --- a/ambuild2/ipc/impl.py Tue Nov 12 20:02:16 2013 -0800
1.2 +++ b/ambuild2/ipc/impl.py Wed Nov 13 16:23:04 2013 -0800
1.3 @@ -18,7 +18,10 @@
1.4 from . import process
1.5 from ambuild2 import util
1.6
1.7 -if util.IsWindows():
1.8 +if util.IsWindows() or util.IsCygwin():
1.9 + # Cygwin doesn't support SCM_RIGHTS (which, I guess, is actually unused)
1.10 + # but more importantly posix_spawn(), so we just cheat and use WinAPI
1.11 + # directly, ignoring the sketchy Unix layer.
1.12 from . import windows as ipc_impl
1.13 elif util.IsLinux():
1.14 from . import linux as ipc_impl
1.15 @@ -34,7 +37,7 @@
1.16 ProcessManager = ipc_impl.ProcessManager
1.17 MessagePump = ipc_impl.MessagePump
1.18
1.19 -if util.IsWindows():
1.20 +if util.IsWindows() or util.IsCygwin():
1.21 from . windows import NamedPipe as Channel
1.22 else:
1.23 from . posix_proc import SocketChannel as Channel
2.1 --- a/ambuild2/ipc/winapi.py Tue Nov 12 20:02:16 2013 -0800
2.2 +++ b/ambuild2/ipc/winapi.py Wed Nov 13 16:23:04 2013 -0800
2.3 @@ -17,7 +17,6 @@
2.4 import ctypes
2.5 import os, sys
2.6 import tempfile
2.7 -from ctypes import WinError
2.8 from ambuild2 import util
2.9
2.10 handle_t = ctypes.c_void_p
2.11 @@ -28,7 +27,55 @@
2.12 INVALID_HANDLE_VALUE = 0xffffffffffffffff
2.13 INVALID_HANDLE = handle_t(INVALID_HANDLE_VALUE)
2.14
2.15 -fnCreateNamedPipeA = ctypes.windll.kernel32.CreateNamedPipeA
2.16 +LANG_NEUTRAL = 0x00
2.17 +SUBLANG_DEFAULT = 0x01
2.18 +
2.19 +def MAKELANGID(primary, sub):
2.20 + return (sub << 10) | primary
2.21 +
2.22 +if sys.platform != 'cygwin':
2.23 + from ctypes import WinError
2.24 + WINDLL = ctypes.windll
2.25 +
2.26 + def sys_executable():
2.27 + return sys.executable
2.28 +else:
2.29 + import subprocess
2.30 +
2.31 + WINDLL = ctypes.cdll
2.32 +
2.33 + sys_executable_ = None
2.34 + def sys_executable():
2.35 + global sys_executable_
2.36 + if not sys_executable_:
2.37 + output = subprocess.check_output(['cygpath', '-w', sys.executable])
2.38 + sys_executable_ = output.strip() + '.exe'
2.39 + return sys_executable_
2.40 +
2.41 + class WindowsError(Exception):
2.42 + def __init__(self, errno, message):
2.43 + self.winerror = errno
2.44 + Exception.__init__(self, message)
2.45 +
2.46 + def WinError():
2.47 + error = GetLastError()
2.48 + buffer = ctypes.create_string_buffer(4096)
2.49 +
2.50 + rval = fnFormatMessage(
2.51 + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2.52 + None,
2.53 + error,
2.54 + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2.55 + ctypes.cast(buffer, ctypes.c_void_p),
2.56 + ctypes.sizeof(buffer),
2.57 + None
2.58 + )
2.59 + if rval == 0:
2.60 + raise Exception('system error {0} while reporting system error {1}'.format(GetLastError(), error))
2.61 +
2.62 + raise WindowsError(error, buffer.value)
2.63 +
2.64 +fnCreateNamedPipeA = WINDLL.kernel32.CreateNamedPipeA
2.65 fnCreateNamedPipeA.argtypes = [
2.66 ctypes.c_char_p, # LPCTSTR lpName
2.67 ctypes.c_int, # DWORD dwOpenMode
2.68 @@ -41,7 +88,7 @@
2.69 ]
2.70 fnCreateNamedPipeA.restype = handle_t
2.71
2.72 -fnCreateFileA = ctypes.windll.kernel32.CreateFileA
2.73 +fnCreateFileA = WINDLL.kernel32.CreateFileA
2.74 fnCreateFileA.argtypes = [
2.75 ctypes.c_char_p, # LPCTSTR lpFileName
2.76 ctypes.c_int, # DWORD dwDesiredAccess
2.77 @@ -53,7 +100,7 @@
2.78 ]
2.79 fnCreateFileA.restype = handle_t
2.80
2.81 -fnCloseHandle = ctypes.windll.kernel32.CloseHandle
2.82 +fnCloseHandle = WINDLL.kernel32.CloseHandle
2.83 fnCloseHandle.argtypes = [ handle_t ]
2.84 fnCloseHandle.restype = ctypes.c_int
2.85
2.86 @@ -85,7 +132,7 @@
2.87 # struct. We have to keep the POINTER type around and use from_address.
2.88 LPOVERLAPPED = ctypes.POINTER(Overlapped)
2.89
2.90 -fnCreateIoCompletionPort = ctypes.windll.kernel32.CreateIoCompletionPort
2.91 +fnCreateIoCompletionPort = WINDLL.kernel32.CreateIoCompletionPort
2.92 fnCreateIoCompletionPort.argtypes = [
2.93 handle_t, # HANDLE FileHandle
2.94 handle_t, # HANDLE ExistingCompletionPort
2.95 @@ -94,7 +141,7 @@
2.96 ]
2.97 fnCreateIoCompletionPort.restype = handle_t
2.98
2.99 -fnGetQueuedCompletionStatus = ctypes.windll.kernel32.GetQueuedCompletionStatus
2.100 +fnGetQueuedCompletionStatus = WINDLL.kernel32.GetQueuedCompletionStatus
2.101 fnGetQueuedCompletionStatus.argtypes = [
2.102 handle_t, # HANDLE CompletionPort
2.103 ctypes.POINTER(ctypes.c_int), # LPDWORD
2.104 @@ -104,7 +151,7 @@
2.105 ]
2.106 fnGetQueuedCompletionStatus.restype = ctypes.c_int
2.107
2.108 -fnCreateProcessA = ctypes.windll.kernel32.CreateProcessA
2.109 +fnCreateProcessA = WINDLL.kernel32.CreateProcessA
2.110 fnCreateProcessA.argtypes = [
2.111 ctypes.c_char_p, # LPCTSTR lpApplicationName
2.112 ctypes.c_char_p, # LPTSTR lpCommandLine
2.113 @@ -119,7 +166,7 @@
2.114 ]
2.115 fnCreateProcessA.restype = ctypes.c_int
2.116
2.117 -fnDuplicateHandle = ctypes.windll.kernel32.DuplicateHandle
2.118 +fnDuplicateHandle = WINDLL.kernel32.DuplicateHandle
2.119 fnDuplicateHandle.argtypes = [
2.120 handle_t, # hSourceProcessHandle
2.121 handle_t, # hSourceHandle,
2.122 @@ -131,14 +178,14 @@
2.123 ]
2.124 fnDuplicateHandle.restype = ctypes.c_int
2.125
2.126 -fnGetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
2.127 +fnGetCurrentProcess = WINDLL.kernel32.GetCurrentProcess
2.128 fnGetCurrentProcess.restype = handle_t
2.129
2.130 -fnGetStdHandle = ctypes.windll.kernel32.GetStdHandle
2.131 +fnGetStdHandle = WINDLL.kernel32.GetStdHandle
2.132 fnGetStdHandle.argtypes = [ ctypes.c_int ]
2.133 fnGetStdHandle.restype = handle_t
2.134
2.135 -fnWriteFile = ctypes.windll.kernel32.WriteFile
2.136 +fnWriteFile = WINDLL.kernel32.WriteFile
2.137 fnWriteFile.argtypes = [
2.138 handle_t, # HANDLE hFile,
2.139 ctypes.c_void_p, # LPCVOID lpBuffer
2.140 @@ -148,7 +195,7 @@
2.141 ]
2.142 fnWriteFile.restype = ctypes.c_int
2.143
2.144 -fnReadFile = ctypes.windll.kernel32.ReadFile
2.145 +fnReadFile = WINDLL.kernel32.ReadFile
2.146 fnReadFile.argtypes = [
2.147 handle_t, # HANDLE hFile,
2.148 ctypes.c_void_p, # LPVOID lpBuffer,
2.149 @@ -158,7 +205,7 @@
2.150 ]
2.151 fnReadFile.restype = ctypes.c_int
2.152
2.153 -fnCreateEvent = ctypes.windll.kernel32.CreateEventA
2.154 +fnCreateEvent = WINDLL.kernel32.CreateEventA
2.155 fnCreateEvent.argtypes = [
2.156 ctypes.c_void_p, # LPSECURITY_ATTRIBUTES lpEventAttributes
2.157 ctypes.c_int, # BOOL bManualReset
2.158 @@ -167,18 +214,18 @@
2.159 ]
2.160 fnCreateEvent.restype = handle_t
2.161
2.162 -fnResetEvent = ctypes.windll.kernel32.ResetEvent
2.163 +fnResetEvent = WINDLL.kernel32.ResetEvent
2.164 fnResetEvent.argtypes = [ handle_t ]
2.165 fnResetEvent.restype = ctypes.c_int
2.166
2.167 -fnGetLastError = ctypes.windll.kernel32.GetLastError
2.168 +fnGetLastError = WINDLL.kernel32.GetLastError
2.169 fnGetLastError.restype = ctypes.c_int
2.170
2.171 -fnWaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
2.172 +fnWaitForSingleObject = WINDLL.kernel32.WaitForSingleObject
2.173 fnWaitForSingleObject.argtypes = [ handle_t, ctypes.c_int ]
2.174 fnWaitForSingleObject.restype = ctypes.c_int
2.175
2.176 -fnWaitForMultipleObjects = ctypes.windll.kernel32.WaitForMultipleObjects
2.177 +fnWaitForMultipleObjects = WINDLL.kernel32.WaitForMultipleObjects
2.178 fnWaitForMultipleObjects.argptypes = [
2.179 ctypes.c_int, # DWORD nCount
2.180 ctypes.POINTER(handle_t), # const HANDLE *lpHandles
2.181 @@ -187,36 +234,51 @@
2.182 ]
2.183 fnWaitForMultipleObjects.restype = ctypes.c_int
2.184
2.185 -fnConnectNamedPipe = ctypes.windll.kernel32.ConnectNamedPipe
2.186 +fnConnectNamedPipe = WINDLL.kernel32.ConnectNamedPipe
2.187 fnConnectNamedPipe.argtypes = [ handle_t, ctypes.POINTER(Overlapped) ]
2.188 fnConnectNamedPipe.restype = ctypes.c_int
2.189
2.190 -fnGetExitCodeProcess = ctypes.windll.kernel32.GetExitCodeProcess
2.191 +fnGetExitCodeProcess = WINDLL.kernel32.GetExitCodeProcess
2.192 fnGetExitCodeProcess.argtypes = [ handle_t, ctypes.POINTER(ctypes.c_int) ]
2.193 fnGetExitCodeProcess.restype = ctypes.c_int
2.194
2.195 -PIPE_ACCESS_DUPLEX = 0x00000003
2.196 -PIPE_TYPE_BYTE = 0x00000000
2.197 -PIPE_TYPE_READMODE_BYTE = 0x00000000
2.198 -FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
2.199 -FILE_FLAG_OVERLAPPED = 0x40000000
2.200 -GENERIC_READ = 0x80000000
2.201 -GENERIC_WRITE = 0x40000000
2.202 -OPEN_EXISTING = 3
2.203 -DUPLICATE_SAME_ACCESS = 0x00000002
2.204 -STARTF_USESTDHANDLES = 0x00000100
2.205 -STD_INPUT_HANDLE = -10
2.206 -STD_OUTPUT_HANDLE = -11
2.207 -STD_ERROR_HANDLE = -12
2.208 -INFINITE = -1
2.209 -WAIT_ABANDONED = 0x00000080
2.210 -WAIT_OBJECT_0 = 0x00000000
2.211 -WAIT_TIMEOUT = 0x00000102
2.212 -WAIT_FAILED = -1
2.213 -STILL_ACTIVE = 259
2.214 -ERROR_BROKEN_PIPE = 109
2.215 -ERROR_PIPE_CONNECTED = 535
2.216 -ERROR_IO_PENDING = 997
2.217 +fnFormatMessage = WINDLL.kernel32.FormatMessageA
2.218 +fnFormatMessage.argtypes = [
2.219 + ctypes.c_int, # DWORD dwFlags
2.220 + ctypes.c_void_p, # LPCVOID lpSource
2.221 + ctypes.c_int, # DWORD dwMessageId
2.222 + ctypes.c_int, # DWRD dwLanguageId
2.223 + ctypes.c_void_p, # LPTSTR lpBuffer
2.224 + ctypes.c_int, # DWORD nSize
2.225 + ctypes.c_void_p # va_list *Arguments
2.226 +]
2.227 +fnFormatMessage.restype = ctypes.c_int
2.228 +
2.229 +PIPE_ACCESS_DUPLEX = 0x00000003
2.230 +PIPE_TYPE_BYTE = 0x00000000
2.231 +PIPE_TYPE_READMODE_BYTE = 0x00000000
2.232 +FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
2.233 +FILE_FLAG_OVERLAPPED = 0x40000000
2.234 +GENERIC_READ = 0x80000000
2.235 +GENERIC_WRITE = 0x40000000
2.236 +OPEN_EXISTING = 3
2.237 +DUPLICATE_SAME_ACCESS = 0x00000002
2.238 +STARTF_USESTDHANDLES = 0x00000100
2.239 +STD_INPUT_HANDLE = -10
2.240 +STD_OUTPUT_HANDLE = -11
2.241 +STD_ERROR_HANDLE = -12
2.242 +INFINITE = -1
2.243 +WAIT_ABANDONED = 0x00000080
2.244 +WAIT_OBJECT_0 = 0x00000000
2.245 +WAIT_TIMEOUT = 0x00000102
2.246 +WAIT_FAILED = -1
2.247 +STILL_ACTIVE = 259
2.248 +FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
2.249 +FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
2.250 +FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
2.251 +ERROR_BROKEN_PIPE = 109
2.252 +ERROR_PIPE_CONNECTED = 535
2.253 +ERROR_IO_PENDING = 997
2.254
2.255 pipe_counter_ = 0
2.256
2.257 @@ -450,8 +512,10 @@
2.258
2.259 proc_info = ProcessInformation()
2.260
2.261 + executable = sys_executable()
2.262 +
2.263 rval = fnCreateProcessA(
2.264 - util.str2b(sys.executable),
2.265 + util.str2b(executable),
2.266 cmdline_buffer,
2.267 None,
2.268 None,
3.1 --- a/ambuild2/ipc/windows.py Tue Nov 12 20:02:16 2013 -0800
3.2 +++ b/ambuild2/ipc/windows.py Wed Nov 13 16:23:04 2013 -0800
3.3 @@ -35,6 +35,10 @@
3.4 if arg == '--pipe':
3.5 pipe = sys.argv[index + 1]
3.6
3.7 + # Cygwin seems to lose the initial \ in translation or something.
3.8 + if pipe.startswith('\\.\\'):
3.9 + pipe = '\\\\.\\' + pipe
3.10 +
3.11 proxy = NamedPipeProxy(name, pipe)
3.12 channel = NamedPipe.from_proxy(proxy)
3.13
4.1 --- a/ambuild2/util.py Tue Nov 12 20:02:16 2013 -0800
4.2 +++ b/ambuild2/util.py Wed Nov 13 16:23:04 2013 -0800
4.3 @@ -27,6 +27,8 @@
4.4 return 'netbsd'
4.5 if IsSolaris():
4.6 return 'solaris'
4.7 + if IsCygwin():
4.8 + return 'cygwin'
4.9 return 'unknown'
4.10
4.11 def IsLinux():
4.12 @@ -42,7 +44,10 @@
4.13 return sys.platform[0:7] == 'openbsd'
4.14
4.15 def IsWindows():
4.16 - return sys.platform == 'win32' or sys.platform == 'cygwin'
4.17 + return sys.platform == 'win32'
4.18 +
4.19 +def IsCygwin():
4.20 + return sys.platform == 'cygwin'
4.21
4.22 def IsMac():
4.23 return sys.platform == 'darwin' or sys.platform[0:6] == 'Darwin'