Search code examples
c++boostlinkerg++linker-errors

Boost::filesystem::directory_iterator causes linker error after upgrade to v1.78.0


I want to use boost::filesystem in my project, and until recently this was possible (v1.65.1). A few days ago, I had to upgrade my boost installation to 1.78.0 and followed the instructions on the site to build the library from source. I executed the following lines:

wget https://boostorg.jfrog.io/artifactory/main/release/1.78.0/source/boost_1_78_0.tar.gz

tar xzvf boost_1_78_0.tar.gz

cd boost_1_78_0/

./bootstrap.sh --prefix=/usr/

./b2

sudo ./b2 install

The test code from boost utilizes boost's filesystem functions. Compilation is fine, but the linker throws an error (see below).

Code

#include <iostream>
#include <boost/filesystem.hpp>

using std::cout;
using namespace boost::filesystem;

int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        cout << "Usage: tut3 path\n";
        return 1;
    }

    path p(argv[1]);

    try
    {
        if (exists(p))
        {
            if (is_regular_file(p))
            {
                cout << p << " size is " << file_size(p) << '\n';
            }
            else if (is_directory(p))
            {
                cout << p << " is a directory containing:\n";

                for (directory_entry const& x : directory_iterator(p))
                    cout << "    " << x.path() << '\n';
            }
            else
                cout << p << " exists, but is not a regular file or directory\n";
        }
        else
            cout << p << " does not exist\n";
    }
    catch (filesystem_error& ex)
    {
        cout << ex.what() << '\n';
    }

    return 0;
}

Compilation and linker commands (generated by eclipse)

g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/main.d" -MT"src/main.d" -o "src/main.o" "../src/main.cpp"
g++  -o "test"  ./src/main.o   -lboost_system -lboost_filesystem

Error

./src/main.o: In function »boost::filesystem::directory_iterator::directory_iterator(boost::filesystem::path const&, boost::filesystem::directory_options)«:
/usr/include/boost/filesystem/directory.hpp:326: Warning: undefined reference to »boost::filesystem::detail::directory_iterator_construct(boost::filesystem::directory_iterator&, boost::filesystem::path const&, unsigned int, boost::system::error_code*)«
makefile:45: recipe for target 'test' failed
collect2: error: ld returned 1 exit status
make: *** [test] Error 1
"make all" terminated with exit code 2. Build might be incomplete.

If I remove the line containing the boost::filesystem::directory_iterator the linking works. I am not sure how to fix this. I initially thought that the old version of boost might interfere, as it still resides within /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1, but when checking the version included in the file, it shows the newer version.

What is happening here?

SOLUTION

In the end, I removed both the original installation as well as the new version and reinstalled the packet under /usr/local. A quick walkthrough to help somebody encountering the same problem:

// remove the dirs under <prefix>/lib/libboost* and <prefix>/include/boost* first
sudo apt purge -y libboost-all-dev libboost*
sudo apt autoremove

// then either install the package via the manager or copy the sources to /usr/local/ or another suitable place
sudo apt install libboost-all-dev    // option with aptitude

Solution

  • The includes are compile time. The shared libraries are linked at link time.

    You didn't explicitly tell the to find the headers, nor did you tell the compiler where to locate the libraries. This means that the standard locations are used.

    Depending on your package manager there may be symlinks like:

    /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1
    /usr/lib/x86_64-linux-gnu/libboost_filesystem.so -> libboost_filesystem.so.1.65.1
    

    It is generally a bad idea to overwrite parts of installed packages with your files. Not in the last place because e.g. such symlinks might not be updated, or if they are they might break a lot of dependencies that you have installed.

    In general, prefer to use a safe prefix (/usr/local e.g.) or build locally and indicate the include/library directories in your build tool, like Eclipse, or on the command line like:

     -I ~/custom/boost_1_77_0/ -L ~/custom/boost_1_77_0/stage/libs
    

    An advantage of choosing /usr/local is that many distros support it and might have it added to the runtime loader's path (see ldconfig).