个人博客地址:https://blog.yookingh.cn
该文章地址:https://blog.yookingh.cn/dev/201215-openssl.html
环境
- sys-os : Vmware - ubuntu-20.04.1-desktop-amd64
- ndk :
- android-ndk-r15c
- android-ndk-r21d
- openssl : openssl-1.1.1h
- sdk : android-sdk_r24.4.1-linux.tgz
- download :
- Vmware - https://www.vmware.com
- Ubuntu - http://releases.ubuntu.com
- ndk - https://dl.google.com
- openssl : https://www.openssl.org
- sdk : https://dl.google.com
安装
虚拟机和Ubuntu安装这里就不细说了。(Ubuntu更换软件源参考:点这里)
-
下载并解压sdk使用
wget
命令和tar
命令# 在指定目录下执行 指定目录(/home/yooking/Public/android) # wget 下载命令 也可以使用 -P 命令安装到指定目录(/home/yooking/Public/android) # wget -P /home/yooking/Public/android https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz # 下载完毕后解压(进入目标文件夹下执行) # -z或--gzip或--ungzip 通过gzip指令处理备份文件。 # -x或--extract或--get 从备份文件中还原文件。 # -v或--verbose 显示指令执行过程。 # -f<备份文件>或--file=<备份文件> 指定备份文件。(也可以在-zxvf后面输入目标地址) tar -zxvf android-sdk_r24.4.1-linux.tgz
-
下载并解压ndk
# 新建文件夹 /home/yooking/Public/android/android-sdk/ndk # 在ndk文件夹中使用wget命令 wget https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip # 和 wget https://dl.google.com/android/repository/android-ndk-r21d-linux-x86_64.zip # 使用unzip解压这两个压缩包 unzip android-ndk-r15c-linux-x86_64.zip unzip android-ndk-r21d-linux-x86_64.zip
-
下载并解压openssl
# 新建文件夹 /home/yooking/Downloads/openssl wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1h.tar.gz # 使用tar命令解压 tar -zxvf openssl-1.1.1h.tar.gz
创建sh脚本文件并编译
r21和r15有不同
从NDK r19开始,由于gcc兼容clang的编译方式有问题,该版本已经移除了相关gcc文件,所以用老方法交叉编译Openssl的时候,会提示找不到gcc文件。
r15下的sh脚本
参考:https://blog.csdn.net/zoujin6649
# 在 /home/yooking/Downloads/openssl/openssl-1.1.1h 目录下执行
gedit build-android-single.sh
# 修改完后保存即可
build-android-single.sh
脚本文件及注释如下
# 设定openssl路径
OPENSSL_HOME=/home/yooking/Downloads/openssl/openssl-1.1.1h
# 打开openssl文件夹
cd $OPENSSL_HOME
# 设置编译环境 可以是armeabi armeabi-v7a arm64-v8a mips mips64 x86 x86_64
ARCH=arm64-v8a
# if 语句判断 并设置 ARCH_NAME TOOL_CHAIN
echo $ARCH
if [ "$ARCH" = "armeabi-v7a" ]; then
ARCH_NAME=android-arm
TOOL_CHAIN=arm-linux-androideabi-4.9
fi
if [ "$ARCH" = "armeabi" ]; then
ARCH_NAME=android-arm
TOOL_CHAIN=arm-linux-androideabi-4.9
fi
if [ "$ARCH" = "arm64-v8a" ]; then
ARCH_NAME=android-arm64
TOOL_CHAIN=aarch64-linux-android-4.9
fi
if [ "$ARCH" = "mips" ]; then
ARCH_NAME=android-mips
TOOL_CHAIN=mipsel-linux-android-4.9
fi
if [ "$ARCH" = "mips64" ]; then
ARCH_NAME=android-mips64
TOOL_CHAIN=mips64el-linux-android-4.9
fi
if [ "$ARCH" = "x86" ]; then
ARCH_NAME=android-x86
TOOL_CHAIN=x86-4.9
fi
if [ "$ARCH" = "x86_64" ]; then
ARCH_NAME=android-x86_64
TOOL_CHAIN=x86_64-4.9
fi
echo $TOOL_CHAIN #TOOL_CHAIN名称
echo $ARCH_NAME
# 删除之前生成的文件并重新创建
rm -rf ./output-$ARCH
mkdir ./output-$ARCH
# 配置NDK路径
export ANDROID_NDK=/home/yooking/Public/android/android-sdk/ndk/android-ndk-r15c
# 配置TOOL_CHAIN路径
export PATH=$ANDROID_NDK/toolchains/$TOOL_CHAIN/prebuilt/linux-x86_64/bin:$PATH
# 执行Configure文件(openssl-1.1.1h 自带该编译文件)
./Configure $ARCH_NAME -D__ANDROID_API__=23 --prefix=$OPENSSL_HOME/output-$ARCH
# 使用make命令
make && make install
执行脚本
# 第一次执行脚本时需要执行config文件,生成Makefile文件
./config
# 第二次或以上执行前须执行
make clean
# Makefile文件生成后,执行sh命令
sh build-android-single.sh
修改脚本为循环编译,编译所有需要的文件
# 生成循环编译脚本
gedit build-android-all.sh
build-android-all.sh
脚本文件内容如下
#!/bin/bash
func_cmp(){
OPENSSL_HOME=/home/yooking/Downloads/openssl/openssl-1.1.1h
cd $OPENSSL_HOME
make clean
rm -rf ./output-$ARCH
mkdir ./output-$ARCH
export ANDROID_NDK=/home/yooking/Public/android/android-sdk/ndk/android-ndk-r21d
export PATH=$ANDROID_NDK/toolchains/$TOOL_CHAIN/prebuilt/linux-x86_64/bin:$PATH
./Configure $ARCH_NAME -D__ANDROID_API__=23 --prefix=$OPENSSL_HOME/output-$ARCH
make && make install
}
for ARCH in armeabi-v7a armeabi arm64-v8a x86 x86_64 #mips mips64
do
echo $ARCH
if [ "$ARCH" = "armeabi-v7a" ]; then
ARCH_NAME=android-arm
TOOL_CHAIN=arm-linux-androideabi-4.9
fi
if [ "$ARCH" = "armeabi" ]; then
ARCH_NAME=android-arm
TOOL_CHAIN=arm-linux-androideabi-4.9
fi
if [ "$ARCH" = "arm64-v8a" ]; then
ARCH_NAME=android-arm64
TOOL_CHAIN=aarch64-linux-android-4.9
fi
if [ "$ARCH" = "mips" ]; then
ARCH_NAME=android-mips
TOOL_CHAIN=mipsel-linux-android-4.9
fi
if [ "$ARCH" = "mips64" ]; then
ARCH_NAME=android-mips64
TOOL_CHAIN=mips64el-linux-android-4.9
fi
if [ "$ARCH" = "x86" ]; then
ARCH_NAME=android-x86
TOOL_CHAIN=x86-4.9
fi
if [ "$ARCH" = "x86_64" ]; then
ARCH_NAME=android-x86_64
TOOL_CHAIN=x86_64-4.9
fi
echo $TOOL_CHAIN
func_cmp
done
执行脚本方法同上,如为第一次执行(即没有Makefile文件),仍需要执行./config
循环编译无需执行make clean
r21下的sh脚本
参考:https://blog.csdn.net/iamadk
# 创建用于生成toolchain路径的Python脚本
gedit toolchains_path.py
Python
脚本内容
#!/usr/bin/env python
"""
Get the toolchains path
"""
import argparse
import atexit
import inspect
import os
import shutil
import stat
import sys
import textwrap
# 获取路径尾部 - 事实上如果是作为android环境的话,可以直接写 linux-x86_64
def get_host_tag_or_die():
"""Return the host tag for this platform. Die if not supported."""
if sys.platform.startswith('linux'):
return 'linux-x86_64'
elif sys.platform == 'darwin':
return 'darwin-x86_64'
elif sys.platform == 'win32' or sys.platform == 'cygwin':
host_tag = 'windows-x86_64'
if not os.path.exists(os.path.join(NDK_DIR, 'prebuilt', host_tag)):
host_tag = 'windows'
return host_tag
sys.exit('Unsupported platform: ' + sys.platform)
# 这里是获取路径的头部 ndk 为外部传入的值
# 如 android-arm android-arm64 android-x86 android-x86_64
# 这里要注意的是 r21 没有android-mips 和 android-mips64
# toolchains/llvm/prebuilt 为固定的路径
def get_toolchain_path_or_die(ndk, host_tag):
"""Return the toolchain path or die."""
toolchain_path = os.path.join(ndk, 'toolchains/llvm/prebuilt',
host_tag)
if not os.path.exists(toolchain_path):
sys.exit('Could not find toolchain: {}'.format(toolchain_path))
return toolchain_path
def main():
"""Program entry point."""
parser = argparse.ArgumentParser(description='Optional app description')
parser.add_argument('--ndk', required=True,
help='The NDK Home directory')
args = parser.parse_args()
host_tag = get_host_tag_or_die()
toolchain_path = get_toolchain_path_or_die(args.ndk, host_tag)
print toolchain_path
if __name__ == '__main__':
main()
创建编译执行脚本
#!/bin/bash
# 防止滚雪球型报错 如果任何语句的执行结果不是true则应该退出
set -e
# linux输出详细日志 r15的脚本中使用的是echo来输出
set -x
# Set directory
OPENSSL_DIR=/home/yooking/Downloads/openssl/openssl-1.1.1h
export ANDROID_NDK_HOME=/home/yooking/Public/android/android-sdk/ndk/android-ndk-r21d
# Find the toolchain for your build machine
# 执行Python脚本 生成 toolchain路径
toolchains_path=$(python toolchains_path.py --ndk ${ANDROID_NDK_HOME})
# Configure the OpenSSL environment, refer to NOTES.ANDROID in OPENSSL_DIR
# Set compiler clang, instead of gcc by default
# 设置clang执行
CC=clang
# Add toolchains bin directory to PATH
PATH=$toolchains_path/bin:$PATH
# Set the Android API levels
ANDROID_API=21
# Set the target architecture
# Can be android-arm, android-arm64, android-x86, android-x86 etc
# 设置编译环境
architecture=android-arm
# Create the make file
cd ${OPENSSL_DIR}
./Configure ${architecture} -D__ANDROID_API__=$ANDROID_API
# Build
make
# Copy the outputs
# 将生成的目标文件复制到对应的目录下
OUTPUT_INCLUDE=$SCRIPTPATH/output/include
OUTPUT_LIB=$SCRIPTPATH/output/lib/${architecture}
mkdir -p $OUTPUT_INCLUDE
mkdir -p $OUTPUT_LIB
cp -RL include/openssl $OUTPUT_INCLUDE
cp libcrypto.so $OUTPUT_LIB
cp libcrypto.a $OUTPUT_LIB
cp libssl.so $OUTPUT_LIB
cp libssl.a $OUTPUT_LIB
执行编译脚本同r15,第一次需要执行./config
生成Makefile,第二次或以上需要清除make记录即make clean
,接下来依旧是创建循环编译脚本
#!/bin/bash
func_cmp(){
# Set directory
OPENSSL_DIR=/home/yooking/Downloads/openssl/openssl-1.1.1h
export ANDROID_NDK_HOME=/home/yooking/Public/android/android-sdk/ndk/android-ndk-r21d
# Find the toolchain for your build machine
toolchains_path=$(python toolchains_path.py --ndk ${ANDROID_NDK_HOME})
# Configure the OpenSSL environment, refer to NOTES.ANDROID in OPENSSL_DIR
# Set compiler clang, instead of gcc by default
CC=clang
# Add toolchains bin directory to PATH
PATH=$toolchains_path/bin:$PATH
# Set the Android API levels
ANDROID_API=21
# Set the target architecture
# Can be android-arm, android-arm64, android-x86, android-x86_64 etc
architecture=$ARCH_NAME
# Create the make file
cd ${OPENSSL_DIR}
./Configure ${architecture} -D__ANDROID_API__=$ANDROID_API
# Build
make
# Copy the outputs
OUTPUT_INCLUDE=$OPENSSL_DIR/output/include
OUTPUT_LIB=$OPENSSL_DIR/output/libs/${ARCH}
mkdir -p $OUTPUT_INCLUDE
mkdir -p $OUTPUT_LIB
cp -RL include/openssl $OUTPUT_INCLUDE
cp libcrypto.so $OUTPUT_LIB
cp libcrypto.a $OUTPUT_LIB
cp libssl.so $OUTPUT_LIB
cp libssl.a $OUTPUT_LIB
# 这里加入make clean 每次编译完成后直接清理
make clean
}
set -e
set -x
# 循环体
for ARCH in armeabi-v7a armeabi arm64-v8a x86 x86_64
do
if [ "$ARCH" = "armeabi-v7a" ]; then
ARCH_NAME=android-arm
fi
if [ "$ARCH" = "armeabi" ]; then
ARCH_NAME=android-arm
fi
if [ "$ARCH" = "arm64-v8a" ]; then
ARCH_NAME=android-arm64
fi
if [ "$ARCH" = "x86" ]; then
ARCH_NAME=android-x86
fi
if [ "$ARCH" = "x86_64" ]; then
ARCH_NAME=android-x86_64
fi
func_cmp
done
引用
-
配置
- Android Studio - gradle:3.5.2
- ndk - android-ndk-r21d
-
使用
将自动生成的cpp下的CMakeLists.txt移动到app下(个人习惯)
同时也要修改app/build.gradle
externalNativeBuild { cmake { path "CMakeLists.txt" version "3.10.2" } }
将
sh脚本文件
执行后生成的libs文件夹复制到app/src/main/cpp
下将
sh脚本文件
执行后生成的include下的openssl文件夹复制到app/src/main/cpp
下-
配置CMakeLists
# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.4.1) # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. # 表示把src/main/cpp加入到include目录,这样在代码中使用:#include <...>就能访问到头文件 # openssl 中 .h 文件的引用方式是 include
而事实上这些是在同一个文件夹下,并不需要openssl/,为使能正常使用 所以添加 include_directories include_directories(src/main/cpp) # 这是原有的 无需修改 add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). src/main/cpp/native-lib.cpp) # 添加两个预编译库 - 1 add_library(# Sets the name of the library. openssl-crypto # Sets the library as a static library. STATIC IMPORTED) set_target_properties( # Specifies the target library. openssl-crypto # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import. # 完整路径 ${CMAKE_SOURCE_DIR}/src/main/cpp/libs/${ANDROID_ABI}/libcrypto.a) # 添加两个预编译库 - 2 add_library(# Sets the name of the library. openssl-ssl # Sets the library as a static library. STATIC IMPORTED) set_target_properties( # Specifies the target library. openssl-ssl # Specifies the parameter you want to define. PROPERTIES IMPORTED_LOCATION # Provides the path to the library you want to import. # 完整路径 ${CMAKE_SOURCE_DIR}/src/main/cpp/libs/${ANDROID_ABI}/libssl.a) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. # 将新的编译库加入链接池中 target_link_libraries( # Specifies the target library. native-lib # Links the target library to the log library # included in the NDK. ${log-lib} openssl-ssl openssl-crypto)