此文大量引用参考
前言
前言都在
PS:有一些基础知识介绍,还是挺重要的。
准备工作
编译环境 mac os x
ndk版本 ndk 16rb
libevent版本 2.1.8
编译工具 cmake
假设我们已经在android studio上安装了ndk和cmake。
首先需要下载libevent ,这里有个问题,如果直接从官网上下载tar包,解压之后是没有CMakeLists.txt文件的,所以无法使用cmake进行编译。所以我们需要从github上直接下载,地址
去clone下来,然后checkout到 release-2.1.8-stable 这个tag上。
环境已经准备就绪。
编译
步骤1
首先打开根目录下的CMakeLists.txt文件,有几处改动
diff --git a/CMakeLists.txt b/CMakeLists.txtindex 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 pathSHELL_FOLDER=$(cd "$(dirname "$0")";pwd)BUILD_PATH=$SHELL_FOLDER/android_build/echo $BUILD_PATHif [ -x "$BUILD_PATH" ]; then rm -rf $BUILD_PATHfimkdir $BUILD_PATHmkdir $BUILD_PATH/outfor abi in armeabi armeabi-v7a arm64-v8a x86 x86_64do #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 declarationarc4random_buf(void *buf_, size_t n)^/Users/yxwang/Library/Android/sdk/ndk-bundle/sysroot/usr/include/stdlib.h:124:6: note: previous declaration is herevoid arc4random_buf(void* __buf, size_t __n); ^1 error generated.
什么意思呢,就是我arc4random_buf重复定义了,并且一处是static一处不是,这就出现了冲突,导致编译失败。我们分别来看下两处代码
// arc4random.cARC4RANDOM_EXPORT voidarc4random_buf(void *buf_, size_t n){ .....}// $NDK_PATH/sysroot/usr/include/stdlib.hvoid 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中的这个方法
voidevutil_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都已经编译出来。