如何建立android的C/C++交叉编译环境
Android的底层是纯粹的linux内核,可以简单的理解为上面跑了个Dalvik Java虚拟机而已。因此,构建android上C/C++的交叉编译环境也就成为了一个很大的需求。特别是对于已经取得root权限的机器,如果能直接运行按需编译的二进制文件,那么将可以做很多有意义和有趣的事情。
很不幸,Google没有直接给出如何建立这个交叉编译环境,但是我们可以借助Google提供的强大的NDK (Native Development Tools)来达到这一目的。NDK的本来目标是编译得到.so动态链接库文件,然后通过JNI提供给上层的Java调用,从而实现C/C++程序的简易迁移。而编译.so和编译成二进制可执行文件的过程是完全一样的,这就给了我们可以发挥的空间。
有两种方式获取交叉编译所需的工具链:git下prebuilt这个project或者直接去下载NDK,我这里arm-eabi的版本是最新的4.4.0。
1 | git clone git://android.git.kernel.org/platform/prebuilt.git |
然后创建一个helloworld.c文件。
1 2 3 4 5 6 | //// root@delleon:~/android/myapp# cat helloworld.c #include <stdio.h> int main() { printf("HelloWorld!n"); return 0; } |
接下来创建Makefile文件。注意修改其中的NDK_DIR和SDKTOOL为自己的目录,修改APP为自己的待编译程序主文件名。另外注意自己的arm-eabi的版本,若有变化则也需要修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #### root@delleon:~/android/myapp# cat Makefile APP=helloworld NDK_DIR := ~/android/android-ndk-r4 NDK_HOST := linux-x86 SDKTOOL := ~/android/android-sdk-linux_86/tools TOOLCHAIN_PREFIX := $(NDK_DIR)/build/prebuilt/$(NDK_HOST)/arm-eabi-4.4.0/bin/arm-eabi- CC := $(TOOLCHAIN_PREFIX)gcc CPP := $(TOOLCHAIN_PREFIX)g++ LD := $(CC) COMMON_FLAGS := -mandroid -ffunction-sections -fdata-sections -Os -g --sysroot=$(NDK_DIR)/build/platforms/android-5/arch-arm -fPIC -fvisibility=hidden -D__NEW__ CFLAGS := $(COMMON_FLAGS) CFLAGS += -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -DSK_RELEASE -DNDEBUG CFLAGS += -UDEBUG -march=armv5te -mtune=xscale -msoft-float -mthumb-interwork -fpic -ffunction-sections -funwind-tables -fstack-protector -fmessage-length=0 -Bdynamic CPPFLAGS := $(COMMON_FLAGS) -fno-rtti -fno-exceptions -fvisibility-inlines-hidden LDFLAGS += --sysroot=$(NDK_DIR)/build/platforms/android-5/arch-arm LDFLAGS += -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc LDFLAGS += -L$(NDK_DIR)/build/prebuilt/$(NDK_HOST)/arm-eabi-4.4.0/lib/gcc/arm-eabi/4.4.0 LDFLAGS += -L$(NDK_DIR)/build/prebuilt/$(NDK_HOST)/arm-eabi-4.4.0/lib/gcc LDFLAGS += -L$(NDK_DIR)/build/prebuilt/$(NDK_HOST)/arm-eabi-4.4.0/arm-eabi/lib LDFLAGS += -nostdlib -lc -llog -lgcc --no-undefined -z $(NDK_DIR)/build/platforms/android-5/arch-arm/usr/lib/crtbegin_dynamic.o $(NDK_DIR)/build/platforms/android-5/arch-arm/usr/lib/crtend_android.o OBJS += $(APP).o all: $(APP) $(APP): $(OBJS) $(LD) $(LDFLAGS) -o $@ $^ %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ %.o: %.cpp $(CPP) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ install: $(APP) $(SDKTOOL)/adb push $(APP) /data/local/bin/$(APP) $(SDKTOOL)/adb shell chmod 755 /data/local/bin/$(APP) run: $(SDKTOOL)/adb shell /data/local/bin/$(APP) clean: @rm -f $(APP).o $(APP) |
最后直接make,然后make install进手机里看一下吧。通过adb shell和手机里的Terminal等软件执行的结果是一样的。
后记:还有一个叫Codesourcery的工具链,下载下来有130多M,我使用它来编译helloworld时无误但是放到手机上则运行不起来。不想细究了,我认为NDK提供的工具链已经非常优秀。感兴趣的朋友可以自己试试Codesourcery。

Cool
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
%.o: %.cpp
$(CPP) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
这里面的 < 表示什么?
应该是被编辑器转义了
@ms 多谢提醒,确实是北编辑器转义了,已修改过来。
呵呵 这个注释倒是解析正确
lz中的是 $ & l t;
TOOLCHAIN_PREFIX := $(NDK_DIR)/build/prebuilt/$(NDK_HOST)/arm-eabi-4.4.0/bin/arm-eabi-
CC := $(TOOLCHAIN_PREFIX)gcc
TOOLCHAIN_PREFIX 这个是不是被截断了
是我看错了 呵呵
hi Leon:
看到你这篇文章,我也尝试了一下,你最后所说的那个Codesourcery我尝试了,可以编译helloworld,在adb shell上可以运行,但是放到机器里面,用机器上的shell就无法运行了,说是没有权限,但是我肯定是取得了root了,比较奇怪。
不知道你是如何解决的?
hooper
@hooper
这个确实诡异,你放在真机的哪个目录下了?一般不要放在/sdcard/下面,没有可执行权限。放在/data/下面比较妥当。