前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​openssl Android编译指南

​openssl Android编译指南

原创
作者头像
望天
发布2019-09-16 17:58:38
6.4K1
发布2019-09-16 17:58:38
举报
文章被收录于专栏:along的开发之旅along的开发之旅

openssl Android编译指南


1. openssl选择分支OpenSSL_1_1_1-stable

代码语言:txt
复制
git checkout OpenSSL_1_1_1-stable

1.1 修改build.info

打开根目录下的build.info, 注释下面几行, 在Line:590~594, 否则会有类似错误提示 ${LDCMD:-g++} ld: unknown option: --sysroot=.

代码语言:txt
复制
  # PROGRAMS_NO_INST=buildtest_cc_$name
  # SOURCE[buildtest_cc_$name]=buildtest_$name.cc
  # GENERATE[buildtest_$name.cc]=generate_buildtest.pl $name
  # INCLUDE[buildtest_cc_$name]=../include
  # DEPEND[buildtest_cc_$name]=../libssl ../libcrypto

1.2 修改Configurations/15-android.conf

默认生成的so命名为libcrypto.so.1.1, 这样样式的在Android中使用System.loadLibrary加载会失败, 因为Android系统不能识别这种so.

查看手机的/system/lib, 也可以发现系统内部的so也都是lib*.so这样的命名.

直接修改so的名字是不行的, 因为在so的SONAME内会指出该so的名字, 该so依赖的其他so名字.(见个例子使用macos上的rpl执行全文字符串替换)

代码语言:txt
复制
> android-ndk-r18b/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readobj -dynamic-table libssl.1.1.so
  0x00000001 NEEDED               Shared library: [libcrypto.1.1.so]
  0x00000001 NEEDED               Shared library: [libdl.so]
  0x00000001 NEEDED               Shared library: [libc.so]
  0x0000000E SONAME               Library soname: [libssl.1.1.so]

为了使Android可以正常加载so, 我们改变生成so的名字. so的版本号在版本管理时还是很有用的, 所以我们生成的so命名格式为libcrypto.1.1.so, 这样既有版本号, 也不影响Android正常加载.

打开Configurations/15-android.conf, 在第173行增加shared_extension => ".\$(SHLIB_VERSION_NUMBER).so", 修改完成后如下所示:

代码语言:txt
复制
    "android" => {
        inherit_from     => [ "linux-generic32" ],
        template         => 1,
        cflags           => add(sub { android_ndk()->{cflags} }),
        cppflags         => add(sub { android_ndk()->{cppflags} }),
        cxxflags         => add(sub { android_ndk()->{cflags} }),
        bn_ops           => sub { android_ndk()->{bn_ops} },
        bin_cflags       => "-pie",
        enable           => [ ],
        # 重定义`shared_extension`, 修改生成的so名字
        shared_extension => ".\$(SHLIB_VERSION_NUMBER).so",
    },

2. 编译前需要安装的工具

代码语言:txt
复制
perl  
make  
ndk

最好在Linux/MacOS下编译, 在Windows下编译最好使用MSYS2, Windows下编译官网没有正式测试.

目前Android在ndk r18里移除了gcc, 在ndk r19里不再推荐Standalone Toolchains, 所以这里我们裸用clang来进行编译. 使用的ndk为r18b. 但是随着编译另外的curl和ffmpeg, 我觉得还是用 Standalone Toolchains更方便些.

同时笔者喜欢使用ripgrep替代grep, 在一些辅助命令中, 你可能会看到rg.

3. 配置和编译

Android是跨平台编译, 你应该使用./Configure而不是./config.

Android支持平台列表:

代码语言:txt
复制
android-arm 
android-arm64 
android-mips 
android-mip64 
android-x86
android-x86_64

不要传递--cross-compile-prefix, ./Configure会基于你输入的platform自动选择.

不过为了调用指定平台的$(CROSS_COMPILE)/gcc编译器, 你仍然需要在PATH里指定特定gcc所在位置, 参考下文配置.

除了PATH外, 你还必须设置ANDROID_NDK_HOME环境变量来指定NDK的目录, 如/some/where/android-ndk-<ver>.

这两个变量, PATHANDROID_NDK_HOME在配置和编译时期都很重要.

NDK通常支持多个Android API级别, 你可以在android-ndk-<ver>/platforms下面找到所有支持的API级别, 如android-14, android-21.

openssl默认会选择最新的API level. 如果你想支持比较老的target platform, 传递-D__ANDROID_API__=Num来配置,

这里Num是target platform的版本号.

