experimental::filesystem linker error
Asked Answered
P

6

129

I try to use the new c++1z features actually on the head of development within gcc 6.0.

If I try this little example:

#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
    fs::path p1 = "/home/pete/checkit";

    std::cout << "p1 = " << p1 << std::endl;
}

I got:

/opt/linux-gnu_6-20151011/bin/g++ --std=c++1z main.cpp -O2 -g -o go
/tmp/ccaGzqFO.o: In function \`std::experimental::filesystem::v1::__cxx11::path::path(char const (&) [36])':
/opt/linux-gnu_6-20151011/include/c++/6.0.0/experimental/bits/fs_path.h:167: undefined reference to `std::experimental::filesystem::v1::__cxx11::path::_M_split_cmpts()'
collect2: error: ld returned 1 exit status

gcc version is the snapshot linux-gnu_6-20151011

Any hints how to link for the new c++1z features?

Puccini answered 15/10, 2015 at 13:28 Comment(0)
P
214

The Filesystem TS is nothing to do with C++1z support, it is a completely separate specification not part of the C++1z working draft. GCC's implementation (in GCC 5.3 and later) is even available in C++11 mode.

You just need to link with -lstdc++fs to use it.

(The relevant library, libstdc++fs.a, is a static library, so as with any static library it should come after any objects that depend on it in the linker command.)

Update Nov 2017: as well as the Filesystem TS, GCC 8.x also has an implementation of the C++17 Filesystem library, defined in <filesystem> and in namespace std::filesystem (N.B. no "experimental" in those names) when using -std=gnu++17 or -std=c++17. GCC's C++17 support is not complete or stable yet, and until it's considered ready for prime time use you also need to link to -lstdc++fs for the C++17 Filesystem features.

Update Jan 2019: starting with GCC 9, the C++17 std::filesystem components can be used without -lstdc++fs (but you still need that library for std::experimental::filesystem).

Update Apr 2024: starting with GCC 13.3 the std::experimental::filesystem symbols are also available in -lstdc++exp (along with the other experimental definitions, such as a contract violation handler, and std::stacktrace symbols).

Pester answered 15/10, 2015 at 22:42 Comment(15)
Is this documented anywhere, I tried to determine this myself and came up w/ nothing, did I miss some resource here?Feudalize
@ShafikYaghmour, I've just updated the docs: gcc.gnu.org/onlinedocs/libstdc++/manual/… gcc.gnu.org/onlinedocs/libstdc++/manual/… gcc.gnu.org/onlinedocs/libstdc++/manual/… (at the bottom)Pester
When I try to use this I get the same linker error. c++ -lstd++fs main.cpp. I am using gcc version 5.3.1 20151207 (Red Hat 5.3.1-2) (GCC) Herra
ok, -lstdc++fs has to be at the end of the line (after the source file at least). I don't understand why some -lxxx need to be at the end and others don't.Herra
@Herra because that's how linkers work. References are resolved left to right, so you need to list static libraries after the objects that use them.Pester
No problem, the idea was to improve the answer. These comments will be deleted soon.Herra
As reported here, std::filesystem is part of C++17.Newbold
@Newbold but this question is about std::experimental::filesystem (the TS) which is not the same thing. I repeat, The Filesystem TS is nothing to do with C++1z support, it is a completely separate specification not part of the C++1z working draft.Pester
Are you saying that, in trunk, -stdc++fs implements both Filesystem TS, and C++17 filesystem?Antipathy
How about GCC 8.2.1? I just tried, and it seems like GCC 8 still requires -lstdc++fs but it is kind of odd because GCC 8 support full set of C++17. No?Loricate
@HCSF, No, GCC 8 does not support full C++17, and what part of "starting with GCC 9, the C++17 std::filesystem components can be used without -lstdc++fs" is not clear?Pester
My distro doesn't have GCC 9 yet. And I thought GCC 8 supports full C++17, and so I felt strange that -lstdc++fs was still required for a compiler that supports full C++17. That's why I asked. Thanks for clarifying.Loricate
how do I add the -lstdc++fs to my CMakeLists.txt?Operculum
Note that with g++ version 7.5.x and with -std=c++17, it's marked as experimental. So you need the -lstdc++fs trick and the experimental namespace. (that's the default compile on Ubuntu 18.04)Didymous
@AlexisWilke I've clarified the answer to say that the C++17 std::filesystem code is only available from GCC 8, so yes, you need to use std::experimental::filesystem with GCC 7 (whether or not you compile with -std=c++17).Pester
D
59

If you are using cmake, add the following line to CMakeLists.txt:

link_libraries(stdc++fs)

So that cmake can link against the corresponding library.

Dialectologist answered 2/9, 2018 at 13:43 Comment(2)
I did target_link_libraries(hello_world_ stdc++fs) and it compiled.Yenyenisei
target_link_libraries did not work for me in g++-8. This workedAdamok
R
14

With clang 4.0+, you need to link against libc++experimental.a

Make sure you're building with libc++ (not libstdc++) with the -stdlib=libc++ (as mentioned in the comments)

