文章目录
发现网上基本上很少有给出Android16k的XLog相关适配,记录一下windows环境从xlog编译到适配16k相关过程。
编译XLog
本地安装Python3
首先下载Python3.14.2
可以在控制台判断Python是否安装成功

安装NDK
现在xlog官方文档写的是下载ndk-r20,我这边下载安装的是ndk-25,可以去Android官方下载,也可以在AndroidStudio下载(路径在sdk目录的ndk文件夹里)
在环境变量中新建NDK_ROOT,值为NDK目录

然后将NDK_ROOT添加到PATH中

验证NDK安装是否成功

安装CMake
这里可以去CMake官网下载,也可以在AndroidStudio下载,这里选择的版本是3.22.1。
验证安装是否成功

安装cygwin
windows还需要cygwin,从 https://cygwin.com 上下载 setup-x86.exe 或 setup-x86_64.exe。
选择Install from Internet

然后下一步下一步,在"User URL"处输入以下地址:
这里选择阿里云的即可

接着点击下一步
接着选择Full

可以选择自己需要的包进行安装,这里需要make, gcc gdb



最后,点击下一步,即可安装成功。
然后还需要在cygwin下的bin目录配置到环境变量PATH中

进行编译
使用cmd进入mars/mars项目,所有的编译脚本都在mars/mars 目录。
执行下面指令
bash
Python build_android.py

这里有4个选项
如果选择编译Mars,选择1或2,如果仅编译XLog,选择3
这里选择3,稍微等一会,就编译成功了

接着,在mars\libraries\mars_xlog_sdk\libs\armeabi-v7a路径下,就可以看到,我们编译后的so文件了。

因为脚本指定了armeabi-v7a和arm64-v8a所有生成了两个so文件,你可以指定具体生成的文件。

