Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undefined symbols using g++-6 on OS X #597

Closed
qianyizh opened this issue Apr 6, 2017 · 5 comments
Closed

Undefined symbols using g++-6 on OS X #597

qianyizh opened this issue Apr 6, 2017 · 5 comments

Comments

@qianyizh
Copy link

qianyizh commented Apr 6, 2017

OS X El Capitan, installed gcc6 and jsoncpp via homebrew:

brew install gcc --without-multilib
brew install jsoncpp

Then build the following code:

#include <json/json.h>
#include <fstream>

int main()
{
    std::ofstream file_out("test.json");
    Json::Value value;
    value["test"] = 1;
    Json::StyledStreamWriter writer;
    writer.write(file_out, value);
    file_out.close();
    return 1;
}

Using command:

g++-6 -g -Wall -I/usr/local/Cellar/jsoncpp/1.8.0/include/ -L/usr/local/Cellar/jsoncpp/1.8.0/lib/ -ljsoncpp ../testjsoncpp.cpp -o test

Error:

Undefined symbols for architecture x86_64:
  "Json::StyledStreamWriter::write(std::basic_ostream<char, std::char_traits<char> >&, Json::Value const&)", referenced from:
      _main in cczWVuKc.o
  "Json::StyledStreamWriter::StyledStreamWriter(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)", referenced from:
      _main in cczWVuKc.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

Note:

  • Using Apple LLVM 8.0 works fine, e.g.,
g++ -g -Wall -I/usr/local/Cellar/jsoncpp/1.8.0/include/ -L/usr/local/Cellar/jsoncpp/1.8.0/lib/ -ljsoncpp ../testjsoncpp.cpp -o test
  • g++-6 on Ubuntu 16.04, with jconcpp 1.7.2-1 (acquired via apt-get) works fine.
  • If Json::StyledStreamWriter related stuff were removed from the code, it works fine.
  • Installed gcc-5 on OS X. Same issue.
@cdunn2001
Copy link
Contributor

StyledStreamWriter is deprecated, but not yet removed. This should work. Something else is going on. Can you try a few more versions?

Best guess: some preprocessor macro is different when you compile from when brew compiled the library.

@qianyizh
Copy link
Author

qianyizh commented Apr 6, 2017

Some updates:

A. I replaced Json::StyledStreamWriter with <<.

#include <json/json.h>
#include <fstream>

int main()
{
    std::ofstream file_out("test.json");
    Json::Value value;
    value["test"] = 1;
    file_out << value;
    file_out.close();
    return 1;
}

Got similar error:

Undefined symbols for architecture x86_64:
  "Json::operator<<(std::basic_ostream<char, std::char_traits<char> >&, Json::Value const&)", referenced from:
      _main in ccaQgzGV.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

B. If I build jsoncpp from source with g++-6, then link to the library. It works fine.
But if I build jsoncpp from source with llvm, then link to the library, it breaks.

My current guess is that by default, llvm and g++-6 use different compiler settings. And the iostream related stuff is very suspicious.

But I could not find out the exact thing that causes the conflicts.

I did this (install libraries using brew/compile with llvm, then build code with g++-6 and link to the library) for other libraries include glew and glfw. They all work fine. Jsoncpp is the first library for which I encountered this problem.

@qianyizh
Copy link
Author

qianyizh commented Apr 6, 2017

Update:

I think it is the conflict between libc++ and libstdc++ when using std::ofstream & as a function parameter.

I tried to build a minimal library with only one function:

#include <iostream>

void test_stream(std::ostream& out) {
    out << "test" << std::endl;
}

And an app that uses this library:

#include <iostream>

void test_stream(std::ostream& out);

int main()
{
    test_stream(std::cout);
    return 1;
}
  1. Compile both library and app with llvm, no problem.
  2. Compile both library and app with g++-6, no problem.
  3. Compile library with llvm, compile app with g++-6, link error.
  4. Vise versa, link error.
  5. Give "-stdlib=libstdc++" to llvm, then it suddenly becomes compatible with g++-6.

However, to solve my problem. I need to either let g++-6 link to libc++, or let brew build with "-stdlib=libstdc++". Both I don't know how to do it.

@cdunn2001
Copy link
Contributor

That's great detective work. But what can we do about it?

@qianyizh
Copy link
Author

qianyizh commented Apr 7, 2017

There are some discussion on stackoverflow too:
http://stackoverflow.com/questions/12542971/using-libstdc-compiled-libraries-with-clang-stdlib-libc

In general, it is bad practice to mix libraries linked against libc++ and libstdc++, since they are implemented differently. As brew and OSX llvm by default links everything to libc++, the easier workaround is to force gcc to link with libc++.

This is done with:
http://libcxx.llvm.org/docs/UsingLibcxx.html#using-libc-with-gcc
It's a lot of compiler flags. But it works for me. So I am okay with this workaround for now.

I think we can close this ticket. The information here should be sufficient for someone to figure out a workaround if he encounters similar issues in the future.

@cdunn2001 thanks for the help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants