Get Your Eclipse-Integrated NDK On!

Sooner or later in your Android game development foray you may find the need to have some code that runs faster. It turns out that Android code written in C runs 10-100 times as fast as its Java counterpart. I can verify this, as I've already moved a few major components in my newest 3D game engine into native land. That's quite a boost but let's face it - C is a pain in the ass and while Eclipse is great for Java, it's not for C, right? Wrong. Here's how to set up a super speedy NDK development environment.

First of all, Eclipse can do way more than just Java. Java is what it's great at and what it was designed for but the architecture makes it so that it can handle any language effectively, including C. There is a component called CDT that allows for C/C++ Development in Eclipse. I'm getting ahead of myself, though. Here's what you need:

Android NDK (Native Development Kit)
Eclipse CDT (C Development Tooling)
If you're in Windows, you'll need Cygwin with the devel packages installed (Especially GCC and Make)

Here's what you need to do:

Install all 3 of those things. I like to install my NDK to c:\Android_NDK. I'll refer to that dir for the rest of this article.
Get acquainted with the NDK. You need to configure each project as an "app" in the c:\Android_NDK\apps dir. Just take a look at the examples. They work and are thorough.

How to test your NDK:
Run cygwin
cd /cygdrive/c/Android_NDK
make APP=hello-jni

It should compile without errors. If you are missing GCC or Make or any other dev packages, you will want to run your Cygwin setup again and check to make sure that all of the development packages are installed. If you have strange errors, I suggest reporting them in the NDK user's group.

Once your NDK is working, you can add an app for your project and set up the basic native framework for your project. Please refer to the examples for this part. You will need a specific build file that tells the compiler what sources to compile. JNI code is usually located in your Android project's jni folder. A file called Android.mk will need to be in there which instructs the compiler on what to compile.

After you get the basic configuration done, you will want to start writing some C. NDK uses Java's standard JNI bindings to work. All of the existing documentation on JNI should apply from this point forward. What to code is beyond the scope of this article.

Now for the good part

If you've done any NDK work, you're probably used to using a text editor or vim or some other editor to edit your C/CPP then running make APP=myapp every time to build, then clicking refresh on your project in Eclipse and then hoping that the shared object library file that gets deployed is current. What a pain in the ass! There's a much, much better way.

Now that you have CDT installed, you can edit all of your C/C++ right from Eclipse. If you right click on a C/CPP source file, just pick Open With--C/C++ Editor and it will use the CDT editor. Much nicer! It won't be able to figure out what the code is doing because it's not compiling it, but it will make editing nice and all in one spot.

Building is a snap as well. Ever used builders in Eclipse? They are configurable triggers that will execute what you configure and refresh resources for you. Make sure you know if you're on the old r3 NDK (upgrade if you are - you should be on r4) and if so, I put different instructions in this list for the different versions. Here's how I set mine up:

Right click on your project, pick properties.
Select "builders" from the left-hand list.
Click "New..." on the right side.
Select "Program" as the configuration type.
I name mine "Native Builder"
Location - c:\cygwin\bin\bash.exe
Working Directory - c:\cygwin\bin
Arguments -
(for NDK r3):
--login -c "cd /cygdrive/c/Android_NDK && make APP=myapp"
(for NDK r4):
--login -c "cd /cygdrive/c/<myapp_project_dir> && /cygdrive/c/Android_NDK/ndk-build"
Make sure you have the two hyphens before login and the quotes after the hyphen-c
Now go to the refresh tab
Check "Refresh resources upon completion"
Select "Specific resources"
Click on the "Specify resources" button and select your project's lib directory.
Check "Recursively include sub-folders"
Now go to the build options tab
Check "Allocate Console"
Check "Launch in background"
Check "Run the builder After a Clean"
Check "Run the builder During manual builds"
Check "Run the builder During auto builds"
Check "Specify working set of relevant resources"
Click on "Specify Resources"
Select your project's JNI directory and all files within.
Now click OK on the bottom.

The assumption here is that cygwin is installed to c:\cygwin, NDK is in c:\Android_NDK and your project is called "myapp". Change where appropriate.

What did you just do?! You made it so that any time you edit any files within your JNI directory and you save them, Eclipse will run the NDK Builder for you via Cygwin and show the compile output in your console. When it finishes, it will refresh your output (lib) directory which will trigger ADT to compile a new APK for you and YOU ARE GOOD TO GO!

This seriously sped me up while working on my current project. I hope you can all benefit from it!

30 Comments

Post a comment here or discuss this and other topics in the forums

NICE!

Indeed very very helpful!!!
Worked out of the box - saves really much time and annoyance :)

Thanks.

Thanks.

Mega thanks!

Works perfectly with NDK 7 as well :)

thanks*1024

Mega thanks! It works perfectly and saves time significantly!

spot on

worked first time

thanks

Console output gone !!?

Still active?

I have same console problem ? Everything works fine, NDK/JNI/APK are all ok except I cannot see the noraml "Android" console output about AVD activities... I can see is the "**** Build of configuration Default for project XXX ****"

