8
votes

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.

3
Try to create a minimal example with your problem. Throw out all lines not related to a single curlpp::options line, remove all additional libraries. If the minimal set works, add more lines and libraries until it breaks.usr1234567
As you can see above, I get the same errors when I try to compile one of the examples included in cURLpp.A.T.
Have you tried with inverse ordering? -lcurlpp -lcurl -lmusr1234567

3 Answers

9
votes

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.

5
votes

You can try to compile your project using old ABI:
g++ -o example00 example00.cpp -D_GLIBCXX_USE_CXX11_ABI=0 -lm -lcurl -lcurlpp

0
votes

For me the following worked on Ubuntu 18.04:

apt-get install libcurl4-openssl-dev
apt-get install libcurlpp-dev

Cmake:

...
add_executable(HTTPPostTest HTTPPostTest.cpp)
TARGET_LINK_LIBRARIES(HTTPPostTest -lcurl -lcurlpp stdc++fs )
...

HTTPPostTest.cpp:

#include <curlpp/cURLpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>
#include <curlpp/Exception.hpp>

int main(int argc, char *argv[]) {
    try {
        curlpp::Cleanup cleaner;
        curlpp::Easy request;
        request.setOpt(new curlpp::options::Url("https://postman-echo.com/post"));
        request.setOpt(new curlpp::options::Verbose(true));
        std::list<std::string> header;
        header.push_back("Content-Type: application/octet-stream");
        request.setOpt(new curlpp::options::HttpHeader(header));
        request.setOpt(new curlpp::options::PostFields("abcd"));
        request.setOpt(new curlpp::options::PostFieldSize(5));
        request.perform();
    } catch ( curlpp::LogicError & e ) {
        std::cout << e.what() << std::endl;
    } catch ( curlpp::RuntimeError & e ) {
        std::cout << e.what() << std::endl;
    }
    return EXIT_SUCCESS;
}