您的位置:首页 > 移动开发 > Android开发

Android开发基础(2.2)--利用NDK搭建自己的Android交叉工具链

2011-02-26 16:51 477 查看
上篇提到的都是使用现有的ndk-build建立共享库。如何建立可执行的C/C++文件?将jni/Android.mk内的

include $(BUILD_SHARED_LIBRARY)
改成include $(BUILD_EXECUTABLE)
即可。那么,想“自由使用”工具链,比如

直接使用gcc/g++那样,尤其是想往Android上面移植 C/C++程序或者库时,如何才能跳出ndk-build的限制?

I.提取Android的gcc工具链

如果你想偷懒的话,你很幸运,有现成的
,附件的perl脚本agcc(csdn搞不出附件,只好链接新帖子




,即可以完成工具链的抽取和封装,可以像使用 gcc 那样使用它,它最先来自

plausible.org/andy/agcc

不过这个是面对整个Android开发包的(包括Android/SDK/NDK的所有文件),而且没有C++/STL支持,我对它进行了修改,使它与上篇给出的ndk-r4配合,完全支持c/c++。

如果你想自己动手,请这样做:

1.分别对

1)生成可执行文件

2)静态库

3)
动态库

4)多个源文件 的不同类型的工程使用

#ndk-build -B V=1



命令,会让ndk-build “揭露出”整个工具链的不同使用过程
,比如上篇中的helloworld工程:

显示:

Compile thumb : helloworld <= /opt/android/android-ndk-r4c/samples/helloworld/jni/helloworld.c

/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/arm-eabi-gcc -I/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/include -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/opt/android/android-ndk-r4c/samples/helloworld/jni -DANDROID -Wa,--noexecstack -O2 -DNDEBUG -g -c -MMD -MP -MF /opt/android/android-ndk-r4c/samples/helloworld/bin/ndk/local/armeabi/objs/helloworld/helloworld.o.d /opt/android/android-ndk-r4c/samples/helloworld/jni/helloworld.c -o /opt/android/android-ndk-r4c/samples/helloworld/bin/ndk/local/armeabi/objs/helloworld/helloworld.o

SharedLibrary : libhelloworld.so

/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/arm-eabi-gcc -nostdlib -Wl,-soname,libhelloworld.so -Wl,-shared,-Bsymbolic /opt/android/android-ndk-r4c/samples/helloworld/bin/ndk/local/armeabi/objs/helloworld/helloworld.o -Wl,--whole-archive -Wl,--no-whole-archive /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libstdc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libsupc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/libgcc.a /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/libc.so /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/libm.so -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-rpath-link=/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libstdc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libsupc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/libgcc.a -o /opt/android/android-ndk-r4c/samples/helloworld/bin/ndk/local/armeabi/libhelloworld.so

......

从这些命令记录分别提取出

1)工具的名称和位置

例如gcc/g++工具是 arm-eabi-gcc/g++,位置是
/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/。。

2)工具相关选项和参数

交叉编译时,最重要的就是编译工具的相关参数设置,以及从环境中提取的文件(头文件夹,链接文件,库文件..)。下面的从上面提取的相关参数就不用我解释了吧?(如果不熟悉这些的话,真的不应该直接从Android上手学交叉编译,道理你们懂的。。)

CC
=
arm-eabi-gcc

CFLAGS/CXXFLAGS
="-fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64"

CPPFLAGS
="-I/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/include -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -I/opt/android/android-ndk-r4c/samples/helloworld/jni -DANDROID
"

CXX
=arm-eabi-g++

LDFLAGS
= "-nostdlib -Wl,-soname,libhelloworld.so -Wl,-shared,-Bsymbolic -Wl,--whole-archive -Wl,--no-whole-archive /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libstdc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libsupc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/libgcc.a /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/libc.so /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/libm.so -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-rpath-link=/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libstdc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/lib/libsupc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/libgcc.a"

3)工具的使用过程

主要是面对不同的源文件(.c/.cpp/.o/.h...),以及不同的目标(生成什么?.o/.exe/.s...),工具的使用过程和参数都是不同的,比如上例:

.c-->.o

$CC $CPPFLAGS $CFLAGS helloworld.c -c -g -o helloworld.o

仅仅 预处理-->编译,未链接

然后

.o-->.so

$CC $LDFLAGS helloworld.o -o libhelloworld.so

完成链接

4)大家可以查看其他几类情况,使用的工具和参数各不相同。

II.直接使用工具链

提取出了工具链,弄清其不同参数和工作流程后,就可以自己指明使用了。首先将工具加入$PATH,然后,例如编译如下的两个全面测试C++功能的.cpp文件,要求ahoo.cpp -->libahoo.so(动态库);a.cpp+libahoo.so --->a(程序):

ahoo.h

#include <cstdlib>
#include <stdexcept>
#include <string>
#include <cstdio>
void ahoo(char** );
class A
{
public:
A();
~A();
};
class B:public A
{
public:
B();
~B();
};


