当前位置: 首页 > news >正文

Cairo库移植到安卓记录

前言

接Android Studio引入ndk编译的so库的故事,这个东西搞了两周以后,由于自己不熟悉Java和安卓开发,踩了不少坑,其中一周时间都是花在怎么用Android Studio上的。。。AS下的新版本Koala,结果网上资料全是旧版本,很多设置完全不同,遇了问题经常不知所措,后面不得已,换成了老一点的2021 dolphin版本,也学会了看安卓官网资料,逐渐才稳定下来。

好在不是紧急项目,后面赶主要任务进度就改成每周抽一天时间去处理,这个任务最核心的在于如何将cairo库移植到安卓环境去使用,这是一个2D绘图库,awtk的画布后端也有cairo的选择,几周摸爬滚打,终于将cairo移植到了安卓上,特此记录下,算是个人进军安卓开发的一小步。

环境

OS:Windows11

Cairo: 1.18.0

Android Studio: Dolphin 2021.3.1.17

NDK: r26

确保上述环境和工具已经下好,NDK用windows或者linux的都行,不过经个人测试,linux相比windows巨慢,linux下编译系统的log输出一条时间都够windows下输出十几条了,我没用虚拟机桌面系统,用的WSL,兴许是WSL本身的性能问题?

Stage1 下载Cairo,Meson编译

cairo下载地址:https://www.cairographics.org/download/

从1.17.8开始,cairo不再使用传统的configure+makefile构建系统了,而是改用一个新的构建系统meson,它的编译语法很像python,但并不像awtk的scons那样是完全基于python, 算是类python语言。

不得不接触新的编译系统多少有些抵触,不过手册和案例看下来,逐渐感觉这个系统香了,因为cairo库有很多依赖比如pixman, glib, freetype等,meson项目上有wrap脚本,在编译的时候发现依赖缺失可以直接从网上下下来特定版本。

要是旧版本的话,不只要自己一个个下依赖去配置,还要考虑依赖树内各个节点的版本兼容的问题,苦不堪言,这个自动下载的功能实在厉害!

对于交叉编译,meson可以通过编写txt文件指定特定平台的编译,我这里目标是armv7平台,给arm的平板使用。

其实还想试试x86平台的,因为AS上arm架构机型没法模拟,无法启动,查了下是电脑架构x86不好模拟arm的原因, 之前自己试过编译,结果遇到的坑根本无法解决,然后看了点科普,才知道手机x86架构算是古早的被市场淘汰的产品,除了模拟器,现在手机平板都是arm架构,看来是没有市场价值,那估计官方也没有考虑这平台,释怀了。。。。只能找arm架构的实机了,好在公司提供了个IDO-EVB3562开发板用来装安卓映像。

不废话,交叉编译设置cross_file_build_win_host_arm.txt如下:

[constants]
android_ndk='D:\Devtools\android-ndk-r26d-win\toolchains\llvm\prebuilt\windows-x86_64\'
android_ndk_toolchain='D:\Devtools\android-ndk-r26d-win\toolchains\llvm\prebuilt\windows-x86_64\bin'[binaries]
c = android_ndk_toolchain / 'armv7a-linux-androideabi33-clang.cmd'
cpp = android_ndk_toolchain / 'armv7a-linux-androideabi33-clang++.cmd'
ar = android_ndk_toolchain / 'llvm-ar.exe'
ld = android_ndk_toolchain / 'ld.exe'
strip = android_ndk_toolchain / 'llvm-strip.exe'[properties]
sys_root = android_ndk / 'sysroot'
c_link_args     = ['-fuse-ld=gold']
cpp_link_args   = ['-fuse-ld=gold'][host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'armv7a'
endian = 'little'

如果linux平台上则是:

[constants]
android_ndk='/mnt/d/Devtools/android-ndk-r26d-linux/toolchains/llvm/prebuilt/linux-x86_64/'
android_ndk_toolchain='/mnt/d/Devtools/android-ndk-r26d-linux/toolchains/llvm/prebuilt/linux-x86_64/bin'[binaries]
c = android_ndk_toolchain / 'armv7a-linux-androideabi33-clang'
cpp = android_ndk_toolchain / 'armv7a-linux-androideabi33-clang++'
ar = android_ndk_toolchain / 'llvm-ar'
ld = android_ndk_toolchain / 'ld'
strip = android_ndk_toolchain / 'llvm-strip'[properties]
sys_root = android_ndk / 'sysroot'
c_link_args     = ['-fuse-ld=gold']
cpp_link_args   = ['-fuse-ld=gold'][host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'armv7a'
endian = 'little'

注意windows版我指定了后缀名,因为meson实际上是脚本,根据路径的文件名执行对应文件,给脚本提供的实际是文件路径。

以下指令启动meson的编译,--cross-file用于指定交叉编译文件

meson setup --cross-file cross_file_build_win_host_arm.txt build_win_host_arm

等待一段时间,让meson把一切配置好,最后meson会弹出项目的各项配置总结:

cairo 1.18.0Surface BackendsImage                   : YESRecording               : YESObserver                : YESMime                    : YESTee                     : YESXlib                    : NOXlib Xrender            : NOQuartz                  : NOQuartz-image            : NOXCB                     : NOWin32                   : NOCairoScript             : YESPostScript              : YESPDF                     : YESSVG                     : YESFont BackendsUser                    : YESFreeType                : YESFontconfig              : YESWin32                   : NOWin32 DWrite            : NOQuartz                  : NOFunctionsPNG functions           : YESX11-xcb                 : NOXCB-shm                 : NOFeatures and Utilitiescairo-trace:            : NOcairo-script-interpreter: YESAPI reference           : NOSubprojectsfontconfig              : YESfreetype2               : YES (from fontconfig)glib                    : NO Dependency "iconv" not found, tried builtin and systemgperf                   : YES (from fontconfig)libintl                 : NO Include dir /usr/local/include does not exist.libpng                  : YESlibxml2                 : YES (from fontconfig)pixman                  : YESUser defined optionsCross files             : cross_file_build_win_host_arm.txt
Found ninja-1.12.1 at D:\Devtools\Meson\ninja.EXE

接下来就加入meson的第二阶段:ninja编译:

ninja -C build_win_host_arm

到了这一步开始编译就开始不风顺了,中间一定会遇到某些问题,比如头文件缺失,或者源码的哪些不规范用法在gcc上过得去,到了ndk的clang就撞error,或者丢了哪些库,不过只要不是系统性问题基本都能解决。我这里先不讲,问题放在最后的踩坑上记录。

Stage2 Cairo安卓项目

ninja编译完成后应该会有以下so库,这些库都要放到后面安卓项目的libs文件夹上,缺一不可。

除了libcpufeatures.so是在ndk内部,其他库应该都能在build_win_host_arm内找到。

libcairo.so
libcpufeatures.so
libfontconfig.so
libfreetype.so
libglib-2.0.so
libintl.so
libpcre2-8.so
libpixman-1.so
libpng16.so
libxml2.so

Android Studio新建NativeC++项目, 后面就是各种配置了, 然而自己不懂安卓开发,在编码实现上还是一头雾水,结果网上一查,其实已经有人把cairo的移植做出来了,把源码适配了下,居然能用。Nice, 那不担心了。

省篇幅,我就直接发源码吧:https://gitee.com/tracker647/cairo-for-android

记录一些注意点:

1.CMake版本务必换成更新的3.22.1,否则不识别编译选项,一些库明明加了硬说没有。

2.adbFilter选项,由于这里用的armv7a,则只指定armv7a就行了。

根据1 2修改后的build.gradle的android部分例:

android {namespace 'com.example.cairotest'compileSdk 32defaultConfig {applicationId "com.example.cairotest"minSdk 24targetSdk 32versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"ndk {abiFilters 'armeabi-v7a'}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt')version '3.22.1'}}buildFeatures {viewBinding true}
}

3.cairo官方提供了一些编码案例,我用的其中一个画星星的例子,画的时候注意看有没有cairo_scale这个函数,这是用来控制整个坐标系放缩的,比如设置了cario_scale(width, height), 后面各种api传坐标就不用加width和height了,直接传百分比就行,用的移植例子一开始没注意,画出来结果一脸懵逼。

最终效果图,桌面是cairo在ubuntu wsl平台的运行结果,平板(IDO-EVB3562开发板连了个电容屏)是安卓平台运行结果。

image-20240806205456842

ninja踩坑

tips:-v打开指令log:

ninja -C $builddir -v

💥**…\subprojects\fontconfig\src/fcint.h:32:10: fatal error: ‘fcstdint.h’ file not found**

一个简单的封装stdint.h的头文件缺失,补全即可,我是拿的其他平台的build文件夹去补的,就奇怪,我在其他平台上这个文件生成的好好的,为什么到了这里就没了?

💥**…/subprojects/pixman/pixman/pixman-arm.c:99:10: fatal error: ‘cpu-features.h’ file not found**

这个文件依赖于ndk的cpufeatures库,正好ndk的cpufeatures文件夹提供了mk文件,直接编译即可,不过生成的是静态库,我这里图后期用的库格式一致改成动态库了。

cd到这个文件夹然后ndk-build:

PS D:\Devtools\android-ndk-r26d-win\sources\android\cpufeatures> ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk

接着就会生成libs和objs文件夹,libs和objs文件夹下有目标库,现在切回到cairo项目,build_linux_host_arm文件夹下有个build.ninja是ninja执行时用的脚本,CV报错指令找到对应command, 把cpu_features头文件加入:

build subprojects/pixman/pixman/libpixman-1.so.p/pixman-arm.c.o: c_COMPILER …/subprojects/pixman/pixman/pixman-arm.c
DEPFILE = “subprojects\pixman\pixman\libpixman-1.so.p\pixman-arm.c.o.d”
DEPFILE_UNQUOTED = subprojects\pixman\pixman\libpixman-1.so.p\pixman-arm.c.o.d
ARGS = “-Isubprojects\pixman\pixman\libpixman-1.so.p” “-Isubprojects\pixman\pixman” “-I…\subprojects\pixman\pixman” “-ID:\Devtools\android-ndk-r26d-win\sources\android\cpufeatures” “-fdiagnostics-color=always” “-D_FILE_OFFSET_BITS=64” “-Wall” “-Winvalid-pch” “-Wextra” “-std=gnu99” “-O0” “-g” “-Wdeclaration-after-statement” “-fno-strict-aliasing” “-fvisibility=hidden” “-Wundef” “-ftrapping-math” “-Wno-unused-local-typedefs” “-DHAVE_CONFIG_H” “-fPIC” “-pthread”

头文件的错误就过去了,接下来链接指令,由于未加入cpufeatures库,必定报错:

💥**…/subprojects/pixman/pixman/pixman-arm.c:108: error: undefined reference to ‘android_getCpuFamily’**
…/subprojects/pixman/pixman/pixman-arm.c:109: error: undefined reference to ‘android_getCpuFeatures’

build.ninja找到对应链接指令,指定库路径, libs和objs都可以,注意架构,这个例子是armv7a:

build subprojects/pixman/pixman/libpixman-1.so: c_LINKER_RSP subprojects/pixman/pixman/libpixman-1.so.p/pixman.c.o subprojects/pixman/pixman/libpixman-1.so.p/pixman-access.c.o

。。。

subprojects/pixman/pixman/libpixman-arm-neon.a subprojects/pixman/pixman/libpixman-arm-simd.a

LINK_ARGS = “D:\Devtools\android-ndk-r26d-win\sources\android\cpufeatures\libs\armeabi-v7a\cpufeatures.so” “-Wl,–as-needed” “-Wl,–no-undefined” “-shared” “-fPIC” “-Wl,-soname,libpixman-1.so” “-fuse-ld=gold” “-Wl,–start-group” “subprojects/pixman/pixman/libpixman-arm-simd.a” “subprojects/pixman/pixman/libpixman-arm-neon.a” “-lm” “-Wl,–end-group” “-pthread”

💥**— stderr —**
Traceback (most recent call last):
File “D:\MyCodeBase\KChartSimulate\cairo-1.18.0\build_win_host_arm\subprojects\glib-2.74.0\gobject\glib-mkenums”, line 486, in
write_output(prod)
File “D:\MyCodeBase\KChartSimulate\cairo-1.18.0\build_win_host_arm\subprojects\glib-2.74.0\gobject\glib-mkenums”, line 97, in write_output
print(output, file=output_stream)
UnicodeEncodeError: ‘gbk’ codec can’t encode character ‘\xa9’ in position 17: illegal multibyte sequence

windows系统下特供错误,版权符号©没有gbk编码,而windows终端就是gdb编码输出中文的,这个卡住过一段时间,试过输入chcp 65001也没用,网上没合理答案,找glib的gitlab提issue也没人理,最后还是问ai找到了解决方法,把这个符号直接替换掉:

def write_output(output):global output_streamoutput = output.replace('\xa9', '')print(output, file=output_stream)

**💥…/subprojects/glib-2.74.0/gio/gsocket.c:497:37: error: passing ‘guint *’ (aka ‘unsigned int *’) to parameter of type 'socklen_t ’ (aka 'int ') converts between pointers to integer types with different sign [-Werror,-Wpointer-sign]
修改build.ninja把-Wpointer-sign去除掉, 或者直接修改源码加入强转,不过十几条error,不值得。

build subprojects/glib-2.74.0/gio/libgio-2.0.so.p/gsocket.c.o: c_COMPILER …/subprojects/glib-2.74.0/gio/gsocket.c || subprojects/glib-2.74.0/gio/gdbus-daemon-generated.h subprojects/glib-2.74.0/gio/gioenumtypes.h subprojects/glib-2.74.0/gio/xdp-dbus.h subprojects/glib-2.74.0/gobject/glib-enumtypes.h
DEPFILE = “subprojects\glib-2.74.0\gio\libgio-2.0.so.p\gsocket.c.o.d”
DEPFILE_UNQUOTED = subprojects\glib-2.74.0\gio\libgio-2.0.so.p\gsocket.c.o.d
ARGS = “-Isubprojects\glib-2.74.0\gio\libgio-2.0.so.p” “-Isubprojects\glib-2.74.0\gio” “-I…\subprojects\glib-2.74.0\gio” “-Isubprojects\glib-2.74.0” “-I…\subprojects\glib-2.74.0” “-Isubprojects\glib-2.74.0\glib” “-I…\subprojects\glib-2.74.0\glib” “-Isubprojects\proxy-libintl” “-I…\subprojects\proxy-libintl” “-Isubprojects\glib-2.74.0\gobject” “-I…\subprojects\glib-2.74.0\gobject” “-Isubprojects\glib-2.74.0\gmodule” “-I…\subprojects\glib-2.74.0\gmodule” “-Isubprojects\glib-2.74.0\subprojects\gvdb” “-I…\subprojects\glib-2.74.0\subprojects\gvdb” “-fdiagnostics-color=always” “-D_FILE_OFFSET_BITS=64” “-Wall” “-Winvalid-pch” “-Wextra” “-Wpedantic” “-std=gnu99” “-O0” “-g” “-D_GNU_SOURCE” “-fno-strict-aliasing” “-DG_ENABLE_DEBUG” “-Wimplicit-fallthrough” “-Wmisleading-indentation” “-Wunused” “-Wno-unused-parameter” “-Wno-cast-function-type” “-Wno-pedantic” “-Wno-format-zero-length” “-Wno-variadic-macros” “-Werror=format=2” “-Werror=init-self” “-Werror=missing-include-dirs” “-Werror=pointer-arith” “-Werror=unused-result” “-Wstrict-prototypes” “-Wno-bad-function-cast” “-Werror=declaration-after-statement” “-Werror=implicit-function-declaration” “-Werror=missing-prototypes” “-Werror=pointer-sign” “-fPIC” “-DG_LOG_DOMAIN=“GLib-GIO”” “-DGIO_COMPILATION” “-DGIO_LAUNCH_DESKTOP=“c:/libexec/gio-launch-desktop”” “-DGIO_MODULE_DIR=“c:/lib/gio/modules”” “-DLOCALSTATEDIR=“c:/var”” “-fvisibility=hidden”

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【登录扫码】--集成企业微信
  • todoList清单(HTML+CSS+JavaScript)
  • Linux中apache服务安装与mysql安装
  • git强制推送代码教程
  • 如何使用css写三角形
  • 操作系统(进程通信)
  • Spring 中的InitializingBean
  • C语言实现数据结构之队列
  • 基于GeoTools使用JavaFx进行矢量数据可视化实战
  • NoSQL之Redis配置与优化
  • 36集网剧《天降神医朱丹溪》电影《百草园里杏花香》在义乌启动
  • Java 并发编程:ReentrantLock 锁与 AQS
  • 【机器人学】6-5.六自由度机器人运动学参数辨识-逆运动学迭代解【附MATLAB代码】
  • 响应式Web设计的发展与特点
  • 【rz sz】Centos/Linux 如何快捷的上传下载文件到系统当中?
  • 【Amaple教程】5. 插件
  • Angular4 模板式表单用法以及验证
  • CentOS6 编译安装 redis-3.2.3
  • co模块的前端实现
  • ES10 特性的完整指南
  • iOS 颜色设置看我就够了
  • iOS帅气加载动画、通知视图、红包助手、引导页、导航栏、朋友圈、小游戏等效果源码...
  • JavaScript设计模式之工厂模式
  • JS变量作用域
  • Leetcode 27 Remove Element
  • maya建模与骨骼动画快速实现人工鱼
  • React-flux杂记
  • SQL 难点解决:记录的引用
  • Vue 2.3、2.4 知识点小结
  • windows下使用nginx调试简介
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 老板让我十分钟上手nx-admin
  • 删除表内多余的重复数据
  • NLPIR智能语义技术让大数据挖掘更简单
  • raise 与 raise ... from 的区别
  • ​zookeeper集群配置与启动
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #13 yum、编译安装与sed命令的使用
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (1)(1.13) SiK无线电高级配置(五)
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (回溯) LeetCode 40. 组合总和II
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (一)u-boot-nand.bin的下载
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)http-server应用
  • .NET C# 操作Neo4j图数据库
  • .net core 外观者设计模式 实现,多种支付选择
  • .Net Remoting(分离服务程序实现) - Part.3