C/C++开发,基于cectd源码打造etcd数据库的win/linux静态编译的c-SDK包

目录

【1】下载源码

【2】编译准备

【3】win编译第三方依赖curl和yajl

【4】win下编译cetcd

【5】搭建etcd服务端,本文是在 win10 下启动etcd服务端

【6】 win的客户端测试

【7】 linux静态编译第三依赖库

【8】linux下编译cetcd

【9】 linux的客户端测试

【10】构建etcd-c-sdk包


        目前市面上满足c/c++的etcd-client-SDK不多,支持win的更寥寥无几,为了实现支持c/c++访问etcd的跨平台和快速移植的 sdk包,本博文在源码cetcd包基础上做进一步调整,实现满足win/linux支持静态编译的etcd-c-client-SDK包。

首先开源cetcd源码下载网址:https://gitee.com/mirrors/cetcd 

该源码包已经实现了linux下可编译动静态库,但需要动态链接第三方库。下面给出具体改造过程:

【1】下载源码

1)下载开源cetcd源码,进入该目录,查看README.md文件,其说明依赖curl库和yajl第三库,创建一个新的子目录third-party,

下载curl:https://curl.haxx.se/download.html,到该子目录,本文下载:curl-7.70.0.zip

下载yajl:GitHub - lloyd/yajl: A fast streaming JSON parsing library in C.,到该子目录,本文下载:yajl-2.1.0.tar.gz

在本目录解压。

【2】编译准备

本文编译需要cmake工具,而curl需要3.0以上的cmake版本支持,确保win/linux的cmake支持3.0以上的版本

本文win安装了cmake-3.8.1版本,linux是在centos7上编译,更新cmake如下:

wget https://cmake.org/files/v3.3/cmake-3.3.2.tar.gz
 tar xzvf cmake-3.3.2.tar.gz
cd cmake-3.3.2
./bootstrap
gmake
#su root
gmake install
#remove old and new config
yum remove cmake -y
ln -s /usr/local/bin/cmake /usr/bin/
cmake --version

【3】win编译第三方依赖curl和yajl

本文win的编译环境是在win10下安装了vs2015,采用64bit编译

1)编译curl,解压curl-7.70.0.zip,进入 cetcd\third-party\curl-7.70.0\winbuild目录,打开BUILD.WINDOWS.txt,里面有具体的编译选项

本文的编译命令为:

nmake /f Makefile.vc mode=static VC=14

 编译输出结果在:

2)编译yajl

解压yajl-2.1.0.tar.gz,进入cetcd\third-party\yajl-2.1.0子目录,创建build-win64子目录,可以打开BUILDING.win32参考编译选项,

进入build-win64子目录,本文的编译命令:

cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..

nmake

编译结果就输出在本目录:

完成了win下的第三方依赖编译。

【4】win下编译cetcd

1)源码调整,回到cectd目录,在cetcd.h开头,我们调整winthread 的支持:

#ifdef __cplusplus
extern "C" {
#endif

#include <curl/curl.h>
#include <stdint.h>
#include "sds/sds.h"
#include "cetcd_array.h"
#define CETCD_VERSION release-v0.0.5
typedef sds cetcd_string;
/**以下调整**/
#ifdef WIN32
typedef HANDLE cetcd_watch_id;
#else
#include <pthread.h>
typedef pthread_t cetcd_watch_id;
#endif
/**以上调整**/
enum HTTP_METHOD {
    ETCD_HTTP_GET,
    ETCD_HTTP_POST,
    ETCD_HTTP_PUT,
    ETCD_HTTP_DELETE,
    ETCD_HTTP_HEAD,
    ETCD_HTTP_OPTION
};

在cetcd.c开头,我们调整winthread 的实现:

调整一:

#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <curl/curl.h>
#include <yajl/yajl_parse.h>
//调整
#ifdef WIN32
#else
#include <sys/select.h>
#include <pthread.h>
#endif

调整二,在行数490左右,调整了win-thread的实现:

cetcd_watch_id cetcd_multi_watch_async(cetcd_client *cli, cetcd_array *watchers) {
    
    void **args;
    args = calloc(2, sizeof(void *));
    args[0] = cli;
    args[1] = watchers;
	#ifdef WIN32
	HANDLE thread =(HANDLE)_beginthread(cetcd_multi_watch_wrapper, NULL, args);
	#else
	pthread_t thread;
    pthread_create(&thread, NULL, (void *(*)(void *))cetcd_multi_watch_wrapper, args);
	#endif
    return thread;
}
int cetcd_multi_watch_async_stop(cetcd_client *cli, cetcd_watch_id wid) {
    (void) cli;
    /* Cancel causes the thread exit immediately, so the resouce has been
     * allocted won't be freed. The memory leak is OK because the process
     * is going to exit.
     * TODO fix the memory leaks
     * */
	#ifdef WIN32
	WaitForSingleObject(wid, INFINITE);
	#else
    pthread_cancel(wid);
    pthread_join(wid, 0);
	#endif
    return 0;
}

在cetcd/example/cetcd_get.c文件小调用方法测试sdk,为了实现win主机和虚拟系统centos7访问在win10 下部署的etcd服务,地址采用win主机的vm 地址:

    cetcd_array_append(&addrs, "http://192.168.174.1:2379");

    cetcd_client_init(&cli, &addrs);
    //以下调整,添加写入
    resp = cetcd_set(&cli, "/test","2",100);
	
    if(resp->err) {
        printf("error :%d, %s (%s)\n", resp->err->ecode, resp->err->message, resp->err->cause);
    }
    //以上调整
    resp = cetcd_get(&cli, "/test");
    if(resp->err) {
        printf("error :%d, %s (%s)\n", resp->err->ecode, resp->err->message, resp->err->cause);
    }
    cetcd_response_print(resp);
    cetcd_response_release(resp);

2)由于cetcd仅有linux的Makefile文件,因此全新构建构建CMakeLists.txt文件,使支持win/linux跨平台编译,

返回cetcd目录,创建CMakeLists.txt(已经涵盖了win/linux编译需求),具体如下,注意标注说明的地方

# CMake 最低版本号要求,主要切合curl最低版本要求
cmake_minimum_required(VERSION 3.0)
# 项目信息
project (etcd-api)
#
if(WIN32)
    message(STATUS "windows compiling...")
    add_definitions(-D_PLATFORM_IS_WINDOWS_)
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
    # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
    set(WIN_OS true)
else(WIN32)
    message(STATUS "linux compiling...")
    add_definitions( -D_PLATFORM_IS_LINUX_)
    set(UNIX_OS true)
    set(_DEBUG true)
    
endif(WIN32)

#库输出目录和测试程序输出
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(LIBRARY_OUTPUT_PATH  ${PROJECT_SOURCE_DIR}/lib)
# 指定源文件的目录,并将名称保存到变量
SET(lib_h
    ${PROJECT_SOURCE_DIR}/sds/sds.h
	${PROJECT_SOURCE_DIR}/cetcd_json_parser.h
    ${PROJECT_SOURCE_DIR}/cetcd_array.h
	${PROJECT_SOURCE_DIR}/cetcd.h
	
  )
  
SET(lib_cpp
    ${PROJECT_SOURCE_DIR}/sds/sds.c
    ${PROJECT_SOURCE_DIR}/cetcd_array.c
	${PROJECT_SOURCE_DIR}/cetcd.c
	
  )
#测试程序  
SET(get_cpp
    ${PROJECT_SOURCE_DIR}/examples/cetcd_get.c
  )
 
SET(lsdir_cpp
    ${PROJECT_SOURCE_DIR}/examples/cetcd_lsdir.c
  )
  
#头文件目录
include_directories("${PROJECT_SOURCE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}/sds")

if (${UNIX_OS})

add_definitions(
  "-W"
  "-fPIC"
  "-Wno-unused-parameter"
  "-DCURL_STATICLIB"
  "-DHTTP_ONLY"
  "-DBUILDING_LIBCURL"
  )
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g -O3 -Wall")

include_directories("${PROJECT_SOURCE_DIR}/third-party/curl-7.70.0/include")
include_directories("${PROJECT_SOURCE_DIR}/third-party/yajl-2.1.0/build-linux/yajl-2.1.0/include")

link_directories(
  "${PROJECT_SOURCE_DIR}/third-party/curl-7.70.0/build-linux/lib"
  "${PROJECT_SOURCE_DIR}/third-party/yajl-2.1.0/build-linux/yajl-2.1.0/lib"
  "${PROJECT_SOURCE_DIR}/lib"
  "/usr/local/lib64"
)
  
# 指定生成目标
add_library(etcd-api STATIC ${lib_h} ${lib_cpp})

# 指定生成目标
add_executable(etcd-test ${lib_h} ${get_cpp})
#注意静态编译下,需要特定指定依赖的一些通用库,否则会链接失败
target_link_libraries(etcd-test
  -lpthread -lcrypto -lssl -lz
  etcd-api.a
  libyajl_s.a
  libcurl.a
)

endif()

if (${WIN_OS})

include_directories("${PROJECT_SOURCE_DIR}/third-party/curl-7.70.0/include")
include_directories("${PROJECT_SOURCE_DIR}/third-party/yajl-2.1.0/build-win64/yajl-2.1.0/include")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")

