c++curllinkercurlpp

Link errors with curlpp


I wrote a c++ program and try to use curlpp to access a http server securely over SSL. The problem is, that I can't link the program.

Operating system: Ubuntu 15.10

Errors:

/usr/bin/cmake -E cmake_link_script CMakeFiles/prtg_probe.dir/link.txt --verbose=1 Wird gelinkt prtg_probe (c++) CMakeFiles/prtg_probe.dir/probe.cpp.o: In function curlpp::internal::OptionContainer, std::allocator >, std::allocator, std::allocator > > >

::OptionContainer(std::__cxx11::list, std::allocator >, std::allocator, std::allocator > > > const&)': /usr/include/curlpp/internal/OptionContainer.inl:38: undefined reference to curlpp::internal::SList::SList(std::__cxx11::list, std::allocator >, std::allocator, std::allocator > > > const&)' CMakeFiles/prtg_probe.dir/probe.cpp.o: In function curlpp::internal::OptionContainer, std::allocator >, std::allocator, std::allocator > > > ::setValue(std::__cxx11::list, std::allocator >, std::allocator, std::allocator > > > const&)': /usr/include/curlpp/internal/OptionContainer.inl:52: undefined reference to `curlpp::internal::SList::operator=(std::__cxx11::list, std::allocator >, std::allocator, std::allocator > > > const&)' ....

This is the code that produces the errors:

#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <cerrno>
#include <boost/bind.hpp>
#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>

....

class myclass
{

....

try
{
    curlpp::Cleanup cleaner;
    curlpp::Easy request;
    ostringstream os;

    request.setOpt(new curlpp::options::Url(&url_announce[0]));
    request.setOpt(new curlpp::options::SslEngineDefault());
    list<string> header;
    header.push_back("Content-Type: text/*");
    request.setOpt(new curlpp::options::HttpHeader(header));
    request.setOpt(new curlpp::options::PostFields(data_announce));
    request.setOpt(new curlpp::options::PostFieldSize((long)data_announce.length()));
    request.setOpt(new curlpp::options::WriteStream(&os));
    request.perform();
    request_announce = os.str();
}
catch (curlpp::LogicError & e)
{
    syslog(LOG_DAEMON, "Error accessing PRTG server: %s", e.what());
}
catch (curlpp::RuntimeError & e)
{
    syslog(LOG_DAEMON, "Error accessing PRTG server: %s", e.what());
}

Every line with curlpp::options::... produces one error at link time. I've looked around and searched Google for hours now, but all I found was to link libcurl together with libcurl. I do that, but still get this errors.

Here is the complete link line:

/usr/bin/c++   -g    CMakeFiles/prtg_probe.dir/sensors.cpp.o 
CMakeFiles/prtg_probe.dir/mini_probe.cpp.o CMakeFiles/prtg_probe.dir/probe.cpp.o
CMakeFiles/prtg_probe.dir/helper.cpp.o 
CMakeFiles/prtg_probe.dir/config.cpp.o CMakeFiles/prtg_probe.dir/main.cpp.o
-o prtg_probe -rdynamic -lm -lpthread -lcrypto -lssl -lcurlpp -lcurl -lboost_system -lboost_filesystem -ljsoncpp -luuid

Does anybody know what I'm missing? Do I have to add one more library and if yes which one?


I've tried to compile the example00.cpp with the following command:

g++ -o example00 example00.cpp -lm -lcurl -lcurlpp

and the result:

/tmp/cc3pcvDc.o: In Funktion `curlpp::OptionTrait<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, (CURLoption)10002>::updateHandleToMe(curlpp::internal::CurlHandle*) const':
example00.cpp: (.text._ZNK6curlpp11OptionTraitINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEL10CURLoption10002EE16updateHandleToMeEPNS_8internal10CurlHandleE[_ZNK6curlpp11OptionTraitINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEL10CURLoption10002EE16updateHandleToMeEPNS_8internal10CurlHandleE]+0x68):
Nicht definierter Verweis auf `curlpp::UnsetOption::UnsetOption(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/tmp/cc3pcvDc.o: In Funktion `curlpp::Option<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::getValue() const':
example00.cpp: (.text._ZNK6curlpp6OptionINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8getValueEv[_ZNK6curlpp6OptionINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE8getValueEv]+0x68):
Nicht definierter Verweis auf `curlpp::UnsetOption::UnsetOption(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status

This looks like the same problem to me.


Solution

  • The problem is that linkage of ccurlcpp::UnsetOption::UnsetOption is partially defective in the lipcurlcpp.so binary.

    The linker's complaint with:

    g++ -o example00 example00.cpp -lm -lcurl -lcurlpp
    

    is:

    undefined reference to `curlpp::UnsetOption::UnsetOption(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
    

    But if I demangle the constructor signatures in libcurlpp.so:

    nm -D -C libcurlpp.so | grep UnsetOption::UnsetOption
    

    I see:

    0000000000021776 T curlpp::UnsetOption::UnsetOption(char const*)
    000000000002173e T curlpp::UnsetOption::UnsetOption(std::string const&)
    

    The std::string hasn't been properly de-typedefed for some reason. If I get the source file in which this constructor is defined from the curlpp 0.7.3 source package, Exception.cpp, compile it:

    curlpp-0.7.3/src/curlpp$ g++ -I../../include -I. -c Exception.cpp
    

    and then demangle the constructor signatures from the object file:

    nm -C Exception.o | grep UnsetOption::UnsetOption
    

    I get:

    00000000000003f4 T curlpp::UnsetOption::UnsetOption(char const*)
    00000000000003c2 T curlpp::UnsetOption::UnsetOption(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
    

    So:

    curlpp::UnsetOption::UnsetOption(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
    

    is the signature the compiler is telling the linker to look for, but that is not the signature in the library. The short explanation of the error is: the library is broken.

    However, we see that no such inconsistency affects the other overload of the constructor:

    curlpp::UnsetOption::UnsetOption(char const*)
    

    nor could it, since the char const * is a builtin type.

    This enables a hack fix. The file in which the undefined-reference call is compiled is (as installed) /usr/include/curlpp/Option.inl, at the line:

    throw UnsetOption(std::string("You are trying to set an unset option to a handle"));
    

    Edit this file, as root, and you see that it (inconsistently) contains two instances of:

    throw UnsetOption(std::string("blah blah"));
    

    and one instance of:

    throw UnsetOption("blah blah");
    

    Change the occurrences of UnsetOption(std::string("blah blah")) to UnsetOption("blah blah"). Then only the good constructor is called in this file and example00, at least, will compile and link.

    If you dislike the hack, or find that the problem re-surfaces elsewhere, then you may download the ubuntu source package curlpp_0.7.3.orig.tar.gz and build and install it yourself. That is the right remedy.