编译用于Androidbusybox

使用arm-eabi-gcc编译busybox,设置-I${NDK_USR}/include -L${NDK_USR}/lib,源文件中出现许多subscripted value is neither array nor pointer nor vector语法error,通不过;换arm-linux-androideabi-gcc设置好-I –L后编译,最后链接阶段报打不开或找不到crtbegin_static.ocrtend_android.o错误,但是这两个目标文件在lib中存在。

试图解决此问题,并回答或解释:

crtbegin_static.ocrtend_android.o是否可以通过给ld选项予以解决?

arm-eabi-gccarm-linux-androideabi-gcc(jni native used)EABI标准上的差异?

Toolchain本身生成时(--with-sysroot)选项的差异和用途区别?

编译jni native codenon-jni native code的步骤;

按照后面的文档所述,编译busybox是使用eabi还是androideabi好呢?

Lib.a for busybox是个什么东西?

Busybox自己带crt.ostartup code?

解决途径:

1. We recommend developers to make themselves familiar with JNI concepts. Alsonote thatthe NDK is *not* a good way towrite non-JNI native code for theAndroid platform.---- extracted from ndk/README.txt

1.Search arm-eabi- & arm-linux-androideabi- PREFIX & --with-sysroot & SYSROOT in Android Makefiles.

2. Read GCC manual – for some options

参考后面资料后继续编译:

menuconfig中设置使用arm-linux-androideabi-toolchain,设置sysrootjellybeantop/prebuilts/ndk/android-ndk-r7/platforms/android-14/arch-arm/(注意是usr目录的上级目录),其中为usr/includeusr/lib),此时不再需要-I-L选项。则去除某些找不到链接项的feature后,可以编译成功,大小为800k左右。

针对编译过程中的语法错误,可以通过查看命令文件名去掉对应目录和名称的feature;针对链接过程中无法解析的符号,主要是libbb中的,可以通过sourceinsight查看源文件搜索出引用的命令,去掉该feature

将编译出来的busybox可执行文件,adb push到手机/system/bbdir/目录,测试

./busybox --help可用;

使用命令/system/bbdir/busybox –install –s.安装(注意命令中的当前目录),测试ls –al可用,还有彩色高亮显示。测试其余命令,可用。

编译完成后浏览源文件目录,发现lib.a被拷贝到每个源码目录下。

Makefile文件中有nostadlib选项:

LD = $(CC)-nostdlib

Makefile.flags文件中有--sysroot设置和SYSROOT环境变量输出:

ifneq ($(subst "",,$(CONFIG_SYSROOT)),)

CFLAGS += --sysroot=$(CONFIG_SYSROOT)

export SYSROOT=$(CONFIG_SYSROOT)

endif

一些问题的解释:

为什么使用arm-eabi-toolchain会频繁报subscripted value is neither array nor pointer nor vector,下面这段busybox/Makefile中的注释也许能回答.

## TODO:

## gcc version 4.4.0 20090506 (Red Hat 4.4.0-4) (GCC) is a PITA:

## const char *ptr; ... off_t v = *(off_t*)ptr; -> BOOM

## and no easy way to convince it to shut the hell up.

## We have a lot of such things all over the place.

## Classic *(off_t*)(void*)ptr does not work,

## and I am unwilling to do crazy gcc specific ({ void *ppp = ...; })

## stuff in macros. This would obfuscate the code too much.

## Maybe try __attribute__((__may_alias__))?

#CFLAGS += $(call cc-ifversion, -eq, 0404, -fno-strict-aliasing)

链接时很多feature使用的API找不到?

这是因为bionic c库实现的限制: The NDK only provides system headers for a very limited set of native APIs and libraries supported by the Android platform.

-nostdlib--with-sysroot的作用?

-nostdlib包含-nostartupfiles-nodefaultlibs两个选项;前者是_start标号所在,可能是crt.o?后者是通常是libgcc(注意这里所说的缺省库标准库不是有些人以讹传讹的C标准库),是实现_init, _fini, __main, _atexit _initarray _finiarray等等这些的编译器标准库.

-sysroot才是指定target系统标准头文件和库文件目录的选项.

Busybox本身有定制的startup code,且不去使用编译器标准库,故加-nostdlib链接选项. Busybox/Makefile中有$(busybox-init), $(busybox-main)和链接布局描述;-sysroot选项主要是指定bionic c头文件和库目录上级rootdir[/usr].

--with-sysroot选项的作用

传给GCC--with-sysroot选项,--sysroot传给LD,其意思是

