Bill Kelly
2008-Sep-23 23:20 UTC
[Eventmachine-talk] building standalone EM library on windows
Greetings! I''ve had the need to build EM as a standalone C library on Windows. It took a bit more work this time than when I first tried a standalone build back in early 2007. As usual it''s all Bill Gates'' fault: Short list of "Winsock Screw-Ups" http://faculty.cs.wwu.edu/meehan/cs467/CS467s03/winsockdiffs.htm Longer list of WinSock vs. BSD compatibility issues: http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html But anyway. The reason EM currently is able to compile on Windows is because ruby.h (via ruby''s win32/win32.h) provides POSIX compatibility functions like open(), read(), write(), close(), etc. (However, not all of these REALLY work with sockets; see below...) So once -D BUILD_FOR_RUBY is removed from the Makefile, and ruby.h is no longer included, a few source files now fail to compile. My pragmatic but inelegant solution (diffs below) was just to add #ifdef''s where needed, replacing calls to close() with closesocket(), and replacing read() with recv(), etc. And I simply disabled routines like evma_send_file_data_to_connection() or KeyboardDescriptor::Read(), which didn''t look like they would work properly on Windows whether they technically compiled or not. Probably a cleaner solution would have been for me to add a win32_compat.cpp and win32_compat.h file which could be included instead of ruby.h, and which would provide the POSIX compatibility functions. However, note that the read() supplied by ruby.h apparently won''t work with sockets anyway. So I believe the EventMachine_t::_ReadLoopBreaker() implementation using read() on Windows will not function correctly, even though it technically compiles under BUILD_FOR_RUBY. (I changed it to call recv() on Windows, instead.) Anyway - I''m not suggesting my patches below be applied as-is. There''s probably a cleaner approach. But here''s what I did in case it''s of use to anyone. Regards, Bill M 791 kb.cpp M 791 em.cpp M 791 cmain.cpp Status against revision: 791 Index: em.cpp ==================================================================--- em.cpp (revision 791) +++ em.cpp (working copy) @@ -116,13 +116,22 @@ for (i = 0; i < Descriptors.size(); i++) delete Descriptors[i]; + #ifdef OS_WIN32 + closesocket (LoopBreakerReader); + closesocket (LoopBreakerWriter); + #else close (LoopBreakerReader); close (LoopBreakerWriter); + #endif + #ifdef HAVE_EPOLL if (epfd != -1) close (epfd); + #endif + #ifdef HAVE_KQUEUE if (kqfd != -1) close (kqfd); + #endif } @@ -824,7 +833,11 @@ * and send a loop-break event back to user code. */ char buffer [1024]; + #ifdef OS_WIN32 + recv (LoopBreakerReader, buffer, sizeof(buffer), 0); + #else read (LoopBreakerReader, buffer, sizeof(buffer)); + #endif if (EventCallback) (*EventCallback)("", EM_LOOPBREAK_SIGNAL, "", 0); } @@ -1669,6 +1682,13 @@ * or NULL if there was a problem. */ + #ifdef OS_WIN32 + throw std::runtime_error ("nonblocking OpenFileForWriting unavailable on this platform"); + #endif + + // The whole rest of this function is only compiled on Unix systems. + #ifdef OS_UNIX + if (!filename || !*filename) return NULL; @@ -1679,7 +1699,8 @@ throw std::runtime_error ("no file-stream allocated"); Add (fsd); return fsd->GetBinding().c_str(); - + + #endif // OS_UNIX } Index: cmain.cpp ==================================================================--- cmain.cpp (revision 791) +++ cmain.cpp (working copy) @@ -468,6 +468,8 @@ evma_send_file_data_to_connection *********************************/ +#if defined(BUILD_FOR_RUBY) || !defined(OS_WIN32) + extern "C" int evma_send_file_data_to_connection (const char *binding, const char *filename) { /* This is a sugaring over send_data_to_connection that reads a file into a @@ -528,3 +530,6 @@ return 0; } +#endif + + Index: kb.cpp ==================================================================--- kb.cpp (revision 791) +++ kb.cpp (working copy) @@ -75,10 +75,12 @@ void KeyboardDescriptor::Read() { + #ifdef OS_UNIX char c; read (GetSocket(), &c, 1); if (EventCallback) (*EventCallback)(GetBinding().c_str(), EM_CONNECTION_READ, &c, 1); + #endif }
James Tucker
2008-Sep-24 04:30 UTC
[Eventmachine-talk] building standalone EM library on windows
Interesting observations. Thanks :) On 24 Sep 2008, at 07:20, Bill Kelly wrote:> Greetings! > > I''ve had the need to build EM as a standalone C library on > Windows. It took a bit more work this time than when I first > tried a standalone build back in early 2007. > > As usual it''s all Bill Gates'' fault: > > Short list of "Winsock Screw-Ups" > http://faculty.cs.wwu.edu/meehan/cs467/CS467s03/winsockdiffs.htm > > Longer list of WinSock vs. BSD compatibility issues: > http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html > > > But anyway. The reason EM currently is able to compile on Windows > is because ruby.h (via ruby''s win32/win32.h) provides > POSIX compatibility functions like open(), read(), write(), > close(), etc. (However, not all of these REALLY work with > sockets; see below...) > > So once -D BUILD_FOR_RUBY is removed from the Makefile, and > ruby.h is no longer included, a few source files now fail to > compile. > > My pragmatic but inelegant solution (diffs below) was just to > add #ifdef''s where needed, replacing calls to close() with > closesocket(), and replacing read() with recv(), etc. And I > simply disabled routines like evma_send_file_data_to_connection() > or KeyboardDescriptor::Read(), which didn''t look like they > would work properly on Windows whether they technically > compiled or not. > > Probably a cleaner solution would have been for me to add > a win32_compat.cpp and win32_compat.h file which could be > included instead of ruby.h, and which would provide the POSIX > compatibility functions. > > However, note that the read() supplied by ruby.h apparently > won''t work with sockets anyway. So I believe the > EventMachine_t::_ReadLoopBreaker() implementation using > read() on Windows will not function correctly, even though > it technically compiles under BUILD_FOR_RUBY. (I changed > it to call recv() on Windows, instead.) > > > Anyway - I''m not suggesting my patches below be applied > as-is. There''s probably a cleaner approach. But here''s > what I did in case it''s of use to anyone. > > > Regards, > > Bill > > > M 791 kb.cpp > M 791 em.cpp > M 791 cmain.cpp > Status against revision: 791 > > > Index: em.cpp > ==================================================================> --- em.cpp (revision 791) > +++ em.cpp (working copy) > @@ -116,13 +116,22 @@ > for (i = 0; i < Descriptors.size(); i++) > delete Descriptors[i]; > > + #ifdef OS_WIN32 > + closesocket (LoopBreakerReader); > + closesocket (LoopBreakerWriter); > + #else > close (LoopBreakerReader); > close (LoopBreakerWriter); > + #endif > > + #ifdef HAVE_EPOLL > if (epfd != -1) > close (epfd); > + #endif > + #ifdef HAVE_KQUEUE > if (kqfd != -1) > close (kqfd); > + #endif > } > > > @@ -824,7 +833,11 @@ > * and send a loop-break event back to user code. > */ > char buffer [1024]; > + #ifdef OS_WIN32 > + recv (LoopBreakerReader, buffer, sizeof(buffer), 0); > + #else > read (LoopBreakerReader, buffer, sizeof(buffer)); > + #endif > if (EventCallback) > (*EventCallback)("", EM_LOOPBREAK_SIGNAL, "", 0); > } > @@ -1669,6 +1682,13 @@ > * or NULL if there was a problem. > */ > > + #ifdef OS_WIN32 > + throw std::runtime_error ("nonblocking OpenFileForWriting > unavailable on this platform"); > + #endif > + > + // The whole rest of this function is only compiled on Unix > systems. > + #ifdef OS_UNIX > + > if (!filename || !*filename) > return NULL; > > @@ -1679,7 +1699,8 @@ > throw std::runtime_error ("no file-stream allocated"); > Add (fsd); > return fsd->GetBinding().c_str(); > - > + > + #endif // OS_UNIX > } > > > Index: cmain.cpp > ==================================================================> --- cmain.cpp (revision 791) > +++ cmain.cpp (working copy) > @@ -468,6 +468,8 @@ > evma_send_file_data_to_connection > *********************************/ > > +#if defined(BUILD_FOR_RUBY) || !defined(OS_WIN32) > + > extern "C" int evma_send_file_data_to_connection (const char > *binding, const char *filename) > { > /* This is a sugaring over send_data_to_connection that reads > a file into a > @@ -528,3 +530,6 @@ > return 0; > } > > +#endif > + > + > Index: kb.cpp > ==================================================================> --- kb.cpp (revision 791) > +++ kb.cpp (working copy) > @@ -75,10 +75,12 @@ > > void KeyboardDescriptor::Read() > { > + #ifdef OS_UNIX > char c; > read (GetSocket(), &c, 1); > if (EventCallback) > (*EventCallback)(GetBinding().c_str(), > EM_CONNECTION_READ, &c, 1); > + #endif > } > > > _______________________________________________ > Eventmachine-talk mailing list > Eventmachine-talk at rubyforge.org > http://rubyforge.org/mailman/listinfo/eventmachine-talk