Rover answered 26/7, 2017 at 16:38 Comment(4)
I also needed -stdlib=libc++ because my clang version was unexpectedly using libstdc++.Chiliad
@BowieOwens thanks, updated answer to make that clear.Rover
When you say "make sure you're building with libc++", how do I do this? (Solution preferably with CMake.) . Thanks.Argolis
@Argolis -stdlib=libc++ or set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")Rover
P
7

Here is a demo that might be helpful to someone in the future:

env: el6, gcc/5.5.0

#include <iostream>
#include <string>
#include <experimental/filesystem>

int main()
{
    std::string path = std::experimental::filesystem::current_path();

    std::cout << "path = " << path << std::endl;
}

The following are compiling and testing. The flags are -std=c++17 -lstdc++fs:

$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/apps/gcc-5.5.0/bin/../libexec/gcc/x86_64-unknown-linux-gnu/5.5.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../configure --prefix=/apps/gcc-5.5.0 --disable-multilib --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=all
Thread model: posix
gcc version 5.5.0 (GCC)

$ ls -lrt /apps/gcc-5.5.0/lib64 | grep libstdc
-rwxr-xr-x. 1 root root  11272436 Jun 25 10:51 libstdc++.so.6.0.21
-rw-r--r--. 1 root root      2419 Jun 25 10:51 libstdc++.so.6.0.21-gdb.py
-rwxr-xr-x. 1 root root       976 Jun 25 10:51 libstdc++.la
-rwxr-xr-x. 1 root root  11272436 Jun 25 10:51 libstdc++.so
-rw-r--r--. 1 root root  10581732 Jun 25 10:51 libstdc++fs.a
-rw-r--r--. 1 root root  28985412 Jun 25 10:51 libstdc++.a
-rwxr-xr-x. 1 root root       916 Jun 25 10:51 libstdc++fs.la
-rwxr-xr-x. 1 root root  11272436 Jun 25 10:51 libstdc++.so.6

$ g++ filesystem-testing.cpp -lstdc++fs -std=c++17
$ ./a.out

$ g++ -std=c++17 filesystem-testing.cpp -lstdc++fs
$ ./a.out
path = /home/userid/projects-c++/filesystem-testing

It also works with flags: -std=c++11

$ g++ -std=c++11 filesystem-testing.cpp -lstdc++fs
$ ./a.out
path = /home/userid/projects-c++/filesystem-testing

The follows had compiling error _ZNSt12experimental10filesystem2v112current_pathB5cxx11Ev

$ g++ -std=c++17 -lstdc++fs filesystem-testing.cpp
/tmp/ccA6Q9oF.o: In function `main':
filesystem-testing.cpp:(.text+0x11): undefined reference to `_ZNSt12experimental10filesystem2v112current_pathB5cxx11Ev'
collect2: error: ld returned 1 exit status

Extra Notes:

The following link might be helpful

How to install gcc8 using devtoolset-8-gcc

Pythia answered 27/6, 2018 at 12:8 Comment(0)
T
1

For

dyld: lazy symbol binding failed: Symbol not found: 
__ZNSt3__14__fs10filesystem4path17replace_extensionERKS2_

and

Undefined symbols for architecture x86_64:   
"std::__1::__fs::filesystem::__current_path(std::__1::error_code*)", 
referenced from:      
sys::path::get_cwd() in Path.cc.o
ld: symbol(s) not found for architecture x86_64

.. try the following:

For LLVM clang >= 10, link with libc++.1.0.dylib supplied by LLVM.

add_link_options("-Wl,-rpath,location_of_llvm_install/lib;location_of_llvm_install/lib/libc++.1.0.dylib")

This is not for Apple Clang, but for LLVM clang installed from official https://releases.llvm.org or by a package manager.

Xcode < 11 doesn't have filesystem header. macOS < 10.15 doesn't have std::filesystem::path symbols in the system dylib at /usr/lib/libc++.1.0.dylib

Trier answered 24/11, 2020 at 8:14 Comment(0)
L
0

You can easily try my code online.

//  currentPath.cpp
// https://stackoverflow.com/questions/33149878#65128193
#include <experimental/filesystem>
#include <iostream>
using namespace std;

int main() {
  cout << "path = " << experimental::filesystem::current_path() << endl;
}

Compile and run:

clang++ currentPath.cpp -lstdc++fs && ./a.out # Linux
clang++ currentPath.cpp -lstdc++fs && ./a.exe # MSYS2, Windows

Note: -lstdc++fs is a linker flag, not a compiler flag. (Important when you write a makefile.)

Expected output:

path = "/path/to/the/current/directory"
Livi answered 3/12, 2020 at 14:43 Comment(1)
If you try to compile and run my code, I believe you will see a good reason to upvote my answer. If you do compile and run, and still don't want to upvote, please consider letting my know why in a comment below. - Admittedly, my answer does have similarities with the answer by @caot, but there are also some significant differences. This is why I prefer to publish an answer of my own rather than suggesting edits to caot's answer.Jodeejodhpur

© 2022 - 2024 — McMap. All rights reserved.