03 Feb 2012 14:28 - by Boris Gulay
Short introduction
I believe that my experience in porting library to new platform will be useful to all who want to do the same for another platforms. Especially because Windows Mobile is very limited in support of standard C library and STL features.
List of problems
To all who don't want to read the whole article.
- Needs special preprocessor directives to compile.
- UUID generation.
- Does not support some standard library routines (threading, file operations).
- Does not support some socket options.
- Some include files have different names.
- Many include files are missing.
- Missing of ANSI library and API functions.
In details
To get started
I made a port on the basis of existing project for MSVC. It is very easy: you just need to add new platform to the project. I've added Windows Mobile 5 because I have SDK installed. Right after adding new platform you can switch to it and press compile button. After compile process stops you will find many errors in the output window. Let's start fixing it.
Preprocessor directives
If you compile just after adding new platform you will receive a lot of errors with undefined symbols. It's because building for WM requires special symbols to be defined.
I pick them from new WM project. So, here they are:
_WIN32_WCE=$(CEVER);UNDER_CE;$(PLATFORMDEFINES);WINCE;$(ARCHFAM);$(_ARCHFAM_)
Variables references in this defines are set inside WM SDK.
To use unicode versions of WinAPI functions (because ANSI are not avaliable on WinCE) you need to add two additional definitions:
UNICODE;_UNICODE
This will switch all WinAPI to unicode. By the way be careful with string arguments you pass to that functions.
UUID generation
Windows code uses UuidCreate function to generate GUIDs and UuidToString to convert it to string representation. This functions live in special RPC library (I mean separate DLL file).
Problem is that WM does not have this library. I've checked not only emulator but also all real devices I have: nothing. Even if you can compile the code (by manually including required header) you build will fail on the linker step.
After short googling and searching over MSDN I found that WM supports another function to generate GUIDs: CoCreateGuid. It also has a function to convert it to string, but as all WM API it produces unicode string.
So my solution was to use CoCreateGuid to generate unique IDs and snprintf (from code for other platforms) to convert it to ANSI string.
I was afraid that CoCreateGuid may require call to CoInitialize to work properly but fortunately it does not.
By the way I have to change class member type to char array because UuidToString allocates memory itself but snprintf requires already allocated buffer.
Missing C library routines
Yes, some functions from C library, available on desktop windows, are missing on WM.- _beginthreadex
- Can be easily changed to CreateThread (function from WINAPI with the same signature). Signature of thread procedure should also be changed. (stdcall calling convention is not supported on WM).
- stat
- I found no acceptable replacement. So just excluded call to this function when compiling for WM with include directive for stat.h (it's also missing). That's why swap directory is not checked to be writeable on Windows Mobile.
- close, unlink, open, lseek
- Can be replaced with WINAPI calls (standard library headers are missing). Some type casts will be required and all string arguments must be in unicode (see below).
Missing socket option
Option SO_EXCLUSIVEADDRUSE (and SO_REUSEADDR) is not supported. So I just excluded call to setsockopt with #ifdef.
Different names of some include files
Fortunately there was only one such file: intrin.h. In WM it's name is cmnintrin.h. I'm not sure is content of this file actually used or not, because VS shows me that code in this file is not available because of missing precompiler directive.
Missing include files
Most of missing files are mentioned above:
- stat.h
- io.h
- types.h
- fcntl.h
- process.h
But the main trouble is with missing errno.h. Global errno variable is actively used by the library so I have to find some way to bring errno back to WM.
After some investigation I've found that library use errno just to pass results of one function call to another. The code does not analyse values returned from system calls. This gives me an idea to just add errno.h from standard library directly to the project.
I've found sources and add two files to the project: errno.hpp (with status code definitions and global variable declarations) and errno.cpp (with variable definitions). I also have to add strerror function (I've implemented it with FormatMessage call).
Missing ANSI functions
Windows Mobile is totally Unicode. It has no ANSI function equivalents like desktop windows has. But the worst thing is that it has no ANSI functions in standard library too.Fortunately there are only few places inside the library where strings are used.
- uuid_t (to convert GUID to string)
- _snprintf function is available in ANSI version.
- swap (file names)
- All API file functions require Unicode string. But file names are generated inside the class so I've just replace std::string to std::wstring and it works.
- error messages
- I found no good way to change it all to Unicode not to convert Unicode string to ANSI. So I just make it return wchat_t string inside char (by casting pointers). Hope errors will happen not so often.
clrzmq (.NET wrapper)
I also make clrzmq compile for WM. There is not so many changes in it so I will not mention it here.
If you will find it interesting you can ask me to write another article about porting clrzmq on Windows Mobile. :)
Post preview:
Close previewHi there - can somebody point me to where the Win Mobile compatible branch can actually be downloaded from.
Or is anybody using this lib - just after the pre-compiled binaries if at all possible.
Thanks
Would be nice if an admin could change the guest post in a way the diff is readable. Sorry for that..
In case someone finds this usefull, below changes I made to make it compile on CE7. ! Not tested it yet !
GIT Clone from zeromq3-x (14da52c3aad5fa83cb167e2bf49200e072a61d1e)
Preprocessor directives:
_WIN32_WCE=$(CEVER);UNDER_CE;$(PLATFORMDEFINES);WINCE;$(ARCHFAM);$(_ARCHFAM_);UNICODE;_UNICODE
Properties of libzmq
C/C++ / General / Debug Information Format:
From 4 to Program Database (/Zi) to get rid of the error Could not generate command line for the 'VCCLCompilerTool' tool
Source code changes made conserns function ''SetHandleInformation'', below the unified diff
src/signaler.cpp | 5 +++++
src/tcp_listener.cpp | 7 +++++++
2 files changed, 12 insertions(+)
diff git a/src/signaler.cpp b/src/signaler.cpp
index 58f2502..a0ceb3b 100644
- a/src/signaler.cpp
b/src/signaler.cpp
-288,9 +288,12 int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_)
*w_ = WSASocket (AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
wsa_assert (*w_ != INVALID_SOCKET);
+#ifndef WINCE
// On Windows, preventing sockets to be inherited by child processes.
BOOL brc = SetHandleInformation ((HANDLE) *w_, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
+#endif
BOOL brc = TRUE;
// Set TCP_NODELAY on writer socket.
rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY,
-305,9 +308,11 int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_)
*r_ = accept (listener, NULL, NULL);
wsa_assert (*r_ != INVALID_SOCKET);
+#ifndef WINCE
// On Windows, preventing sockets to be inherited by child processes.
brc = SetHandleInformation ((HANDLE) *r_, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
+#endif
// We don't need the listening socket anymore. Close it.
rc = closesocket (listener);
diff git a/src/tcp_listener.cpp b/src/tcp_listener.cpp
index 789deca..7134bbd 100644
- a/src/tcp_listener.cpp
b/src/tcp_listener.cpp
-177,9 +177,13 int zmq::tcp_listener_t::set_address (const char *addr_)
errno = wsa_error_to_errno (WSAGetLastError ());
return -1;
}
+
#ifndef WINCE
// On Windows, preventing sockets to be inherited by child processes.
BOOL brc = SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#endif
+
#else
if (s == -1)
return -1;
-250,9 +254,12 zmq::fd_t zmq::tcp_listener_t::accept ()
WSAGetLastError () == WSAECONNRESET);
return retired_fd;
}
#ifndef WINCE
// On Windows, preventing sockets to be inherited by child processes.
BOOL brc = SetHandleInformation ((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#endif
+
#else
if (sock == -1) {
errno_assert (errno == EAGAIN || errno == EWOULDBLOCK ||
Do you have this lib up and running? If so, do you have it posted somewhere?
We have used ICE for WM but we are looking to move to 0MQ.