問題
部分C++代碼庫,Release版本與Debug版本速度差別很是大,拿以前的Dlib的人臉檢測來講,Debug版本在手機上跑速度基本上是15秒1幀,而Release版本差很少是1秒2幀,這個速度差別很是的大。android
AS上始終編譯不出Release版本的庫文件,又不會在Linux下去編譯SO文件(技術不行,,,加上Android運行環境和Linux也有一點區別)c++
通過多天的摸索,大概有了思路,記錄回顧一下。程序員
Android Studio使用Cmake時的版本設置問題
使用CmakeLists.txt指定,無效。。。
使用build.gradle的arguments指定-DBUILD_TYPE=Release,無效。。。
cppFlags指定-O2或-O3,一樣無效。。。
探查目錄結構
發現一:AS爲了加速使用Cmake的編譯效率,Configure模塊後,會生成.ExternalNativeBuild文件夾,發現該目錄下有cmake/debug和cmake/release兩種版本的配置文件。json
繼續往裏面看,發現有cmake_build_command.txt和android_gradle_build.json。
android_gradle_build.json內容爲以下形式: windows
其中的flags爲編譯此文件的參數。向後拖動,會發現帶有-g、-O0(-O2)等。架構
Debug版本和Release版本的最大區別就是有沒有加入調試信息和有沒有進行優化。優化選項極大的影響了程序的執行速度和效率。jvm
下面的思路是找到這些參數的出處。工具
再來看cmake_build_command.txt內容爲以下:gradle
Executable : F:\sdk\android-sdk-windows\cmake\3.6.4111459\bin\cmake.exe
arguments :
-HE:\AS_Workspace\TestDlibModule0103\dlibtool
-BE:\AS_Workspace\TestDlibModule0103\dlibtool\.externalNativeBuild\cmake\debug\arm64-v8a
-DANDROID_ABI=arm64-v8a
-DANDROID_PLATFORM=android-21
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=E:\AS_Workspace\TestDlibModule0103\dlibtool\build\intermediates\cmake\debug\obj\arm64-v8a
-DCMAKE_BUILD_TYPE=Debug
-DANDROID_NDK=F:\sdk\android-sdk-windows\ndk-bundle
-DCMAKE_CXX_FLAGS=-std=c++11
-DCMAKE_TOOLCHAIN_FILE=F:\sdk\android-sdk-windows\ndk-bundle\build\cmake\android.toolchain.cmake
-DCMAKE_MAKE_PROGRAM=F:\sdk\android-sdk-windows\cmake\3.6.4111459\bin\ninja.exe
-GAndroid Gradle - Ninja
-DANDROID_PLATFORM=android-19
-DANDROID_TOOLCHAIN=clang
-DANDROID_STL=c++_shared
jvmArgs :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
裏面定義了一些參數,發現有-DCMAKE_TOOLCHAIN_FILE=F:\sdk\android-sdk-windows\ndk-bundle\build\cmake\android.toolchain.cmake這樣的參數,打開該文件。優化
可看到以下內容:
找到了一些默認配置,其實都是NDK爲了方便咱們編譯,使用了該工具進行編譯參數上的簡化。
向下翻動,發現目標-g:
上面是通用的flags,不知道爲何默認使用了-g,帶有調試信息的標誌。
下面是Debug和Release的標誌信息。此時的疑問:該處有Dubug和Release版本的區分,爲何在外面進行修改參數,不起做用呢?
猜想、嘗試
.ExternalNativeBuild/cmake/debug和.ExternalNativeBuild/cmake/release中的android_gradle_build.json的flags實際上是不同的。
Debug的flags是-O0,不進行任何優化。
Release的flags是-Os,進行了不縮小代碼體積的O3優化(至關於-O2.5)。
Build/intermediates/下是一些中間文件,找到cmake文件夾,發現只有debug文件夾,說明只生成了debug版本的庫文件。
發現了build variants這麼個東西,欣喜若狂的發現了Release,修改爲Release,立馬Make 模塊名。
從中間文件那裏看到,生成了須要的Release版本的庫文件,大小明顯比Debug版本的要小。
驗證
拷貝到主工程的Jnilibs下,編譯APK,安裝,運行,速度果真相比Debug版本提高不少不少。
使用預編譯的庫出現的問題
發現主工程與導入的module(用到了JNI)關聯後,即便在build.gradle設置了sourceSets.main.jniLib.srcDirs,粘貼了生成好的庫文件,主工程編譯時,仍是會先去檢查被關聯的module的intermediates文件夾中的cmake的debug下的debug版本的so庫是否存在以及是否被替換(猜想應該在哪裏配置了的),若不存在或被替換,則從新去編譯module,生成最新的so庫文件。
而後自動拷貝到生成APK中去。
進一步發現
主工程的libs中的文件優先於module的中間文件的,也就是說APK中的SO庫是來自於libs,但仍是會進行上面的檢查和編譯。
除非刪掉module下的C++代碼和取消CmakeLists.txt,讓Module變成純的JAVA庫。
小問題
因爲module中設置了STL=c++_shared,一開始只將我本身的庫拷貝到了另外的工程的libs去,發現運行時報錯,說找不到libc++_shared.so庫文件,可是在本身的工程中,就不會出現這樣的問題。
本身的工程中,發如今生成的APK中的libs下是有這個庫文件的,猜測也是默認將中間文件添加到了主工程的庫文件當中去(就像上面的那樣,本身的工程中,即便在libs中不加本身的庫,可是有依賴關係的話,主工程就會自動加依賴模塊的庫文件進去,而在別人的工程中,沒有關聯的module或添加的是純JAVA庫不編譯C++代碼)。
解決辦法 手動拷貝libc++_shared.so到主工程的libs下,看成預編譯的庫使用,該文件可在android-sdk-windows\ndk-bundle\sources\cxx-stl\llvm-libc++\libs找到不一樣架構的庫文件。 --------------------- 做者:從程序猿到程序員 來源:CSDN 原文:https://blog.csdn.net/u012525096/article/details/79069623 版權聲明:本文爲博主原創文章,轉載請附上博文連接!