Update 1/9/2014: TL;DR version: Go to bottom of this post for a way to get Cygwin to be able to call non-Cygwin programs.
After having spent the time to make some bash scripts that happen to be of significant size, newer versions of Cygwin have broken them. These scripts call into native Win32 applications that don't link with Cygwin, which is apparently not officially supported by Cygwin.
This has come as a surprise to me, as for years I was under the impression that Cygwin could be used in a more mixed environment that combines both native non-Cygwin Win32 apps, and POSIX programs using the Cygwin compatibility layer. But apparently only the POSIX compatibility layer is really supported, and if native Win32 non-Cygwin apps work then it is considered a happy coincidence.
I found this out from an incompatibility I ran into with running programs compiled against the .NET Framework from within Cygwin. This used to work fine, but was broken a few months ago. Specifically, standard output from a .NET program that is piped to any other Win32 program's standard input will generally cause the receiving Win32 program to get a premature end-of-file signal because Cygwin recently switched to message pipes from byte pipes a few months ago - and message pipes appear to be incompatible with any receiving app using Visual C++ or .NET Framework. This is because .NET issues a null write to the standard output, which is only passed on to the receiving app if a message pipe is used. The receiving app successfully reads zero bytes, so thinks it is end-of-file. The project lead doesn't appear to consider this to be a real problem, since they apparently don't really support running non-Cygwin programs from within Cygwin (surprise!).
To quote the project lead Christopher Faylor from multiple e-mails on the mailing list:
What you are seeing may be because Cygwin was changed to use
message-type pipes a couple of revisions ago. This is not going to
change. The change was adopted to fix a problem with Cygwin programs
and those are obviously our #1 priority.
Regardless of how many people use Visual C++ or .NET they are really
not our target audience. It's nice when things work for people who
don't want to use UNIX tools but they are not our primary focus.
Fixing problems for people who want to use non-Cygwin stuff is not
something that I find a high priority.
From pipe.cc: Note that the write side of the pipe is opened as PIPE_TYPE_MESSAGE.
This seems to more closely mimic Linux pipe behavior and is
definitely required for pty handling since fhandler_pty_master writes
to the pipe in chunks, terminated by newline when CANON mode is
specified.
The above comment shows an "and" relationship here. Message type
pipes more closely mimic Linux (UNIX) pipe behavior AND are definitely
required for ptys.
I agree with James that the runtimes are probably buggy BUT I also
agree that cygwin should be able to have a handle these scenarios.
Your complete agreement with each other is not going to have much
effect. Cygwin source code is not changed by voting.
Even if this one issue is ultimately fixed somehow - who knows - they might break something else in 3 months and not care to fix the regression. They might consider a patch, but it would take me quite awhile to figure out something that works. I think my time is better spent elsewhere, because it's clear that they are quite willing to break compatibility with native Win32 apps and don't want to waste more time on getting Win32 apps to work. So I guess Cygwin shouldn't be considered a stable platform for mixed Win32/Cygwin environments - what are my alternatives? Where should I start that would avoid a complete rewrite into something other than bash? I don't use more than the base Cygwin installation + some basic perl scripts.
UPDATE: After the posting of this original question, they did eventually a new pipe_byte
flag in the CYGWIN
environment variable: look at the documentation. If this flag is set, it will fix the problem discussed above. When invoking a non-Cygwin Win32 program, always make sure that the pipe_byte
flag is set.
However, I have since uncovered an incompatibility with .NET Framework 4.0 and Cygwin. Previous versions of .NET Framework don't have this issue. I mentioned the issue first on the Cygwin mailing list here:
Pipe syncronization and incompatibility between Cygwin and .NET Framework 4.0
Getting no fruitful responses, I investigated further and found that Cygwin is creating overlapped pipes, which causes the problem. Note that trying to use non-overlapped Win32 API calls with an overlapped pipe is undefined, and most (all?) Win32 non-Cygwin programs don't use overlapped I/O with their standard file handles. I submitted a patch that creates a pipe_nooverlap
flag in the CYGWIN
environment variable that prevents this from happening:
Patch to optionally disable overlapped pipes
Unfortunately, they have rejected the patch, so you'll never see this in the main Cygwin DLL:
Re: Patch to optionally disable overlapped pipes
The reasoning for rejecting the patch:
- It was implied that I broke the signal implementation in Cygwin; I have not found this to be the case, as signals still use overlapped pipes.
- They don't feel like adding an environment variable flag, even though it is apparently fixing problems.
- They don't want to support code that even has the option of having non-overlapped pipes.
With reasoning and attitudes like this, I'm afraid I can't think of any way to change the patch to suit their requirements... they seem determined to forbid non-overlapped pipes from ever being used. I have been using the patch for awhile now, and have not had any problems with it. Also, I can't think of any situations that the pipe_nooverlap
flag will break (see my follow-up e-mail on their mailing list), but I left it as a flag just in case there is trouble.
So, if you want to call non-Cygwin Win32 or .NET Framework programs from Cygwin, you need to do the following:
- Apply my patch to the source of whatever Cygwin version you are using. Do not expect this patch to show up in future Cygwin versions.
- Set the
pipe_byte
and pipe_nooverlap
flags in the CYGWIN
environment variable.
This works... for now!!! I post this in case it helps anyone else who still wants to use Cygwin for some things.
See Question&Answers more detail:
os