ubuntu11.0.4下编译Android2.3源码过程

本文记录了在Ubuntu 11.0.4下编译Android 2.3源码的过程,包括解决各种编译错误的方法,例如权限不足、缺少依赖库等问题。

ubuntu11.0.4下编译Android2.3源码过程

最近几天修改Android系统源码,遇到很多让人崩溃的问题。现在根据记忆写下,以后方便解决。

从2.3开始,jdk使用1.6版本及Linux系统使用64位,所以很多工具都要重新安装。

以下是第一次编译时遇到的问题:

1、权限不够遇到多次
/bin/bash: prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gcc: 权限不够
/bin/bash: prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gcc: 权限不够
/bin/bash: build/core/find-jdk-tools-jar.sh: 权限不够
/bin/bash: build/tools/findleaves.py: 权限不够
/bin/bash: build/tools/findleaves.py: 权限不够
Checking API: checkapi-last
/bin/bash: out/host/linux-x86/bin/apicheck: 权限不够

解决:
chmod a+x prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-gcc
对所有没有权限的文件增加可执行权限

2.make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o] 错误 1
在32位下编译,直接make就可以了
在64位下编译,会出一些错误,需要额外安装一些包:
A, 没有gnu/stubs-32.h文件:
/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: 没有该文件或目录
make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o] 错误 1
解决方法:
确定你的系统是x86_64 GNU/Linux
root@mm-desktop:/home/mm/android# uname -a
Linux mm-desktop 2.6.27-9-generic #1 SMP Thu Nov 20 22:15:32 UTC 2008 x86_64 GNU/Linux
安装libc6-dev-i386
sudo apt-get install libc6-dev-i386

B。找不到-lstdc++
/usr/bin/ld: cannot find -lstdc++
解决方法:
安装 g++-multilib,lib32z1-dev 和 lib32ncurses5-dev
apt-get install g++-4.2-multilib lib32z1-dev lib32ncurses5-dev


3.make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp] 错误 1
安装 g++-4.5-multilib
$ sudo aptitude install git-core gnupg flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev java-common unixodbc

4.arm-eabi-gcc: error trying to exec 'cc1': execvp: No such file or directory

同事编kernel的时候总是会报下面的错误~~最后发现是交叉编译工具的权限问题,chmod -R 777 * 就可以了
arm-eabi-gcc: error trying to exec 'cc1': execvp: No such file or directory
总结一下:
1、确认CROSS-COMPILE的目录在PATH里面
2、确认cc1是存在的
3、确认交叉编译工具的权限

摘录:

错误处理
在Ubuntu10.10(64位)编译Android2.3源码时,遇到各种各样的问题。不是缺这个,就是少那个。现把这些问题和解决方法罗列出来,供大家参考。

错误:
/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory
make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o] 错误 1

解决:
  sudo apt-get install libc6-dev-i386

错误:
make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp] error 1

解决:
  sudo apt-get install g++-multilib

错误:
external/clearsilver/cgi/cgi.c:22: fatal error: zlib.h: No such file or directory
compilation terminated.
make: *** [out/host/linux-x86/obj/SHARED_LIBRARIES/libneo_cgi_intermediates/cgi.o] Error 1

解决:
sudo apt-get install zlib1g-dev

错误:
/usr/bin/ld: cannot find -lz
collect2: ld returned 1 exit status
make: *** [out/host/linux-x86/obj/EXECUTABLES/aapt_intermediates/aapt] Error 1

解决:
sudo apt-get install lib32z1-dev

错误:
bison -d-o out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl_language_y.cpp frameworks/base/tools/aidl/aidl_language_y.y
/bin/bash: bison: command not found
make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl_language_y.cpp] Error 127

解决:
sudo apt-get install bison

错误:
Lex: aidl <= frameworks/base/tools/aidl/aidl_language_l.l
/bin/bash: flex: command not found
make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl_language_l.cpp] Error 127

解决:
sudo apt-get install flex

错误:
/usr/bin/ld: cannot find -lncurses
collect2: ld returned 1 exit status
make: *** [out/host/linux-x86/obj/EXECUTABLES/adb_intermediates/adb] Error 1

解决:
sudo apt-get install lib32ncurses5-dev

错误:
prebuilt/linux-x86/sdl/include/SDL/SDL_syswm.h:55: fatal error: X11/Xlib.h: No such file or directory
compilation terminated.
make: *** [out/host/linux-x86/obj/EXECUTABLES/emulator_intermediates/android/main-common.o] Error 1

