find_library does not find stdc++fs

I have the following:

$ find /usr -name '*stdc*'
/usr/lib/gcc/x86_64-redhat-linux/10/32/libstdc++.a
/usr/lib/gcc/x86_64-redhat-linux/10/32/libstdc++.so
/usr/lib/gcc/x86_64-redhat-linux/10/32/libstdc++fs.a
/usr/lib/gcc/x86_64-redhat-linux/10/libstdc++fs.a
/usr/lib/gcc/x86_64-redhat-linux/10/libstdc++.so
/usr/lib64/libstdc++.so.6
/usr/lib64/libstdc++.so.6.0.28

Yet:

find_library(STDCPPFS_LIBRARY NAMES stdc++fs)

tells me “not found”. What can I do ? I cannot hardcode paths as I want that code to work on any Linux distro. I cannot just do a blanket add of target_link_libraries(stdc++fs) because more recent distros / toolchains / … don’t have it, which causes link errors.

I’m not sure why you’d be wanting to find this particular library. I’d expect the compiler would find the right one if you linked to stdc++fs. Either of the following should work:

target_link_libraries(SomeTarget PRIVATE stdc++fs)

To answer your question more directly, find_library() won’t be looking in any of the directories where you have a libstdc++fs.* file. You’d have to provide it with hints, but really I’d be looking to let the compiler provide it on its own with the default linker search path.

You would need to provide the logic that works out whether libstdc++fs.* needs to be linked rather than simply relying on whether you can find such a library or not. That probably means logic that only links it for specific version ranges of specific compilers. For example, cppreference.com contains the following note near the bottom of that page:

Using this library may require additional compiler/linker options. GNU implementation prior to 9.1 requires linking with -lstdc++fs and LLVM implementation prior to LLVM 9.0 requires linking with -lc++fs.

I’m not sure why you’d be wanting to find this particular library.

Well, because on some platforms it’s there and on others it’s not and I need my code to work on all these platforms. For instance when I compile with libc++13 under Linux there isn’t any such library as the feature has been merged within libc++ directly.

Shouldn’t cmake guarantee that I can use std::filesystem without issue ?

Also

target_link_libraries(SomeTarget PRIVATE stdc++fs)

does not work, here it tells me that it does not find the library when linking on systems without that lib (linux with a clang/lld toolchain):

ld.lld: error: unable to find library -lstdc++fs

See the part I quoted earlier for clang/LLVM:

You may find CMAKE_CXX_COMPILER_ID and CMAKE_CXX_COMPILER_VERSION useful in working out if and which library you need to link to.

That is when using libc++, I’m still using libstdc++ in some case. (And CMake does not provide an easy way to tell which standard library is being used).

But again: is this an official CMake position that it’s not possible to simply have <filesystem> just work without having to ifdef for every {gcc / clang}x{libc++,libstdc++} version under the sun ?

filesystem is now part of C++17 standard, so it can be used without any special flags on compile or link steps for compilers supporting this standard.

In my opinion, it is too costly (and useless) to try to support, in CMake, compilers offering a non-standard way to use filesystem. Moreover, various compilers, before C++17, offers only a partial or buggy filesystem implementation.

Sorry for resurrecting this old thread but I’m also struggling with this problem. I’ve been getting along so far with a large hierarchy of compiler id and version testing, but I’ve got a new twist. Cray’s Clang-based compiler and ICC Clang front end both show up with a complier ID of “Clang”, but Cray’s Clang version 12 requires stdc++fs, Apple’s Clang 12 won’t accept it. Debian’s Clang package could go either way. Is there any other way to distinguish which Clang I’m using or a way to find libstdc++fs?

@ben.boeckel @brad.king @chuckatkins Do you folks know if there is a secondary variable that would differentiate these different Clang variants? I don’t have access to Cray or ICC Clang to check.

Is that just due to which version of Debian you are using (so, just which Clang version)?

Intel’s Clang frontend should be IntelLLVM. I suspect a new ID will be required for Cray clang (especially if its versioning differs from upstream Clang).

It’s “Debian clang version 11.0.1-2”. By “can go either way” I mean it doesn’t require stdc++fs, but if I pass -lstdc++fs it doesn’t complain either.

As an answer to the original question, I found this “FindFilesystem.cmake” script. So, so I don’t need Clang variant divination anymore.

The HPC I’m trying to build on comes with CMake 3.17, so I apologize if this has been fixed. The default CC in PrgEnv-cray shows up in CMake as “Clang”. The version string is “Cray clang version 12.0.3”.

The only thing weird about it I’ve come across is that it requires -lstdc++fs to use std::filesystem.

This requirement comes from the version of the GNU libstdc++ in use. Early implementations of std::filesystem were kept out of the main -lstdc++ that the compiler driver links by default in order to avoid committing to a stable ABI immediately. Instead one must explicitly link -lstdc++fs to get those symbols. Newer versions of libstdc++ have the symbols integrated.

There are some FindFilesystem scripts out in the wild that try to hide this distinction. Upstream CMake never gained one to avoid permanently maintaining infrastructure only needed for a transitional period.

I’m familiar with the history of the library. What’s specifically weird is Cray’s Clang 12 requires it when Clang’s documentation says it’s only required in Clang 9 and my experience with many other versions and variants doesn’t contradict that clam. It’s like Cray went out of their way to extend the transitional period.

Clang docs are probably talking about libc++. If Cray is using an older libstdc++, even newer Clang would need to link AFAIK (though a link to the docs in question would help).