Использование libcurl в программе на C ++ приводит к тому, что компилятор Visual C ++ выдает ошибки - PullRequest
4 голосов
/ 12 июня 2019

Я скомпилировал libcurl в Windows, используя компилятор Visual C ++ в dll. В дополнение к скомпилированному исходному коду libcurl, эта dll содержит простую тестовую программу, которая выглядит следующим образом:

Заголовок (HttpClient.h):

#pragma once

#include <string>

#include "curl/curl.h"


namespace My::Project
{
  class HttpClient
  {
  public:
    HttpClient();
    ~HttpClient();
    std::string Get(std::string address);

  private:
    CURL* easy_handle;
  };
}

Реализация (HttpClient.cpp):

#include "HttpClient.h"

#include <iostream>

using namespace My::Project


HttpClient::HttpClient()
{
  easy_handle = curl_easy_init();
  curl_global_init(CURL_GLOBAL_ALL);
}


HttpClient::~HttpClient()
{
  curl_global_cleanup();
}


static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
  ((std::string*)userp)->append((char*)contents, size * nmemb);
  return size * nmemb;
}


std::string HttpClient::Get(std::string address)
{
  std::string html;

  curl_easy_setopt(easy_handle, CURLOPT_URL, address.c_str());
  curl_easy_setopt(easy_handle, CURLOPT_FOLLOWLOCATION, 1L);
  curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, WriteCallback);
  curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &html);
  CURLcode returnValue = curl_easy_perform(easy_handle);

  if(returnValue != CURLE_OK)
  {
    html = "Failed to retrieve HTML";
  }

  curl_easy_cleanup(easy_handle);
  return html;
}

Эта тестовая программа прекрасно компилируется.

(Кстати: я знаю, что curl_global_init и curl_global_cleanup должны вызываться только один раз. Это всего лишь тестовая программа ...)

Теперь я хочу сослаться на эту dll в другой dll, создать экземпляр класса HttpClient и использовать его следующим образом:

#include "<relative-path>/HttpClient.h" 

using namespace My::Project;

// Within a constructor of another class
HttpClient client;
std::string html = client.Get("https://www.google.com/");

Вызов компилятора, использованный для компиляции второй DLL, выглядит следующим образом:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\bin\HostX86\x64\CL.exe
/c
/I<project path>
/I"Generated Files\\"
/Iobj\Debug\x64\
/I<path to curl source>\curl\include
/ZI
/JMC
/ZW
/ZW:nostdlib
/nologo
/W3
/WX-
/diagnostics:column
/sdl
/MP
/Od
/Oy-
/D _WINRT_DLL
/D _WINDLL
/D _UNICODE
/D UNICODE
/D _DEBUG
/D WINAPI_FAMILY=WINAPI_FAMILY_APP
/D __WRL_NO_DEFAULT_LIB__
/Gm-
/EHsc
/RTC1
/MDd
/GS
/fp:precise
/Zc:wchar_t
/Zc:forScope
/Zc:inline
/std:c++17
/Yu"pch.h"
/Fp"obj\Debug\x64\pch.pch"
/Fo"obj\Debug\x64\\"
/Fd"obj\Debug\x64\vc142.pdb"
/Gd
/TP
/wd28204
/FU"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.21.27702\lib\x86\store\references\platform.winmd"
/FU"<other winmd files>
/analyze-
/FC
/errorReport:prompt
/bigobj
<path to cpp file invoking HttpClient>

Однако попытка скомпилировать второй dll приводит к тому, что компилятор Visual C ++ выдает следующие ошибки:

<path to curl source>\curl\include\curl\curl.h(134,29): error C4430:  missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\curl.h(134,16): error C2146:  syntax error: missing ';' before identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(397,52): error C2061:  syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(407,23): error C2079:  'curl_sockaddr::addr' uses undefined struct 'sockaddr'
<path to curl source>\curl\include\curl\curl.h(411,3): error C2065:  'curl_opensocket_callback': undeclared identifier
<path to curl source>\curl\include\curl\curl.h(411,27): error C4430:  missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\curl.h(411,27): error C2378:  'curl_socket_t': redefinition; symbol cannot be overloaded with a typedef
<path to curl source>\curl\include\curl\curl.h(134): message :  see declaration of 'curl_socket_t'
<path to curl source>\curl\include\curl\curl.h(411,28): error C2513:  'int': no variable declared before '='
<path to curl source>\curl\include\curl\curl.h(411,28): error C2143:  syntax error: missing ';' before '('
<path to curl source>\curl\include\curl\curl.h(411,34): error C2062:  type 'void' unexpected
<path to curl source>\curl\include\curl\curl.h(416,59): error C2061:  syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(113,19): error C3646:  'fd': unknown override specifier
<path to curl source>\curl\include\curl\multi.h(113,19): error C4430:  missing type specifier - int assumed. Note: C++ does not support default-int
<path to curl source>\curl\include\curl\multi.h(157,47): error C2061:  syntax error: identifier 'fd_set'
<path to curl source>\curl\include\curl\multi.h(271,51): error C2061:  syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(292,76): error C2061:  syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(296,62): error C2061:  syntax error: identifier 'curl_socket_t'
<path to curl source>\curl\include\curl\multi.h(410,55): error C2061:  syntax error: identifier 'curl_socket_t'

