Building on Boost with ICU statically on Windows using MSVC does not link against the static ICU libraries; instead it links always against the ICU DLLs.
Years after reporting this to the Boost.Locale bug tracker, and asking on the Boost users mailing list, I decided it’s time to make a step forward, as it seems, no one has an answer.
Tracking down the problem and fixing it was not easy. I spent a considerable amount of time, primarily because Boost’s Jam syntax and capabilities were new to me, so I had to learn it … well at least enough to get on with the actual problem.
Looking at the jam build scripts of the Boost libraries that use ICU, i.e. Boost.Locale and Boost.Regex, it became apparent that there was no detection code for the static ICU libraries. This of course is not explicitly mentioned while building and I found no indication of this in the documentation. It’s unlikely many users even notice, until they attempt to use it for statically linking their executables. Certainly there must be a reason behind this, but from what I understand it has to do probably with ICU’s past.
Ok, so knowing where the problem was, I felt I was making progress.
I hacked quickly into the respective Jamfiles the necessary support for the static ICU libraries, which are named sicuXX.lib for release and sicuXXd.lib for debug. However, despite my best efforts to pass the libraries to the linker the resulting static Boost.Locale and Boost.Regex contained no trace of ICU. I went to the Boost IRC channel on Freenode and asked, but nobody quite knew what’s wrong. Nevertheless, I got a bit of extra info on how to debug Boost.Build scripts (many thx to jhunold & grafikrobot!). I added on my b2 command line -d +2
, which enabled me to see what is passed on the linker. Clearly, the MSVC linker was never aware of the ICU static libraries, despite adding the right <linkflags>
feature for the linker.
I decided to dig deeper. I searched through the msvc toolset code of Boost Jam (in boost_src/tools/build/src/tools/msvc.jam) and there you had it:
l.1174: toolset.flags msvc.archive .LD$(api)/$(cpu-conditions) : $(setup-script)$(linker) /lib /NOLOGO ;
That means the library is build using the msvc.archive, not the msvc.link. What does msvc.archive is using then?
l.1482: toolset.flags msvc.archive AROPTIONS <archiveflags> ;
Aha! So msvc.archive is using the <archiveflags>
feature and not <linkflags>
as the msvc.link does! That’s typical on unix environments, when statically linking, I should have thought of it earlier! Unfortunately, this is not documented in the Boost.Build documentation either. Once I switched to <archiveflags>
for the static libs and rebuild the Boost.Libraries I got these sizeable .lib files that were a good indication that the ICU code was included. I looked at the build log and it was clearly there: the various sicuXX.lib files were passed properly to the linker this time.
I hacked together a test case and compiled it against the freshly build static Boost.Regex, and there you have it. A static binary that can be run without requiring further ICU linking and have no other dependencies whatsoever!
I hope the Boost maintainers of the respective Boost Locale and Regex libs will eventually be able to polish and integrate this into upstream Boost. Boost is understaffed and the maintainers can’t keep up with the load of fixing bugs and adding features. It’s clear, don’t blame them; I don’t. My patch is not clean right now, because it uses my own custom Precompiled ICU libraries, that link against static runtimes (/MT). To go upstream it would at least require that my changes are nicely integrated into the existing Jamfiles. Maybe I find some time and do that too. In the meantime, you can find Boost with ICU and Python support in my Precompiled Boost page; complete with patches, built instructions and a batch file to use to build Boost yourself, if you don’t like my builds.
I shall not forget to thank the Boost developers for handing to the world one of the most advanced C++ libraries around. Thanks!
Enjoy!