Add Cygwin support.
authorDavid Anderson <danderson@mozilla.com>
Wed Nov 13 16:23:04 2013 -0800 (2013-11-13)
changeset 184b8e9518bd03b
parent 183 79c328e57f26
child 187 5a6d0d4b6007
Add Cygwin support.
ambuild2/ipc/impl.py
ambuild2/ipc/winapi.py
ambuild2/ipc/windows.py
ambuild2/util.py
     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'