CMake's equivalent of AC_SEARCH_LIBS (to find std::filesystem)?

In autotools one can do the following for example:

AC_SEARCH_LIBS(clock_gettime, rt)

which will add the -lrt flag only when it’s available and needed. (I’m not claiming that my statement is 100% exact, but this one-liner performs a set of tests and as a consequence works across a very wide range of operating systems, compilers and standard libraries and either adds the flag or skips it.)

I would like to use a similar functionality in CMake to figure out whether or not I need the flag -lstdc++fs to use std::filesystem (with a C++17-capable compiler). There’s an existing thread in Correct way to link std::filesystem with GCC 8?, but the accepted solution link_libraries( "$<$<AND:$<CXX_COMPILER_ID:GNU>,$<VERSION_LESS:$<CXX_COMPILER_VERSION>,9.0>>:-lstdc++fs>" ) sounds like a nightmare if I also want to properly support all the compilers and different standard libraries (libc++, stdlibc++). It sounds fine for gcc, but one needs to do the same for clang and who-knows-which-other-compilers. Another solution uses 60 lines of code to achieve roughly the equivalent of what autotools do with a single line.

What I would really like to achieve is the following:

  • try to compile with the -lstdc++fs flag
  • try to compile without the flag

(I don’t care in which order) and provide feedback about the option that works correctly for std::filesystem, without having to provide tons of hardcoded knowledge about various compiler and operating system versions (that require, don’t require or refuse to work with that flag).

In this particular case I don’t want to care too much about really old compilers, but supporting gcc 8 (for Debian and Ubuntu) is still somewhat unavoidable, and I definitely need support for clang on various operating systems.

1 Like

It seems like there is an ongoing discussion on whether this is something that should be addressed in upstream CMake and if so how. So unfortunately, there is no “correct” solution provided by CMake and for now every project has to come up with their own approach to solve this.

IMHO a reasonable and well working approach is to use a FindFilesystem module like this one. Simply save it somewhere in your project (commonly a cmake/ directory) and prepend that path to CMAKE_MODULE_PATH in order to use it. The module performs several check_cxx_source_compiles() checks (+ 1 hard-coded special case) to figure out which flag is required and then provides and interface target as an abstraction that can be used like this:

find_package(Filesystem REQUIRED)
target_link_libraries(myLib PRIVATE Filesystem::Filesystem)

This approach is analogous to the FindThreads module with its Threads::Threads target provided by CMake.

Awesome, thank you. I took the original module and that one works fine even with gcc 7.

I keep my fingers crossed that CMake will eventually include some useful code into the codebase to better support this library.

Of course I’m still curious how to generally solve this with other libraries when there’s no-one to write those 250 lines of code for you.

Most other libraries don’t have a different way of linking to them for each compiler/toolchain; you just find_package, pkg_check_modules, or create some IMPORTED targets out of find_library calls yourself.

It’s rather ironic that the standard filesystem library is one of the most inconsistent across compiler vendors.

The point is that different OSs might place a function in a differently named library; e.g. standard C library functions dealing with complex numbers might end up in libc, or in libm, there is no telling without actually checking each particular OS, whereas autoconf would allow creating a universally valid test.