AndroidStudio項目CMakeLists解析

來源:互聯網
上載者:User

標籤:nat   上層   format   att   backtrace   crash   oge   written   依賴   

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

 

上面的完成的有注釋的內容,但其中最核心的也就幾句,下面分別做介紹:

cmake_minimum_required(VERSION 3.4.1) 用來設定在編譯本地庫時我們需要的最小的cmake版本,AndroidStudio自動產生,我們幾乎不需要自己管。

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 )

add_library用來設定編譯產生的本地庫的名字為native-libSHARED表示編譯產生的是動態連結程式庫(這個概念前面已經提到過了),src/main/cpp/native-lib.cpp表示參與編譯的檔案的路徑,這裡面可以寫多個檔案的路徑。

find_library 是用來添加一些我們在編譯我們的本地庫的時候需要依賴的一些庫,由於cmake已經知道系統庫的路徑,所以我們這裡只是指定使用log庫,然後給log庫起別名為log-lib便於我們後面引用,此處的log庫是我們後面調試時需要用來打log日誌的庫,是NDK為我們提供的。

target_link_libraries 是為了關聯我們自己的庫和一些第三方庫或者系統庫,這裡把我們把自己的庫native-lib庫和log庫關聯起來。

NDK自訂配置

1 . 添加多個參與編譯的C/C++檔案

首先,我們發現我們上面的例子都是涉及到一個C++檔案,那麼我們實際的項目不可能只有一個C++檔案,所以我們首先要改變CMakeLists.txt檔案,如下 :

add_library( HelloNDK             SHARED             src/main/cpp/HelloNDK.c             src/main/cpp/HelloJNI.c)

簡單吧,簡單明了,但是這裡要注意的是,你在寫路徑的時候一定要注意當前的CMakeLists.txt在項目中的位置,上面的路徑是相對於CMakeLists.txt 寫的。

2 . 我們想編譯出多個so庫

大家會發現,我們上面這樣寫,由於只有一個CMakeLists.txt檔案,所以我們會把所有的C/C++檔案編譯成一個so庫,這是很不合適的,這裡我們就試著學學怎麼編譯出多個so庫。

先放上我的專案檔夾結構圖:

然後看看我們每個CMakeLists.txt檔案是怎麼寫的:

one檔案夾內的CMakeLists.txt檔案的內容:

ADD_LIBRARY(one-lib SHARED one-lib.c)target_link_libraries(one-lib log)

two檔案夾內的CMakeLists.txt檔案的內容:

ADD_LIBRARY(two-lib SHARED two-lib.c)target_link_libraries(two-lib log)

app目錄下的CMakeLists.txt檔案的內容

# Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)add_library( HelloNDK             SHARED             src/main/cpp/HelloNDK.c             src/main/cpp/HelloJNI.c)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 )target_link_libraries(HelloNDK log)ADD_SUBDIRECTORY(src/main/cpp/one)ADD_SUBDIRECTORY(src/main/cpp/two)

通過以上的配置我們可以看出CMakeLists.txt 檔案的配置是支援繼承的,所以我們在子設定檔中只是寫了不同的特殊配置項的配置,最後在最上層的檔案中配置子設定檔的路徑即可,現在編譯項目,我們會在 <項目目錄>\app\build\intermediates\cmake\debug\obj\armeabi 下面就可以看到產生的動態連結程式庫。而且是三個動態連結程式庫

3 . 更改動態連結程式庫產生的目錄

我們是不是發現上面的so庫的路徑太深了,不好找,沒事,可以配置,我們只需要在頂層的CMakeLists.txt檔案中加入下面這句就可以了

#設定產生的so動態庫最後輸出的路徑set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})

然後我們就可以在app/src/main下看到jniLibs目錄,在其中看到我們的動態連結程式庫的檔案夾和檔案(這裡直接配置到了系統預設的路徑,如果配置到其他路徑需要在gradle檔案中使用jinLibs.srcDirs = [‘newDir‘]進行指定)。

NDK錯誤調試

在開發的過程中,難免會遇到bug,那怎麼辦,打log啊,下面我們就談談打log和看log的姿勢。

1 . 在C/C++檔案中打log

(1) 在C/C++檔案中添加標頭檔

#include <android/log.h>
  • 1

上面是列印日誌的標頭檔,必須添加

(2) 添加列印日誌的宏定義和TAG

//log定義#define  LOG    "JNILOG" // 這個是自訂的LOG的TAG#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 定義LOGD類型#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) // 定義LOGI類型#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) // 定義LOGW類型#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定義LOGE類型#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__) // 定義LOGF類型

上面的記錄層級和Android中的log是對應的。

(3) 經過上面兩步,我們就可以列印日誌啦

int len = 5;LOGE("我是log %d", len);

現在我們就可以在logcat中看到我們列印的日誌啦。

2 . 查看報錯資訊

首先我們先手動寫一個錯誤,我們在上面的C檔案中找一個函數,裡面寫入如下代碼:

int * p = NULL;*p = 100;

上面是一個null 指標異常,我們運行程式,發現崩潰了,然後查看控制台,只有下面一行資訊:

libc: Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 17481

完全看不懂上面的資訊好吧,這個也太不明顯了,下面我們就學習一下如何將上面的資訊變得清楚明了

我們需要用到是ndk-stack工具,它在我們的ndk根目錄下,它可以協助我們把上面的資訊轉化為更為易懂更詳細的報錯資訊,下面看看怎麼做:

(1) 開啟AndroidStudio中的命令列,輸入adb logcat > log.txt

上面這句我們是使用adb命令捕獲log日誌並寫入log.txt檔案,然後我們就可以在項目根目錄下看到log.txt檔案

(2) 將log.txt開啟看到報錯資訊,如下:

F/libc    (17481): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 17481 (dekong.ndkdemo1)I/DEBUG   (   67): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***I/DEBUG   (   67): Build fingerprint: ‘generic/vbox86p/vbox86p:5.0/LRX21M/genymotion08251046:userdebug/test-keys‘I/DEBUG   (   67): Revision: ‘0‘I/DEBUG   (   67): ABI: ‘x86‘I/DEBUG   (   67): pid: 17481, tid: 17481, name: dekong.ndkdemo1  >>> com.codekong.ndkdemo1 <<<I/DEBUG   (   67): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0I/DEBUG   (   67):     eax 00000000  ebx f3494fcc  ecx ffa881a0  edx 00000000I/DEBUG   (   67):     esi f434e2b0  edi 00000000I/DEBUG   (   67):     xcs 00000023  xds 0000002b  xes 0000002b  xfs 00000007  xss 0000002bI/DEBUG   (   67):     eip f3492a06  ebp ffa88318  esp ffa88280  flags 00210246I/DEBUG   (   67):I/DEBUG   (   67): backtrace:I/DEBUG   (   67):     #00 pc 00000a06  /data/app/com.codekong.ndkdemo1-2/lib/x86/libHelloNDK.so (Java_com_codekong_ndkdemo1_MainActivity_updateFile+150)I/DEBUG   (   67):     #01 pc 0026e27b  /data/dalvik-cache/x86/[email protected]@com.codekong.ndkdemo1-[email protected]@classes.dexI/DEBUG   (   67):     #02 pc 9770ee7d  <unknown>I/DEBUG   (   67):     #03 pc a4016838  <unknown>I/DEBUG   (   67):I/DEBUG   (   67): Tombstone written to: /data/tombstones/tombstone_05

現在的報錯資訊還是看不懂,所以我們需要使用ndk-stack轉化一下:

(3) 繼續在AndroidStudio中的命令列中輸入如下命令(在這之前,我們必須要將ndk-stack的路徑添加到環境變數,以便於我們在命令列中直接使用它)

ndk-stack -sym app/build/intermediates/cmake/debug/obj/x86 -dump ./log.txt

上面的-sym後面的參數為你的對應平台(我是Genymotion模擬器,x86平台)的路徑,如果你按照上面的步驟改了路徑,那就需要寫改過的路徑,-dump後面的參數就是我們上一步得出的log.txt檔案,執行結果如下:

********** Crash dump: **********Build fingerprint: ‘generic/vbox86p/vbox86p:5.0/LRX21M/genymotion08251046:userdebug/test-keys‘pid: 17481, tid: 17481, name: dekong.ndkdemo1  >>> com.codekong.ndkdemo1 <<<signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0Stack frame I/DEBUG   (   67):     #00 pc 00000a06  /data/app/com.codekong.ndkdemo1-2/lib/x86/libHelloNDK.so (Java_com_codekong_ndkdemo1_MainActivity_updateFile+150): Routine Java_com_codekong_ndkdemo1_MainActivity_updateFile at F:\AndroidFirstCode\NDKDemo1\app\src\main\cpp/HelloJNI.c:32Stack frame I/DEBUG   (   67):     #01 pc 0026e27b  /data/dalvik-cache/x86/[email protected]@com.codekong.ndkdemo1-[email protected][email protected].dexStack frame I/DEBUG   (   67):     #02 pc 9770ee7d  <unknown>: Unable to open symbol file app/build/intermediates/cmake/debug/obj/x86/<unknown>. Error (22): Invalid argumentStack frame I/DEBUG   (   67):     #03 pc a4016838  <unknown>: Unable to open symbol file app/build/intermediates/cmake/debug/obj/x86/<unknown>. Error (22): Invalid argumentCrash dump is completed

尤其是上面的一句:

g_ndkdemo1_MainActivity_updateFile+150): Routine Java_com_codekong_ndkdemo1_MainActivity_updateFile at F:\AndroidFirstCode\NDKDemo1\app\src\main\cpp/HelloJNI.c:32

準確指出了發生錯誤的行數

AndroidStudio項目CMakeLists解析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.