示例: compile for JELLY_BEAN(Android 4.1, API Level16) on ARM with NDK r18b

代码语言:txt
复制
export ANDROID_NDK=/Users/along/Library/Android/android-ndk-r18b
export PATH=$ANDROID_NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin:$PATH
export CC=clang
export RANLIB=:
export AR=llvm-ar
export ARFLAGS=rs
./Configure android-arm -D__ANDROID_API__=16 --prefix=$(pwd)/android-arm
make 
make install

这里clang表示, 当ARFLAGS=rs时, RANLIB不是必须的, 所以这里留空.

这样就会在android-arm目录下生成.so和.a文件.

代码语言:txt
复制
> tree -L 2
.
├── bin
│   ├── c_rehash
│   └── openssl
├── include
│   └── openssl
├── lib
│   ├── engines-1.1
│   ├── libcrypto.1.1.so
│   ├── libcrypto.a
│   ├── libcrypto.so -> libcrypto.1.1.so
│   ├── libssl.1.1.so
│   ├── libssl.a
│   ├── libssl.so -> libssl.1.1.so
│   └── pkgconfig

> rg -uu --files . | rg so$\|a$ | xargs ls -alh
-rwxr-xr-x  1 along  staff   2.5M Mar 28 16:45 ./lib/libcrypto.1.1.so
-rw-r--r--  1 along  staff   3.9M Mar 28 16:45 ./lib/libcrypto.a
-rwxr-xr-x  1 along  staff   577K Mar 28 16:45 ./lib/libssl.1.1.so
-rw-r--r--  1 along  staff   737K Mar 28 16:45 ./lib/libssl.a

注意

早期的OpenSSL版本依赖于CROSS_SYSROOT变量, 这个变量一般设置为$ANDROID_NDK_HOME/platforms/android-<api>/arch-<arch>, 是为了指定headers-n-libraries位置. 新版本openssl中, 为了兼容旧项目, 这个变量仍可以被识别. 但是由于CROSS_SYSROOT包含了Android的API level, 再传递-D__ANDROID_API__=Num可能导致冲突, 因为openssl不支持混合提供这两个变量. 建议不在使用CROSS_SYSROOT.

4. 使用

在CMakeList中使用如下

代码语言:txt
复制
cmake_minimum_required(VERSION 3.4.1)
# 要打的so名字 native-lib
add_library(native-lib SHARED native-lib.cpp)
# 引入openssl的头文件
target_include_directories(native-lib PRIVATE ${CMAKE_SOURCE_DIR}/include)
# 引入 libssl.1.1.so
add_library(mylibssl SHARED IMPORTED)
set_target_properties(mylibssl PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libssl.1.1.so)
# 引入 libcrpto.1.1.so
add_library(mylibcrypto SHARED IMPORTED)
set_target_properties(mylibcrypto PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libcrypto.1.1.so)
# 引入系统log
find_library(log-lib log)
# 注意find_library和add_library的库名, 引用方式不一样. 使用{mylibssl}时, 不会报错, 但是libssl.so并没有被找到, 只会提示找不到函数定义
target_link_libraries(native-lib
        ${log-lib}
        mylibssl
        mylibcrypto
        )

这样在Java代码中就可以使用如下方式加载.

代码语言:txt
复制
        System.loadLibrary("ssl.1.1");
        System.loadLibrary("crypto.1.1");

5. 解惑

遇到不解的, 还是查看github上的openssl文档和issue, 里面有很多前人提的问题.

Android是INSTALLNOTES.ANDROID, 编译遇到问题, 可以查看INSTALL的Troubleshooting章节.

官网推荐的帮助:

代码语言:txt
复制
        INSTALL         Linux, Unix, Windows, OpenVMS, ...
        NOTES.*         INSTALL addendums for different platforms

最后提醒下, 不要过度参考"https://wiki.openssl.org/index.php/Android", github上openssl的维护人员称该文档太久没有更新, 参考INSTALL和NOTES.*.

6. 参考文档:

https://github.com/openssl/openssl/blob/6bc62a620e/NOTES.ANDROID

https://github.com/openssl/openssl/blob/6bc62a620e/INSTALL

https://developer.android.com/ndk/guides/standalone_toolchain

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. openssl选择分支OpenSSL_1_1_1-stable
    • 1.1 修改build.info
      • 1.2 修改Configurations/15-android.conf
      • 2. 编译前需要安装的工具
      • 3. 配置和编译
        • 注意
        • 4. 使用
        • 5. 解惑
        • 6. 参考文档:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档