1、从 https://github.com/curl/curl.git 拉取curl的源码,我是直接下载的zip包
2、本地解压zip包到对应的目录
3、根据情况打开curl-all.sln解决方案,这里使用的是curl\projects\Windows\VC7.1\curl-all.sln
4、编译LIB Release、LIB Release-LIB OPENSSL、LIB Debug、LIB Debug-LIB OPENSSL的libcurl.lib文件,此时在目录下生成如下文件(生成的最终的文件名需要配置,否则都是libcurl.lib和libcurld.lib)
到这里,curl的静态库就编译完成了。
curl支持生成动态库,也可以由用户通过加载libcurl.lib生成自定义的curl动态库。
选择以下4项编译对应的curl库即可
用户直接加载dll就可以啦,如下:
#include "stdafx.h"
#include "curl/curl.h"
typedef CURLcode (*pcurl_global_init)(long flags);
typedef CURL* (*pcurl_easy_init)(void);
int _tmain(int argc, _TCHAR* argv[])
{
CURLcode ret = CURLE_OK;
CURL* curl = NULL;
HMODULE hDll = LoadLibrary(L"H:\\Project\\testCurlDll\\lib\\libcurl.dll");
pcurl_global_init global_init = (pcurl_global_init)GetProcAddress(hDll, "curl_global_init");
if (NULL != global_init)
{
ret = global_init(CURL_GLOBAL_DEFAULT);
}
pcurl_easy_init easy_init = (pcurl_easy_init)GetProcAddress(hDll, "curl_easy_init");
if (NULL != easy_init)
{
curl = easy_init();
}
system("pause");
return 0;
}
用户可以根据自己的需要,导出对应的curl的接口,实际上就是对curl函数的进一步封装。
如下:
#pragma once
#include "curl/curl.h"
class ICurl
{
public:
virtual ~ICurl(){};
virtual BOOL my_curl_global_init(long lFlags) = 0;
virtual void my_curl_global_cleanup() = 0;
virtual CURL* my_curl_easy_init() = 0;
virtual struct my_curl_slist* curl_slist_append(struct curl_slist* pCurlList, const char *pContext) = 0;
virtual CURLcode my_curl_easy_setopt(CURL *pCurl, CURLoption option, ...) = 0;
virtual CURLcode my_curl_easy_perform(CURL *pCurl) = 0;
virtual CURLcode my_curl_easy_getinfo(CURL *pCurl, CURLINFO info, ...) = 0;
virtual void my_curl_slist_free_all(struct curl_slist* pCurlList) = 0;
virtual void my_curl_easy_cleanup(CURL* pCurl) = 0;
virtual CURLFORMcode my_curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...) = 0;
virtual const char* my_curl_easy_strerror(CURLcode error) = 0;
};
主要是加载lib文件实现
#ifdef _DEBUG
#pragma comment(lib,"libcurlssld.lib")
#else
#pragma comment(lib,"libcurlssl.lib")
#endif
void CCurl::my_curl_global_cleanup()
{
curl_global_cleanup();
}
如上,直接调用lib的函数实现即可。这里为什么用libcurlssl.lib(LIB Release-LIB OPENSSL)呢?这是为了让curl支持https通讯方式。如果我们中途需要切换为https通讯方式,但是使用的lib是LIB Release编译方式的,那在执行curl_formadd时会返回错误码:CURLE_UNSUPPORTED_PROTOCOL,意思是libcurl中不支持https。
为了使用https,那就得让curl支持https,所以问题还是在curl上。我们知道https由2部分组成:http + ssl/tls,在http的基础上加了处理加解密信息,由此可知https传输的数据都是加密后的数据。因此我们只要编译支持ssl的curl库即可支持使用https。即LIB Release-LIB OPENSSL编译方式生成的libcurl.lib就能支持https。
1)出现
CCurl.obj : error LNK2001: unresolved external symbol __imp__FormAdd
1>CCurl.obj : error LNK2001: unresolved external symbol __imp__Curl_vsetopt
1>CCurl.obj : error LNK2001: unresolved external symbol __imp__curl_global_cleanup
1>CCurl.obj : error LNK2001: unresolved external symbol __imp__curl_slist_free_all
1>CCurl.obj : error LNK2001: unresolved external symbol __imp__curl_easy_init
原因是没有加上预编译头CURL_STATICLIB,右键工程——属性——C++——Preprocessor——Preprocessor Definitions加入CURL_STATICLIB即可
2)
curl_setup_once.h(274) : error C2628: ‘<unnamed-tag>‘ followed by ‘bool‘ is illegal (did you forget a ‘;‘?)
这种情况在编译curl源码的静态库和动态库时不会出现,一般是在其他模块引用时会出现。这是因为curl源码中存在curl/lib/share.c/h,这2个文件和vs安装目录Microsoft Visual Studio 9.0\VC\include下的share.h同名并都被引用,因此编译时就出现了这个问题。解决办法就是修改一下curl源码库中curl/lib/share.c/h的文件名,可修改为curl_share.c/h,同时修改一下curl源码库中文件:
主要是将其中的#include "share.h"改为#include "curl_share.h"即可,重新编译一下LIB Release、LIB Release-LIB OPENSSL、LIB Debug、LIB Debug-LIB OPENSSL这4种curl库,完成之后再编译一下自己的dll模块,发现就没有错误了。
1、从定义的接口可知
virtual CURLcode my_curl_easy_setopt(CURL *pCurl, CURLoption option, ...) = 0;
virtual CURLFORMcode my_curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...) = 0;
curl_easy_setopt在curl源码中的实现是
va_list arg;
CURLcode result;
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
va_start(arg, tag);
result = Curl_vsetopt(data, tag, arg);
va_end(arg);
return result;
curl_formadd在curl源码中的实现是
va_list arg;
CURLFORMcode result;
va_start(arg, last_post);
result = FormAdd(httppost, last_post, arg);
va_end(arg);
return result;
由此可知源码中是直接通过va_list获取可变参数的,但这样的话,我们的自定义接口最后一个参数也是可变类型的,那我们怎么将这个值传给lib中的curl_formadd或者curl_easy_setop呢?如果我们在my_curl_easy_setop中使用va_list 获取可变参数列表,在lib中有调用va_list 获取一次,明显是不对的。那我们可以怎么做呢?
由curl源码可知这2个接口的实现,所以我们可以直接实现接口的功能,不调用curl库中对应的curl_easy_setop或curl_formadd就可以了。这个时候我们发现Curl_vsetopt和FormAdd不支持外部模块使用,这就好办了,我们可以在curl/include/curl/curl.h中添加这2个函数的声明,如下:
CURL_EXTERN CURLFORMcode FormAdd(struct curl_httppost **httppost, struct curl_httppost **last_post, va_list params);
CURL_EXTERN CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
变成生成libcurl库,这个时候外部模块就可以使用FormAdd和Curl_vsetopt啦。