常见错误说明:
1、make:*** No rule specified and no make file found. Stop.
错误的原因估计是(cat : Linux命令,显示文件的内容):工程名与Aplication.mk中的APP_MOUDLES不一致。
2、make: *** No rule to make target “XXXXXX”, needed by “ndk-app-XXXXX”. Stop.
这个错误的主要原因是:编译C文件为最后的so库文件需要2个文件:Application.mk、Android.mk,如下图所示:
MK文件如何设置,看了上面的图一目了然【详细的说明还是要去看文档】,以下几点需要注意:
· 文件的相对路径是否正确(Application.mk中的APP_PROJECT_PATH设置相对路径),如下图所示:
这些在Android NDKzhong 都有“严格”规范的,在android-ndk的文档中都有详细说明。
· 工程文件名、Aplication.mk中的APP_MOUDLES、Android.m中的LOCAL_SRC_FILES是否完全一致。Android.m中的LOCAL_SRC_FILES是输出库文件的名称【NDK会默认的加上前缀lib(如果LOCAL_SRC_FILES中已经是以lib开头就不添加),以及后缀.so】,但是尝试后发现这个地方必须与Aplication.mk中的APP_MOUDLES一致,否则就会导致上述错误。
3、make: ***[XXXX]Errror 1
这个错误只要大家仔细看下就明白是C 的编译错误,C 代码无法编译。
如何编写C文件【native file】中的函数说明?从Java Source File推导出C/C++ Native File,可以参考以下4步:
1) 编译java文件【Java sources:包含我们需要的native函数】,如下图所示:
2) 使用命令javac JNITest.jva && javah JNITest,命令运行后增加了2个文件:
JNITest.jva编译后的文件JNITest.class、JNITest.h,这个文件就是我们需要的头文件,如下图所示:
3) 修改函数名,如何修改?我们先分析Android-NDK中的例子程序:
从上面的例子发现,函数名分为4部分:
按照上面的规则修改就可以了。
4) 将上面的函数声明拷贝出来,在jni文件中创建一个*.c文件,按照上述函数结构实现函数,如下图所示:
这样我们就从Java Source File一步一步的得到C/C++ Native File。
4、程序运行时崩溃,这个时候我们需要注意以下几个问题:
库文件的加载:
编译后的so文件是libJNITest.so,而实际加载的库文件名是: JNITest【这实际上是Unix的“规范”,在Android NDK的文档OVERVIEW.txt中有详细说明】;还有Linux系统区分大小写的,所以如果上面的代码中,将加载的库文件名写成jnitest,也会导致运行崩溃。
解决NDK出现error: exception handling disabled, use -fexceptions to enable的问题
问题来源:
UDT的android平台移植过程中,在用NDK编译buffer.cpp文件时出现error: exception handling disabled, use -fexceptions to enable。
问题解决:
此问题的出现是编译器的异常异常捕获被禁用了,需要在Android.mk文件中开启。在Android.mk文件中添加:LOCAL_CPPFLAGS += -fexceptions就可以了。或者在Application.mk文件中添加APP_CPPFLAGS += -fexceptions
也是可以的。
补充:
Android NDK r5对C++的支持情况
android平台提供了一个最小化的C++运行库(/system/lib/libstdc++)以及与之对应的头文件。
1、C++的异常支持:
从NDK r5就开始NDK的工具链就开始支持了C++的异常控制,只不过为了通用性的原因,所有的C++原文件被编译的时候都是默认的是-fno-exceptions,即不不支持异常控制的。
使用-fexceptions标记可以开启异常控制。所以你只需要在你的每个模块的Android.mk中添加LOCAL_CPPFLAGS += -fexceptions就可以了。
更简单的是,在你的Application.mk文件中添加APP_CPPFLAGS += -fexceptions,这种配置会自动应用到你工程的所有模块当中。
注意:
已被废弃的"arm-eabi-4.4.0"工具链提供的向后兼容的NDK是不支持异常的。
2、RTTI support:
从NDK r5开始,NDK工具链也开始支持C++ RTTI(Runtime Type Information)了。但是,为了通用性的,所有的C++源文件被构建的时候默认是不支持RRRI的(-fno-rtti)。需要开启的话,你需要在Android.mk中添加:LOCAL_CPPFLAGS += -frtti,或者更简单的做法是在Application.mk添加APP_CPPFLAGS += -frtti。
注意:
已被废弃的"arm-eabi-4.4.0"工具链提供的向后兼容的NDK是不支持RTTI的。
III. Selecting the C++ Standard Library Implementation:
By default, the headers and libraries for the minimal C++ runtime system
library (/system/lib/libstdc++.so) are used when building C++ sources.
You can however select a different implementation by setting the variable
APP_STL to something else in your Application.mk, for example:
APP_STL := stlport_static
To select the static STLport implementation provided with this NDK.
Value APP_STL values are the following:
system -> Use the default minimal C++ runtime library.
stlport_static -> Use STLport built as a static library.
stlport_shared -> Use STLport built as a shared library.
WARNING: IMPORTANT CAVEAT
AT THE MOMENT, OUR STLPORT IMPLEMENTATION DOES NOT SUPPORT EXCEPTIONS
AND RTTI. PLEASE BE SURE TO NOT USE -fexceptions OR -frtti IN ALL
MODULES THAT USE IT.
WARNING: END OF IMPORTANT CAVEAT
"stlport_shared" is preferred if you have several shared libraries in your
project that use the C++ STL, because it avoids duplication of functions
and more importantly of global variables (e.g. std::cout) in each one of
them, which can have surprising results.
On the other hand, you will have to load it explicitely when starting your
application, as in the following example:
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("foo");
System.loadLibrary("bar");
}
Where both "libfoo.so" and "libbar.so" depend on "libstlport_shared.so".
Note that the shared library's name if "libstlport_shared.so" to avoid
naming conflicts with certain Android system images which include a
system-level libstlport.so (which happens to not be ABI-stable and
cannot be used from NDK-generated machine code).
"stlport_static" is preferred if you have only one shared library in your
project: only the STL functions and variables you actually need will be
linked to your machine code, reducing its code size, and you won't need
to load the dynamic stlport_shared at startup.
IV. STLport-specific issues:
----------------------------
This NDK provides prebuilt static and shared libraries for STLport,
but you can force it to be rebuilt from sources by defining the following
in your environment or your Application.mk before building:
STLPORT_FORCE_REBUILD := true
STLport is licensed under a BSD-style open-source license. See
sources/cxx-stl/stlport/README for more details about the library.
V. Future Plans:
----------------
- Make STLport compatible with C++ exceptions and RTTI
- Full GNU libstdc++ support
开发遇到的问题:
LOCAL_SHARED_LIBRARIES和LOCAL_SHARED_LIBRARY:注意前者是复数S形式,用于Link多个库(只有一个也可以用),后者只能添加一个链接库,可恶的文档关于Prebuilts的介绍里面给出的例子是LOCAL_SHARED_LIBRARY,使用两个库的时候第二个库死也link不上。
某些依赖关系很有问题,makefile只能clean掉jni文件夹下的obj文件;更换不同版本的C++ RunTime实现必须要clean,否则会出现link错误;注意一共有四种libstdc++实现,什么都不写默认是系统自带没有STL的版本,另外三种在SDK自带文档CPLUSPLUS-SUPPORT当中列出。从系统默认libstdc++切换到带STL的版本同样需要clean
使用STL的时候,APP_STL := xxx 这句话需要写在Application.mk当中,而不是Android.mk
argument list too long问题:文件很多的时候会出现这种编译或链接报错的情况,不过这个问题源自孩儿他爸Linux的遗传,某些系统命令对于输入参数长度有限制,把工程文件夹映射到一个盘符路径会好一些。对于Android有人给出了修改SDK的makefile的补丁,似乎是去掉了某个echo命令。
2012.02.26 补充,NDK r7未发现此问题,可能已修正
使用$(call import-module, hello-gl2/jni) 命令import库的时候,如果发生下面的报错:
Android NDK: Are you sure your NDK_MODULE_PATH variable is properly
需要注意NDK_MODULE_PATH是一个环境变量而不是makefile中的变量。不把库的搜索路径作为一个工程属性而是一个系统属性,这种方式或许更适用于系统库,而不是自己写的第三方库。
关于Android不支持wchar_t的说法:wchar_t作为一种变量类型是内置支持的,和大多数*nix实现一样,为4字节,但是wchar.h中的一系列函数在Android NDK还没有提供,也就是说你需要自己想办法计算wchar_t*的字符串长度、比较字符内容等等。推荐使用CrystaX制作的加强版NDK解决此问题,传送门如下:
http://www.crystax.net/en/android/ndk
经试验由官方NDK r7迁移到此版本(r7-4)没遇到什么问题,作者的修改最大的两个亮点,
1. 增加了GCC4.6.3的选择,可以获得c++0x的部分支持,以及更好的内存性能(这一点没有测试过)
2. 完善了wchar_t一族函数的支持,当然,需要启动之后setlocale一下才能够正确的swprintf汉字的字符串。这一点多说两句,虽然很多人骂微软,但是的确windows才是对开发人员最友好的平台,大家的locale默认都是"C",但是win32上面啥都不用改就能swprintf汉字文本,*niux、iOS都做不到。
NDK代码编译完毕后,需要在Eclipse中选中工程按F5 refresh一下,在Eclipse之外的任何代码资源改动都需要此步骤。有些时候还会出现莫名其妙的编译错误需要clean,嗯,是不是想起了XCode?
资源组织方式,可以使用AssetManager,需要注意不要让SDK的打包apk工具把asset目录的文件压缩,否则在AssetManager Open文件的时候可能会抛异常(具体情况取决于android系统版本,在某些机器上正常读取,某些机器会抛异常。根据某些人的说法,读取带有压缩的asset文件,AssetManager会把文件解压到内存中,如果系统内存不足就会抛异常;对于非压缩文件,直接读取数据即可没有这一道开销)。通常在asset目录容量超过1M的文件会被压缩,但是有几种扩展名的文件可以确保不会被压缩,打包工具认为这些类型的文件已经过压缩,无需再压,常见的.zip.mp3都没有问题(2012.03.11 更正:".zip"不行,如果是真正的zip文件不会被压缩,如果其他格式文件改后缀伪装成zip仍然会被压缩,使用mp3后缀名看来是最好的选择)
例子:如果你在asset文件夹下面放了一个2M的a.wav文件,改成a.mp3或者a.zip即可(当然你读取的时候还是按照wav读)。具体有没有被压缩,用zip文件管理工具(譬如7zip)打开apk文件,看原始大小和压缩后大小即可。
HelperScene.obj : error LNK2019: 无法解析的外部符号 "public: static classcocos2d::CCLuaEngine * __cdecl cocos2d::CCLuaEngine::engine(void)" (?engine@CCLuaEngine@cocos2d@@SAPAV12@XZ),该符号在函数 "public: virtual bool __thiscall HelperScene::init(void)" (?init@HelperScene@@UAE_NXZ) 中被引用
这个错误,我是通过把luaEngine文件考到自己的工程下解决的
Error 1:
$ ndk-build
/cygdrive/c/andy/abc/obj/local/armeabi-v7a/objs/abc//hellow.o.d:1: *** [color=#FF0000]multiple target patterns[/color]. Stop.
quick fix: Delete Obj folder from “C:\andy\prjM\obj\local\armeabi-v7a” then run ndk-build
or refer this
Error 2:
Android.mk:44: *** [color=#FF0000]commands commence before first target[/color]. Stop.
fix: Check there are no comments,no space ,no empty line in the src includes of Android.mk
For example:
wrong:
[code]LOCAL_SRC_FILES :=file1.cpp\
file1al.cpp\
#file1atures.cpp\
file1r.cpp\
file1le.cpp\
Satfile1.cpp\
Sfile1l.cpp\
file1e.cpp\
Sfile1face.cpp\[/code]
3rd line has #, 4th line has space(check with cursor),5th line is empty line
Right:
[code]LOCAL_SRC_FILES :=file1.cpp\
file1al.cpp\
file1atures.cp\
file1r.cpp\
file1le.cpp\
Satfile1.cpp\
Sfile1l.cpp\
file1e.cpp\
Sfile1face.cpp\[/code]
Error 3:
$ ndk-build clean
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/cygdrive/c/android-ndk-r4b/build/core/build-local.mk:85: *** [color=#FF0000]Android NDK: Aborting[/color] . Stop.
Fix: include Android.mk location inside global application.mk and Android.mk
Run the command from the parent directory with app.mk and and.mk resides
Error 4:
Please define ANDROID_NDK_ROOT to point to the root of your Android NDK installation.
Use case while executing shell script xxx-desktop:~/bin/u/android-ndk-r5/build/tools$ ./rebuild-all-prebuilt.sh
Please define ANDROID_NDK_ROOT to point to the root of your Android NDK installation.
// Run the script inside NDK root directory like shown below
xxx-desktop:~/bin/u/android-ndk-r5/build/tools$ cd ..
xxx-desktop:~/bin/u/android-ndk-r5/build$ cd ..
xxxx-desktop:~/bin/u/android-ndk-r5$ ./build/tools/rebuild-all-prebuilt.sh
Error 5:
NDK r5 app(native-activity,native-audio,native-plasma) build problem Compiling native-activity,native-audio,native-plasma on ndk-r5 give compile errors stating header not found and so on ……
Quick fix: Rebuild all prebuilt
i;e execute shell script rebuild-all-prebuilt.sh to build on latest toolchain provided by android which will take for a while (atleast on my pc)
xxx-desktop:~/bin/u/android-ndk-r5$ ./build/tools/rebuild-all-prebuilt.sh
To follow build in another terminal, please use: tail -F /tmp/ndk-toolchain/build-CtAG7s/log.txt
Download sources from android.git.kernel.org
Using git clone prefix: git://android.git.kernel.org/toolchain
downloading sources for toolchain/binutils
downloading sources for toolchain/build
downloading sources for toolchain/gcc
downloading sources for toolchain/gdb
downloading sources for toolchain/gmp
downloading sources for toolchain/gold
downloading sources for toolchain/mpfr
Patching toolchain sources
Toolchain sources downloaded and copied to /tmp/ndk-toolchain/build-CtAG7s/src
Cleaning up...
Done.
Building arm-eabi-4.4.0 toolchain... (this can be long)
ERROR: Could bot build arm-eabi-4.4.0 toolchain!
xxxx-desktop:~/bin/u/android-ndk-r5$
Now change to native-activity folder and call ndk-build for successful libnative-activity.so
xxx-desktop:~/bin/u/android-ndk-r5/samples/native-activity$ ndk-build
Compile thumb : native-activity <= main.c
Compile thumb : android_native_app_glue <= android_native_app_glue.c
StaticLibrary : libandroid_native_app_glue.a
SharedLibrary : libnative-activity.so
Install : libnative-activity.so => libs/armeabi/libnative-activity.so
undefined reference to error解决方法
1 没有指定对应的库(.o/.a/.so)
使用了库中定义的实体,但没有指定库(-lXXX)或者没有指定库路径(-LYYY),会导致该错误,
2 连接库参数的顺序不对
在默认情况下,对于-l 使用库的要求是越是基础的库越要写在后面,无论是静态还动态
3 gcc/ld 版本不匹配
gcc/ld的版本的兼容性问题,由于gcc2 到gcc3大版本的兼容性存在问题(其实gcc3.2到3.4也一定程度上存在这样的问题) 当在高版本机器上使用低版本的机器就会导致这样的错误, 这个问题比较常见在32位的环境上, 另外就在32位环境不小心使用了64位的库或者反过来64位环境使用了32位的库.
4 C/C++相互依赖和链接
gcc和g++编译结果的混用需要保证能够extern "C" 两边都可以使用的接口,在我们的64位环境中gcc链接g++的库还需要加上-lstdc++,具体见前文对于混合编译的说明
5 运行期报错
这个问题基本上是由于程序使用了dlopen方式载入.so, 但.so没有把所有需要的库都链接上,具体参加上文中对于静态库和动态库混合使用的说明
工作积累之NDK编译STL
方法:
1.在jni目录下新建Application.mk; 加入APP_STL := stlport_static 右边的值还可以换成下面几个:
system - 使用默认最小的C++运行库,这样生成的应用体积小,内存占用小,但部分功能将无法支持
stlport_static - 使用STLport作为静态库,这项是Android开发网极力推荐的
stlport_shared - STLport 作为动态库,这个可能产生兼容性和部分低版本的Android固件,目前不推荐使用。
gnustl_static - 使用 GNU libstdc++ 作为静态库
默认情况下STLPORT是不支持C++异常处理和RTTI,所以不要出现-fexceptions 或-frtti ,如果真的需要可以使用gnustl_static来支持标准C++的特性,但生成的文件体积会偏大,运行效率会低一些。
支持C++异常处理,在Application.mk中加入LOCAL_CPPFLAGS += -fexceptions这句,同理支持RTTI,则加入LOCAL_CPPFLAGS += -frtti,这里再次提醒大家,第二条说的使用gnustl静态库,而不是stlport。
强制重新编译STLPort ,在Application.mk中加入STLPORT_FORCE_REBUILD := true 可以强制重新编译STLPort源码,由于一些原因可能自己需要修改下STLPort库,一般普通的开发者无需使用此项
2. 在要使用STL的cpp文件中包含相关的头文件,并且使用using namespace std;