Thanks

Thanks

NDK-r4 makes life simple

Seems that with NDK-r4 this becomes much much easier. See http://www.experts-exchange.com/Programming/Editors_IDEs/Java/Eclipse/A_...

When you create the C/C++

When you create the C/C++ project of your Android project, go to Properties -- C/C++ Build -- Environment and Add INCLUDE variable with C:\APPS\android-ndk-r4\build\platforms\android-8\arch-arm\usr\include or whatever.

To make "Jump to error" work

Instead of making a new builder, you can separate C++ project for your native code, then
go to "Properties", "C/C++ Build" , and set

Builder type:
c:\cygwin\bin\bash.exe --login -c "/cygdrive/c/my_project/make.sh" -k

I point it to a shell script (make.sh) which does...

/{cygwin path to ndk}/ndk-build 2>&1 | awk '{gsub(/\/cygdrive\/c\/my_project\//,"");print}'

The "awk" reformats the paths of error reports so Eclipse sees just the local path and then "jump to error" works. ;-)

Sorry, this was written for

Sorry, this was written for NDK r3. They changed it for r4 so now you just have to do the following as the arguments to the NDK Builder:

--login -c "cd /cygdrive/c/<project_dir> && /cygdrive/c/Android_NDK/ndk-build"

Eclipse really does work pretty well but with any new IDE and build environment, there is a learning curve and this is no exception. Just check all the settings and make sure you know what is supposed to be happening and verify that it actually is :)

NDK r4b problem

OK, I'm pulling out my hair here trying to get a build working with NDK r4b. I have NDK r4b, Eclipse & full CDT package installed. Trying to use your instructions, in Cygwin's bash shell I navigate to the NDK directory:

$ cd /cygdrive/c/Android/android-ndk-r4b

Then try the make:

$ make app=hello-jni

It kicks out:

make: *** No targets specified and no makefile found. Stop.

I noticed that in NDK r4b, there is no longer an "apps" directory, but they're all in a "samples" directory. If I make an "apps" directory and copy the sample code into it, I get another error:

Android NDK: Missing file: apps/hello-jni/Application.mk !
build/core/main.mk:86: *** Android NDK: Aborting . Stop.

It looks like things have been restructured so that the application.mk files are no longer in the root directories of the samples but in the 'jni' directories. Before I start monkeying around with where these things are, I thought I'd see if you have some suggestions from your experience.

Any pointers here? So far, working on this platform has been a real nightmare -- Trying to get anything done at all in Eclipse has been an uphill battle, where it sometimes builds the .spk files; other times it does not, despite no errors. Restarting Eclipse *sometimes* corrects the problem; sometimes not. While working on a project in Eclipse it'll sometimes ward about an include path that does not exist when in fact it does.

I'd appreciate hearing what you suggest!

Thank you for your excellent job.

For now, Android NDK offers 'ndk-build' for us not to 'cd' to the project directory.
Arguments field can be modified as shown below. (for win32)
--login -c "ndk-build -C `cygpath -u '${build_project}' `"

maybe
--login -c "ndk-build -C '${build_project}'" (for non-win32)

I hope this will be helpful.

Console output?

I've got an approximation of this set up (in OSX) and it's working wonderfully, with one exception. I'm not getting the output from my ndk-build in the standard console. It's flashing up for half a second or so before disappearing, and I can't figure out how to either pipe it into the normal console or at least keep that output open separately. The result is that if the ndk-build fails, I'm unable to see that it has...

Anyone have any thoughts?

On Linux

Thanks for the post -- very nice.

On linux instead of feeding commands to bash, I created a shell script at ~/bin/build_ndk_app with the following 2 lines:
cd /home/zach/android/android-ndk
make APP=$1 -B

And then I just point the builder to this script, and add the project name for the argument.

Thanks again.

A Treasure!

Robert, I sincerely thank you for this wonderful tip!
I was happy with CDT and using Eclipse to edit C/C++ files and makefiles, but I never ventured into making the process entirely automatic and efficient!

Thank you so much!

Yes, right click on the file

Yes, right click on the file in Package Explorer or Navigator or Java Explorer or whatever view you use to get around your project. Click Open With. If things are installed correctly, you'll have several Android options including a Layout Editor, Menu EDitor, Manifest Editor, etc. Choose Android Manifest Editor.

If you don't have those options, you should uninstall/reinstall ADT.

thank you for your

thank you for your help!

Question: Since I've followed these instructions, now I've lost my SDK-ish XML editor in my java projects. Its just a plain text editor and I don't have the nifty AndroidManifest.xml editor to easily handle updating my files (including the "Export APK Wizard". Any ideas?

Nice example

I just fixed one issue i was facing.
changed library was not reflecting in my apk but later i realized that my project path in eclipse was different with the one i was compiling :)
its working fine now

very usefull but one issue with me

Hi Dear,

Thanks for sharing it.
i set it up as advised but when i change anything in c file, it doesn't create new shared library.
i also changed Application.mk, removed library from lib but still getting this msg

