Compile and use redis 3.0 under vc2010 under Windows 7

Compile and use redis 3.0 under vc2010 under Windows 7

In the project, multiple machines frequently read and write and synchronize some parameters. The original plan was implemented through MySQL temporary tables, which had some impact on efficiency, so it was changed to redis. In the project, redis, web and mysql are linux platforms, and the client is windows 7 platform C++ application process, operating LoRa and other hardware devices.

1. Compile hiredis

According to the description of many blog posts on the Internet, the hiredis library is required to access redis in the C++ environment. From the downloaded redis3.0 source code, it is found that hiredis has been integrated in the project. The following is the directory structure of
redis3.0 : ├─deps
├─msvs
│ ├─hiredis
│ ├─lua
│ ├ ……
│ ├─Samples
│ ├─setups
│ └─tools
├─src
│ └─Win32_Interop
├─tests
└─utils

Among them, there is a hiredis.vcxproj file in the msvc directory, and a Win32_Interop.vcxproj file in the src directory. These two are library files that the C++ client needs to call.

Note that these two .vcxproj projects are of vc2012 version, and the source code uses some Cxx11 syntax, such as automatic derivation, variable length parameter template, constant member assignment, etc. Therefore, some small changes to the source code are required.

1.1 Compile Win32_Interop.vcxproj

Add to the solution, and then change the "Platform Toolset" from v120 to v100 in "Properties -> Platform Properties -> General", and "Configuration Type" to "Static Library (.lib)";
compile and report a lot Compilation error. Don't worry, these errors actually have commonalities, just use vim regular expressions to replace them.

(1) Small changes to the direct initialization and assignment of vector

In Win32_CommandLine.cpp, there is the following code:

static RedisParamterMapper g_redisArgMap = {...};

Solution:
Write a loader class, assign a value to the variable in its constructor, and then define a global loader variable, for example;

class g_redisArgMap_loader {
public:
	g_redisArgMap_loader() 
	{
		// QFork flags
		g_redisArgMap.insert(std::pair<string, ParamExtractor*>(cQFork,	&fp2));	// qfork [QForkControlMemoryMap handle] [parent process id]
		...
	}
	...
};
static g_redisArgMap_loader g_redisArgMap_loader_object = g_redisArgMap_loader();

(2) for (auto …) statement

for (auto p : sentinelSubCommands) {...}
解决:
for (vector<string>::iterator p = sentinelSubCommands.begin(); p != sentinelSubCommands.end(); p++) {...}

(3) Variable length parameter template (dllfunctor_stdcall)

This is not troublesome to solve, comment out the definition of dllfunctor_stdcall in win32_variadicfunctor.h, and then write the regular expression by vim, and replace the code as follows:

原始代码:
auto f_WSACleanup = dllfunctor_stdcall<int>("ws2_32.dll", "WSACleanup");
替换后的代码:
int (WSAAPI * f_WSACleanup)( void ) =  (int(\_\_stdcall * )())DLLMap::getInstance().getProcAddress("ws2\_32.dll", "WSACleanup");
vim正则式:
:%s/auto\s*\(\w\+\)\s* = dllfunctor_\w\+<\([^>,]\+\),*\s*\([^>]\+\)>/\2 (WSAAPI * \1)(\3) =  (\2(__stdcall *)(\3))DLLMap::getInstance().getProcAddress/gc

Other minor problems can be solved by yourself.

The compilation is successful, and the Win32_Interop.lib file is generated.

1.2 编译 hiredis.vcxproj

Add to the solution, in "Properties -> Platform Properties -> General", change the "Platform Tool Set" from v120 to v100, and the "Configuration Type" to "Static Library (.lib)";
in the "Additional Include Directory" Add "$(ProjectDir)...\src\Win32_Interop" in ";
compile, report that the winapifamily.h file cannot be found.

(1) Make small changes to the source code

As mentioned earlier, hiredis.vcxproj in redis3.0 supports windows 8.x from vc2012 and above, and winapifamily.h is the header file in WDK 8 (Windows driver Kit). Here, we need to make some small changes to the source code.
In the file "redis-3.0\src\win32_interop\ws2tcpip.h", add the following code:

#define PICEA_12345_INCLUDED		1

#if (PICEA_12345_INCLUDED)
#ifndef _Outptr_					// SAL2.0中的宏,vc2010的SAL1.0中未定义
	#define _Outptr_
