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 :

安装

  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/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)
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容