Microsoft is bringing Windows to a new class of small devices. Riding the crest of the “Internet of Things” movement, Microsoft is looking to capitalize on devices and sensor capabilities of popular development boards. Recently, members of the Windows Developer Program for IoT have been able to gain access to a build of Windows which supports the Intel Galileo chipset.
Bringing Windows to small devices is a huge feat that opens the door to many development opportunities. Of course, this means, a lot of existing code can be brought over to aid in creating IoT solutions. This post aims to identify the specifics of compiling two open source libraries to this new version of Windows.
The libraries in question concern apache-qpid-proton a light-weight messaging framework for sending AMQP messages and OpenSSL, an open-source library for implement Secure Socket Layer protocols.
Why these two libraries? They were necessary for creating a Win32 application capable of sending AMQPS messages up to an Azure Event Hub as part of Galieo device support in the super awesome Connect the Dots project from MSOpenTech. More importantly, we get to encounter two rather distinct compilation exercises. Apache Qpid can send AMQP (without the S) messages on its own, but Azure requires these are sent over SSL. So we need to compile Apache Qpid against OpenSSL to get AMQPS support. In addition, Apache Qpid gives us a Visual Studio Solution to work with while OpenSSL is built using a makefile in combination with Perl and python processors for producing the makefile itself. This post will explain these scenarios and the necessary changes required to target Windows for IoT through the Visual Studio project for Apache Qpid and the makefile for Open SSL.
Let’s begin by looking at the default property configuration for the Apache Qpid Visual Studio Project:
Normally, when compiling a Win32 application for a desktop PC, we will compile against Win32 libraries contained in C:\Windows\System32. When targeting the Intel Galileo board you will notice that the default Intel Galileo Wiring App template contained in the Windows Developer Program for IoT MSI links against a single library, mincore.lib. Jer’s blog goes into the best known detail on what this is. Long story short, we need to compile against mincore.lib in order to obtain code capable of running on the Galileo as the mappings for System and Win32 functions are completely different in Windows for IoT and contained in this particular lib. This sets the basis for rules #1 and #2.
1. Remove all references to System 32 libs and replace with a reference to Mincore.lib
2. For all references removed in step 1, add these Dlls to the IgnoreDefaultLibraries Collection, this ensures that the linker will not attempt to link to these Dlls, as we want to link to references in Mincore only. Note: I have added compatible OpenSSL binaries to Additional Dependencies to enable OpenSSL support
In addition, we need to consider the hardware present on the Galileo board itself. Intel outfits the board with an Intel® Quark™ SoC X1000 application processor, a 32-bit, single-core, single-thread, Intel® Pentium® processor instruction set architecture (ISA)-compatible, operating at speeds up to 400 MHz. This processor does not support enhanced instruction sets including SSE, SSE2, AVX, or AVX 2. This sets the basis for rule #3.
3. Ensure all code is compiled with the /arch:IA32 compiler flag
You can now build Apache-Qpid-Proton to target Windows for IoT on the Intel Galileo, however, in order to be useful, we need to compile again OpenSSL as Azure event hubs require that we send messages using AMQPS. Without OpenSSL support, we can only send AMQP messages which will be ignored by the Azure event hub.
There is an excellent article on compiling Apache-Qpid Proton against OpenSSL for Windows @ https://code.msdn.microsoft.com/windowsazure/Using-Apache-Qpid-Proton-C-afd76504
I don’t want to reproduce the content there so let’s talk about the changes necessary to target the Windows on the Galileo board.
In step A.3 the author describes the process for compiling the OpenSSL dynamic linking libraries using “nmake –f ms\ntdll.mak install”. Nmake is Microsoft’s build tool for building makefiles. To use the tool you can access it within a Visual Studio command prompt, from it’s actual location in C:\Program Files (x86)\Microsoft Visual Studio X.X\VC\bin, or call C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\vsvars32.bat in a standard command prompt to allow for the path to nmake to be available in your current shell. The problem is the default makefile is configured to build against Win32, i.e. Win32 on the desktop.
Let’s take what we learned above and apply it to the ntdll makefile:
Inside the untouched ntdll.mak you will see the following:
# Set your compiler options
PLATFORM=VC-WIN32
CC=cl
CFLAG= /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS -DDSO_WIN32 -W3 -Gs0 -GF -Gy -nologo -DOPENSSL_SYSNAME_WIN32 -DWIN32_LEAN_AND_MEAN -DL_ENDIAN -D_CRT_SECURE_NO_DEPRECATE -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE
APP_CFLAG= /Zi /Fd$(TMP_D)/app
LIB_CFLAG= /Zi /Fd$(TMP_D)/lib -D_WINDLL
SHLIB_CFLAG=
APP_EX_OBJ=setargv.obj $(OBJ_D)\applink.obj /implib:$(TMP_D)\junk.lib
SHLIB_EX_OBJ=
# add extra libraries to this define, for solaris -lsocket -lnsl would
# be added
EX_LIBS=ws2_32.lib gdi32.lib advapi32.lib crypt32.lib user32.lib
# The OpenSSL directory
SRC_D=.
LINK=link
LFLAGS=/nologo /subsystem:console /opt:ref /debug
We essentially have a section of the makefile which outlines compiler flags and linker flags. Here we can apply the rules from above to create a makefile that will produce a Win32 compatible library which targets the Intel Galileo.
Applying Rule #1 we remove the libs mentioned in EX_LIBS and replace with mincore.lib
Applying Rule #2 we take the libs that were in EX_LIBS and add to the linker flags (LFLAG): /NODEFAULTLIB:NAMEOFLIBARY
Applying Rule #3 we add /arch:IA32 to each compiler flag (*CFLAG)
This yields the following changes:
# Set your compiler options
PLATFORM=VC-WIN32
CC=cl
CFLAG= /arch:IA32 /MD /Ox /O2 /Ob2 -DOPENSSL_THREADS -DDSO_WIN32 -W3 -Gs0 -GF -Gy -nologo -DOPENSSL_SYSNAME_WIN32 -DWIN32_LEAN_AND_MEAN -DL_ENDIAN -D_CRT_SECURE_NO_DEPRECATE -DOPENSSL_USE_APPLINK -I. -DOPENSSL_NO_RC5 -DOPENSSL_NO_MD2 -DOPENSSL_NO_KRB5 -DOPENSSL_NO_JPAKE -DOPENSSL_NO_STATIC_ENGINE
APP_CFLAG= /arch:IA32 /Zi /Fd$(TMP_D)/app
LIB_CFLAG= /arch:IA32 /Zi /Fd$(TMP_D)/lib -D_WINDLL
SHLIB_CFLAG= /arch:IA32
APP_EX_OBJ=setargv.obj $(OBJ_D)\applink.obj /implib:$(TMP_D)\junk.lib
SHLIB_EX_OBJ=
# add extra libraries to this define, for solaris -lsocket -lnsl would
# be added
EX_LIBS=mincore.lib
# The OpenSSL directory
SRC_D=.
LINK=link
LFLAGS=/NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ws2_32.lib /NODEFAULTLIB:gdi32.lib /NODEFAULTLIB:advapi32.lib /NODEFAULTLIB:crypt32.lib /NODEFAULTLIB:user32.lib /nologo /subsystem:console /opt:ref /debug
RSC=rc
I have posted the the complete changes made to ntdll.mak compatible with the Windows for IoT on Intel Galileo @ https://gist.github.com/toolboc/490d53bdddc6626bce04
We can now build the OpenSSL libraries, but you will notice you receive a variety of errors. This is due to missing functions in mincore.lib that were available in the original System32 dlls.
For example:
Creating library out32dll\libeay32.lib and object out32dll\libeay32.exp
cryptlib.obj : error LNK2019: unresolved external symbol __imp__DeregisterEventSource@4 referenced in function _OPENSSL_showfatal
cryptlib.obj : error LNK2019: unresolved external symbol __imp__RegisterEventSourceA@8 referenced in function _OPENSSL_showfatal
cryptlib.obj : error LNK2019: unresolved external symbol __imp__ReportEventA@36 referenced in function _OPENSSL_showfatal
cryptlib.obj : error LNK2019: unresolved external symbol __imp__GetProcessWindowStation@0 referenced in function _OPENSSL_isservice
cryptlib.obj : error LNK2019: unresolved external symbol __imp__GetUserObjectInformationW@20 referenced in function _OPENSSL_isservice
cryptlib.obj : error LNK2019: unresolved external symbol __imp__MessageBoxA@16 referenced in function _OPENSSL_showfatal
cryptlib.obj : error LNK2019: unresolved external symbol __imp__GetDesktopWindow@0 referenced in function _OPENSSL_isservice
rand_win.obj : error LNK2019: unresolved external symbol __imp__CreateCompatibleBitmap@12 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__DeleteObject@4 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__GetDeviceCaps@8 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__GetDIBits@28 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__GetObjectA@12 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__GetDC@4 referenced in function _readscreen
rand_win.obj : error LNK2019: unresolved external symbol __imp__ReleaseDC@8 referenced in function _readscreen
You will notice that these errors actually kind of make sense. Recall Window for IoT (mincore) is stripped down to approximately 171 MB. As a result, many unnecessary functions are removed, such as GetProessWindow and MessageBox as shown above (as there isn’t a GUI available on the stripped down mincore). We now need to modify the source (as safely as possible) to resolve these externals. In my case, I simply commented out the missing method where necessary. Of course, this may have unintended side effects, but due to the fact that most of the missing calls deal with the GUI, you are probably okay.
Continue this until the only errors you receive are in creating the e_capi.obj
Now run nmake -i -f ms\ntdll.mak install (-i will ignore compilation errors, namely the ones coming from e_capi)
Capi is one of the engines used by OpenSSL and it is probably important but I could not get around the compilation errors without essentially breaking it completely so I left it out. This will still produce a valid libeay32.dll and ssleay32.dll. You can verify by copying these dlls along with the created openssl.exe and not that it runs on the Galileo! (Note: you can resolve the error mentioned by copying the produced openssl.cnf to the directory mentioned)
Now to truly compile Apache-Qpid_Proton with OpenSSL support, you would continue forward from step B of https://code.msdn.microsoft.com/windowsazure/Using-Apache-Qpid-Proton-C-afd76504
Upon recreating and opening the Apache-Qpid-Proton Visual Studio solution, you would need to modify all the proton project using Rules #1 – #3 as defined above.
Of course, if you wish to obtain the precompiled binaries and see an example of using Apache-Qpid-Proton with OpenSSL support in a Galileo Wiring app, you may refer to this pull request in the Connect the Dots Project by MS OpenTech: https://github.com/MSOpenTech/connectthedots/pull/20
Happy Hacking! Here’s to a great ideas and developments on Windows for IoT!
2 comments for “Porting Open Source Libraries to Windows for IoT (mincore)”