make: Nothing to be done for `all'.

ADC2 was a good experience

ADC2 was a good experience and was the kind of motivation I really needed to get my butt kicked into gear. I'm glad that you enjoyed the game. For how rushed the LR3D v1.0 entry was, I was happy just to have it in the top 20.

Our new game is a world of difference in quality. I haven't posted anything yet because I'm waiting until I have something really substantial to show.

Great to hear you are working

Great to hear you are working on a new game! I was disappointed that you didn't win a prize in the ADC2. LR3D and Project INF were my favorite arcade entries and neither game won.

Profiling is good because

Profiling is good because it'll show you where you're really losing a lot of cycles. Working with strings is really bad. There are tons of allocations that happen even on simple concatenations.

OpenGL for sprites is really fast on any device that has hardware acceleration (a GPU). It takes a little bit of though to get your head around it because you have to set up the scene ahead of time and know to use a texture atlas and start learning about UVs on quads and such but once you get it, it's not that hard. I'm doing another 2D game after I finish my current 3D one and I'll be doing all OpenGL for it.

Using an update and draw

Using an update and draw timer is a good idea. I have an FPS counter already but obviously that doesn't give a whole lot of information about why performance has gone down. I have primarily been relying on using method tracing in Debug to figure out what causes the slowdown; it's actually been incredibly helpful. The only issue is that I can't actually run trace mode on the emulator, given that it runs about 6 times slower than the Droid. I've learned quite a lot about performance though. For instance, I had no idea how absurdly long it takes to do something like "string1" + "string2", or how much less efficient a small HashMap is compared to a small array, even if you don't use all the elements.

I just thought of another thing as well that you probably know. Does using OpenGL give a significant performance increase for drawing? For example, my app is done almost completely with sprites, so I rely quite heavily on Canvas.drawBitmap() and its overloads. I've optimized the update methods to the point where any more gains would be trivial compared to the draw time. Do you think switching to the OpenGL equivalent would net a reasonable performance increase?

I have a healthy mix of Java

I have a healthy mix of Java and C for my games. I use Java for the majority of the code and C for the really math intensive stuff, like collisions and heavy geometry operations.

The only way to find out what kind of performance you'll get on a G1 is to test on a G1-class phone. The G1, MyTouch, Eris and Hero all perform about the same because they all have the same MSM7201A chip.

What I like to do now is I run an FPS counter along with an update timer. The update timer shows me how long (in ms) my last update took. That way if the FPS drops badly, I can see if it's my update (CPU-bound) or if it's the GPU slowing down. Adding additional timers to watch AI or other things is also a good idea. More mature engines graph out these things so that you can see how several of the subsystems are performing in real-time.

Excellent post

Thank you for this; I will probably be setting this up for my next project. I'm barely able to chug the sort of performance I need for my current game using Java and a SurfaceView, but it's too late to justify changing now. I've had to implement a whole lot of performance optimizations, but you can only go so far. NDK should help a lot. I assume you're using C++ with OpenGL ES?

You've mentioned performance differences between G1 and the Droid before, so quick question: With my droid running my game I can get 60 fps most of the time, dropping to 40 fps when things get a bit more messy. Obviously I'll have to do some real testing on one, but do you think it would maintain 20-30 fps on the G1 given the performance on the droid? Testing on multiple phones is very difficult with how expensive they are outside of a contract...

You need to install Cygwin

You need to install Cygwin with the full devel packages to get make and gcc.

Hello! (First sorry for my

Hello!

(First sorry for my bad english)
Thank you for this great tutorial, it worked like a charm for me! Theres only one thing that i like to be available with NDK development in Eclipse: to specify where editor look for header files, so it could provide me IntelliSense like tips. I found an another tutorial about this topic here: http://cdtdoug.blogspot.com/2009/09/using-cdt-for-android-native.html this does it by converting the project into a C/C++ one. If i go into the project properties i can specify the platform headers under the C/C++ settings by pointing to the directory in the NDK's folder, so editor get knows about the code elements there. Although i don't know how to add your automatic compiling to this project, also it can't build the project anyway, Eclipse can't find make program (i guess because we didn't specify the toolchain to use for this). Do you have any suggestions what should i do to achive what i like to do?

Thanks if you spare some time for my problem!

Elaboration

The new project is very ambitious but is coming along. What I can say about it is that it's a first/third-person (sort-of) FPS game. It's a hybrid of things. We've spent most of our time working on the technology and so far so good, though I'm finding it difficult to work with the limitations of the G1-class GPU at the moment.

I'll be posting some screenshots and hope to have a nice demo out in a month.

Thanks for reading!

Great post

A guy working directly on cdt posted something similar a couple of months ago. It's definitely a big plus whend doing ndk projects, altough build times can sometimes get on your nerves (I'm looking at you bullet physics library!).

Care to elaborate on your new project? How about doing something similar to the light racer 3d dev blog for it? I think that would make a lot of people happy, including me :)