解决:
sudo apt-get install libx11-dev

错误:
sh: gperf: not found
calling gperf failed: 32512 at ./makeprop.pl line 96.
make: *** [out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates/WebCore/css/CSSPropertyNames.h] Error 25
make: *** Deleting file `out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates/WebCore/css/CSSPropertyNames.h'

解决:
sudo apt-get install gperf

错误:
build/core/java.mk:9: *** bin: Target java module does not define any source or resource files. Stop.

解决:
删除源码根目录下的bin文件夹,这个文件夹是导入eclipse时创建的。

cannot find -lXXX
所有编译过程中遇到的类似这样的错误,都是缺少libXXX这样的库,解决方法就是:
首先:利用命令:apt-cache search XXX 进行库搜索
然后:找那些libXXX-dev这样的库进行安装,命令就是:sudo apt-get install libXXX-dev
最后:继续执行make

生成固件

1.在源码根目录下执行一下:
.build/envsetup.sh

2.通过所有编译(make)或模块编译(mmm)

需要使用超级用户进行编译,要不会出现一下权限问题

3.通过 export -p 查看HOME 的路径是否正确,否则修改 HOME 锁指向的路径为home/用户 中,直接 export HOME="/home/用户"
4.在“/home/用户”目录下新建文件夹 firmware
5.在Android 源码根目录下 执行./mkimage.sh

修改./mkimage.sh 中的路径指向 “/home/用户”目录下的文件夹 firmware

固件在firmware中生成




错误1:

注意:external/protobuf/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java 使用了未经检查或不安全的操作。

注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。
注意:external/protobuf/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java 使用了未经检查或不安全的操作。
注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。
Generated: (out/target/product/generic/android-info.txt)
host C: acp <= build/tools/acp/acp.c
host C++: libhost <= build/libs/host/pseudolocalize.cpp
host C: libhost <= build/libs/host/CopyFile.c
<命令行>:0:0: 警告: “_FORTIFY_SOURCE”重定义 [默认启用]
<built-in>:0:0: 附注: 这是先前定义的位置
<命令行>:0:0: 警告: “_FORTIFY_SOURCE”重定义 [默认启用]
<built-in>:0:0: 附注: 这是先前定义的位置
In file included from build/libs/host/CopyFile.c:11:0:
build/libs/host/include/host/CopyFile.h:5:22: 致命错误: sys/stat.h:没有那个文件或目录
编译中断。
In file included from /usr/include/stdlib.h:25:0,
from build/tools/acp/acp.c:11:
/usr/include/features.h:323:26: 致命错误: bits/predefs.h:没有那个文件或目录
编译中断。
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libhost_intermediates/CopyFile.o] 错误 1
make: *** 正在等待未完成的任务....
make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o] 错误 1
<命令行>:0:0: 警告: “_FORTIFY_SOURCE”重定义 [默认启用]
<built-in>:0:0: 附注: 这是先前定义的位置
In file included from /usr/include/c++/4.6/x86_64-linux-gnu/32/bits/os_defines.h:40:0,
from /usr/include/c++/4.6/x86_64-linux-gnu/32/bits/c++config.h:392,
from /usr/include/c++/4.6/string:40,
from build/libs/host/include/host/pseudolocalize.h:4,
from build/libs/host/pseudolocalize.cpp:1:
/usr/include/features.h:323:26: 致命错误: bits/predefs.h:没有那个文件或目录
编译中断。

make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libhost_intermediates/pseudolocalize.o] 错误 1


注意:某些输入文件使用或覆盖了已过时的 API。
注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。
注意:某些输入文件使用了未经检查或不安全的操作。

注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。

解决方法:sudo apt-get install libc6-dev-i386

http://www.blogjava.net/ZircoN/archive/2011/11/13/363452.html

错误2:

frameworks/base/libs/utils/RefBase.cpp: 在成员函数‘void android::RefBase::weakref_type::trackMe(bool, bool)’中:
frameworks/base/libs/utils/RefBase.cpp:483:67: 错误: 将‘const android::RefBase::weakref_impl’作为‘void android::RefBase::weakref_impl::trackMe(bool, bool)’的‘this’实参时丢弃了类型限定 [-fpermissive]
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] 错误 1
make: *** 正在等待未完成的任务....
frameworks/base/libs/utils/ResourceTypes.cpp: 在成员函数‘void android::ResTable::print(bool) const’中:
frameworks/base/libs/utils/ResourceTypes.cpp:4369:84: 警告: 将一个整数转换为大小不同的指针 [-Wint-to-pointer-cast]

frameworks/base/libs/utils/ResourceTypes.cpp:4375:43: 警告: 将一个整数转换为大小不同的指针 [-Wint-to-pointer-cast]

参考网上的解决方法:

$geditframeworks/base/libs/utils/Android.mk

将下面一行

LOCAL_CFLAGS+=-DLIBUTILS_NATIVE=1$(TOOL_CFLAGS)

改成

LOCAL_CFLAGS+=-DLIBUTILS_NATIVE=1$(TOOL_CFLAGS)–fpermissive

http://www.blogjava.net/ZircoN/archive/2011/11/13/363452.html

问题并没有解决,反而又出现了新的错误:

host C++: libutils <= frameworks/base/libs/utils/Asset.cpp
g++: –fpermissive:没有那个文件或目录
注意:某些输入文件使用或覆盖了已过时的 API。
注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。
注意:某些输入文件使用了未经检查或不安全的操作。
注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/Asset.o] 错误 1
make: *** 正在删除文件“out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/Asset.o”

make: *** 正在等待未完成的任务....

这个错误主要是gcc版本过高引起的:最终解决办法是:

( 11.10的gcc版本过高

http://hi.baidu.com/designhouse/blog/item/fec5cdbf8d6a231618d81fc1.html)

ubuntu 11.10的gcc版本是4.6.1,版本太高,编译android时出错,要把gcc版本改为4.4.3。

通过gcc -v命令可以发现gcc库在/usr/lib/gcc/i686-linux-gnu目录下,该目录下有当前系统支持的各种版本gcc库 。在安装gcc 4.4前该目录下是没有4.4目录的,安装gcc 4.4后该目录下就会多出4.4这个目录,且该4.4目录下有各种相应库文件。

ubuntu 32bit系统下安装gcc 4.4的最好方法是仅用以下两条命令,不需要其它命令,否则编译时可能会出错。

sudo apt-get install gcc-4.4

sudo apt-get install g++-4.4



装完后在/usr/bin目录下

$ ls -l gcc*

lrwxrwxrwx 1 root root 7 2011-10-29 09:11 gcc -> gcc-4.6

-rwxr-xr-x 1 root root 224544 2011-10-06 05:47 gcc-4.4

-rwxr-xr-x 1 root root 302104 2011-09-17 05:43 gcc-4.6

发现gcc 链接到gcc-4.6, 需要将它改为链接到gcc-4.4 :

sudo mv gcc gcc.bak

sudo ln -s gcc-4.4 gcc

错误3:

g++: g++: selected multilib '32' not installed
selected multilib '32' not installed
make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl] 错误 1
make: *** 正在等待未完成的任务....
make: *** [out/host/linux-x86/obj/lib/libESR_Portable.so] 错误 1

解决方法:

输入:sudo apt-get install gcc-multilib

sudo apt-get install g++-multilib后出现新问题:


g++: g++: host SharedLib: libfst (out/host/linux-x86/obj/lib/libfst.so)
g++: selected multilib '32' not installedselected multilib '32' not installed

selected multilib '32' not installed
make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl] 错误 1
make: *** 正在等待未完成的任务....
make: *** [out/host/linux-x86/obj/lib/libESR_Portable.so] 错误 1

make: *** [out/host/linux-x86/obj/lib/libfst.so] 错误 1

解决方法


sudo apt-get install libc6-dev ia32-libs lib32ncurses5-dev x11proto-core-dev libx11-dev lib32readline-gplv2-dev lib32z-dev libgl1-mesa-dev mingw32 tofrodos python-markdown libxml2-utils

sudo apt-get install g++-4.4-multilib

错误4:



Could not load 'clearsilver-jni'
java.library.path = out/host/linux-x86/lib
Could not load 'clearsilver-jni'
java.library.path = out/host/linux-x86/lib
make: *** [out/target/common/docs/api-stubs-timestamp] 错误 45
make: *** 正在等待未完成的任务....
make: *** [out/target/common/docs/doc-comment-check-timestamp] 错误 45

解决方法:

这是由于clearsilver 在编译时如果检测到使用Java JDK 6,就使用64位编译。要避开此错误,需要修改下面四个文件:

* external/clearsilver/cgi/Android.mk
* external/clearsilver/java-jni/Android.mk
* external/clearsilver/util/Android.mk
* external/clearsilver/cs/Android.mk

把这四个Makefile中的下列语句注掉即可:

# This forces a 64-bit build for Java6
# Comment by Easwy
# LOCAL_CFLAGS += -m64
# LOCAL_LDFLAGS += -m64

然后在external/clearsilver目录中执行一下make clean,然后回到项目根目录,继续make即可。

当编译完成时,生成的image文件放在out/target/product/generic目录中。


gedit /root/.bashrc
export PATH=/root/android/mydroid/out/host/linux-x86/bin:$PATH
export ANDROID_PRODUCT_OUT=/root/android/mydroid/out/target/product/generic
export ANDROID_SWT=/root/android/mydroid/out/host/linux-x86/framework

在源码目录下的out/target/product/generic/目录下运行
emulator -image system.img -data userdata.img -ramdisk ramdisk.img 命令

错误5:

emulator

NAND: could not write file system.img, File exists



编译Android源代码

请按照“获取Android源代码”一节中的内容安装所需的相关包,否则在编译源代码的时候会报很多的错。为了方便起见,现将所有需要安装的包罗列如下,其中有些包是可选的,但最好都装上,同时,在安装之前,最好先更新一下:


$ sudo aptitude update

$ sudo aptitude upgrade


Ubuntu Linux 32x86


$ sudo aptitude install git-core gnupg flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev make gcc g++ libc6dev patch texinfo ncursesdev python2.6 valgrind lib32readline5-dev


$ sudo aptitude install sunjava6jdk


Ubuntu Linux 64x86


$ sudo apt-get install git-core gnupg flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev make gcc g++ libc6-dev patch texinfo ncurses-dev python2.6 valgrind gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev


$ sudo ln -s /usr/lib32/libX11.so.6 /usr/lib32/libX11.so

$ sudo aptitude install sunjava6jdk


基本上安装上面罗列的包,编译时就不会有太大的问题,下面列举本人(64位机子,Ubuntu10.04系统)在编译时出现的一些错误,以及在出现错误时,相关的解决包。虽然google已将这些必需包在 android文档中进行说明了,但在此声明这些问题的解决还是参考网址:http://code.google.com/p/android/issues/detail?id=1005


/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory make: *** [out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp.o] Error 1


解决包:$ sudo aptitude install libc6-dev-i386


/usr/bin/ld: cannot find -lstdc++

collect2: ld returned 1 exit status

make: *** [out/host/linux-x86/obj/EXECUTABLES/aidl_intermediates/aidl] Error 1


dpkg-query -l &> packages.txt (该工具可用来查询dpkg数据库)

解决包:$ sudo aptitude install g++-multilib


/usr/bin/ld: cannot find -lncurses

collect2: ld returned 1 exit status

make: *** [out/host/linux-x86/obj/EXECUTABLES/adb_intermediates/adb] Error 1

make: *** Waiting for unfinished jobs....


解决包:$ sudo aptitude search lib32ncurses5-dev


/usr/bin/ld: cannot find -lz

collect2: ld returned 1 exit status

make: *** [out/host/linux-x86/obj/EXECUTABLES/zipalign_intermediates/zipalign] Error 1

make: *** Waiting for unfinished jobs....


解决包:$ sudo aptitude install lib32z-dev


同时,网友kees.jongenburger提出了使用getlibs(该工具可自动解决32位程序在64位系统上的依赖关系)来解决这个问题。具体用法如下:

$ getlibs -l libz.so

libz.so: zlib1g-dev

	The following i386 packages will be installed:
                                                            	zlib1g-dev
                                                            	Continue [Y/n]? y
                                                            	Downloading ...
                                                            	Installing libraries ...
                                                            	具体getlibs工具的介绍请参考网址: 	http://ubuntuforums.org/showthread.php?t=474790 

注:在“获取Android源代码”一节中已介绍使用java 6时会有不兼容的问题,但经过测试发现,如果仅仅makemake 不包括make sdk),用sunjava6jdk 是没有问题的。而make sdk,就会有问题,严格来说是在make doc 时会出问题,它需要的javadoc 版本为1.5

因此,我们安装完sun‐java6‐jdk 后最好再安装sun‐java5‐jdk,或者只安装sun‐java5‐jdk。这里sun‐java6‐jdk sun‐java5‐jdk 都安装,并只修改javadoc.1.gz javadoc。因为只有这两个是make sdk 用到的。这样的话,除了javadoc 工具是用1.5 版本,其它均用1.6 版本,java的安装目录及结构如下:


derek@derek-desktop:/usr/lib/jvm$ ls -l

total 4

lrwxrwxrwx 1 root root 19 2010-08-20 23:19 java-6-sun -> java-6-sun-1.6.0.20

drwxr-xr-x 8 root root 4096 2010-08-21 00:06 java-6-sun-1.6.0.20

sudo aptitude install sun‐java5‐jdk (现在发现找不到java 5的包,可能是源的问题)


修改javadoc link

$ cd /etc/alternatives

$ sudo rm javadoc.1.gz

$ sudo ln ‐s /usr/lib/jvm/java‐1.5.0‐sun/man/man1/javadoc.1.gz javadoc.1.gz

$ sudo rm javadoc

$ sudo ln ‐s /usr/lib/jvm/java‐1.5.0‐sun/bin/javadoc javadoc


但是,本人在编译2.2系统时测试发现使用java 6并没有上述问题。估计应该是解决了。所以上述对javadoc这快的处理就可以不做了。





设置环境变量


$ vim ~/.bashrc

增加如下的环境变量,包括java以及android程序开发、运行的一些环境变量


JAVA_HOME=/usr/lib/jvm/java-6-sun

export JAVA_HOME

JRE_HOME=${JAVA_HOME}/jre

export JRE_HOME

export ANDROID_JAVA_HOME=${JAVA_HOME}

export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH

export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin

HOME_BIN=~/android/bin/

export PATH=${PATH}:${JAVA_PATH}:${HOME_BIN}


$ source ~/.bashrc (使环境变量的设置立即生效,即同步变化)


编译android源码

$ cd ~/android/androidplatform/ cd android源码目录)

$ make (或者使用 make -jn 命令,其中,n值的确定参考原则为2m-1m为处理器核数,本人实验机子为双核,故用 make -j3

这个过程很久,大概花两个小时左右,编译完后将得到~/android/androidplatform/out 目录,可参加附件中的目录树文件。


编译SDK

直接执行make 是不包括make sdk 的。make sdk 用来生成SDK,这样,我们就可以用与源码同步的SDK 来开发 android 了。

1查看~/android/androidplatform/frameworks/base/include/utils/Asset.h

$ cd ~/android/androidplatform/

$ vim frameworks/base/include/utils/Asset.h


查看 UNCOMPRESS_DATA_MAX 值:

enum {

/* data larger than this does not get uncompressed into a buffer */

#ifdef HAVE_ANDROID_OS

UNCOMPRESS_DATA_MAX = 1 * 1024 * 1024

#else

UNCOMPRESS_DATA_MAX = 2 * 1024 * 1024

#endif

};


由于Eclipse 编译工程需要大于1.3M buffer,如果仅为1 * 1024 * 1024

请改为2 * 1024 * 1024,由于本人实验的版本为2.2已使用enum进行了更正,故不用修改。


输入以下命令进行sdk编译:

$ make sdk

注意如果这里出现问题请按照上面所介绍的将javadoc换回1.5版本。

编译后生成的SDK 存放在~/android/android/platform/out/host/linuxx86/sdk/ , 此目录下有androidsdk_eng.xxx_linuxx86.zip androidsdk_eng.xxx_linuxx86 目录。androidsdk_eng.xxx_linuxx86 就是SDK 目录。参加附件中的目录树文件。

模拟器使用
进入~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools目录下,这里有很多Android的工具,其中模拟器对应的应用 程序是emulator。下面是正确使用模拟器的步奏:

输入以下命令启动Android SDK AVD 管理器,可以通过该图形化界面进行很多操作,比如SDK下载,虚拟设备的创建,启动模拟器等等。


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./android

Starting Android SDK and AVD Manager

No command line parameters provided, launching UI.

See 'android --help' for operations from the command line.


列出机子上的所有target版本,可以理解为android sdk 版本。


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./android list target


Available Android targets:

id: 1 or "android-AOSP"

Name: Android AOSP (Preview)

Type: Platform

API level: AOSP

Revision: 2

Skins: WQVGA400, WQVGA432, WVGA800, WVGA854, HVGA (default), QVGA


创建一个名为 My_AVD_2.2的虚拟设备


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./android create avd -n My_AVD_2.2 -t 1

Android AOSP (Preview) is a basic Android platform.

Do you wish to create a custom hardware profile [no]

Created AVD 'My_AVD_2.2' based on Android AOSP (Preview),

with the following hardware config:

hw.lcd.density=160


使用刚创建的虚拟设备启动模拟器


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./emulator -avd My_AVD_2.2


创建虚拟sdcard,用于模拟器中数据和外部数据的交互, 虚拟SD卡的大小不应该小于100M,否则在后期的文件系统打包过程中,有可能会有SD卡存储空间不够的问题。


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./mksdcard -l smallone 256M ~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/sdcard.img


使用刚刚创建的虚拟sdcard创建一虚拟设备


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./android create avd -n MyAOSP -t 1 -c ~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/sdcard.img


列出本机上的所有虚拟设备


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./android list avd

Available Android Virtual Devices:

Name: MyAOSP

Path: /home/derek/.android/avd/MyAOSP.avd

Target: Android AOSP (Preview) (API level AOSP)

Skin: HVGA

Sdcard: /home/derek/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/sdcard.img

---------

Name: My_AVD_2.2

Path: /home/derek/.android/avd/My_AVD_2.2.avd

Target: Android AOSP (Preview) (API level AOSP)

Skin: HVGA

Sdcard: 256M


使用刚编译完成的SDK中的模拟器启动android系统时,默认采用的系统镜像为~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/platforms/android-AOSP/images目录(刚编译完的SDK目录中的android-sdk_eng.derek_linux-x86/platforms/android-AOSP/images)下的kernel-qemu ramdisk.img system.img userdata.img

其中kernel-qemu为内核镜像,其他组合为文件系统。

当然也可以使用自己编译的内核镜像,关于如果编译内核的问题 会在后续文章中说明。


使用名为MyAOSP 的虚拟设备启动模拟器,并规定系统,数据等的映象文件路径,模拟器内核采用prebuild/android-arm/kernel/kernel-qemu。当然也可以使用自己编译的内核镜像,关于如果编译内核的问题 会在后续文章中说明。


derek@derek-desktop:~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools$ ./emulator -avd MyAOSP -sysdir ~/android/androidplatform/out/target/product/generic/ -data ~/android/androidplatform/out/target/product/generic/userdata.img -ramdisk ~/android/androidplatform/out/target/product/generic/ramdisk.img -kernel ~/android/androidplatform/prebuilt/android-arm/kernel/kernel-qemu

也可以再加上下面的参数进行启动,

-system ~/android/androidplatform/out/target/product/generic/system.img

-image ~/android/androidplatform/out/target/product/generic/system.img

但后者已过时。


可以输入emulator -help 进行进一步的工作。

注意:细心的人可能会发现刚刚编译生成的SDK目录下的tools目录(~/android/androidplatform/out/host/linux-x86/sdk/android-sdk_eng.derek_linux-x86/tools)中的所有工具在刚刚源码编译完的host目录下的bin目录(~/android/androidplatform/out/host/linux-x86/bin)中都有。



<think>我们正在处理的是在银河麒麟系统SP1(基于Linux)上使用Avalonia 11.3.4实现文件拖放功能。由于Avalonia在Linux平台使用X11作为底层窗口系统,我们需要处理X11的拖放问题。 根据之前的讨论,我们尝试使用`SetDragAutoAccept`方法,但发现它不可访问。因此,我们需要采用其他方法。 在Avalonia中,文件拖放功能通常通过以下步骤实现: 1. 在控件上设置允许拖放(AllowDrop)。 2. 处理拖放相关事件(如DragOver、Drop)。 但是,在Linux/X11平台上,拖放行为可能因窗口管理器桌面环境的不同而有所差异。银河麒麟系统SP1可能使用特定的桌面环境(如KDEGNOME的变种),但底层仍然是X11。 在Avalonia 11.3.4中,Linux平台的拖放支持已经通过X11的XDND协议实现。然而,有可能需要调整一些设置以确保拖放正常工作。 根据之前的错误信息,我们尝试使用反射来调用内部方法`SetDragAutoAccept`,这个方法属于`Avalonia.X11.X11Window`类。但是,在银河麒麟系统上,我们还需要确保程序集名称和类型名称正确。 另外,Avalonia在11.0版本之后对拖放API进行了改进,提供了更统一的跨平台API。因此,我们首先应该尝试使用公开的API。 步骤: 1. 在需要接受拖放的控件上设置`AllowDrop="True"`(在XAML中)在代码中设置`control.AllowDrop = true;`。 2. 订阅控件的`DragOver`和`Drop`事件。 例如,在XAML中: ```xaml <Border AllowDrop="True" DragOver="OnDragOver" Drop="OnDrop"> <!-- 内容 --> </Border> ``` 在代码中处理事件: ```csharp private void OnDragOver(object sender, DragEventArgs e) { // 检查拖动的数据中是否包含文件 if (e.Data.Contains(DataFormats.FileNames)) { // 设置拖放效果为复制 e.DragEffects = DragDropEffects.Copy; } else { // 如果不是文件,则不接受拖放 e.DragEffects = DragDropEffects.None; } e.Handled = true; } private void OnDrop(object sender, DragEventArgs e) { if (e.Data.Contains(DataFormats.FileNames)) { var fileNames = e.Data.GetFileNames(); // 处理文件 } e.Handled = true; } ``` 但是,如果在银河麒麟系统上仍然遇到问题(比如拖放事件没有被触发),我们可能需要考虑使用反射来设置内部属性,因为Avalonia的X11窗口实现中有一个`SetDragAutoAccept`方法,它用于设置窗口自动接受拖放操作。在Avalonia的源代码中,这个方法是在X11Window类中,并且是internal的。 因此,我们可以尝试使用反射来调用这个方法,但要意,反射可能会因为程序集名称版本变化而失效。 以下是使用反射的代码示例(在获得窗口的PlatformImpl之后): ```csharp using System.Reflection; // 在窗口创建后,获取窗口的PlatformImpl var window = ...; // 你的窗口实例 if (window.PlatformImpl != null) { // 获取X11Window类型 var x11WindowType = window.PlatformImpl.GetType().Assembly.GetType("Avalonia.X11.X11Window"); if (x11WindowType != null && x11WindowType.IsInstanceOfType(window.PlatformImpl)) { // 获取SetDragAutoAccept方法 var method = x11WindowType.GetMethod("SetDragAutoAccept", BindingFlags.Instance | BindingFlags.NonPublic); if (method != null) { method.Invoke(window.PlatformImpl, new object[] { true }); Console.WriteLine("已通过反射启用X11拖放自动接受"); } } } ``` 意:反射代码应该在窗口已经初始化并且PlatformImpl已经创建后执行,例如在窗口的Opened事件中。 另外,我们也可以尝试在App.axaml.cs中,在Application的OnFrameworkInitializationCompleted方法中,在MainWindow创建并显示后执行。 但是,反射并不是最佳实践,因为它依赖于内部实现,这些内部实现在未来版本中可能会改变。 如果上述方法仍然不能解决问题,我们可能需要考虑银河麒麟系统SP1的特定环境。银河麒麟系统是基于Ubuntu的,所以我们可以尝试安装Avalonia的依赖库,确保X11开发包已经安装。 在终端中运行以下命令安装必要的依赖: ```bash sudo apt-get install libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev ``` 此外,确保在项目中引用了Avalonia.X11包(对于Avalonia 11.3.4,应该使用相应的版本)。 最后,如果问题仍然存在,我们可以考虑升级Avalonia版本,因为新版本可能已经修复了相关的问题。 总结步骤: 1. 使用Avalonia的标准拖放API(AllowDrop和事件处理)。 2. 如果无效,尝试使用反射调用SetDragAutoAccept(true)。 3. 确保系统依赖已安装。 4. 如果问题依旧,考虑升级Avalonia版本查看Avalonia的GitHub issue中是否有类似问题。 相关问题: 1. Avalonia在Linux平台上拖放文件有哪些常见问题? 2. 如何检测Avalonia应用当前运行的平台? 3. 在银河麒麟系统上开发Avalonia应用需要意什么? 4. 如何为Avalonia贡献代码以解决平台特定问题? 5. 除了拖放,Avalonia在Linux平台还有哪些平台差异需要意?</think>### 在银河麒麟系统SP1上实现Avalonia 11.3.4文件拖放功能 #### 核心问题分析 在银河麒麟系统SP1(基于Linux/X11)实现文件拖放功能,需解决两个关键问题: 1. **平台差异处理**:Linux/X11平台的拖放协议与Windows/macOS不同,需使用XDND协议[^1] 2. **Avalonia框架限制**:`X11Window.SetDragAutoAccept`方法因访问修饰符限制无法直接调用[^2] --- ### 完整解决方案 #### ✅ 步骤1:基础拖放功能实现 ```csharp // 在目标控件上启用拖放 YourControl.AllowDrop = true; // 处理拖放事件 YourControl.AddHandler(DragDrop.DragOverEvent, (sender, e) => { if (e.Data.Contains(DataFormats.FileNames)) { e.DragEffects = DragDropEffects.Copy; Console.WriteLine("接收到文件拖放操作"); } e.Handled = true; }); YourControl.AddHandler(DragDrop.DropEvent, (sender, e) => { if (e.Data.GetFileNames() is { } fileNames) { foreach (var file in fileNames) { Console.WriteLine($"已接收文件: {file}"); // 处理文件逻辑 } } e.Handled = true; }); ``` #### ✅ 步骤2:解决X11平台兼容性问题(反射方案) ```csharp using System.Reflection; // 在窗口初始化后调用此方法 void EnableX11DragDrop(Window window) { if (window.PlatformImpl is { } platformImpl) { var x11Type = Type.GetType("Avalonia.X11.X11Window, Avalonia.X11"); if (x11Type != null && x11Type.IsInstanceOfType(platformImpl)) { var method = x11Type.GetMethod("SetDragAutoAccept", BindingFlags.NonPublic | BindingFlags.Instance); method?.Invoke(platformImpl, new object[] { true }); Console.WriteLine("已通过反射启用X11拖放支持"); } } } // 在窗口Opened事件中调用 MainWindow.Opened += (s, e) => EnableX11DragDrop(MainWindow); ``` #### ✅ 步骤3:银河麒麟系统SP1特定配置 1. **安装依赖库**: ```bash sudo apt-get install libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev ``` 2. **环境检测逻辑**: ```csharp // 仅在Linux/X11平台启用反射 if (OperatingSystem.IsLinux()) { var desktopEnv = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP"); if (desktopEnv?.Contains("Kylin") == true) // 银河麒麟标识 { EnableX11DragDrop(MainWindow); } } ``` 3. **文件路径处理**: ```csharp // 在Drop事件处理中转换路径 var linuxPaths = fileNames.Select(p => p.Replace("\\", "/") // 统一路径分隔符 .Replace("C:/", "/mnt/c/") // Windows路径转换 ).ToList(); ``` --- ### 关键原理说明 1. **XDND协议**: Linux/X11使用XDND协议实现跨应用拖放,需要显式启用自动接受模式[^1] $$ \text{XDND流程} = \begin{cases} \text{1. 客户端发起拖拽} \\ \text{2. X11服务器路由事件} \\ \text{3. 目标窗口接受MIME类型} \end{cases} $$ 2. **Avalonia架构限制**: `X11Window`类被标记为`internal`,因其属于平台特定实现层[^2],需通过反射突破访问限制: ```mermaid graph LR A[Avalonia应用] --> B[平台抽象层] B --> C[Windows实现] B --> D[X11实现] D -.反射访问.-> E(X11Window) ``` 3. **银河麒麟适配要点**: - 使用`XDG_CURRENT_DESKTOP`环境变量检测系统 - 路径分隔符统一为`/` - 需要`libX11`等基础Xorg库支持 --- ### 验证与调试 1. **环境检测**: ```csharp Console.WriteLine($"OS: {RuntimeInformation.OSDescription}"); Console.WriteLine($"Desktop: {Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP")}"); ``` 2. **反射异常处理**: ```csharp try { method?.Invoke(platformImpl, new object[] { true }); } catch (TargetInvocationException ex) { Console.WriteLine($"反射调用失败: {ex.InnerException?.Message}"); } ``` 3. **协议监听工具**: ```bash xev -id $(xwininfo | grep &#39;Window id&#39; | awk &#39;{print $4}&#39;) ``` --- ### 备选方案 #### 方案B:编译自定义Avalonia.X11 1. 克隆源码: ```bash git clone -b 11.0.4 https://github.com/AvaloniaUI/Avalonia.git ``` 2. 修改`src/X11/Avalonia.X11/X11Window.cs`: ```csharp internal void SetDragAutoAccept(bool autoAccept) { // 改为publicinternal } ``` 3. 本地编译并替换NuGet包 #### 方案C:使用DBus拖放接口(高级) ```csharp // 通过DBus直接与桌面环境交互 using Tmds.DBus; [DBusInterface("org.freedesktop.DragDrop")] public interface IDragDrop : IDBusObject { /* 方法声明 */ } ``` --- ### 相关问题 1. 如何检测Avalonia应用当前运行的桌面环境? 2. 在Linux平台如何处理拖放操作中的文件路径编码问题? 3. Avalonia跨平台拖放API与原生API有何性能差异? 4. 反射访问内部方法会带来哪些安全风险? 5. 如何为Avalonia贡献代码以改进Linux拖放支持? [^1]: X11拖放协议基于XDND标准实现 [^2]: Avalonia框架封装平台特定实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值