注意事项(会导致编译不过)
- build_android.py文件中的ANDROID_STL_FILE需要换成你ndk不同cpu架构的so文件路径
- ANDROID_STRIP_FILE用于指定不同CPU架构(ABI)对应的strip工具路径,目的在于编译完.so动态库之后,剥离调试符号、减小文件体积。你可以发现不执行strip和执行strip,so文件体积大小还是差别挺大的。NDK r19+移除了独立的GCC/Clang toolchain目录结构,NDK 19+所有架构的strip工具都统一为llvm-strip( D:\AndroidSDK\ndk\25.1.8937393\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-strip.exe)
主要修改代码
py
#!/usr/bin/env python3
import os
import sys
import glob
import time
import shutil
import platform
from mars_utils import *
SCRIPT_PATH = os.path.split(os.path.realpath(__file__))[0]
def system_is_windows():
return platform.system() == 'Windows'
def system_architecture_is64():
return platform.machine().endswith('64')
if system_is_windows():
ANDROID_GENERATOR = '-G "Unix Makefiles"'
else:
ANDROID_GENERATOR = ''
try:
NDK_ROOT = os.environ['NDK_ROOT']
except KeyError as identifier:
NDK_ROOT = ''
BUILD_OUT_PATH = 'cmake_build/Android'
ANDROID_LIBS_INSTALL_PATH = BUILD_OUT_PATH + '/'
ANDROID_BUILD_CMD = 'cmake "%s" %s -DANDROID_ABI="%s" ' \
'-DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=%s/build/cmake/android.toolchain.cmake ' \
'-DANDROID_TOOLCHAIN=clang -DANDROID_NDK=%s ' \
'-DANDROID_PLATFORM=android-21 ' \
'-DANDROID_STL="c++_shared" ' \
'&& cmake --build . %s --config Release -- -j8'
ANDROID_SYMBOL_PATH = 'libraries/mars_android_sdk/obj/local/'
ANDROID_LIBS_PATH = 'libraries/mars_android_sdk/libs/'
ANDROID_XLOG_SYMBOL_PATH = 'libraries/mars_xlog_sdk/obj/local/'
ANDROID_XLOG_LIBS_PATH = 'libraries/mars_xlog_sdk/libs/'
ANDROID_STRIP_FILE = NDK_ROOT + '/toolchains/llvm/prebuilt/%s/bin/llvm-strip'
ANDROID_STL_FILE = {
'armeabi-v7a': NDK_ROOT + '/toolchains/llvm/prebuilt/%s/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so',
'arm64-v8a': NDK_ROOT + '/toolchains/llvm/prebuilt/%s/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so',
'x86': NDK_ROOT + '/toolchains/llvm/prebuilt/%s/sysroot/usr/lib/i686-linux-android/libc++_shared.so',
'x86_64': NDK_ROOT + '/toolchains/llvm/prebuilt/%s/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so',
}
def get_android_strip_cmd():
system_str = platform.system().lower()
if (system_architecture_is64()):
system_str = system_str + '-x86_64'
else:
pass
strip_cmd = ANDROID_STRIP_FILE %(system_str)
print('Android strip cmd:%s' %(strip_cmd))
return strip_cmd
def get_android_stl_cmd(arch):
system_str = platform.system().lower()
if (system_architecture_is64()):
system_str = system_str + '-x86_64'
else:
pass
stl_cmd = ANDROID_STL_FILE[arch] %(system_str)
print('Android stl cmd:%s' %(stl_cmd))
return stl_cmd
def build_android(incremental, arch, target_option=''):
before_time = time.time()
clean(BUILD_OUT_PATH, incremental)
os.chdir(BUILD_OUT_PATH)
build_cmd = ANDROID_BUILD_CMD %(SCRIPT_PATH, ANDROID_GENERATOR, arch, NDK_ROOT, NDK_ROOT, target_option)
print("build cmd:" + build_cmd)
ret = os.system(build_cmd)
os.chdir(SCRIPT_PATH)
if 0 != ret:
print('!!!!!!!!!!!!!!!!!!build fail!!!!!!!!!!!!!!!!!!!!')
return False
if len(target_option) > 0:
symbol_path = ANDROID_XLOG_SYMBOL_PATH
lib_path = ANDROID_XLOG_LIBS_PATH
else:
symbol_path = ANDROID_SYMBOL_PATH
lib_path = ANDROID_LIBS_PATH
if not os.path.exists(symbol_path):
os.makedirs(symbol_path)
symbol_path = symbol_path + arch
if os.path.exists(symbol_path):
shutil.rmtree(symbol_path)
os.mkdir(symbol_path)
if not os.path.exists(lib_path):
os.makedirs(lib_path)
lib_path = lib_path + arch
if os.path.exists(lib_path):
shutil.rmtree(lib_path)
os.mkdir(lib_path)
for f in glob.glob(ANDROID_LIBS_INSTALL_PATH + "*.so"):
shutil.copy(f, symbol_path)
shutil.copy(f, lib_path)
# copy stl
stl_cmd = get_android_stl_cmd(arch)
shutil.copy(stl_cmd, symbol_path)
shutil.copy(stl_cmd, lib_path)
#strip
strip_cmd = get_android_strip_cmd()
for f in glob.glob('%s/*.so' %(lib_path)):
os.system('%s %s' %(strip_cmd, f))
print('==================Output========================')
print('libs(release): %s' %(lib_path))
print('symbols(must store permanently): %s' %(symbol_path))
after_time = time.time()
print("use time:%d s" % (int(after_time - before_time)))
return True
def main(incremental, archs, target_option='', tag=''):
if not check_ndk_env():
return
gen_mars_revision_file(SCRIPT_PATH + '/comm', tag)
# if os.path.exists(ANDROID_LIBS_PATH):
# shutil.rmtree(ANDROID_LIBS_PATH)
# if os.path.exists(ANDROID_SYMBOL_PATH):
# shutil.rmtree(ANDROID_SYMBOL_PATH)
for arch in archs:
if not build_android(incremental, arch, target_option):
return
if __name__ == '__main__':
while True:
if len(sys.argv) >= 3:
archs = sys.argv[2:]
main(False, archs, tag=sys.argv[1])
break
else:
archs = {'armeabi-v7a', 'arm64-v8a'}
num = input('Enter menu:\n1. Clean && build mars.\n2. Build incrementally mars.\n3. Clean && build xlog.\n4. Exit\n')
if num == '1':
main(False, archs)
break
elif num == '2':
main(True, archs)
break
elif num == '3':
main(False, archs, '--target libzstd_static marsxlog')
break
elif num == '4':
break
else:
main(False, archs)
break
16k适配
可以参考官方16kB适配地址
Android NDK r28 及更高版本
NDK 版本 r28 及更高版本默认编译为 16 KB 对齐。
Android NDK r27
为了支持使用 Android NDK 版本 r27 及更高版本编译 16 KB 对齐的共享库,您需要按如下方式更新 ndk-build、build.gradle、build.gradle.kts 或链接器标志:
在 build.gradle 文件中,设置实参 -DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON:
bash
android {
...
defaultConfig {
...
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
}
}
}
}
Android NDK r26 及更低版本
请务必始终更新 NDK。此功能仅应在万不得已时使用,且不保证提供支持。
如需支持使用 Android NDK 版本 r26 或更低版本编译 16 KB 对齐的共享库,您需要按如下方式更新 ndk-build 或 cmake 配置:
更新 CMakeLists.txt 以启用 16 KB ELF 对齐:
c
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384")
这里使用的是NDK25
c
cmake_minimum_required (VERSION 3.6)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE PATH "Installation directory" FORCE)
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
include_directories(openssl/include)
add_subdirectory(comm comm)
add_subdirectory(boot boot)
add_subdirectory(boost boost)
add_subdirectory(app app)
add_subdirectory(baseevent baseevent)
add_subdirectory(xlog xlog)
add_subdirectory(sdt sdt)
add_subdirectory(stn stn)
# for zstd
option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
option(ZSTD_BUILD_SHARED "BUILD SHARED LIBRARIES" OFF)
set(ZSTD_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zstd")
set(LIBRARY_DIR ${ZSTD_SOURCE_DIR}/lib)
include(GNUInstallDirs)
add_subdirectory(zstd/build/cmake/lib zstd)
project (mars)
#target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384")
#[[if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wno-deprecated-builtins)
add_compile_options(-Wno-error=deprecated-builtins)
add_compile_options(-Wno-error=deprecated-declarations)
endif()]]
include(comm/CMakeUtils.txt)
include_directories(.)
include_directories(..)
set(SELF_LIBS_OUT ${CMAKE_SYSTEM_NAME}.out)
if(ANDROID)
if(NATIVE_CALLBACK)
message("common native callback")
add_definitions(-DNATIVE_CALLBACK)
endif()
find_library(log-lib log)
find_library(z-lib z)
link_directories(app baseevent xlog sdt stn comm boost zstd)
# marsxlog
set(SELF_LIB_NAME marsxlog)
file(GLOB SELF_SRC_FILES libraries/mars_android_sdk/jni/JNI_OnLoad.cc
libraries/mars_xlog_sdk/jni/import.cc)
add_library(${SELF_LIB_NAME} SHARED ${SELF_SRC_FILES})
set_target_properties(${SELF_LIB_NAME} PROPERTIES LINK_FLAGS "-Wl,-z,max-page-size=16384")
install(TARGETS ${SELF_LIB_NAME} LIBRARY DESTINATION ${SELF_LIBS_OUT} ARCHIVE DESTINATION ${SELF_LIBS_OUT})
get_filename_component(EXPORT_XLOG_EXP_FILE libraries/mars_android_sdk/jni/export.exp ABSOLUTE)
set(SELF_XLOG_LINKER_FLAG "-Wl,--gc-sections -Wl,--version-script='${EXPORT_XLOG_EXP_FILE}'")
if(ANDROID_ABI STREQUAL "x86_64" OR ANDROID_ABI STREQUAL "x86")
set(SELF_XLOG_LINKER_FLAG "-Wl,--gc-sections -Wl,--version-script='${EXPORT_XLOG_EXP_FILE}' -Wl,--no-warn-shared-textrel")
endif()
target_link_libraries(${SELF_LIB_NAME} "${SELF_XLOG_LINKER_FLAG}"
xlog
mars-boost
comm
libzstd_static
${log-lib}
${z-lib}
)
# marsstn
set(SELF_LIB_NAME marsstn)
file(GLOB SELF_SRC_FILES libraries/mars_android_sdk/jni/*.cc)
add_library(${SELF_LIB_NAME} SHARED ${SELF_SRC_FILES})
set_target_properties(${SELF_LIB_NAME} PROPERTIES LINK_FLAGS "-Wl,-z,max-page-size=16384")
install(TARGETS ${SELF_LIB_NAME} LIBRARY DESTINATION ${SELF_LIBS_OUT} ARCHIVE DESTINATION ${SELF_LIBS_OUT})
link_directories(${SELF_LIBS_OUT})
find_library(CRYPT_LIB crypto PATHS openssl/openssl_lib_android/${ANDROID_ABI} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
find_library(SSL_LIB ssl PATHS openssl/openssl_lib_android/${ANDROID_ABI} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
target_link_libraries(${SELF_LIB_NAME} "-Wl,--gc-sections"
${log-lib}
stn
sdt
app
baseevent
comm
boot
mars-boost
marsxlog
libzstd_static
${SSL_LIB}
${CRYPT_LIB})
endif()
这里在marsxlog和marsstn里的add_library之后加上了 set_target_properties(${SELF_LIB_NAME} PROPERTIES LINK_FLAGS "-Wl,-z,max-page-size=16384")
为什么用 set_target_properties(... LINK_FLAGS ...) 而不是target_link_options?
- 声明了 cmake_minimum_required(VERSION 3.6)
- target_link_options() 是 CMake 3.13+ 才引入的
- 在 CMake 3.6 中使用它会导致 配置失败
- set_target_properties(... LINK_FLAGS ...) 是 CMake 2.8+ 就支持的旧式方法,完全兼容
实际上如果你使用的是NDK28基本上按官网说的就一步到位了。
最后可以通过在google应用市场下载Libcheker,可以帮忙分析我们的app支不支持16kb,比较方便快捷。


看到标有16kb标签的so文件说明适配好了