The "sysroot" is the location the cross compiler will look for header files and libraries. The sysroot directory acts as if it is the root of the system,. So, for example, header files go in $SYSROOT/usr/include/ and library files go in $SYSROOT/usr/lib/, etc.

因为这是在目标系统的文件系统的/usr目录下的头文件和库文件目录,所以使用前无论是编译GCC还是编译应用程序,都要首先确保该目录存在。

Toolchain本身生成时(--with-sysroot)选项的差异和用途区别?

如果Toolchain仅仅用来编译内核,不用来编译应用程序那么不需要设定--sysroot,因为编译内核并不需要C库,这是用户态程序使用的。

但是如果该Toolchain也用来编译使用libc用户态程序,那么To be able to build and link applications, the cross-compiler needs access to the system header files. As building the compiler also uses some of these files, installing these files needs to be done first. If you have access to the target machine, you can just copy the files into $SYSROOT. Otherwise, you'll need to download the files from the proper distribution.

configargs.h文件中可以看出androidarm-eabi-toolchainarm-linux-androideabi-toolchain在生成时,是加了--with-sysroot的。

arm-eabi-gccarm-linux-androideabi-gcc(jni native used)EABI标准上的差异?

差异可能主要在JNI界面上的寄存器使用上.应用级别so就用androideabi toolchain编译。此外

Arm-linux-androideabi-toolchainDVM配合, Android NDK Dev Guide: Android NDK Overview: III. NDK development in practice大致描述了JNI开发的路径,使用的Makefile.

Standalone compiler不是说建议用来编译non-jni native code;而是说可以不必将源码按NDK development的步骤集成到整个Android代码树,可以做为独立的二进制工具编译jni native code,生成的so仍然在DVM管理下运行.

androidarm-eabi-toolchainlib目录下基本上有libarm-elf-linux-sim.a libbfd.a libiberty.a libintl.agcc目录下crtbegin.o crtend.o libgcc.a libgcov等几个c runtime库和gcc本省的库,可以看出并没有c库支持;arm-linux-androideabi-toolchainlib目录也基本类似。所以开发应用so时,需要指定—sysroot,即指定c头文件和库。在android上可选择的几乎就是ndk中的bionic头文件和库了, 还有一些framework级别的库

既然建议编译busybox最好使用sysrooted toolchain, ndk toolchain文档也描述其用来生成non-jni native code is NOT good, 那么用其生成的busybox运行有什么隐患吗?

因为menuconfig,配置静态链接bionic c,所以虽然使用androideabi规约编译代码,但是如果需要系统调用的时候,该层面仍然按照系统调用的ABI规约,所以可正常运行;但是如果是动态链接的,没有DVM参与管理,那么可能就不能正常运行了.

使用arm-eabi-和静态链接glibc的话,由于glibcbionic支持更多的接口,可以选择更多的busybox feature。但是前提是解决掉源码中通不过编译的error

所参考文章附录

使用NDK Build Android上的busybox

Android上,为了某些需要,我们需要一个小而精减的busybox(如果不懂busybox是什么),请跳过此文。当然我们也可以用gcctoolchainsbuild但生成出来的那个二进制文件的size会让你疯狂。而用NDK生成出来的二进制则是gcc生成的五分之一左右。我做过试验,同样一个busybox的配置,gcc生成的busybox460k左右,NDK生成出来的则是84k

如果研究过NDK,可以看到他有一个toolchains目录,这目录里装的就是用来编译生成能在android上运行的程序的编译器。例如目录

/opt/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin

这目录下就是编译器,而编译链接需要的头文件和库则在对应的平台的目录里,例如

/opt/android-ndk-r6/platforms/android-9/arch-arm/usr

下的includelib

下面开始正题,首先需要哪些环境:

1. Linux系统环境,我这里是(Ubuntu 10.x),你也可以用一个虚拟机,我就是用的虚拟机。

2. 安装了gccmake,和NDK,可以从上面内容看到,我用的是r5c版。这些怎么配置这里略过,网上一搜一大把。

3. http://www.linuxidc.com/Linux/2011-08/40704.htm上下载busybox源代码

开始

1. /opt/android-ndk-r6/platforms/android-9/arch-arm/usr下的includelib覆盖拷贝/opt/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi目录下。这里用哪个平台的头文件和库你自己可以看着办。差别不大。

2. 解压busybox包,然后进入解压后的busybox目录

3. make menuconfig

在配置里,有几项是要选上的。

Busybox Settings->Build Options->

