OpenSSL的编译和使用

个人博客地址:https://blog.yookingh.cn
该文章地址:https://blog.yookingh.cn/dev/201215-openssl.html

环境

  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 :
    • 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

安装

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

  2. 下载并解压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
    
  3. 下载并解压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
    
  4. 下载并解压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

引用

  1. 配置

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

    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

    # 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)
    

你可能感兴趣的:(OpenSSL的编译和使用)