我从这里克隆了libgip的hg存储库: https://hg.nih.at/libzip/
我知道有一个用于android的libzip软件包,但首先我想尝试使用原始软件包,因为我希望我的未来项目在其他平台上使用相同版本的库源操作,直到我可以管理。
我对CMake构建系统不太熟悉, 所以我从构建测试NDK项目的Android Studio生成的cmake_build_command.txt中借用了必要的参数。
所以,我执行cmake的批处理文件是这样的:
rmdir /S /Q build
"C:\Android\sdk\cmake\3.6.4111459\bin\cmake.exe"^
.^
-H"D:\Project\External\libzip"^
-B"D:\Project\External\libzip\build"^
-G"Android Gradle - Ninja"^
-D"ANDROID_ABI=x86"^
-D"ANDROID_NDK=C:\Android\sdk\ndk-bundle"^
-D"CMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\Project\External\libzip\build"^
-D"CMAKE_BUILD_TYPE=Debug"^
-D"CMAKE_MAKE_PROGRAM=C:\Android\sdk\cmake\3.6.4111459\bin\ninja.exe"^
-D"CMAKE_TOOLCHAIN_FILE=C:\Android\sdk\ndk-bundle\build\cmake\android.toolchain.cmake"^
-D"ANDROID_PLATFORM=android-23"
cd build
C:\Android\sdk\cmake\3.6.4111459\bin\ninja.exe
这是输出:
D:\Project\External\libzip>"C:\Android\sdk\cmake\3.6.4111459\bin\cmake.exe" . -H"D:\Project\External\libzip" -B"D:\Project\External\libzip\build" -G"Android Gradle - Ninja" -D"ANDROID_ABI=x86" -D"ANDROID_NDK=C:\Android\sdk\ndk-bundle" -D"CMAKE_LIBRARY_OUTPUT_DIRECTORY=D:\Project\External\libzip\build" -D"CMAKE_BUILD_TYPE=Debug" -D"CMAKE_MAKE_PROGRAM=C:\Android\sdk\cmake\3.6.4111459\bin\ninja.exe" -D"CMAKE_TOOLCHAIN_FILE=C:\Android\sdk\ndk-bundle\build\cmake\android.toolchain.cmake" -D"ANDROID_PLATFORM=android-23"
-- Check for working C compiler: C:/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe
-- Check for working C compiler: C:/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/windows-x86_64/bin/clang.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Looking for _chmod
-- Looking for _chmod - not found
-- Looking for _close
-- Looking for _close - not found
-- Looking for _dup
-- Looking for _dup - not found
-- Looking for _fdopen
-- Looking for _fdopen - not found
-- Looking for _fileno
-- Looking for _fileno - not found
-- Looking for _open
-- Looking for _open - not found
-- Looking for _setmode
-- Looking for _setmode - not found
-- Looking for _snprintf
-- Looking for _snprintf - not found
-- Looking for _strdup
-- Looking for _strdup - not found
-- Looking for _stricmp
-- Looking for _stricmp - not found
-- Looking for _strtoi64
-- Looking for _strtoi64 - not found
-- Looking for _strtoui64
-- Looking for _strtoui64 - not found
-- Looking for _umask
-- Looking for _umask - not found
-- Looking for _unlink
-- Looking for _unlink - not found
-- Looking for explict_bzero
-- Looking for explict_bzero - not found
-- Looking for explicit_memset
-- Looking for explicit_memset - not found
-- Looking for fileno
-- Looking for fileno - found
-- Looking for fseeko
-- Looking for fseeko - found
-- Looking for ftello
-- Looking for ftello - found
-- Looking for getprogname
-- Looking for getprogname - found
-- Looking for open
-- Looking for open - found
-- Looking for mkstemp
-- Looking for mkstemp - found
-- Looking for setmode
-- Looking for setmode - not found
-- Looking for snprintf
-- Looking for snprintf - found
-- Looking for strcasecmp
-- Looking for strcasecmp - found
-- Looking for strdup
-- Looking for strdup - found
-- Looking for stricmp
-- Looking for stricmp - not found
-- Looking for strtoll
-- Looking for strtoll - found
-- Looking for strtoull
-- Looking for strtoull - found
-- Looking for include file fts.h
-- Looking for include file fts.h - found
-- Looking for include file stdbool.h
-- Looking for include file stdbool.h - found
-- Looking for include file strings.h
-- Looking for include file strings.h - found
-- Looking for include file unistd.h
-- Looking for include file unistd.h - found
-- Looking for include file inttypes.h
-- Looking for include file inttypes.h - found
-- Looking for include file stdint.h
-- Looking for include file stdint.h - found
-- Looking for include file sys/types.h
-- Looking for include file sys/types.h - found
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Check size of __int8
-- Check size of __int8 - failed
-- Check size of int8_t
-- Check size of int8_t - done
-- Check size of uint8_t
-- Check size of uint8_t - done
-- Check size of __int16
-- Check size of __int16 - failed
-- Check size of int16_t
-- Check size of int16_t - done
-- Check size of uint16_t
-- Check size of uint16_t - done
-- Check size of __int32
-- Check size of __int32 - failed
-- Check size of int32_t
-- Check size of int32_t - done
-- Check size of uint32_t
-- Check size of uint32_t - done
-- Check size of __int64
-- Check size of __int64 - failed
-- Check size of int64_t
-- Check size of int64_t - done
-- Check size of uint64_t
-- Check size of uint64_t - done
-- Check size of short
-- Check size of short - done
-- Check size of int
-- Check size of int - done
-- Check size of long
-- Check size of long - done
-- Check size of long long
-- Check size of long long - done
-- Check size of off_t
-- Check size of off_t - done
-- Check size of size_t
-- Check size of size_t - done
-- Check size of ssize_t
-- Check size of ssize_t - done
-- Check if the system is big endian
-- Searching 16 bit integer
-- Check size of unsigned short
-- Check size of unsigned short - done
-- Using unsigned short
-- Check if the system is big endian - little endian
-- Found ZLIB: C:/Android/sdk/ndk-bundle/platforms/android-23/arch-x86/usr/lib/libz.so (found version "1.2.3")
-- Could NOT find BZip2 (missing: BZIP2_LIBRARIES BZIP2_INCLUDE_DIR)
-- Looking for getopt
-- Looking for getopt - found
-- Configuring done
-- Generating done
-- Build files have been written to: D:/Project/External/libzip/build
D:\Project\External\libzip>cd build
D:\Project\External\libzip\build>C:\Android\sdk\cmake\3.6.4111459\bin\ninja.exe
[133/133] Linking C executable regress\tryopen
我将此与我的项目联系起来:
include_directories( ../../../External/libzip/lib
../../../External/libzip/build
)
target_link_libraries( native-lib
${z-lib}
D:/Project/External/libzip/build/lib/libzip.a
)
我用这个gradle设置构建了我的ndk项目:
externalNativeBuild {
cmake {
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_static"
cppFlags "-std=c++14", "-frtti", "-fexceptions"
}
}
ndk {
abiFilters "x86"
}
老实说,我没想到会轻易做到这一点。 但令人惊讶的是,它与我的测试NDK项目成功链接并顺利运行。 我可以用zip_open()打开我的apk文件,并且没有问题地读取各个文件的内容。
但在我意识到其他ABI并非如此之后不久。 在除了我的初始尝试之外的所有其他ABI中,即arm64-v8a,zip_open()返回NULL。 我可以用调试器检查的是zip_open()的参数变得一团糟,apk路径的字符串突然变成“1”,而其他所有的东西都在zip_open()里面也是垃圾。
后来我也发现x86_64与模拟器的工作方式就像arm64-v8a一样,但x86再次失败。 所以我怀疑这是某种32/64位问题,但我无法弄清楚究竟是什么导致了这个问题。
我还尝试了一些其他与gcc工具链和-D“CMAKE_C_FLAGS = -m32”的组合,但对我没什么用。
有帮助吗?
(并且要清楚,以上所有代码片段均来自x86设置,而不是成功的arm64或x86_64。)
修改
我找到了问题的根源,所以我想在这里分享。
首先,我不应该拥有受信任的Android原生调试器。 正如我上面提到的,zip_open()中的所有参数看起来都已损坏,但它只是调试器吐出错误信息。 从那里我浪费了相当多的时间来挖掘错误的地方,比如召集会议等。
问题的真正根源是libzip源中的一个表达式:
offset < ZIP_FSEEK_MIN
其中“ZIP_FSEEK_MIN”定义为-0x80000000L,“offset”在我的情况下为-65578。
当然它应该产生“假”,但它不是在32位ABI中。 (请注意,“offset”是zip_int64_t,在任何平台上都是64位整数。)
所以我进行了一些测试,结果是:
offset < ZIP_FSEEK_MIN // yield "true"
offset < -0x80000000L // yield "true"
offset < -0x80000000LL // yield "false"
offset < -0x80000000LL-1LL // yield "false"
offset < -0x80000000L+1L // yield "true"
offset < -0x7fffffffL-1L // yield "false", sometimes cause crash in armeabi
offset < -2147483648 // yield "false"
似乎-0x80000000L是表示最小有符号32位整数的“坏形式”。 所有std c库都将其定义为“-0x7fffffffL-1L”或“-2147483647i32 - 1”。
还有一个可怕的角落案例,其中“-0x7fffffffL-1L”导致程序在armeabi中崩溃(v7a和x86很好),但我找不到确切的条件来触发它。 (我甚至不确定如何处理这个问题。)
就是这样。以下是我从中学到的东西:
谢谢。