In the days after Christmas of 2023 I finally managed to reorganize my home office setup into a decent workplace environment. This in itself might be worth a blog post. While doing this, something really bad happened: I broke one of my KVM switches by accident. My working environment employs two KVM switches with each connected to one monitor, and a total of 6 computers that are somehow connected to these KVMs. One KVM switch, which is not the one I destroyed, is an 8 port switch with analog video signal (i.e. VGA) which all of those 6 machines are using for analog video output. This KVM is connected to one of my two workplace monitors via VGA. The other one (the one I broke), a 4 port switch, uses digital video (i.e. DVI) and is connected to the other monitor via DVI. So only the four most decent of those 6 computers are connected to this KVM switch, so these four out of six computers can be run in a multimonitor setup and the other two ones, which are rarely used and sort of vintage, are run in a single monitor setup using only analog video output via the 8 port switch.
In case you don't know: KVM is an acronym for "Keyboard-Video-Mouse". A KVM switch is a device that allows to connect multiple computers with their video output and their keyboard and mouse input to exactly one monitor, keyboard and mouse. For a dual monitor setup, you need two KVM switches with one of them switching keyboard and mouse in addition to the video signal. KVM switches allow you to switch channels or ports so different computers attached to the switch can be made the ones whose video output is shown on the monitor and that receive keyboard or mouse input.
For some reason, I virtually managed to physically destroy the push buttons at the front of the 4 port KVM. Maybe the KVM was leaning with the front side turned down and two much pressure broke the push buttons. The next image shows how this KVM looks like:
So what can you do, if the push buttons of a KVM switch do not work anymore? I opened the case of the KVM and tried the push buttons without the case and soon realized that channels cannot be switched anymore using them, at least the push buttons for channel 1 and channel 2 were dead as nails. I reassembled the KVM and began to think: "Isn't there always a keyboard key combination that switches channels from a keyboard?". And yes Virginia, there is one for this KVM switch: You need to press Scroll Lock twice, followed by the enter key. So this shouldn't be a problem, right? Just hit Scroll Lock twice followed by the enter key once on the keyboard. Nope: My keyboard for all of those 6 machines is not connected to the 4 port switch, but instead to the 8 port switch, because otherwise the two vintage computers enjoy no keyboard support! So I quickly attached a small size USB keyboard to the 4 port switch and tried if I can use this in the interim for switching ports on the 4 port switch - and it worked. The next image shows this small keyboard hidden under one of the monitors:
While this works, it is really cumbersome to always exactly hit scroll lock twice, followed by a single press of the enter key and it admittedly looks really ugly. A better solution had to be found...
I remembered that something like 12 years ago or so, I bought a couple of Teensy devices and two foot pedals. At that time I used my first bunch of tablet devices running Windows 8 which I thought could make up good digital replacements for paper sheet music that I could use during rehearsals or gigs to demonstrate my uniqueness and technical avantgarde. The problem with having music sheet pages displayed on a tablet device while playing is this: You cannot switch forth and back between pages easily while using both hands to play your instrument, so my idea back then was to implement a USB keyboard with a Teensy device and two foot pedals which would send a Page-Up keystroke or a Page-Down keystroke when pressed. For some reason this project never came to life and I have long since disbanded the stupid idea of playing music from a computer screen. Paper based music sheets are so much more flexible after all.
This is what such a teensy device looks like, in my case it is a quite out-of-date Teensy 2.0 device:
The Teensy has a mini USB port that is used both for programming it via the Arduino IDE and for its operational use when it is programmed to act as an HID (human input) device, namely as a USB keyboard. First of all I quickly soldered two pin header rows to the Teensy board in order to plug it into a breadboard, adding a 10 kOhm pull-up resistor and the foot pedal switch. This is how the breadboard design looks like:
You can see that heavy-duty foot pedal switch to the right of the breadboard. The code I used to program the Teensy is pretty darn simple:
}
The foot pedal switch has its contacts closed when in its normal position, but opens the contact, if the pedal is pressed. So all the code does is detect the event when PIN_D7 is raised from GND (0V) to +5v DC via the 10 kOhm pull-up resistor and then it executes the function PressScrollLock twice and the function PressEnter once. Both functions do what their names suggest: They press and release their respective keyboard key with an arbitrary delay of 100ms inbetween. DISCLAIMER: I know I could optimize this code, it is not DRY, but that was not the point of this experiment.
Having this breadboard design was fine and after attaching it to the KVM it actually worked instantly, I could switch KVM channels via the foot pedal switch, hooray! But having a breadboard design on my desk was none the better than the interim approach using the small USB keyboard. So I quickly soldered the Teensy with its pin header rows and the pull-up resistor onto a somewhat larger hole-matrix board along with the connectors to the foot pedal. I chose an old DRAM package plastics case where everything would fit in quite neatly:
Some glueing later this piece of hardware looks like this:
Looks quite nice, doesn't it? But it only gets better: The complete device with the casing closed with the help of two wire straps looks like this:
Doesn't that look almost... professional?
And as a final picture this one: it shows how the switch is sitting on my desk at the same position as the small USB keyboard before. Definitely an improvement and worth spending an otherwise boring new year eve's afternoon.
]]>
automake, patch, perl, dos2unix, make, makedepend
You can download the full list of components in my cygwin installation here.
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".
In the following I assume that cygwin is installed into c:\cygwin64. In case your installation directory is different, set an environment variable named "CYGWIN_PATH" that points to your installation directory of cygwin prior to invocation of my build scripts, or edit the file named createcfg.bat among the script files in the zip for this article and set the value of "INTERNAL_CYGWIN_PATH" in this file to your cygwin installation path.
I further assume that the NDK that comes with Visual Studio 2022 is installed in c:\Microsoft\AndroidNDK\android-ndk-r23c. In case it is someplace else, set an environment variable named "OPENSSL_ANDROID_NDK_ROOT" that points to your NDK installation prior to invocation of my build scripts, or edit the file named createcfg.bat among the script files in the zip for this article and set the value of "INTERNAL_OPENSSL_ANDROID_NDK_ROOT" in this file to your NDK installation path.
In order to build version 3.1.4 of OpenSSL for Android first download this zip file containing my scripts onto your Windows box with Visual Studio 2022 and the native Android build tools installed. Unpack the file into a directory and a subdirectory named "androidopenssl3.1.x" will be created. Open a command prompt and navigate into this directory. Now download version 3.1.4 of OpenSSL here (in case this link doesn't work, try this one which should point to the archive of old builds) and copy it into that directory as well.
After all that, run the build.bat batch file within the command prompt and sit back. On my Ryzen 5 5600X it takes something like 25 minutes to build the whole shebang. You will find 4 subdirectories (arm, arm64, x86 and x86_64) for the 4 supported processor architectures that each contain a directory with the name of the openssl file name (without the extension tar.gz, so in case of version 3.1.4 of OpenSSL this directory name is "openssl-3.1.4"). Within that directory you will find libssl.a and libcrypto.a built for the corresponding processor architecture.
In case you would want to build dynamic libraries as well, edit the file buildplatform.sh and remove "-no-shared" from the configure options.
And finally: If you want to build a newer version of OpenSSL than 3.1.4, download its tarball into the directory where you unpacked the build scripts and change the value of "OPENSSL_VERSION" in createcfg.bat from "openssl-3.1.4" to the name of your tarball (but without the extension ".tar.gz"). Do the same for "ANDROID_API" (which is set to the value 23 in my scripts) if you want to target a different Android API version than 23.
The license for these shell scripts of mine is the same as for OpenSSL, so nothing should change for you.
]]>
chmod +x build.sh
in this directory followed by
./build.sh
In case you want to build a newer or different version of OpenSSL 3.1x, edit build.sh and change the value for OPENSSLVERSION on line 4 which currently looks like this:
OPENSSLVERSION=openssl-3.1.3
Change this line to the file name of your tarball without the trailing .tar.gz extension.
I do not know if these scripts also work on an ARM based Mac, I am still working with an Intel based Mac running Mac OS Ventura with XCode 14.3.1. These scripts only build libraries for the two remaining processor architectures relevant for iOS/iPadOS today: x64 and arm64.
The license for these shell scripts of mine is the same as for OpenSSL, so nothing should change for you.
]]>
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.
In order to use the scripts I have written, follow theses steps:
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
]]>
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.
]]>
The original and official page on the web that I parsed for getting all download links is this.
]]>
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).
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.
In order to use the scripts I have written, follow theses steps:
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".
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.
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.
All the files I have written use the OpenSSL license, so nothing should change for you if you are already using OpenSSL.
]]>