安卓下的so,由于需要链接第三方lib库,导出符号时,总是会将第三方的符号也导出了。
根据LD链接,可以指定相应的version_script,简化的version_script为如下格式:
{ global: XXXXXXXXXXX; YYYYYYYYYYYY; local:*; };
XXXXXXXXXXX与YYYYYYYYYYYY即需要导出的符号。
研究了一下,利用nm.exe与awk.exe,实现了在windows下交叉编译时,只导出指定符号
关键代码行:
add_custom_command(TARGET abcd PRE_LINK COMMAND ${ANDROID_NDK}/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-nm.exe -g "$(abcd_OBJECTS)" > ${CMAKE_CURRENT_BINARY_DIR}/cwCrypt_${ANDROID_ABI}.txt COMMAND ..\..\..\..\awk.exe "BEGIN{print(\"{\nglobal:\")} / T /{print $$NF,\";\"} END {print(\"local:*;}\;\")}" ${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.txt > ${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.def COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.txt )
这儿的abcd,即将要链接出来的so文件,默认只导出编译abcd时指定的目标文件中的符号;
利用awk的/ T /过滤掉非导出的符号
这儿会生成一个abcd_armv8.txt及abcd_armv8.def
此命令后会删除txt文件,相应def文件则使用如下命令来删除
add_custom_command(TARGET abcd POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.def)
使用相应的def文件可以有两种实现方式,如下:
#set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--version-script,"${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.def" ${CMAKE_SHARED_LINKER_FLAGS}") set_target_properties(abcd PROPERTIES LINK_FLAGS "-Wl,--version-script,"${CMAKE_CURRENT_BINARY_DIR}/abcd_${ANDROID_ABI}.def"")
如此后,编译出来的so文件,将只剩下编译库时中指定导出的符号,其余符号均会被隐藏为内部符号