[*] Build BusyBox as a static binary (no shared libs)
Cross Compiler prefix: /opt/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-

Busybox Settings->General Configuration->

[*] Enable options for full-blown desktop systems
[ ] Provide compatible behavior for rare corner cases (bigger code)

[*] Enable obsolete features removed before SUSv3

[ ] Avoid using GCC-specific code constructs

[*] Enable Linux-specific applets and features

Buffer allocation policy (Allocate with Malloc) --->

[*] Show terse applet usage messages

[*] Show verbose applet usage messages

[*] Store applet usage messages in compressed form

[*] Support --install [-s] to install applet links at runtime

[*] Don't use /usr

[ ] Enable locale support (system needs locale for this to work)

[ ] Support Unicode

[*] Support for --long-options

[*] Use the devpts filesystem for Unix98 PTYs

[ ] Clean up all memory before exiting (usually not needed)

[ ] Support wtmp file

[ ] Support utmp file

[ ] Support writing pidfiles

[ ] Support for SUID/SGID handling

[ ] Support NSA Security Enhanced Linux

[ ] exec prefers applets

(/proc/self/exe) Path to BusyBox executable

剩下的其他的按自己的需要来选配,

4.ESC退出,最后会问你是否保存配置,别多按ESC,会不保存的。选择yes按回车保存。

5. 修改Makefile.flags.去掉 crypt库的链接,当然一些用到crpyt库的功能也得从第3步的配置里去掉,例如密码之类的。

6.make

这期间会有些编译错误

我碰到过一个找不到sys/user.h的错误,我把/opt/Android-ndk-r6/tmakeoolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/include/linux/user.h拷贝到/opt/android-ndk-r6/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/include/sys下搞定。

还有一个找不到sys/kd.h的错误也同样处理

还碰到过一个找不到strchrnul函数的定义。我用strchr替代之。例如editor/sed.c

//原代码 unsigned idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters;

// 替换代码。

char* tmp_p = strchr(cmd_letters, sed_cmd->cmd);
unsigned idx = tmp_p ? tmp_p - cmd_letters : strlen(tmp_p);

还有libbb/obscure.c line 113,注释掉那3行。

如果编译碰到错误无法解决时,把对应编译出错的工具打勾去掉再重新make,例如editors/vi.c有个函数找不到,我就重新配置了一下busybox,Editors里的vi给去掉了。然后重新编译。

我还去掉了Init Utilities->bootchartd, poweroff,halt, and reboot,

Busybox Settings->Busybox Library Tuning->

[ ] Command line editing-à lineedit.c

当然最好是只选CoreUtils

7.生成出来了busybox,将其拷贝到android手机上,就能用了。

备注:其实那些编译错误都是可以解决的,用strchr替换strchrul,还有用其他函数替代fputs_unlocked,大家有兴趣可以自己研究下。

这些错误都是因为NDK里的头文件和库与GNU GCC的头文件有些差异或者给去掉了一些文件导致的。

Situation with toolchain sysroot

It is possible to build toolchain with sysroot, but that is a special-purpose option. Here are short description of 4 types of toolchains available in Android world:

1 arm-linux-androideabi toolchain. This is the main toolchain used for current builds. It differs from the bare-metal toolchain (see below) in that thetarget platform is arm-linux-androideabi, not arm-eabi.

2 Bare-metal toolchain. In Android 2.x releases, this was used to build entire (monolithic) platform. This toolchain is built as decsribed above,without --with-sysroot switch. This is all that wasneeded to build platform, because libc, libm, etc. are built as part of the platform, and build takes care to pass explicit references to them to build other packages (it uses-nostdlib -libc, etc.).In newer releases, the arm-linux-androideabi toolchain is used instead. The bare-metal toolchain is stilluseful to build bits and pieces that are loaded before the OS is up, such as u-boot.

3 Toolchain built using these instructions and --with-sysroot . Such toolchain is not needed during normal Android development process, which consists of building monolithic platform once, and then build (Java/Dalvik-based) applications for it using SDK/NDK. However, sometimes you need to build additional software whichruns on system, platform level. One example isbuilding busybox outside of normal platform build. Another isbuilding official Android toolchain benchmark suite. For such cases, after you build monolothic platform, you can build a sysrooted toolchain for it. Note that youdon't need to rebuild platform with this sysrooted toolchain - as described above, just bare-metal compiler needed to build platform, toolchain's libc is explicitly ignored during platform build using -nostdlib switch.