#注意需要一些特定的定义
add_definitions(
  "-D_CRT_SECURE_NO_WARNINGS"
  "-D_WINSOCK_DEPRECATED_NO_WARNINGS"
  "-DNO_WARN_MBCS_MFC_DEPRECATION"
  "-DWIN32_LEAN_AND_MEAN"
  "-D_CRT_NONSTDC_NO_DEPRECATE"
  "-D_CRT_SECURE_NO_WARNINGS"
  "-DCURL_STATICLIB"
  "-DHTTP_ONLY"
  "-DBUILDING_LIBCURL"
)

link_directories(
  "${PROJECT_SOURCE_DIR}/third-party/curl-7.70.0/builds/libcurl-vc14-x64-release-static-ipv6-sspi-winssl/lib"
  "${PROJECT_SOURCE_DIR}/third-party/yajl-2.1.0/build-win64/yajl-2.1.0/lib"
  "${PROJECT_SOURCE_DIR}/lib"
)

if (CMAKE_BUILD_TYPE STREQUAL "Debug")

# 指定生成目标
add_library(etcd-apid STATIC ${lib_h} ${lib_cpp})

# 指定生成目标
add_executable(etcd-testd ${lib_h} ${get_cpp})
#注意静态编译下,需要特定指定依赖的一些通用库
target_link_libraries(etcd-testd
  Crypt32.lib Normaliz.lib ws2_32.lib winmm.lib wldap32.lib
  libcurl_a.lib
  yajl_s.lib
  etcd-apid.lib
)

else(CMAKE_BUILD_TYPE)

# 指定生成目标
add_library(etcd-api STATIC ${lib_h} ${lib_cpp})

# 指定生成目标
add_executable(etcd-test ${lib_h} ${get_cpp})

target_link_libraries(etcd-test
  Crypt32.lib Normaliz.lib ws2_32.lib winmm.lib wldap32.lib
  libcurl_a.lib
  yajl_s.lib
  etcd-api.lib
)

endif (CMAKE_BUILD_TYPE)

endif()

3)在cetcd目录,创建build-win64子目录,进入该目录

cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release ..
#cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Debug ..
nmake

【5】搭建etcd服务端,本文是在 win10 下启动etcd服务端

先下载:Releases · etcd-io/etcd · GitHub

解压后进入etcd-v3.4.7-windows-amd64目录,

先构建配置文件conf.yml:

listen-client-urls: http://127.0.0.1:2379,http://192.168.174.1:2379  
advertise-client-urls: http://127.0.0.1:2380,http://192.168.174.1:2380
enable-v2: true

然后在命令行启动:

etcd.exe --config-file conf.yml

如果需要搭建win下开机启动的etcd服务,请参考本人另一篇博文:

win10下搭建etcd的开机启动服务_py_free的博客-CSDN博客

【6】 win的客户端测试

进入cetcd/bin目录下,启动etcd-test.exe,程序逻辑为先向服务put数据,然后又get数据,具体输入结果类似下图:

【7】 linux静态编译第三依赖库

1)对于yajl编译,由于本文是采用将源码挂载到虚拟机上,因此编译会无法创建ln错误,因此本文直接取消动态库创建和软连接的编译:

进入cetcd\third-party\yajl-2.1.0目录,打开  CMakeLists.txt,取消了test源码的编译:

ADD_SUBDIRECTORY(src)
#ADD_SUBDIRECTORY(test)
ADD_SUBDIRECTORY(reformatter)
ADD_SUBDIRECTORY(verify)
ADD_SUBDIRECTORY(example)
ADD_SUBDIRECTORY(perf)

INCLUDE(YAJLDoc.cmake)

# a test target
#ADD_CUSTOM_TARGET(test
#                  ./run_tests.sh ${CMAKE_CURRENT_BINARY_DIR}/test/parsing/yajl_test
#                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test/parsing)

#ADD_CUSTOM_TARGET(test-api ${CMAKE_CURRENT_SOURCE_DIR}/test/api/run_tests.sh
#                  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test/api)

进入cetcd\third-party\yajl-2.1.0\src目录,打开  CMakeLists.txt,注销动态库、软连接、pkg等编译选项:

SET (SRCS yajl.c yajl_lex.c yajl_parser.c yajl_buf.c
          yajl_encode.c yajl_gen.c yajl_alloc.c
          yajl_tree.c yajl_version.c
)
SET (HDRS yajl_parser.h yajl_lex.h yajl_buf.h yajl_encode.h yajl_alloc.h)
SET (PUB_HDRS api/yajl_parse.h api/yajl_gen.h api/yajl_common.h api/yajl_tree.h)

# useful when fixing lexer bugs.
#ADD_DEFINITIONS(-DYAJL_LEXER_DEBUG)

