2022-04-22

ansak-string, ansak-lib and packaging sqlite

Six years ago, I went for a holiday with my wife, just the two of us -- pretty much the first such holiday (measured in weeks, not week-ends) we had taken since our first child was born. It wasn't off to some sun-soaked beach -- we've never been that kind of couple -- but we had a wonderful time, camping (not glamping), hotelling, time-share-condo-ing, eating out etc. Along with spending time together, we each did some of "our own" things, too, together in silent (or not so silent) companionship and not. I spent a bunch of time reading, some time biking and some time writing software. Like I do for work. Only this time, it was for me. I joked to myself that I was prepping for a "retirement project" and maybe I was. We'll have to see how that turns out but for the moment, I had a lot of fun.

When I got back, in talking about it with a colleague, I immediately got side-tracked: his response regarding one part (a simple API for re-encoding strings between wide and narrow) was, "Oh! we need that. Can you package it?" So, I made some modifications to the repository, and to the CMake script to enable that -- a lot of it was sequestering away everything but the string library so that all they got was what they really wanted. And so I discovered, that even for my own software, if you're not careful, a long line of "yaks" will show up in need of "shaving". It took over some of my free time for awhile but I was able to deliver something they could use, and then nothing more came of it. Some work-churning that followed diverted me still further and it took awhile to get back to it. But this month, I think the yak-shaving has come to something of an end.

I could spend some time describing the different yaks, but I want to point out a yak-razor-forge that I designed for myself, that took care of a bunch of them, and could be useful to others. About six months ago, I asked my brother (a network tech, not a developer) to try my stuff out. His first response was, "why can't I ./configure, make, and make install it?"

That "ancient" paradigm of "download -- ./configure -- make -- make install" has served open source projects well for deployment, at least for the consumers of the tarballs constructed to be deployed that way. For producers, especially those of us who came to it later in the game, the autoconf and automake tools that support it are bewildering. Learning to use them well, and then using them repeatedly for oneself can be daunting. And then, it's not even much good on a non-Cygwin, non-msys2 Windows environment. But the paradigm, for the end user at least, is wonderful.

The kind of code I was writing was platform-independent C++11 (and I'm loving the continuing updates) with few package dependencies on other things, so a full autoconf/automake approach was wrong-headed anyway. Yet, for deployment on Linux, MacOS, Cygwin and msys2, the result of such an approach made a lot of sense, even if one arrived at it by other means. So I wrote my own minimal configure script that determines the platform, chooses a few defaults for things and then writes them into a file that the Makefile includes.

The Makefile is very simple, mostly a cmake dispatcher, as that was one of my early choices. By the way, if I am missing out on a better cross-platform meta-build system, somebody please tell me? So far cmake is making my life very easy and making me feel smarter than I really am every time I poke at it.

But on Windows, not even a marginally good GNU make is available by default, or where it is, it doesn't interoperate well with other parts of Windows, to my knowledge. As for the end result, there really isn't a "standard place" to put 3rd party headers and libraries -- at least to my knowledge and in wide-spread use. So, I decided to use a default prefix (and allow it to be over-ridden) of C:\ProgramData -- it seemed an easy call to me, and I have seen some feints in that direction. Sub-directories from there of include\, lib\ and bin\ seemed logical, too. And as for a "make" stand-in, remembering Dave Beazley's "Discovering Python" video, the choice there was obvious, too: python. I did give PowerShell a shot on the way there but at the end of the day? No comparison.

Once I'd decided to use python, the choice between python 2 and python 3 was also obvious (for feature-set if not for the Jan 2020 sunset of python 2) but how to make sure of that? And how to run things as, "download -- .\configure -- make -- make install"? So I wrote a configure.cmd that looks for python, makes sure it's python 3 (in a python-version-independent way) and calls configure.py. Before that script completes, it writes a make.cmd file that uses the python 3 that was found for configure.py to run a make.py. That script imports the configvars just produced to influence how it should do what it wants to do -- in the same way as the Makefile does.

On the non-Windows side, by this time, with help from a good friend, I had been using CPack inside cmake to produce tarballs, RPMs, Debian packages and arch ZST files. CPack will also produce NSIS installers automatically, but it struck me that they were aimed at applications, not libraries (and so far, I'm writing libraries). So I wrote my own NSIS installer scripts, too. make package on Windows produces one of those.

After completing the work for ansak-string, I extended it to ansak-lib as well. When I got around to doing the Windows work I ran into another dependency issue. I intend to use sqlite3 (props to D. Richard Hipp for this excellent resource) for my back-end storage and I have some C++ classes wrapping it. Checking for SQLite3's existence at build time is too late. Downloading and "installing it" to where I want it during configure for ansak-lib wasn't hard manually, but the more I tried to accomplish it automatically, the messier it looked. I hit on a cleaner solution, alongside ansak-string (the original shave-off I did for my mates at work) ansak-lib (includes the sqlite3 C++ classes). I produced a sqlite_msvc_packager that uses the same "download -- .\configure -- make -- make install" cycle.

So there it is: a packaging solution for Sqlite3 and a couple of libraries you might find useful (especially this means of reading files of lines of text -- any width, any ordering -- as though they were lines of UTF-8 text). But even more useful, perhaps is the meta-facility I developed and described above: a flexible way of deploying libraries, either directly (make install) or through install sets -- and Python3 helped me bring it all to Windows, too.