準(zhǔn)備
安裝 win10 上的 Linux子系統(tǒng)(WSL),我選的是 ubuntu
下載 linux 版本的 android-ndk, 我使用的版本是 android-ndk-r21-linux-x86_64 目前最新的版本
下載 dcmtk 的 源碼 ,我使用的版本號(hào)是3.6.5
下載 dcmtk support 包,我選擇的是 dcmtk-3.6.5-win64-support-MD-iconv-msvc-15.8.zip
安裝一個(gè) Visual Studio朝蜘,我使用的是2017版
安裝Cmake 編譯工具
首先說明一下萍歉,為了Android SO庫(kù)的成功,我們需要先編譯一個(gè) VS 的版本燕耿,所以才會(huì)要求先安裝一個(gè) Visual Studio低千,廢話不多說,上面的東西都安裝好了嗎冗澈,去吧钦勘,皮卡 開始吧!
開始
編譯VS版本
我是按照 Jason大神的指示一步一步完成的亚亲,居然還有視頻教程个盆,大神就是大神 。一步一步走下來朵栖,就會(huì)得到一個(gè)編譯完成的 DCMTK 開發(fā)庫(kù)了颊亮。為了湊字?jǐn)?shù),為了記憶深刻一點(diǎn)陨溅,畢竟吃了很多灰终惑,就放幾個(gè)關(guān)鍵知識(shí)點(diǎn)。
CMake_INSTALL_PREFIX 路徑最好不要放在C盤门扇,以防萬一需要管理員權(quán)限雹有,無法生成文件
VS 工程屬性,設(shè)置字符集和運(yùn)行庫(kù)
-
重要:將支持庫(kù)包里的zlib_d.lib拷貝到生成的lib目錄下(如果是區(qū)別Debug庫(kù)和Release庫(kù)臼寄,則應(yīng)該拷貝這兩個(gè)不同的文件霸奕,都改名為zlib.lib,然后在附加庫(kù)配置上填寫zlib.lib)
大概就是這樣了吉拳,大神還提供了驗(yàn)證程序质帅,感謝。
開始編譯Android so庫(kù)
-
打開 WSL留攒,進(jìn)入 dcmtk 源代碼目錄下
由于編譯會(huì)產(chǎn)生很多中間文件煤惩,為了保持源代碼目錄的整潔性,所以在目錄下新建一個(gè) cmake-build 文件夾
mkdir cmake-build
cd cmake-build
進(jìn)入cmake-build 文件夾后炼邀,直接執(zhí)行 cmake 命令魄揉,是不行的,因?yàn)镃make 不知道你要編譯什么平臺(tái)拭宁、什么架構(gòu)洛退、編譯工具鏈?zhǔn)裁吹臇|西都不知道,所以只會(huì)編譯一個(gè)默認(rèn)版本的杰标,作為一個(gè)炮灰以及菜鳥兵怯,我都趟過這些坑。先不說坑了在旱,之后再補(bǔ)摇零。
執(zhí)行命令
cmake -DCMAKE_TOOLCHAIN_FILE=../../android-ndk/android-ndk-r21/build/cmake/android.toolchain.cmake -DANDROID_NDK=../../android-ndk/android-ndk-r21/ -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DBUILD_SHARED_LIBS=ON ..
大概是意思是:我要在 ..
上級(jí)目錄進(jìn)行編譯操作,編譯工具鏈用的是android-ndk里面自帶的 android.toolchain.cmake
,同時(shí)指定了一下 android-ndk
的路徑驻仅,畢竟是要編譯在Android使用的嘛谅畅,最后,直接就編譯 Release 版本吧噪服,平臺(tái)架構(gòu)選擇的是 arm64 的毡泻,還有,我要編譯 so動(dòng)態(tài)鏈接庫(kù)粘优,不是.a
所以開啟 build_shared_libs
開關(guān)吧仇味。
靜候佳音就可以了。
噢雹顺,只有DNK丹墨,沒有SDK不行?還有ANDROID_EMULATOR 的事嬉愧?
那就去 CMake/dcmtkUseAndroidSDK.cmake 一探究竟:
發(fā)現(xiàn)很多函數(shù)贩挣,比如
function(DCMTK_SETUP_ANDROID_EMULATOR)
function(DCMTK_ANDROID_LIST_EMULATORS ONLINE OFFLINE)
function(DCMTK_ANDROID_EMULATOR_GENERATE_UUID VAR)
function(DCMTK_ANDROID_GET_EMULATOR_UUID EMULATOR_NAME VAR)
function(DCMTK_ANDROID_GET_EMULATOR_NAME VAR EMULATOR_UUID)
function(DCMTK_ANDROID_START_EMULATOR VAR)
function(DCMTK_ANDROID_WAIT_FOR_EMULATOR VAR)
function(DCMTK_ANDROID_STOP_EMULATOR VAR)
function(DCMTK_ANDROID_PUSH VAR)
function(DCMTK_ANDROID_SHELL VAR)
...
為什么要使用模擬器呢?經(jīng)過一段時(shí)間摸索没酣,大概的意思就是需要開啟一個(gè)模擬器驗(yàn)證一下編譯的東西能否運(yùn)行王财,我沒有驗(yàn)證這個(gè)事實(shí),但是我覺得我不需要驗(yàn)證了裕便,我相信cmake绒净,T_T有點(diǎn)虛。
那怎么改動(dòng)呢偿衰,我把所有看到的相關(guān) Emulator的函數(shù)挂疆,第一句就寫了 return() ,相當(dāng)于把這個(gè)功能廢了哎垦,但是又不影響別的地方調(diào)用囱嫩,主要是根本改不動(dòng)其他地方.....
就是上面那樣。
然后重新執(zhí)行 cmake 指令
cmake -DCMAKE_TOOLCHAIN_FILE=../../android-ndk/android-ndk-r21/build/cmake/android.toolchain.cmake -DANDROID_NDK=../../android-ndk/android-ndk-r21/ -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DBUILD_SHARED_LIBS=ON ..
之前那個(gè)錯(cuò)誤沒有了漏设,現(xiàn)在又冒出來另一個(gè)錯(cuò)誤:
出錯(cuò)了,不知道為啥今妄。
然后make一下郑口,看看具體的錯(cuò)誤。
看樣子是缺少了很多變量的定義盾鳞,完全不知道怎么回事犬性,通過一段時(shí)間的摸索與對(duì)比,發(fā)現(xiàn)了VS編譯出來的東西與這里cmake出來的東西有一點(diǎn)點(diǎn)區(qū)別腾仅,那就是 arith.h
文件
首先看 cmake-build 目錄下的 (根本沒有)
cmake-build\config\indclude\dcmtk\config\arith.h
但是
內(nèi)容是這樣的:
#ifndef CONFIG_ARITH_H
#define CONFIG_ARITH_H
#define DCMTK_SIGNED_CHAR_DIGITS10 2
#define DCMTK_UNSIGNED_CHAR_DIGITS10 2
#define DCMTK_SIGNED_SHORT_DIGITS10 4
#define DCMTK_UNSIGNED_SHORT_DIGITS10 4
#define DCMTK_SIGNED_INT_DIGITS10 9
#define DCMTK_UNSIGNED_INT_DIGITS10 9
#define DCMTK_SIGNED_LONG_DIGITS10 18
#define DCMTK_UNSIGNED_LONG_DIGITS10 19
#define DCMTK_FLOAT_MAX_DIGITS10 9
#define DCMTK_DOUBLE_MAX_DIGITS10 17
然后打開由VS編譯的版本乒裆,在下面這個(gè)目錄下
\config\include\dcmtk\config\arith.h
#ifndef CONFIG_ARITH_H
#define CONFIG_ARITH_H
#define DCMTK_SIGNED_CHAR_DIGITS10 2
#define DCMTK_UNSIGNED_CHAR_DIGITS10 2
#define DCMTK_SIGNED_SHORT_DIGITS10 4
#define DCMTK_UNSIGNED_SHORT_DIGITS10 4
#define DCMTK_SIGNED_INT_DIGITS10 9
#define DCMTK_UNSIGNED_INT_DIGITS10 9
#define DCMTK_SIGNED_LONG_DIGITS10 9
#define DCMTK_UNSIGNED_LONG_DIGITS10 9
#define DCMTK_FLOAT_MAX_DIGITS10 9
#define DCMTK_DOUBLE_MAX_DIGITS10 17
#define DCMTK_CHAR_TRAPS OFTrue
#define DCMTK_CHAR_MODULO OFTrue
#define DCMTK_SIGNED_CHAR_TRAPS OFTrue
#define DCMTK_SIGNED_CHAR_MODULO OFTrue
#define DCMTK_UNSIGNED_CHAR_TRAPS OFTrue
#define DCMTK_UNSIGNED_CHAR_MODULO OFTrue
#define DCMTK_SIGNED_SHORT_TRAPS OFTrue
#define DCMTK_SIGNED_SHORT_MODULO OFTrue
#define DCMTK_UNSIGNED_SHORT_TRAPS OFTrue
#define DCMTK_UNSIGNED_SHORT_MODULO OFTrue
#define DCMTK_SIGNED_INT_TRAPS OFTrue
#define DCMTK_SIGNED_INT_MODULO OFTrue
#define DCMTK_UNSIGNED_INT_TRAPS OFTrue
#define DCMTK_UNSIGNED_INT_MODULO OFTrue
#define DCMTK_SIGNED_LONG_TRAPS OFTrue
#define DCMTK_SIGNED_LONG_MODULO OFTrue
#define DCMTK_UNSIGNED_LONG_TRAPS OFTrue
#define DCMTK_UNSIGNED_LONG_MODULO OFTrue
#define DCMTK_FLOAT_TRAPS OFFalse
#define DCMTK_DOUBLE_TRAPS OFFalse
#define DCMTK_FLOAT_HAS_INFINITY OFTrue
#define DCMTK_FLOAT_INFINITY *OFreinterpret_cast( const float*, "\000\000\200\177" )
#define DCMTK_DOUBLE_HAS_INFINITY OFTrue
#define DCMTK_DOUBLE_INFINITY *OFreinterpret_cast( const double*, "\000\000\000\000\000\000\360\177" )
#define DCMTK_FLOAT_HAS_QUIET_NAN OFTrue
#define DCMTK_FLOAT_QUIET_NAN *OFreinterpret_cast( const float*, "\000\000\300\377" )
#define DCMTK_DOUBLE_HAS_QUIET_NAN OFTrue
#define DCMTK_DOUBLE_QUIET_NAN *OFreinterpret_cast( const double*, "\000\000\000\000\000\000\370\377" )
#define DCMTK_FLOAT_HAS_SIGNALING_NAN OFTrue
#define DCMTK_FLOAT_SIGNALING_NAN *OFreinterpret_cast( const float*, "\001\000\200\377" )
#define DCMTK_DOUBLE_HAS_SIGNALING_NAN OFTrue
#define DCMTK_DOUBLE_SIGNALING_NAN *OFreinterpret_cast( const double*, "\001\000\000\000\000\000\360\377" )
#define DCMTK_FLOAT_IS_IEC559 OFTrue
#define DCMTK_DOUBLE_IS_IEC559 OFTrue
#define DCMTK_FLOAT_HAS_DENORM OFdenorm_present
#define DCMTK_FLOAT_DENORM_MIN *OFreinterpret_cast( const float*, "\001\000\000\000" )
#define DCMTK_DOUBLE_HAS_DENORM OFdenorm_present
#define DCMTK_DOUBLE_DENORM_MIN *OFreinterpret_cast( const double*, "\001\000\000\000\000\000\000\000" )
#define DCMTK_FLOAT_TINYNESS_BEFORE OFTrue
#define DCMTK_DOUBLE_TINYNESS_BEFORE OFTrue
#define DCMTK_FLOAT_HAS_DENORM_LOSS OFTrue
#define DCMTK_DOUBLE_HAS_DENORM_LOSS OFTrue
#define DCMTK_ROUND_STYLE 1
#endif // CONFIG_ARITH_H
而且隨便看幾個(gè)變量,其實(shí)就是錯(cuò)誤里面報(bào)錯(cuò)的缺少的變量推励。
把多的比較完整的內(nèi)容復(fù)制到 文件中
cmake-build\config\indclude\dcmtk\config\arith.h
然后再執(zhí)行 cmake 命令
cmake -DCMAKE_TOOLCHAIN_FILE=../../android-ndk/android-ndk-r21/build/cmake/android.toolchain.cmake -DANDROID_NDK=../../android-ndk/android-ndk-r21/ -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DBUILD_SHARED_LIBS=ON ..
看到了讓人欣喜的文字
Configuring done
Generating done
最后鹤耍,執(zhí)行 make 命令
make
驗(yàn)證就是 Android JNI 的基本流程了
把 so 庫(kù)放在 libs 文件夾內(nèi)
寫好 CMakeList.txt 文件
編譯好之后有很多庫(kù)肉迫,挑選自己需要使用的模塊進(jìn)行引用就可以了。
已發(fā)布至 jimbray-我說的這句話是謊話