# Ensure defined when building YAJL (as opposed to using it from
# another project).  Used to ensure correct function export when
# building win32 DLL.
ADD_DEFINITIONS(-DYAJL_BUILD)

# set up some paths
SET (libDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/lib)
SET (incDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/include/yajl)
#SET (shareDir ${CMAKE_CURRENT_BINARY_DIR}/../${YAJL_DIST_NAME}/share/pkgconfig)

# set the output path for libraries
SET(LIBRARY_OUTPUT_PATH ${libDir})

ADD_LIBRARY(yajl_s STATIC ${SRCS} ${HDRS} ${PUB_HDRS})

#ADD_LIBRARY(yajl SHARED ${SRCS} ${HDRS} ${PUB_HDRS})

#### setup shared library version number
#SET_TARGET_PROPERTIES(yajl PROPERTIES
#                      DEFINE_SYMBOL YAJL_SHARED
#                      SOVERSION ${YAJL_MAJOR}
#                      VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO})

#### ensure a .dylib has correct absolute installation paths upon installation
IF(APPLE)
  MESSAGE("INSTALL_NAME_DIR: ${CMAKE_INSTALL_PREFIX}/lib")
  SET_TARGET_PROPERTIES(yajl PROPERTIES
                        INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
ENDIF(APPLE)

#### build up an sdk as a post build step

# create some directories
FILE(MAKE_DIRECTORY ${libDir})
FILE(MAKE_DIRECTORY ${incDir})

# generate build-time source
SET(dollar $)
CONFIGURE_FILE(api/yajl_version.h.cmake ${incDir}/yajl_version.h)
#CONFIGURE_FILE(yajl.pc.cmake ${shareDir}/yajl.pc)

# copy public headers to output directory
FOREACH (header ${PUB_HDRS})
  SET (header ${CMAKE_CURRENT_SOURCE_DIR}/${header})

  EXEC_PROGRAM(${CMAKE_COMMAND} ARGS -E copy_if_different ${header} ${incDir})

  ADD_CUSTOM_COMMAND(TARGET yajl_s POST_BUILD
      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${header} ${incDir})
ENDFOREACH (header ${PUB_HDRS})

INCLUDE_DIRECTORIES(${incDir}/..)

# at build time you may specify the cmake variable LIB_SUFFIX to handle
# 64-bit systems which use 'lib64'
#INSTALL(TARGETS yajl
#        RUNTIME DESTINATION lib${LIB_SUFFIX}
#        LIBRARY DESTINATION lib${LIB_SUFFIX}
#        ARCHIVE DESTINATION lib${LIB_SUFFIX})
INSTALL(TARGETS yajl_s ARCHIVE DESTINATION lib${LIB_SUFFIX})
INSTALL(FILES ${PUB_HDRS} DESTINATION include/yajl)
INSTALL(FILES ${incDir}/yajl_version.h DESTINATION include/yajl)
#INSTALL(FILES ${shareDir}/yajl.pc DESTINATION share/pkgconfig)

回到third-party\yajl-2.1.0目录,创建build-linux子目录,并进入该目录

cmake ..
make

编译结果就在本目录下:

2)linux编译curl库

进入cetcd\third-party\curl-7.70.0,打开CMakeLists.txt文件,去关掉动态库编译,当然其他选项按实际需要设置即可,如下:

option(CURL_WERROR "Turn compiler warnings into errors" OFF)
option(PICKY_COMPILER "Enable picky compiler options" OFF)
option(BUILD_CURL_EXE "Set to ON to build curl executable." OFF)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)

创建子目录build-linux,进入该目录,编译:

cmake ..
make

#注意本文需要openssl支持,因此需要安装openssl,如果遇到需要升级可以参考本博文另一篇文章:

centos7编译libcoap时openssl版本过低,升级openssl_py_free的博客-CSDN博客_centos7下载openssl版本过低

编译完成,其编译结果libcurl.a 在本目录的lib子目录下。

【8】linux下编译cetcd

进入cetcd目录,由于在win编译时已经创建的CMakeLists.txt涵盖了linux的部分(详见【4】2)文段),因此,直接创建子目录build-linux,并进入该目录编译即可:

cmake ..
make

编译结果如下:

【9】 linux的客户端测试

服务端采用win搭建的etcd服务,win主机地址192.168.174.1,centos7虚拟机的地址192.168.174.130,

进入cetcd/bin目录, 启动etcd-test进行测试

【10】构建etcd-c-sdk包

        win/Linux编译完成后,可以将相关头文件和静态库打包,构建出etcd-c-sdk包,具体头文件和库依赖请参考CMakeLists.txt文件,打包好的 SDK就可以放在项目中直接使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

py_free-物联智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值