Android跨平台编译 —— libevent

2018-02-27 11:23:49来源:oschina作者:街角的小丑人点击

分享

此文大量引用参考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/outfor 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都已经编译出来。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台