#endif
#ifndef _In_reads_bytes_			// SAL2.0中的宏,vc2010的SAL1.0中未定义,写个假的
	#define _In_reads_bytes_(a)
#endif
#ifndef _Out_writes_opt_			// SAL2.0中的宏,vc2010的SAL1.0中未定义,写个假的
	#define _Out_writes_opt_(a)
#endif
#endif

#if (PICEA_12345_INCLUDED || WINVER <= _WIN32_WINNT_WS03)
	#include "win32_winapifamily.h"
#else
	#include <winapifamily.h>
#endif

(2) Compile

编译成功,生成hiredis.lib文件。

1.3 Compile libjemalloc, lua, RedisBenchmark, etc.

These libraries are all .c files.
If a "macro definition" error occurs, add #include <errno.h> at the beginning of the file to solve it;

If a variable declaration error occurs, it is because the vc2010 compiler does not allow variable declarations in the c function statement, for example:

void f(void) {
	if (...) { /*statement*/ ... }
	int i;	//这里vc2010会报告错误
	i=0;
}
解决方法: 将变量声明在函数开头即可

In particular, functions such as isnan and isinf, which are only available in Cxx11/VC2013, can be found on the Internet and added to the project (I wrote a vc2010-porting.cpp file and added it to the project).

1.4 Compile RedisCli, RedisCheckAof, etc.

These projects are not dependent on RedisServer, and there is no impact on compilation or compilation.
The treatment method is the same as 1.3.

1.5 Compile RedisServer

The changes to the source code are the same as 1.1 and 1.3, and vc2010-porting.cpp is added to handle functions such as isnan.
Then, compile and pass.
Press F5 to debug, the redis startup window appears

2. Use hiredis

Create a new win32 project, then right-click the project name, properties -> configuration properties -> VC++ directory -> include directory, add the path of hiredis into
$(SolutionDir)redis-3.0\deps\hiredis

Right-click the project name->Properties->Configuration Properties->VC++ Directory->Library Directory, and add the paths of hiredis.lib and Win32_Interop.lib
(Solution D ir) (SolutionDir)(SolutionDir)(Configuration)\

Right-click the project name -> Properties -> Linker -> Input -> Additional dependencies, add hiredis.lib, Win32_Interop and ws2_32.lib

Sample code (test passed)

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>

extern "C"
{
//#include <win32fixes.h>
}

#include <ICRSINT.H>
#include <windows.h>

#define REDIS_SERVER_IP		"192.168.x.x"
#define REDIS_SERVER_PORT	6379
#define REDIS_SERVER_PASS	"xxxxxx"

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

using namespace std;

void redis_test_proc()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 1), &wsaData);

	redisContext * redis_ctx_;
	redisReply *reply;
	struct timeval timeout = { 1, 500000 }; // 1.5 seconds

	redis_ctx_ = redisConnectWithTimeout((char*)REDIS_SERVER_IP, REDIS_SERVER_PORT, timeout);
	if (NULL != redis_ctx_ && redis_ctx_->err) {
		printf("Connection error: %s\n", redis_ctx_->errstr);
		exit(1);
	}

	reply = (redisReply *)redisCommand(redis_ctx_, "auth "REDIS_SERVER_PASS);
	if (REDIS_REPLY_ERROR == reply->type) {
		printf("Authentication failed: %s\n", reply->str);
	}
	freeReplyObject(reply);

	/* Set a key */
	reply = (redisReply *)redisCommand(redis_ctx_, "SET %s %s", "foo", "kivifriut is delicious ...");
	if (REDIS_REPLY_ERROR == reply->type) {
		printf("SET failed (%s:%d): %s\n", __FUNCTION__, __LINE__, reply->str);
		// TODO: 延迟x秒重连
	} else {
		printf("SET foo: %s\n", reply->str);
	}
	freeReplyObject(reply);


	/* Try a GET and two INCR */
	reply = (redisReply *)redisCommand(redis_ctx_, "GET foo");
	printf("GET foo: %s\n", reply->str);
	freeReplyObject(reply);

	redisFree(redis_ctx_);
}
int main(int argc, _TCHAR* argv[])
{
	redis_test_proc();
	system("pause");
	return 0;
}

Output:

SET foo: OK
GET foo: kivifriut is delicious ...
请按任意键继续. . .

Source code:
https://download.csdn.net/download/hylaking/10729376

Guess you like

Origin blog.csdn.net/hylaking/article/details/83113905