在ndk或者jni開發(fā)過程中,我們經(jīng)常會有打日志的需求,并且需要顯示日志輸出的源文件名稱、行數(shù)等信息,這時候就需要我們輸出一個完整的日志格式。本文針對采用ndk-build方式編譯,如果是采用cmake編譯,不再本文討論范圍之內(nèi)
常見宏
首先我們看一下ANSI C標(biāo)準(zhǔn)中幾個標(biāo)準(zhǔn)預(yù)定義宏:
-
__LINE__:在源代碼中插入當(dāng)前源代碼行號; -
__FILE__:在源文件中插入當(dāng)前源文件名; -
__DATE__:在源文件中插入當(dāng)前的編譯日期; -
__TIME__:在源文件中插入當(dāng)前編譯時間; -
__STDC__:當(dāng)要求程序嚴格遵循ANSI C標(biāo)準(zhǔn)時該標(biāo)識被賦值為1;
假設(shè)你的日志輸出格式:
#define NEW_LINE "\r\n"
#define G_STRLOC __FILE__ ":" G_STRINGIFY (__LINE__)
#define DEBUG(fmt, ...) {
debug_to_file(G_STRLOC " " fmt NEW_LINE, ## __VA_ARGS__);
}
我們可以看到,這里定義的了一個宏__FILE__這個就是當(dāng)前源文件
舉個栗子
正如上面例子所示,使用了__FILE__之后,默認情況下,輸出的路徑是編譯該源文件時,該源文件在編譯環(huán)境下的全路徑,例如你的源文件路徑是在/User/eggsy/Demo/src/main/jni/test.c,在該文件的58行中有代碼
58 DEBUG("ouput demo log %s","success");
那么輸出的時候日志就是
/User/eggsy/Demo/src/main/jni/test.c:58 ouput demo log success
這里我們看到輸出的就是在源文件的全路徑,當(dāng)前路徑看起來過長了,如果你的工程目錄層級在系統(tǒng)更深處,那么這里前面打印出來的日志路徑就非常長了,其實對我們最重要的是從jni目錄開始日志路徑,能夠完整說明源文件路徑
解決方案
傳統(tǒng)方式
先來說下傳統(tǒng)的編譯方式,采用ndk-build方式,我們經(jīng)常需要在如下目錄下放置Android.mk與Application.mk文件

在build.gradle中我們需要配置指定Android.mk文件位置
// 引入工程外部的編譯文件
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
這種方式編譯出來的,日志中源文件路徑就是全路徑。
優(yōu)化方式
優(yōu)化方式就是我們需要切到src/main/jni目錄下,
cd src/main/jni
執(zhí)行ndk-build命令
ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk NDK_LIBS_OUT=../output/libs
-
NDK_PROJECT_PATH:指定工程的路徑,由于我們已經(jīng)cd到了jni目錄,這里就用.表示當(dāng)前路徑 -
NDK_APPLICATION_MK:表示application的配置 -
APP_BUILD_SCRIPT:表示構(gòu)建腳本的路徑 -
NDK_LIBS_OUT:表示最后生成動靜態(tài)的位置
所以我們看到如上圖目錄結(jié)構(gòu)中的ouput目錄下會生成我們編譯的庫。
最后生成日志的時候,就是相對路徑啦,沒有前面一大堆絕對路徑?。。?/p>
LOCAL_SRC_FILES源碼路徑
最后距離成功還差一步,,參考上面的《目錄結(jié)構(gòu)》圖片,在Android.mk中,在引用源文件的時候,要用相對路徑,如果使用絕對路徑(LOCAL_PATH變量+源文件),上面的修改就無效了,例如
LOCAL_SRC_FILES := $(LOCAL_PATH)/andsrc/demo.c ......
需要改為
LOCAL_SRC_FILES := andsrc/demo.c ......
這樣的相對路徑,相對路徑是相對于Android.mk的當(dāng)前路徑而言。
總結(jié)
其實這個小技巧很簡單,但是真正遇到的時候可能會困擾一些同學(xué)很久,最關(guān)鍵的就是編譯的時候需要指定NDK_PROJECT_PATH、NDK_APPLICATION_MK、APP_BUILD_SCRIPT參數(shù)啦,當(dāng)然這些參數(shù)你也可以配置在gradle中,無需手動執(zhí)行