4 NDK toolchain. This isused for Android application development. This is completely different layer from system, platform layer - all Android application are Dalvik managed once, any native-CPU code goes in form of JNI shared libraries. NDK toolchain is intended to buildjust such JNI shared libs. NDK toolchain is build separately from the platform toolchain, with other set of scripts (See "make ndk" in platform tree.

关于Android toolchain的,好像有点过时?

JellyBean里面, 1, 2, 4都成了arm-linux-androideabi-toolchain?

看来2所说的bare-metal toolchain是用来编译内核和C库的,without --with-sysroot这个东西本身生成就不需要C库, 编译内核也根本不需要C库; 编译完内核然后编译C库, 编译用户空间的程序; -nostdlib -libc, etc此处可能是指编译用户程序有的不使用编译器的startup和标准库, 有的使用-libc选项, 有的使用其它选项等等. 而此处编译其它用户态程序使用的C库, 也是bionic.

1和4很明显是arm-linux-androideabi-toolchain.

3这套关键是--with-sysroot指向哪儿呢?使用哪套C?自己指定套吗?指定套实现了bionic没实现接口的?<mntent.h>(C--- FILE).

FILE *setmntent(const char *filename, const char *type);

struct mntent *getmntent(FILE *fp);

int addmntent(FILE *fp, const struct mntent *mnt);

int endmntent(FILE *fp);

char *hasmntopt(const struct mntent *mnt, const char *opt);

struct mntent *getmntent_r(FILE *fp, struct mntent *mntbuf,char *buf, int buflen);

那可以用bare-metal编译套glibc,然后--with-sysroot指定给此套编译器使用?静态链接应该没问题,但是动态就不行了. Android使用/system/lib/linker而不是ld,自己再编译个/system/lib/ld.so.反正也能找到其源码(No。不是自己编译的,是glibc库里带的).搞上两套C,看来需要再建个libxx目录,不然冲突. Glibc+pthread在别的嵌入式系统上怎么porting,这儿就怎么porting,只是给ld信息默认去libxx目录找就行.

附录-------摘自GCC buildmanual.

Installing GCC: Configuration

http://gcc.gnu.org/install/configure.html

Options specification

--with-native-system-header-dir=dirname

Specifies that dirname is the directory that contains native system header files, rather than/usr/include. This option is most useful if you are creating a compiler that should be isolated from the system as much as possible. It is most commonly used with the--with-sysroot option and will cause GCC to searchdirname inside the system root specified by that option.

Cross-Compiler-Specific Options

The following options only apply to building cross compilers.

--with-sysroot

--with-sysroot=dir

Tells GCC to considerdir as the root of a tree that contains (a subset of) the root filesystem ofthe target operating system. Target system headers, libraries and run-time object files will be searched for in there.More specifically, this acts as if--sysroot=dir was added to the default options of the built compiler. The specified directory is not copied into the install tree, unlike the options--with-headers and--with-libs that this option obsoletes.The default value, in case--with-sysroot is not given an argument, is${gcc_tooldir}/sys-root. If the specified directory is a subdirectory of${exec_prefix}, then it will be found relative to the GCC binaries if the installation tree is moved.

This option affects the system root for the compiler used to build target libraries (which runs on the build system) and the compiler newly installed withmake install; it does not affect the compiler which is used to build GCC itself.

If you specify the--with-native-system-header-dir=dirname option then the compiler will search that directory withindirname for native system headers rather than the default/usr/include.

--with-build-sysroot

--with-build-sysroot=dir

Tells GCC to considerdir as the system root (see--with-sysroot) while building target libraries, instead of the directory specified with--with-sysroot. This option is only useful when you are already using--with-sysroot. You can use--with-build-sysroot when you are configuring with--prefix set to a directory that is different from the one in which you are installing GCC and your target libraries.

This option affects the system root for the compiler used to build target libraries (which runs on the build system); it does not affect the compiler which is used to build GCC itself.

If you specify the--with-native-system-header-dir=dirname option then the compiler will search that directory withindirname for native system headers rather than the default/usr/include.

--with-headers

--with-headers=dir

Deprecated in favor of--with-sysroot. Specifies that target headers are available when building a cross compiler. Thedir argument specifies a directory which has the target include files. These include files will be copied into thegcc install directory.This option with the dir argument is required when building a cross compiler, ifprefix/target/sys-include doesn't pre-exist. If prefix/target/sys-include does pre-exist, the dir argument may be omitted. fixincludes will be run on these files to make them compatible with GCC.

--without-headers

Tells GCC not use any target headers from a libc when building a cross compiler. When crossing to GNU/Linux, you need the headers so GCC can build the exception handling for libgcc.

--with-libs

--with-libs="dir1dir2 ... dirN"

Deprecated in favor of--with-sysroot. Specifies a list of directories which contain the target runtime libraries. These libraries will be copied into thegcc install directory. If the directory list is omitted, this option has no effect.

--with-newlib

Specifies that `newlib' is being used as the target C library. This causes __eprintf to be omitted fromlibgcc.a on the assumption that it will be provided by `newlib'.

--with-build-time-tools=dir

Specifies where to find the set of target tools (assembler, linker, etc.) that will be used while building GCC itself. This option can be useful if the directory layouts are different between the system you are building GCC on, and the system where you will deploy it.

For example, on an `ia64-hp-hpux' system, you may have the GNU assembler and linker in /usr/bin, and the native tools in a different path, and build a toolchain that expects to find the native tools in /usr/bin.

When you use this option, you should ensure thatdir includesar,as,ld,nm,ranlib andstrip if necessary, and possiblyobjdump. Otherwise, GCC may use an inconsistent set of tools.

Using the GNU Compiler Collection

--sysroot=dir

Use dir as the logical root directory for headers and libraries. For example, if the compiler would normally search for headers in ‘/usr/include’ and libraries in ‘/usr/lib’, it will instead search ‘dir/usr/include’ and ‘dir/usr/lib’.

If you use both this option and the ‘-isysroot’ option, then the ‘--sysroot’ option will apply to libraries, but the ‘-isysroot’ option will apply to header files.

The GNU linker (beginning with version 2.16) has the necessary support for this option. If your linker does not support this option, the header file aspect of ‘--sysroot’ will still work, but the library aspect will not.

-isysroot dir

This option is like the ‘--sysroot’ option, but applies only to header files(except for Darwin targets, where it applies to both header files and libraries).

See the ‘--sysroot’ option for more information.

-nostartfiles

Do not use the standard system startup files when linking. The standard system libraries are used normally, unless ‘-nostdlib’ or ‘-nodefaultlibs’ is used.

-nodefaultlibs

Do not use the standard system libraries when linking. Only the libraries you specify will be passed to the linker, options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, will be ignored. The standard startup files are used normally, unless ‘-nostartfiles’ is used. The compiler may generate calls to memcmp, memset, memcpy and memmove. These

entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified.

-nostdlib

Do not use the standard system startup files or libraries when linking. No startup files and only the libraries you specify will be passed to the linker, options specifying linkage of the system libraries, such as -static-libgcc or -shared-libgcc, will be ignored. The compiler may generate calls to memcmp, memset, memcpy and memmove. These entries are usually resolved by entries in libc. These entry points should be supplied through some other mechanism when this option is specified.

One of the standard libraries bypassed by ‘-nostdlib’ and ‘-nodefaultlibs’ is ‘libgcc.a’, a library of internal subroutines which GCC uses to overcome shortcomings of particular machines, or special needs for some languages. (See Section “Interfacing to GCC Output” in GNU Compiler Collection (GCC) Internals, for more discussion of ‘libgcc.a’.) In most cases, you need ‘libgcc.a’ even when you want to avoid other standard libraries. In other words, when you specify ‘-nostdlib’ or ‘-nodefaultlibs’ you should usually specify ‘-lgcc’ as well. This ensures that you have no unresolved references to internal GCC library subroutines. (For example, ‘__main’, used to ensure C++ constructors will be called; seeSection “collect2” in GNU Compiler Collection (GCC)Internals.)

更多相关文章

  1. 一、开发环境搭建及配置
  2. android开发教程(八)——环境搭建之android-ndk
  3. Windows10环境下Android(安卓)studio NDK编译assimp
  4. 【JAVA】生成一个32位的随机数。防止重复,保留唯一性
  5. TensorFlow in Android
  6. android 通过platform.pk8,platform.x509.pem生成jks签名文件
  7. android 读书笔记 1
  8. android-----JNI学习 helloworld
  9. Android(安卓)building system

随机推荐

  1. 神器 | JupyterLab,极其强大的下一代noteb
  2. VS2019学生版的下载安装并使用
  3. java 读取 application配置文件
  4. Centos8基础,Yum软件包管理
  5. 知乎千赞回答 | 为什么自学python看不进
  6. 一不小心,我爬取了100万条微博评论
  7. 15款好用到爆炸的Jupyter Lab插件
  8. Python地图可视化三大秘密武器
  9. 50个关于IPython的使用技巧,get起来!
  10. 类比MySQL,学习Tableau