"True story, true story!"
There are two jazz musicians who are great buddies. They hang out and play together for years, virtually inseparable. Unfortunately, one of them is struck by a truck and killed. About a week later his friend wakes up in the middle of the night with a start because he can feel a presence in the room. He calls out, "Who's there? Who's there? What's going on?" "It's me --Bob," replies a faraway voice. Excitedly he sits up in bed. "Bob! Bob! Is that you? Where are you?" "Well," says the voice, "I'm in heaven now." "Heaven! You're in heaven! That's wonderful! What's it like?" "It's great, man. I gotta tell you, I'm jamming up here every day. I'm playing with Bird, and 'Trane, and Count Basie drops in all the time! Man it is smokin'!" "Oh, wow!" says his friend. "That sounds fantastic, tell me more, tell me more!" "Let me put it this way," continues the voice. "There's good news and bad news. The good news is that these guys are in top form. I mean I have *never* heard them sound better. They are *wailing* up here." "The bad news is that God has this girlfriend that sings..."
Building OpenSSL 1.1.1 for Android on Windows with the Visual Studio 2017 native toolchain and cygwin
Disclaimer: The build scripts outlined in this post have been created in my own spare time. The license of the code is the same license as is used for OpenSSL.
A while ago I wrote about Building OpenSSL 1.0.2 for Android on Windows with Visual Studio 2017, and also how to build OpenSSL 1.1.1 for iOS/iPadOS. This time, I will show how to build OpenSSL 1.1.1 for Android on Windows with the Visual Studio 2017 native toolchain and cygwin.
The procedure outlined here produces actually working static or dynamic libraries and has the same prerequisites as in the article before on how to build version 1.0.2 of the libraries, but with one addition: The cygwin install will also require the installation of gnu make and patch.
Using the scripts
In order to use the scripts I have written, follow theses steps:
- Make sure all preconditions are fulfilled, as described above (cygwin with make and patch) and in the article on building version 1.0.2
- Unpack the zip File (Download) into a writable directory, make sure that you have the "Change permissions" right for the directory and all its files and subdirectories granted, otherwise the calls to chmod in the build scripts will fail (cygwin places some strange NULL SID ACEs into the DACL of files that are granted execution right using chmod which requires the "Change permissions" access right)
- Download openssl-1.1.1l.tar.gz from openssl.org (Download) and copy it into the directory created in the previous step.
- Open a windows command prompt and change the current directory to the directory from the above steps
- Execute "build.bat" and wait
- Find the header files or the build under platform specific subdirectories like arch-x86, arch-arm in the subdirectory openssl-1.1.1l/include and find the libraries (libcrypto.a, libssl.a, libcrypto.so and libssl.so) directly in the subdirectory openssl-1.1.1l.
OPENSSLNAME=openssl-1.1.1l
#
# in order to build with dynamic libraries (i.e. libcrypto.so and libssl.so in addition to
# only libcrypto.a and libssl.a, remove the -no-shared flag from the following command line:
#
perl Configure $SSL_TARGET $OPTIONS $ADD_CFLAGS -I$NDK_PATH/sysroot/usr/include/$TRIBLE $ADD_LIB_FLAGS -no-shared
/usr/bin/make
Building OpenSSL 1.1.1 for iOS
Building OpenSSL for iOS has never been easier than with version 1.1.1. Required software for this purpose is a decent Mac with XCode and XCode command line tools installed. I have wrapped the build process into two shell scripts here and here. Download your version of OpenSSL 1.1.1 here and place the tarball you have downloaded alongside these two shell scripts in a directory on your mac. Then open a terminal, navigate into this directory and execute this in order to make the shell script executable:
chmod +x build.sh
At the time this post was written, version 1.1.1i of OpenSSL was the most recent version, so if you have downloaded a newer version than that, edit build.sh and locate line 4 which looks like this:
OPENSSLVERSION=openssl-1.1.1i
change the value of this string to the name of the OpenSSL tarball you have without the trailing ".tar.gz".
After that, execute the buildscript on the command line:
./build.sh
This will really take some time, be prepared for half an hour or longer. At the very end, you will get a subdirectory with a multiplatform version (i386, x86_64, armv7, armv7s, arm64) of libssl.a and libcrypto.a in the "build/lib" subdirectory. The subdirectory "build" also contains the relevant header files in individual subdirectories for the different platforms.
The license for these shell scripts of mine is the same as for OpenSSL, so nothing should change for you.
Downloading all msdn magazine issues in one fell swoop
Unfortunately, in late 2019 the venerable msdn magazine's last issue appeared. In the mid nineties I had a subscription of its predecessor, the MSJ, which was later converted into an msdn magazine subscription. For archiving purposes I was looking for a way to download all past issues of msdn magazine in some easy way and decided to massage the download document on the web (which might disappear without any notice at any time) a bit in order to extract the raw download URLs. The result is this batch file that requires curl to be found via the PATH environment variable. It downloads a whopping 3.3GB of pdf and chm files that fit neatly on a writable 4.7 GB DVD. Download your copy of all msdn magazine articles before the download links go the way of all flesh...
The original and official page on the web that I parsed for getting all download links is this.
Building OpenSSL for Android on Windows with the Visual Studio 2017 native Toolchain and Cygwin
Building OpenSSL is an arcane thing to do sometimes. I have nowhere on the web found a real simple solution to build OpenSSL for Android that met the number one requirement for me: Being able to build on a build host (or development host) that runs Windows. I simply do not want to maintain another build machine running some Linux flavor only in order to be able to build an OpenSSL static library and a shared library that uses the former. I would rather want to use Visual Studio 2017 with its support for native C/C++ development which also suggests using the same toolchain for building the static OpenSSL library and the shared libraries that are going to consume it. Since I am planning to use Xamarin for my mobile apps, having the entire development and build process on a Windows box would be a big win for me.
DISCLAIMER: I have not yet tried, whether the OpenSSL libraries produced with my set of scripts and configuration files actually work in a real world Android app. But the build procedures themselves succeed and create the familiar libcrypto.a, libcrypto.so.1.0.0, libssl.a and libssl.so.1.0.0 files which are also all in the correct binary format as you can easily verify running readelf on them (the build script actually does this).
Challenges
Since OpenSSL for Android is usually built on a Linux host using Google's NDK, its entire build procedure also heavily relies on infrastructure that is usually found on a Linux box: Shell scripts, PERL, symbolic links and build tools like make and friends. None of these infrastructure elements can be found on a standard Windows box and things like symbolic links have been unfeasible until the arrival of Windows 10 Build 10.0.15063, at least for non-administrative accounts (you do develop and build as a LUA user, don't ya?). So we need a Unix-like environment for this purpose running on Windows plus some other arcane preconditions set which we will see in a moment. WSL cannot be used for this purpose because it only allows 64-bit Linux applications to be executed. However, the NDK that Google ships for Linux comes with a number of 32-bit applications which are not a problem when executed on a "real" installation of Linux but call for trouble on WSL. So the only option left over for this purpose is Cygwin.
Using the scripts
In order to use the scripts I have written, follow theses steps:
- Make sure all preconditions are fulfilled, as described in the paragraph below
- Unpack the zip File (Download) into a writable directory, make sure that you have the "Change permissions" right for the directory and all its files and subdirectories granted, otherwise the calls to chmod in the build scripts will fail (cygwin places some strange NULL SID ACEs into the DACL of files that are granted execution right using chmod which requires the "Change permissions" access right)
- Download openssl-1.0.2q.tar.gz from openssl.org (Download) and copy it into the directory created in the previous step.
- Open a windows command prompt and change the current directory to the directory from the above steps
- Execute "build.bat" and wait (on my Ryzen Vega this takes something like 22 minutes)
- Find the header files and libraries for the build in a platform specific subdirectory like arch-x86, arch-arm in the subdirectory build\<android-api-version>
Preconditions
In order to use the build scripts, you need Microsoft Visual Studio 2017 installed with the "Mobile development with C++" workload enabled. Unless disabled during Visual Studio Setup, this will create subdirectories like these in c:\Microsoft\AndroidNDK64: android-ndk-r12b, android-ndk-r13b, android-ndk-r15c. You might have them also in the directory c:\Microsoft\AndroidNDK. These directories contain the NDK in different versions and I assume that later versions of Visual Studio will ship with even newer Versions of the NDK than the ones mentioned here. The scripts of mine will assume that the r15c-Version of the NDK is installed in c:\Microsoft\AndroidNDK64\android-ndk-r15c but you can set your installation directory of the NDK prior to execution of the build scripts by setting the OPENSSL_ANDROID_NDK_ROOT environment variable in the command prompt to something like c:\Microsoft\AndroidNDK64\android-ndk-r12b like this:
set OPENSSL_ANDROID_NDK_ROOT=c:\Microsoft\AndroidNDK64\android-ndk-r12b
You also have to install cygwin, I have not tried with the 32-bit version of cygwin but I assume it works as well. Cygwin is a huge beast and we have to use only a tiny fraction of it for our purposes. Unfortunately is installer is not even digitally signed with an Authenticode signature, so be sure to check it with its signature file and a tool like Kleopatra in order to verify authenticity. When installing cygwin you can use the standard installation options (which will create a bash environment with PERL and other good stuff) but be sure to also install the following programs: dos2unix, makedepend, automake. We need dos2unix in order to convert a dynamically created shell script from CRLF-notation to LF-notation consumable by the cygwin bash and we need makedepend and automake for building via the OpenSSL shell scripts. The build scripts of mine assume that cygwin is installed in the c:\cygwin64 directory but you can override this much like with the above OPENSSL_ANDROID_NDK_ROOT environment variable. So, e.g. if you have installed cygwin into d:\cygwin64, type the following in the command prompt prior to execution of build.bat:
set CYGWIN_PATH=d:\cygwin64
You might want to create a permanent CYGWIN_PATH environment variable for you development or build machine unless it is installed at the default location c:\cygwin64.
Since the build scripts for OpenSSL on Linux make heavy use of symbolic links for header files, you should also turn on "Developer Mode" on your build and development host (which should be Windows 10 10.0.15063 or later), otherwise the build scripts cannot be executed successfully by a standard user. From Windows 10 10.0.15063 on, symbolic links can be created on Windows machines without administrative permissions if the box is running in "Developer Mode".
How it works
build.bat will invoke creatcfg.bat and buildall.bat in succession. The purpose of creatcfg.bat is to create the Setenv-build.sh build script and the buildall.bat batch file with the configuration set via the CYGWIN_PATH and the OPENSSL_ANDROID_NDK_ROOT environment variables. While we are at it: You can also set the Android API version to be used for the build with the ANDROID_API environment variable (default value: android-21) like this prior to execution of build.bat:
set ANDROID_API=android-26
buildall.bat, which is created by creatcfg.bat is then executed by build.bat and will invoke the cygwin bash three times with arguments to execute. The first one will convert the newly created Setenv-build.sh from CRLF notation to LF notation with dos2unix, so the cygwin bash can consume it properly. The second will execute "chmod a+x" for all shell script files (this is the place where you will get an Access Denied error if the user executing this script does not have the "Change permissions" access right). And the last one will execute the buildall.sh shell script.
buildall.sh will first clean up the build subdirectory, if it exists and will recreate it and grant everyone full control to the build subdirectory (ok, this is cargo cult, I don't really know if we really need this with developer mode turned on and the "Change permissions" access right set as documented before). After that it will invoke buildplatform.sh or each Android hardware platform and pipe stdout and stderr into a log file (arm64_build.log, arm_build.log, mips64_build.log, mips_build.log, x86_64_build.log and x86_build.log).
buildplatform.sh takes the build architecture as an argument and will first invoke the dynamically created shell script Setenv-build.sh, which will set a couple of environment variables that depend on your cygwin installation path, the NDK path being set and the Android API version chosen, as explained above. After that, buildplatform.sh will invoke an architecture specific configuraton file like Setenv-mips.sh which will set architecture specific environment variables. It then creates a subdirectory for the architecture value passed as an argument and will then unpack the openssl tarball into this directory. It is the buildplatform.sh shell script where you also would want to change the name of this tarball once a newer version as 1.0.2q has been released, simply by changing the value of the OPENSSLNAME variable.
After the tarball has been unpacked, the buildplatform.sh script will copy the Configure file from my set of script files over the one that comes with the tarball. The reason is that the Configure file in the tarball is missing entries for the x86_64 build, the arm64 build and the mips64 build. You might want to check, once a newer version than 1.0.2q is used, if this copy step is still necessary and if it doesn't break other builds, e.g. if the compiler options for GCC are changed in the standard Configure file from the tarball.
After that, the buildplatform.sh will perform the usual OpenSSL build sequence of
perl -pi -e 's/install: all install_docs install_sw/install: install_docs install_sw/g' Makefile.org
perl configure $OPENSSL_CONFIG_ARCH shared no-asm no-ssl2 no-ssl3 no-comp no-hw no-engine make depend
make all
in order to build the platform (OPENSSL_CONFIG_ARCH is a variable denoting the hardware platform name).
Once a hardware platform is built with make all, the buildplatform.sh script invokes readelf for the generated library files so you can verify in the platform build log, that the created binaries have the proper format. The subsequent make install_sw step will then copy the build output into the build subdirectory. For some reason, this step fails, as you can see in the log files, but library files and header files are copied successfully, so I assume this step is complete enough to be usable.
Fun fact: Try to observe a running build with Process Explorer and the image path being shown as a column. You will then notice that the actual make.exe being invoked in the build process is not the one from cygwin but instead a binary that is part of the Visual Studio NDK installation.
Leftover stuff
I would guess that the same result with my scripts could be achieved with the Windows version of Google's NDK. Drop me a note if you would like to share your results. Initially, some three years ago, I had started creating a build recipe for OpenSSL on Windows with Cygwin which finally emerged into today's version of the build scripts, so simply pointing the OPENSSL_ANDROID_NDK_ROOT environment variable to the location where the Google NDK is installed might already work. At some point I decided to give the Microsoft Compilers a chance and this worked out pretty flawlessly. This also relieved me from having to install yet another SDK on my development and build boxes, this time Google's NDK.
License
All the files I have written use the OpenSSL license, so nothing should change for you if you are already using OpenSSL.