0%

OpenSSL的编译和使用

环境

  1. sys-os : Vmware - ubuntu-20.04.1-desktop-amd64
  2. ndk :
    • android-ndk-r15c
    • android-ndk-r21d
  3. openssl : openssl-1.1.1h
  4. sdk : android-sdk_r24.4.1-linux.tgz
  5. download :

安装

  1. 虚拟机和Ubuntu安装这里就不细说了。(Ubuntu更换软件源参考:点这里)

  2. 下载并解压sdk使用wget命令和tar命令

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 在指定目录下执行 指定目录(/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
  3. 下载并解压ndk

    1
    2
    3
    4
    5
    6
    7
    8
    # 新建文件夹 /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
  4. 下载并解压openssl

    1
    2
    3
    4
    # 新建文件夹 /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

1
2
3
# 在 /home/yooking/Downloads/openssl/openssl-1.1.1h 目录下执行
gedit build-android-single.sh
# 修改完后保存即可

build-android-single.sh脚本文件及注释如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 设定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

执行脚本

1
2
3
4
5
6
# 第一次执行脚本时需要执行config文件,生成Makefile文件
./config
# 第二次或以上执行前须执行
make clean
# Makefile文件生成后,执行sh命令
sh build-android-single.sh

修改脚本为循环编译,编译所有需要的文件

1
2
# 生成循环编译脚本
gedit build-android-all.sh

build-android-all.sh脚本文件内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/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

1
2
# 创建用于生成toolchain路径的Python脚本
gedit toolchains_path.py

Python脚本内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/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()

创建编译执行脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/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,接下来依旧是创建循环编译脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/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

引用

  1. 配置

    • Android Studio - gradle:3.5.2
    • ndk - android-ndk-r21d
  2. 使用
    将自动生成的cpp下的CMakeLists.txt移动到app下(个人习惯)
    同时也要修改app/build.gradle

    1
    2
    3
    4
    5
    6
    externalNativeBuild {
    cmake {
    path "CMakeLists.txt"
    version "3.10.2"
    }
    }
  3. sh脚本文件执行后生成的libs文件夹复制到app/src/main/cpp

  4. sh脚本文件执行后生成的include下的openssl文件夹复制到app/src/main/cpp

  5. 配置CMakeLists

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    # 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/symhacks.h> 而事实上这些是在同一个文件夹下,并不需要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)

使用

------------本文结束感谢您的阅读------------

Thank you for your accept!