Вслед за первым сообщением об ошибке я получаю следующий фрагмент кода в curl.h:

131:  #ifndef curl_socket_typedef
132:  /* socket typedef */
133:  #if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
134:  typedef SOCKET curl_socket_t;
135:  #define CURL_SOCKET_BAD INVALID_SOCKET
136:  #else
137:  typedef int curl_socket_t;
138:  #define CURL_SOCKET_BAD -1
139:  #endif
140:  #define curl_socket_typedef
141:  #endif /* curl_socket_typedef */

Таким образом, компилятор по существу жалуется на следующую строку:

134:  typedef SOCKET curl_socket_t;

Однако в настоящее время я не знаю, в чем именно проблема. Один и тот же код прекрасно компилируется с Clang для Android и iOS.

Кто-нибудь видит, что нужно сделать, чтобы компилировать это с Visual C ++?

Ответы [ 2 ]

1 голос
/ 20 июня 2019

Как было указано, SOCKET определяется Windows. Более конкретно, это определено в WinSock2.h. Я включил этот конкретный заголовок, но без решения проблем. Однако второй dll использует предварительно скомпилированный заголовочный файл (pch.h). Как только я включил WinSock2.h в файл pch.h, ошибки компилятора были окончательно исправлены.

Однако для создания libcurl для приложений Windows UWP необходимо сделать еще один важный шаг. Включение WinSock2.h в файл pch.h только исправило ошибки компилятора, но привело к двум ошибкам компоновщика, которые выглядят следующим образом:

error LNK2019: unresolved external symbol __imp_VerSetConditionMask referenced in function Curl_verify_windows_version
error LNK2019: unresolved external symbol __imp_VerifyVersionInfoA referenced in function Curl_verify_windows_version
fatal error LNK1120: 2 unresolved externals

Эти термины могут быть решены путем указания компоновщику включить дополнительную библиотеку OneCore.lib. Microsoft описывает эту библиотеку следующим образом:

Для удобства в комплекте Microsoft SDK для разработки программного обеспечения (SDK) предоставляется библиотека OneCore.lib, которая обеспечивает экспорт для подмножества Win32 API, общих для всех устройств Windows 10. Свяжите свое классическое настольное приложение или драйвер с OneCore.lib (и без других библиотек), чтобы получить доступ к этим API. Если вы связываете свое приложение или драйвер с OneCore.lib и вызываете только API Win32 в этой библиотеке, тогда ваше приложение или драйвер успешно загрузится на все устройства Windows 10.

См. ссылку для более подробной информации о OneCore.lib.

0 голосов
/ 15 июня 2019

Вот код, который будет работать.Я запустил его и также получил результат.

#include <iostream>
#include <stdlib.h>
#define CURL_STATICLIB
#include "curl\curl.h"
#include <string>

#pragma comment(lib, "crypt32")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")


class HttpClient
{
public:
    HttpClient();
    ~HttpClient();
    std::string Get(std::string address);

private:
    CURL* easy_handle;
};

HttpClient::HttpClient()
{
    easy_handle = curl_easy_init();
    curl_global_init(CURL_GLOBAL_ALL);
}

HttpClient::~HttpClient()
{
    curl_global_cleanup();
}

static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp)
{
    ((std::string*)userp)->append((char*)contents, size * nmemb);
    return size * nmemb;
}

std::string HttpClient::Get(std::string address)
{
    std::string html;

    curl_easy_setopt(easy_handle, CURLOPT_URL, address.c_str());
    curl_easy_setopt(easy_handle, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, &html);
    CURLcode returnValue = curl_easy_perform(easy_handle);

    if (returnValue != CURLE_OK)
    {
        html = "Failed to retrieve HTML";
    }

    curl_easy_cleanup(easy_handle);
    return html;
}

int main()
{
    HttpClient client;
    std::string html = client.Get("https://www.google.com/");
    std::cout << html;
    std::cin.get();
    return 0;
}

Также обязательно добавьте следующее:

Линкер> Дополнительные зависимости> Normaliz.lib

Надеюсь, это поможет.

...