Skip to content →

Updating the Lucena Utilities Library for C++17, Part 1—Determining Supported Configurations

This is the continuation of a series on the Lucena Utilities Library (LUL).

Today, I’ll outline some requirements for the Library, and then discuss supported configurations.

C++17, Build Systems, and More

As a tool intended to be picked up by new projects and used over the course of years, it is sensible to focus on C++17 as a baseline. Supported platforms are assumed to have fully-compliant C++14 implementations and build with C++17 as the target dialect. LUL will focus on smoothing out the behavior of non-conforming compilers and incomplete implementations, providing aliases to equivalent compiler extensions, reference Standard Library and Technical Specification (TS) implementations where possible, and documenting hopeless cases where they exist. For practical reasons, the cutoff for earliest-supported compilers will be very recent; legacy support for older compilers will be dropped to avoid the testing and support burden (also, LUL was not previously publicly released, and all current client needs are well-known).

Now for some technical details:

Direct compiler support is provided for Microsoft Visual C++ (MSVS 2017 5.7+), Apple LLVM 9.1+ (Xcode 9.4.1+), and gcc 7.2+. GCC support could reasonably be rolled back to 6.3, but since anything post-4.9 annihilates our current in-house use cases, we may as well go with something more forward-looking. clang 6+ could be trivially adapted from the Apple LLVM cases, but no test facilities are set up, mostly because not even the BSDs seem to be using it, yet. Support for other compiler setups (e.g., minGW) has been dropped for the time being. [Update: The Xcode minimum will likely be bumped to 10.0+—once it’s released—in order to pick up proper native support for <any>, <optional>, and <variant>, as well as std::is_invocable (as opposed to the defunct std::is_callable). This will eliminate the last of the non-native C++17 Standard Library reference implementations, allowing us to finally require C++17 as a baseline requirement. An unfortunate side effect of this change is that it will probably establish a minimum requirement of macOS 10.14+ or iOS 12.0+ for Apple platforms; the reasons for this are discussed in a later blog post. Note that the other compilers have already had their minimum versions bumped to reflect this objective; direct testing has been supplemented and guided by these helpful tables on cppreference.com.]

Default Standard Library implementations are supported for each compiler; it would not be terribly complicated to add additional support if there is demand. Supported target OS’s currently include 64-bit macOS (10.13 SDK, x86_64), 64-bit Windows 8.1+ (x86_64 or equivalent), 64-bit Linux (Ubuntu 17.10 or equivalent, x86_64 or equivalent), and 64-bit iOS (11.2 SDK, Apple A8). Supported build systems are those of the host IDEs on macOS and Windows, and CodeLite’s make derivative on Linux; support for Autotools is unlikely, but support for CMake is a possibility. Note that build system “support” entails configuration files (e.g., .xcconfigs, .props, etc.) that can be added to a project component-wise. At this time, LUL requires a particular directory structure as a side effect of avoiding preprocessing scripts. Mitigating this will be the topic of a future blog post.

Justification

The baseline specification probably seems a bit hand-wavy. It is. The purpose of a library like this isn’t to provide, for example, all the benefits of running C++2a in a C++14 compiler, but to provide as many of the benefits as possible of running a fully-compliant C++17 implementation in a not-quite-compliant C++17 compiler. As such, we’ve picked most-of-the-way there, commonly accessible environments as the basis for this foundational library. Expect minor improvements and fixes, but also expect this version to be gutted when the next technology shift occurs, just as happened with the C++11 and C++14 versions. Teams requiring the old version for use with their old compilers targeting old tech will still have access to it, but backwards compatibility is a non-goal for LUL.

Explicitly, entire libraries and applications are expected to be built on top of LUL. Generally, once a build environment is chosen for a major project, it doesn’t—or shouldn’t—change. If the project survives long enough for a major rewrite, changing out a foundational piece might be perfectly acceptable depending on the project objectives, and if it isn’t, the old version is still there. This is not to say that future versions will go out of their way to introduce breaking changes, but if Modules or a standardized C++ ABI ever happen, things could change quite a bit.

Selecting LUL is mostly about avoiding having to research and write all the tests yourself if you wish to use a recent C++ dialect and its support libraries on a popular platform. It’s also designed to have minimal impact on compile time and code complexity. If you need to support older compilers or more diverse platforms, something like Boost.Config may be more appropriate.

Conclusion

With the basics out of the way, future entries in this series will focus on design changes to the Library and their related implementation changes. The focus will primarily be on the impact of the failed predictions mentioned at the start of this post—namely standardized feature detection, support for Modules, and the development of a universal C++ ABI—and how we will work around them, or continue to anticipate them.

[Update: added references and requirements changes, aka the Links-and-Pedantry Update]

Published in Programming Projects