ahoo.cpp

#include"ahoo.h"
int hana;
A::A(){printf("ahoooooooooo coming!/n");}
A::~A(){printf("ahoooooooooo dying!/n");}
void ahoo(char**  a)
{
hana = 100;
printf("sizeof hana:%d/n",hana);
*a=(char*) malloc(256);
memset(*a,0,256);
std::string s = "Hello from JNI !";
try
{
if (std::getenv("NON_EXISTENT_ENVIRONMENT_VARIABLE") == NULL)
throw std::runtime_error("libahoo.so:--exception.runtime_error.string:/t--琉球の海風にいる !");
}
catch (std::exception &ex)
{
s = ex.what();
s = s+"/nlibahoo.so:--exception.catch.string:/t--You are Foooooooooyoooooooed!/n";
}
strcpy(*a,s.c_str());
}


a.cpp

#include "ahoo.h"
#include"pthread.h"
B::B(){printf("bagaaaaaaaaa coming!/n");}
B::~B(){printf("bagaaaaaaaaa dying!/n");}
template <typename T>
class C
{
public:
T a;
T b;
C(T fa,T fb):a(fa),b(fb){printf("%s/n%s/n",a.c_str(),b.c_str());}
};
typedef void* (*thread_main_t)(void*);
extern int hana;
int main()
{
pthread_t thread;
char* ah =NULL;
B* pb=new B;
delete pb;
C<std::string> c("Horaaaaaaaaaaa","Woraaaaaaaaaaaa");
pthread_create(&thread,NULL,(thread_main_t)&ahoo,(void*)&ah);
pthread_join(thread,NULL);
printf("sizeof hana:%d/n",hana);
if(ah)
{
printf("%s",ah);
free(ah);
}
std::string str="づっと、づっと乙女の側に居るように!/n";
printf("a/t:--string:/t--%s/n",str.c_str());
return 0;
}


命令就是:(都是先编译,再链接,注意参数的区别)

1)ahoo.cpp--->ahoo.o a.cpp-->a.o

arm-eabi-g++ ahoo.cpp -I/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/include -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -DNDEBUG -mthumb-interwork -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fPIC -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wno-psabi -Wa,--noexecstack -Os -O2 -c -o ahoo.o

arm-eabi-g++ a.cpp -I/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/include -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID -DNDEBUG -mthumb-interwork -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fPIC -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wno-psabi -Wa,--noexecstack -Os -O2 -c -o a.o

2) ahoo.o -->libahoo.so

arm-eabi-gcc
ahoo.o -nostdlib -Wl,-shared,-Bsymbolic -Wl,--whole-archive
-Wl,--no-whole-archive -Wl,--no-undefined -Wl,-z,noexecstack
-Wl,-rpath-link=/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib
-L/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib
-lc -lm
/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/arm-eabi/lib/libstdc++.a
/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/arm-eabi/lib/libsupc++.a
/opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/lib/gcc/arm-eabi/4.4.0/libgcc.a
-o libahoo.so

3) a.o -->a

arm-eabi-gcc a.o -nostdlib -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-rpath-link=/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib -L/opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib -lc -lm /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/arm-eabi/lib/libstdc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/arm-eabi/lib/libsupc++.a /opt/android/android-ndk-r4c/build/prebuilt/linux-x86/arm-eabi-4.4.0/lib/gcc/arm-eabi/4.4.0/libgcc.a /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/crtend_android.o /opt/android/android-ndk-r4c/build/platforms/android-8/arch-arm/usr/lib/crtbegin_dynamic.o -o a -lahoo -L./

你是什么感觉呢,不觉得太长太麻烦了吗?何苦呢?何必呢?所以我才将所有的内容都封装在agcc
内的啊,你难道不想也这样做吗?(尤其是对程序或者库进行 ./configure 的时候!),上面的例子,直接用我的agcc
的话(先将包含arm-eabi-*的路径加入$PATH


#agcc ahoo.cpp -shared -o libahoo.so

Compile Thumb++ :ahoo.cpp ===> ahoo.o

...

Link ARM shared lib : ahoo.o ====> libahoo.so

...

#agcc a.cpp -o a -lahoo -L./

Compile Thumb++ :a.cpp ===> a.o

....

Link ARM executable : a.o ====> a

...

# file a

a: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

#file libahoo.so

libahoo.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, not stripped

#arm-eabi-readelf -d a

Dynamic section at offset 0x132cc contains 23 entries:

Tag Type Name/Value

0x00000001 (NEEDED) Shared library: [libc.so]

0x00000001 (NEEDED) Shared library: [libm.so]

0x00000001 (NEEDED) Shared library: [libahoo.so]

0x00000020 (PREINIT_ARRAY) 0x1c2a4

0x00000021 (PREINIT_ARRAYSZ) 0x8

.................

搞定!现在你也可以从自己的NDK出发提取组合自己的工具链了吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: