Android跨平台编译 —— libevent

此文大量引用参考 https://www.dplord.com/2017/10/10/android-ndk-compile-libevent/

前言

    前言都在 Android跨平台编译 —— BOOST

    PS:有一些基础知识介绍,还是挺重要的。

    

准备工作

    编译环境 mac os x

    ndk版本 ndk 16rb

    libevent版本 2.1.8

    编译工具 cmake

    假设我们已经在android studio上安装了ndk和cmake。

    首先需要下载libevent ,这里有个问题,如果直接从官网上下载tar包,解压之后是没有CMakeLists.txt文件的,所以无法使用cmake进行编译。所以我们需要从github上直接下载,地址https://github.com/libevent/libevent

    去clone下来,然后checkout到 release-2.1.8-stable 这个tag上。

    环境已经准备就绪。

    

编译

步骤1

   首先打开根目录下的CMakeLists.txt文件,有几处改动

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4a34f3d..c32721d1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,7 +105,7 @@ option(EVENT__BUILD_SHARED_LIBRARIES
     "Define if libevent should be built with shared libraries instead of archives" OFF)
 
 option(EVENT__DISABLE_DEBUG_MODE
-    "Define if libevent should build without support for a debug mode" OFF)
+    "Define if libevent should build without support for a debug mode" ON)
 
 option(EVENT__ENABLE_VERBOSE_DEBUG
     "Enables verbose debugging" OFF)
@@ -117,7 +117,7 @@ option(EVENT__DISABLE_THREAD_SUPPORT
     "Define if libevent should not be compiled with thread support" OFF)
 
 option(EVENT__DISABLE_OPENSSL
-    "Define if libevent should build without support for OpenSSL encrpytion" OFF)
+    "Define if libevent should build without support for OpenSSL encrpytion" ON)
 
 option(EVENT__DISABLE_BENCHMARK
     "Defines if libevent should build without the benchmark exectuables" OFF)
@@ -328,8 +328,8 @@ CHECK_FUNCTION_EXISTS_EX(strtoll EVENT__HAVE_STRTOLL)
 CHECK_FUNCTION_EXISTS_EX(vasprintf EVENT__HAVE_VASPRINTF)
 CHECK_FUNCTION_EXISTS_EX(sysctl EVENT__HAVE_SYSCTL)
 CHECK_FUNCTION_EXISTS_EX(accept4 EVENT__HAVE_ACCEPT4)
-CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
-CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)
+#CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
+#CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)
 CHECK_FUNCTION_EXISTS_EX(epoll_create1 EVENT__HAVE_EPOLL_CREATE1)
 CHECK_FUNCTION_EXISTS_EX(getegid EVENT__HAVE_GETEGID)
 CHECK_FUNCTION_EXISTS_EX(geteuid EVENT__HAVE_GETEUID)
@@ -492,7 +492,7 @@ CHECK_TYPE_SIZE("void *" EVENT__SIZEOF_VOID_P)
 #CHECK_FILE_OFFSET_BITS()
 #set(EVENT___FILE_OFFSET_BITS _FILE_OFFSET_BITS)
 
-include(CheckWaitpidSupportWNOWAIT)
+#include(CheckWaitpidSupportWNOWAIT)
 
 # Verify kqueue works with pipes.
 if (EVENT__HAVE_KQUEUE)
@@ -846,17 +846,17 @@ if (EVENT__BUILD_SHARED_LIBRARIES)
                                       ${CMAKE_THREAD_LIBS_INIT}
                                       ${LIB_PLATFORM})
 
-  set_target_properties(event
-        PROPERTIES SOVERSION
-            ${EVENT_ABI_LIBVERSION})
+#  set_target_properties(event
+#        PROPERTIES SOVERSION
+#            ${EVENT_ABI_LIBVERSION})
 
-  set_target_properties(event_core
-        PROPERTIES SOVERSION
-            ${EVENT_ABI_LIBVERSION})
+#  set_target_properties(event_core
+#        PROPERTIES SOVERSION
+#            ${EVENT_ABI_LIBVERSION})
 
-  set_target_properties(event_extra
-        PROPERTIES SOVERSION
-            ${EVENT_ABI_LIBVERSION})
+#  set_target_properties(event_extra
+#        PROPERTIES SOVERSION
+#            ${EVENT_ABI_LIBVERSION})
 
 else (EVENT__BUILD_SHARED_LIBRARIES)
     set(EVENT_EXTRA_FOR_TEST event_extra)

    首先我关闭了debug模式和openssl的支持(关于需要的设置因人而异,用户可以自己选择设置。)

    另外我关闭了arc4random和arc4random_buf的检测(关于这部分我会在下文说明)

    去掉了CheckWaitpidSupportWNOWAIT

    另外去掉了编译出来的库文件的版本后缀。(比如最后库文件是libevent.a 而不是libevent.a.2.1.8)

步骤2

    在根目录下创建android.sh,内容如下

NDK_PATH=/Users/yxwang/Library/Android/sdk/ndk-bundle/ #换成你自己的ndk path
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)

BUILD_PATH=$SHELL_FOLDER/android_build/
echo $BUILD_PATH
if [ -x "$BUILD_PATH" ]; then
		rm -rf $BUILD_PATH
fi
mkdir $BUILD_PATH
mkdir $BUILD_PATH/out


