1. 程式人生 > >(轉)android openssl 編譯+demo

(轉)android openssl 編譯+demo

https://blog.csdn.net/lllkey/article/details/82117026

android openssl 編譯+demo

ndk編譯openssl,”armeabi-v7a” “arm64-v8a” “x86” “x86_64” “mip” “mip_64”

  • openssl版本:https://www.openssl.org/source/
  • 參考:
    openssl教程
    openssl推薦的Setenv-android.sh
    ios的openssl編譯:https://github.com/palmerc/CMake_OpenSSL
    目錄:
    
        compile-openssl-android.sh:主要執行程式。
        Setenv-android-input.sh:需要呼叫的設定環境變數程式,基於Setenv-android.h。
        result:編譯完成的結果目錄。
        openssl_change:修改的openssl中的檔案。
    

    執行方法

  • 1 按照本地ndk和openssl路徑修改compile-openssl-android.sh中相關定義
    _ANDROID_NDK_ROOT:ndk絕對路徑
    _OPENSSL_GCC_VERSION:gcc版本號:從ndk絕對路徑/toolchains中看後面的版本號
    _ANDROID_API:從ndk絕對路徑/platforms中找到合適的安卓的版本
    _OPENSSL_ROOT:openssl的絕對路徑
    _INSTALL_ROOT:生成的檔案的絕對路徑
    2 執行compile-openssl-android.sh檔案
    3 將編譯結果複製到/testJniOpenssl/app/src/main/jniLibs目錄中,執行android專案
    ./compile-openssl-android.sh
    

    主要工作

    檔案compile-openssl-android.sh

  • 迴圈各個架構,分別編譯。
  • 步驟:

  • 1 建立結果目錄
    2 根據架構做不同變數設定
    3 設定結果目錄
    4 設定到openssl原始碼目錄,開始在此目錄工作
    5 clean
    6 呼叫say_hello配置各種環境變數
    7 配置openssl,config
    8 編譯,make depend, make。。。
    9 建立結果目錄的lib和include,並將結果複製進去。
    

    除了上述執行方法中提到的之外,其中主要變數含義如下:

    BUILD_SHARED:是否編譯so。
    BUILD_CLANG:本來考慮使用clang編譯,但是現在失敗,但是不用。
    basepath:當前sh呼叫目錄,方便Setenv-android-input.sh的呼叫。
    PLATFORM_LIBRARY_PREFIX:生成的庫的字首,libssl.so,如:lib。
    STATIC_LIBRARY_SUFFIX:靜態庫字尾,如:.a。
    SHARED_LIBRARY_SUFFIX:動態庫字尾,如:.so。
    OPENSSL_MODULES:生成的庫名稱。
    NCPU:make執行緒數。
    OPENSSL_LIBRARIES:最終的生成庫的全稱陣列。如:libssl.a libssl.so。。。
    TARGET_ARCHITECTURE:當前架構,如:x86_64
    INSTALL_DIR:安裝目錄,基於_INSTALL_ROOT目錄之後得到的當前架構的目錄。
    SOURCE_DIR:openssl的目錄。
    ANDROID_EABI_PREFIX:方便之後的字首呼叫,如:x86_64-linux-android。
    ANDROID_DEV_INCLUDE_ROOT:可能包含標頭檔案的目錄名稱,目前與ANDROID_EABI_PREFIX相同。
    ANDROID_TOOLS:ld,gcc,ranlib的路徑,用於Setenv-android-input.sh中確定檔案存在的作用。
    CFLAGS:
    OPTIONS:
    ANDROID_DEV_INCLUDE:在openssl中Configure中需要用到的標頭檔案包含路徑,由於當前ndk版本不同,標頭檔案路徑可能不同,包含了多個可能有標頭檔案的路徑。
    CONFIGURE_COMMAND:openssl的config命令
    LIB_INSTALL_DIR:輸出結果的lib目錄。
    INCLUDE_INSTALL_DIR:輸出結果的include目錄。
    OPENSSL_INCLUDE_DIR:openssl的include目錄。用於複製到INCLUDE_INSTALL_DIR。
    

    檔案Setenv-android-input.sh

        由於在呼叫Setenv-android檔案比較省事,因此直接呼叫,但是需要環境變數保留,新增函式say_hello(),作為函式呼叫。
        雖然有BUILD_CLANG的判斷和環境變數設定,但是由於Clang在openssl中ld會有引數錯誤,所以仍需要檢視原因。
        按照openssl中所講,FIPS_SIG報錯不用關心。
        其中主要變數含義如下:  
     

        ANDROID_NDK_ROOT:ndk路徑
        _ANDROID_EABI:/ndk-bundle/toolchains下的目錄名稱,如:x86_64-4.9。
        _ANDROID_ARCH:/ndk-bundle/platforms/android-27下的目錄名稱,如:arch-x86_64.
        **_ANDROID_API:如:android-27。
        ANDROID_TOOLCHAIN:執行相關執行程式的目錄。如:/ndk-bundle/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin
        PATH:很重要,將ANDROID_TOOLCHAIN新增到環境變數PATH,才能直接呼叫相關的gcc,不然需要設定為絕對路徑。
        ANDROID_TOOLCHAIN_HOST:與ndk安裝相關,為了之後呼叫目錄。如:darwin-x86_64。
        ANDROID_SYSROOT:如:/ndk-bundle/platforms/android-27/arch-x86_64
        CROSS_SYSROOT:ANDROID_SYSROOT
        NDK_SYSROOT:ANDROID_SYSROOT
        MACHINE,RELEASE,SYSTEM,ARCH:為openssl推薦新增,沒有找到用的地方。
        CROSS_COMPILE:字首,在openssl中的Configure中可以看到呼叫gcc的名稱x86_64-linux-android-gcc。如:x86_64-linux-android-。
        ANDROID_DEV:很重要,在openssl中的Configure中可以看到呼叫此路徑下的lib。如:/ndk-bundle/platforms/android-27/arch-x86_64/usr

    openssl中檔案的主要修改

    /Configure檔案

  • 新增x86_64,mips64,64位的時候(由於在ld的時候報錯找不到crtbegin_so.o,需要修改為lib64),ndk中的目錄為lib64:/ndk-bundle/platforms/android-27/arch-mips64/usr/lib64
    由於在某一版本之後ndk的include路徑修改為sysroot下,因此需要新增環境變數:ANDROID_DEV_INCLUDE,作為include的路徑。
    新增在指令碼中定義的CFLAGS:\$(CFLAGS)
    關於android相關內容改為如下,註釋掉原有的內容:
    # Android: linux-* but without pointers to headers and libs.
    # "android","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    # "android-x86","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    # "android-armv7","gcc:-march=armv7-a -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    # "android-mips","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android","gcc: \$(CFLAGS) -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android-x86","gcc: \$(CFLAGS) -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android-armv7","gcc: \$(CFLAGS) -march=armv7-a -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android-mips","gcc: \$(CFLAGS) -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android-x86_64","gcc: \$(CFLAGS) -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib64 -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
    
    "android-mips64","gcc: \$(CFLAGS) -I\$(ANDROID_DEV_INCLUDE) -B\$(ANDROID_DEV)/lib64 -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",

    *PS:由於mips64使用asm加速找不到合適的mips64r6,總報錯,因此修改為no_asm*
    testJniOpenssl測試demo
    jni呼叫openssl函式PKCS5_PBKDF2_HMAC,並將結果返回到介面。專案最低sdk版本為21。在某次更新ndk之後,目前是ndk17,發現platforms的各個版本中arch-mips和arch-mips64目錄都只剩下了一個檔案,沒有lib目錄(如:/xxx/android-sdk-macosx/ndk-bundle/platforms/android-21/),因此無法再編譯mips和arch-mips64的內容了。
    遇到問題

        各種基礎標頭檔案找不到,如stdlib.h等標頭檔案
        解決方法:ndk中支援的標頭檔案沒找到,可以看到報錯的那句中-I的目錄是否有問題,如果有問題,則檢視Configure檔案中的-I後的標頭檔案目錄是否正確,如果正確,則看到配置的目錄中是否有include目錄,如果錯誤,修改sh中定義的目錄,或者Configure中的環境變數,參照當前使用的ANDROID_DEV_INCLUDE。

        openssl支援的架構配置錯誤
        解決方法:確定Configure中是否有當前配置的架構

        在安卓中呼叫的時候出現如下問題:
     

     FAILED: : && /xxx/android-sdk-macosx/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ --target=armv7-none-linux-androideabi --gcc-toolchain=/xxx/android-sdk-macosx/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=/xxx/android-sdk-macosx/ndk-bundle/sysroot -fPIC -isystem /xxx/android-sdk-macosx/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -frtti -fexceptions -O0 -fno-limit-debug-info -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a --sysroot /xxx/android-sdk-macosx/ndk-bundle/platforms/android-15/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o CMakeFiles/native-lib.dir/src/main/cpp/openssl-jni.c.o ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a ../../../../src/main/jniLibs/armeabi-v7a/lib/libssl.a -ldl -llog -latomic -lm "/xxx/android-sdk-macosx/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/libgnustl_static.a" && : ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(cryptlib.o):cryptlib.c:function OPENSSL_showfatal: error: undefined reference to 'stderr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(cryptlib.o):cryptlib.c:function OPENSSL_stderr: error: undefined reference to 'stderr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function close_console: error: undefined reference to 'stdin' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function close_console: error: undefined reference to 'stderr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'signal' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function open_console: error: undefined reference to 'tcgetattr' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function open_console: error: undefined reference to 'stdin' ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function open_console: error: undefined reference to 'stderr' clang++: error: linker command failed with exit code 1 (use -v to see invocation) ninja: build stopped: subcommand failed.

    原因:在ndk15+做了一些改變
    解決方法:在CFLAGS中新增:-D__ANDROID_API__=$_API
    參考:[https://github.com/android-ndk/ndk/issues/445#issuecomment-313322546](https://github.com/android-ndk/ndk/issues/445#issuecomment-313322546)
    PS:此方法在我測試時無用(新增–deprecated-headers,方法無用),我這編譯呼叫時會報如下錯誤:

  • usage: make_standalone_toolchain.py [-h] --arch {arm,arm64,mips,mips64,x86,x86_64} [--api API] [--stl {gnustl,libc++,stlport}] [--force] [-v] [--package-dir PACKAGE_DIR | --install-dir INSTALL_DIR] make_standalone_toolchain.py: error: unrecognized arguments: --deprecated-headers
    

    在安卓中呼叫的時候出現如下問題:

    bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o CMakeFiles/native-lib.dir/src/main/cpp/openssl-jni.c.o  ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a ../../../../src/main/jniLibs/armeabi-v7a/lib/libssl.a -ldl -llog -latomic -lm "/xxx/android-sdk-macosx/ndk-bundle/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/libgnustl_static.a" && :
      /xxx/android-sdk-macosx/ndk-bundle/sources/cxx-stl/llvm-libc++/include/stdexcept:136: error: undefined reference to 'std::logic_error::logic_error(char const*)'
      ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'signal'
      ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr'
      ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function read_string_inner: error: undefined reference to 'tcsetattr'
      ../../../../src/main/jniLibs/armeabi-v7a/lib/libcrypto.a(ui_openssl.o):ui_openssl.c:function open_console: error: undefined reference to 'tcgetattr'
      clang++: error: linker command failed with exit code 1 (use -v to see invocation)
      ninja: build stopped: subcommand failed.

    原因:在編譯openssl的時候,版本用的是21版本編譯,而在android專案中最低版本設定的為15,會報這個錯。因為ndk中的
    /xxx/android-sdk-macosx/ndk-bundle/platforms/android-15/目錄下沒有這兩個架構。
    解決方法:如果要用arm64-v8a或者x86_64架構,需要將最低版本設定為21,或者暫時不使用這兩個架構。

        as編譯時報錯
     

    cxx-stl/llvm-libc /include/stdexcept:136: error: undefined reference to 'std::logic_error::logic_error(char const*)'

    解決方法:在cmake中的引數新增:arguments "-DANDROID_STL=c++_static"
    參考:android.mk中的解決方法
    cmake中的解決方法
    待做

        由於時間問題,目前還有一些冗餘的變數,還未精簡。
        現在clang編譯還是不通過,需要繼續瞭解。參考:ics-openvpn中使用的openssl.cmake這個是Clang可以編譯好的,但是需要固定openssl的各個c檔案,如果換openssl版本,則需要重新改,不清楚是否有其他方法更方便一些。

    程式碼:github上程式碼