1

My code used to copmile well previously, until boost library got updated with changes in asio. In my code, I define a variable: boost::shared_ptr<Face> face(boost::make_shared<ThreadsafeFace>(io_service)); which, as can be seen, takes io_service for the constructor. Face and ThreadsafeFace are a library classes, my app links to. The problem occurs at linking stage of my binary, where I get undefined symbols error:

Undefined symbols for architecture x86_64:
  "ndn::ThreadsafeFace::ThreadsafeFace(boost::asio::io_context&)", referenced from:
      boost::detail::sp_if_not_array<ndn::ThreadsafeFace>::type boost::make_shared<ndn::ThreadsafeFace, boost::asio::io_context&>(boost::asio::io_context&&&) in ndnrtc_client-main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

As can be seen, linker can't find a constructor for ThreadsafeFace that takes boost::asio::io_context& argument. And it won't -- because library does not provide one. The only one library does provide -- is with io_service argument. Now, I don't quite understand, where does this constructor definition come from, as neither my code, nor library's code have this definition.

This makes me think that with new boost (I'm linking against 1.67 using homebrew, macOS), io_service gets replaced by io_context automatically (during preprocessing?), thus leading to the problem.

I tried providing -DBOOST_ASIO_ENABLE_OLD_SERVICES when compiling my code, but it didn't help either.

Shall I downgrade boost version until library gets updated?

UPDATE I've ran clang for preprocessing (clang++ -E ...) and found this in the output:

# 21 "/usr/local/include/boost/asio/io_service.hpp" 2 3

namespace boost {
namespace asio {



typedef io_context io_service;


}
}

Which confirms that all io_service variables will in fact be io_context and guarantee headaches.

peetonn
  • 2,942
  • 4
  • 32
  • 49

1 Answers1

0

"Which confirms that all io_service variables will in fact be io_context and guarantee headaches"

In fact that guarantees no headaches. Typedefs are aliases: they're exactly the same. So io_service becomes just another way to refer to the same type, even if the spelling happens to be different in some spots. This is actually what you need.

Reading the message:

Undefined symbols for architecture x86_64: "ndn::ThreadsafeFace::ThreadsafeFace(boost::asio::io_context&)", referenced from: boost::detail::sp_if_not_array::type boost::make_shared(boost::asio::io_context&&&) in ndnrtc_client-main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

This tells you that ndn::ThreadsafeFace does provide the required constructor, because it's referenced from your code. If it weren't provided, it would have been a compile error, not a link error.

So your problem is different. You either lack a linker input, or the library object you link against was compiled /differently/ in such a way that it doesn't provide the definition of the constructor that is declared when you include the header that declares ThreadsafeFace.

Usually, this happens if namespaces change, or when you (ab)used compiler defines to change the meaning of the code (did you perhaps mess around with something like #define io_context io_service? Because that is a recipe for headaches).

Note linker errors can even result when you use different compiler versions/flags when compiling your code versus when compiling the library.

For far more troubleshooting tips see: What is an undefined reference/unresolved external symbol error and how do I fix it?

sehe
  • 374,641
  • 47
  • 450
  • 633