for abi in armeabi armeabi-v7a arm64-v8a x86 x86_64
do

  #cmake      
  MakePath=./cmake/build-$abi
  echo $MakePath
	if [ -x "$MakePath" ]; then
		rm -rf $MakePath
	fi
	mkdir $MakePath
	
	OUTPUT_PATH=$BUILD_PATH/out/$abi/
	echo $OUTPUT_PATH
	if [ -x "$OUTPUT_PATH" ]; then
		rm -rf $OUTPUT_PATH
	fi
	mkdir $OUTPUT_PATH
	
	cd $MakePath
	
    # DCMAKE_INSTALL_PREFIX 最后install的路径 这里是 android_build/$abi
    # DCMAKE_TOOLCHAIN_FILE 这个的路劲在android studio中创建一个带有ndk的项目,编译一下,然后
    # 在.externalNativeBuild/cmake/***/cmake_build_command.txt中找到
    # stl 我们使用c++_static
	cmake -DCMAKE_TOOLCHAIN_FILE=$NDK_PATH/build/cmake/android.toolchain.cmake \
    -DANDROID_NDK=$NDK_PATH                      \
    -DCMAKE_BUILD_TYPE=Release                     \
    -DANDROID_ABI=$abi          \
    -DANDROID_NATIVE_API_LEVEL=16                  \
    -DANDROID_STL=c++_static \
    -DCMAKE_CXX_FLAGS=-frtti -fexceptions --std=c++1z \
    -DCMAKE_INSTALL_PREFIX=$OUTPUT_PATH \
    ../..
	
	make -j4
	make install
	
	cd ../..
	
done

     

步骤三

    运行上面的脚本 (chmod +x android.sh添加执行权限才能运行。)

    发现在编译过程中会报出如下错误

            ^
In file included from /Users/yxwang/workspace/gittest/libevent/evutil_rand.c:134:
/Users/yxwang/workspace/gittest/libevent/./arc4random.c:498:1: error: static declaration of 'arc4random_buf' follows non-static
      declaration
arc4random_buf(void *buf_, size_t n)
^
/Users/yxwang/Library/Android/sdk/ndk-bundle/sysroot/usr/include/stdlib.h:124:6: note: previous declaration is here
void arc4random_buf(void* __buf, size_t __n);
     ^
1 error generated.

    什么意思呢,就是我arc4random_buf重复定义了,并且一处是static一处不是,这就出现了冲突,导致编译失败。我们分别来看下两处代码

// arc4random.c

ARC4RANDOM_EXPORT void
arc4random_buf(void *buf_, size_t n)
{
	.....
}

// $NDK_PATH/sysroot/usr/include/stdlib.h
void arc4random_buf(void* __buf, size_t __n);

    其中ARC4RANDOM_EXPORT在evutil_rand.c中有定义

#define ARC4RANDOM_EXPORT static

    查看evutil_rand.c文件,有一个非常关键的宏 EVENT__HAVE_ARC4RANDOM 表示运行的系统是否自带ARC4RANDOM功能。

    如果没有自带,那么ARC4RANDOM_EXPORT 才会被定义为static。这里他被定义为static了,也就是我们告诉了编译器我们没有自带ARC4RANDOM。我们是如何实现的?就是通过

    -CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
    -CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)
    +#CHECK_FUNCTION_EXISTS_EX(arc4random EVENT__HAVE_ARC4RANDOM)
    +#CHECK_FUNCTION_EXISTS_EX(arc4random_buf EVENT__HAVE_ARC4RANDOM_BUF)

    关闭了arc4random检测。

    如果我们开启这个检测,EVENT__HAVE_ARC4RANDOM就会被设置为 1 。

    我们可以通过查看编译过程中自动生成的 event-config.h 文件查看这个宏是否有被设置。

    (如果使用上面提供的脚本可以在cmake/build-xxx/include/event2文件夹中找到自动生成的文件)

    所以干嘛多次一举嘛!干脆开启这个检测好了,尝试编译,竟然通过了!!但是,有个并不算好的消息,一旦你打开检测,cmake检测到arc4random存在,arc4random_buf存在,就把宏打开了,表示你已经实现了arc4random相关的代码了,我就不去定义实现了。

    然后在运行使用的时候,比如调用到了evutil_rand.c中的这个方法

void
evutil_secure_rng_add_bytes(const char *buf, size_t n)
{
	arc4random_addrandom((unsigned char*)buf,
	    n>(size_t)INT_MAX ? INT_MAX : (int)n);
}

    进一步会调用arc4random_addrandom,编译器就会报错,表示arc4random_addrandom这个函数不存在!

    虽然在libevent中这个函数式定义了但是它是现在arc4random.c文件中,只有EVENT__HAVE_ARC4RANDOM未设置的时候才会被#include到evutil_rand.c中。

    所以理论上来说arc4random_addrandom一旦你设置了EVENT__HAVE_ARC4RANDOM,就意味着你需要去实现arc4random_addrandom方法,但是在ndk中,arc4random是被裁剪了的,他只有如下三个方法

                                uint32_t arc4random(void);
                                uint32_t arc4random_uniform(uint32_t __upper_bound);
                                void arc4random_buf(void* __buf, size_t __n);

    我们可以在stdlib.h中看到声明。

    所以为了解决这个问题,做法是手动修改stdlib.h文件,将以上三个定义注释掉。(编译通过之后重新打开,保证我们没有修改ndk,防止以后使用错误)其中stdlib.h文件在ndk-bundle/sysroot/usr/include中。

编译完成

    再次运行android.sh之后编译完成,输出文件在android-build文件夹中,各个abi都已经编译出来。

猜你喜欢

转载自my.oschina.net/zzxzzg/blog/1623523
今日推荐