Configuring VES for Eclipse and ndk-build
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Recently, I needed a visualization framework for my project. Since one of the requirements of the project is to render scientific datasets and since this is not the main requirement (there are more important features to be implemented), I needed a quick solution. After some search and with the suggestions of my advisor in Aviz I decided to use VES, which is VTK OpenGL ES Rendering Toolkit. VES integrates with the Visualization Toolkit (VTK) to deliver scientific and medical visualization capabilities to mobile application developers. However, VES is not the only layer on top of VTK there is one more layer called Kiwi. The architecture is basically as follows:
As you can see the architecture has two different branches on top of Kiwi. These are to be used for iOS or Android. I will talk about the Android part here. Before talking about the Eclipse and ndk-build configuration I highly recommend you too watch this webinar about VES.
The biggest problem I had through the building process was to create an Eclipse project. The project itself uses CMake and is configured to create makefiles which can be used via Nmake. After creating these makefiles and building VES some other scripts needed to be run to create an Android project. You can import this Android project directly to Eclipse but you cannot build the native part from it. You should run a separate compile script to build the native part and create the .so library file. Then you can run the project from Eclipse again.
Consequently, I started trying to create a one-button build configuration. At first I played with the CMake configurations (for about two weeks) but I couldn't manage to create a decent eclipse project which can be built (maybe it's because I was not very experienced in Cmake but I don't know). Then I turned to ndk-build which is android's native development kit's build script. For ndk-build to be run you need an Android.mk and Application.mk(optional) file. These files are a little different from a normal makefile. After a 2 days of struggle I had the project building with the help of my colleague. At the end, the project we had was not building the whole ves source code but it was linking the libraries created by ves build to the KiwiNative.cpp.
Returning to the project itself, the first step to start building apps with VES of course compiling and building it. The best way to start this process is either the video I linked above or the developer guide in their website (developer guide for Linux and Mac can be found here). I will briefly go over the project structure and some scripts here and then explain my approach to make the project more portable with eclipse and ndk-build.
For building a visual studio command prompt is necessary to use the nmake command. VS Express 2012 is enough for this or any other VS distribution which includes the nmake tool.
The project structure
Following the instructions in the website or in the video you will see that some scripts should be run. I will give a brief explanation of these script and the folder structure of the project.
+—Apps
| +—Android
| | +—CMakeBuild
| | | configure.bat
| | | \—build
| | | +—CMakeExternals
| | | | +—Build
| | | | | +—eigen
| | | | | +—ves-android
| | | | | +—vtk-host
| | | | +—Download
| | | | | +—eigen
| | | | | +—ves-android
| | | | | +—vtk-android
| | | | | +—vtk-host
| | | | +—Install
| | | | | +—eigen
| | | | | +—ves-android
| | | | | +—vtk-android
| | | | | +—vtk-host
| | +—Kiwi
| | | configure.bat
| | | tools.bat
| | | compile.bat
| | | run.bat
After cloning the repository from git://vtk.org/VES.git you will get the above structure more or less. I omit some stuff to focus on the folders that I want. As far as I remember the CMakeExternals folder is created when you run the configure.bat script inside Android\CMakeBuild. So following the developer guide, you run the configure.bat. Let’s see briefly what this does:
@echo off
rem Set the NDK path here
set ANDROID_NDK=c:/tools/android-ndk-r8
rem set ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.4.3
set CMAKE_DEFAULT_GENERATOR="NMake Makefiles"
set BUILD_TYPE=Release
rem set CMAKE_HOST_WIN32=1
set CL=/MP
set build_dir=%CD%\build
set source_dir=%CD%\..\..\..
echo Android NDK directory: %ANDROID_NDK%
echo Build type: %BUILD_TYPE%
cmake.exe -E make_directory "%build_dir%"
cd"%build_dir%"
cmake.exe -G %CMAKE_DEFAULT_GENERATOR% -DCMAKE_BUILD_TYPE:STRING=%BUILD_TYPE% -DVES_ANDROID_SUPERBUILD:BOOL=TRUE "%source_dir%"
cd ..
echo Configuration done.
echo To build VES, go to the build directory and type nmake.
echo Don't forget to add tools and platforms directory of Android SDK to PATH env var.
Lets first look at the CMAKE_DEFAULT_GENERATOR and BUILD_TYPE part. This part is where you set the build type and the cmake generator. I have played with the cmake generator for 2 weeks to be able to create a portable eclipse project. I have tried "Eclipse CDT4 – NMake Makefiles" in Windows and "Eclipse CDT4 – Unix Makefiles" in Ubuntu. However, in the end I gave up and build the ves according to the developer guide and link the static libraries to ndk-build to be able to make the project portable. More on this later… You can also change the build type to be able to build the created libraries later on with a tool like gdb.
Through the end of the file calls to the cmake.exe are the real commands doing the job of creating the makefiles and stuff. This is basically running cmake to create appropriate folders and make files for the project to be used later while compiling the code. The superbuild variable is explained in more detail in the developer guide of VES. As you can see the build folder is actually inside the project structure. I guess this has a special purpose since the webinar I shared in this article says something like that. In the webinar, you can see that the guy is actually creating a link to an outside folder but using the original build folder inside the project structure. I guess this has to do with some relative path issues. So this was another problem which stops me creating an eclipse project. Since eclipse gets confused by in source builds, it was impossible to directly import the created project from here and the out-of-source build was not working as I expected. Search google for "out of source build" for more detail on this subject.
After running configure.bat you go to the build folder which is just created and run nmake command. This is going to build the VES project and create .a files which are normally static library files but in the webinar the guy says these are actually archive files. Anyway I will call them static library files (so this is like .lib in windows and dynamic libraries (.so) are like .dll in windows). These libraries are inside folders named lib which are located inside CMakeExternals\Install separated in their corresponding folders. For example, CMakeExternals\Install\vtk-android\lib. After this process you normally go to Apps\Android\Kiwi folder and run the scripts there to create the Android project and link these libraries to your project together with KiwiNative.cpp.
My setup takes a follows a different path at this point. Since we want to work together on this project with my colleague and we do not want to put all the source files to SVN. In addition to this, we want to be free of the relative path stuff of the project.
Examining the makefile inside Kiwi application folder we found out that the real makefile it uses is called build.make which is located inside \Kiwi\jni\CMakeFiles\KiwiNative.dir and examining this file it can be seen that it creates a seperate .o from KiwiNative.cpp (which is our main jni file) and link all the other libraries which are created before to it to create the file library which is libKiwiNative.so. So trying follow the conventions inside this file we try to create a stand-alone android application project with ndk-build. On the road, we encountered really random looking errors related to OpenGL, function definitions and even the order of the libraries linked. Finally we came up with an Android.mk and Application.mk files. I will add the original files at the end of this article. However, there are two things that I want to emphasize.
The first one is make sure whether your project uses STL or not (This is a general suggestions but in our case, VES, yes it uses STL). If it uses make sure you include that in your Application.mk:
APP_STL := gnustl_shared
The second thing is you should pay attention to the order of the linked libraries. Solving this problem took some time.. since the order looked arbitrary to us but then we used the order from the original build.make file and everything was resolved.
Beside this two points other stuff was straight forward we carried all the include folders from Android\CMakeBuild\build\CMakeExternals\Install into jni folder of our project. We created LOCAL_MODULEs for all the .a library files. For example:
—-
include $(CLEAR_VARS)
LOCAL_MODULE := libvesShaders
LOCAL_SRC_FILES = ves-android/lib/libvesShaders.a
include $(PREBUILT_STATIC_LIBRARY)
—–
Then we included these local modules to our last LOCAL_MODULE which is a BUILD_SHARED_LIBRARY file. This module is as follows:
—–
include $(CLEAR_VARS)
LOCAL_STATIC_LIBRARIES := libkiwi libvesShaders libves libvtkIOXML libvtkIOLegacy libvtkIOPLY libvtkIOGeometry libvtkFiltersModeling libvtkImagingCore libvtkRenderingFreeType libvtkRenderingCore libvtkIOImage libvtkDICOMParser libvtkmetaio libvtkpng libvtktiff libvtkjpeg libvtkFiltersSources libvtkFiltersGeometry libvtkIOXMLParser libvtkIOCore libvtkexpat libvtkFiltersExtraction libvtkFiltersGeneral libvtkFiltersCore libvtkCommonExecutionModel libvtkCommonComputationalGeometry libvtkCommonDataModel libvtkCommonMisc libvtkCommonTransforms libvtkCommonSystem libvtkCommonMath libvtkCommonCore libvtksys libvtkfreetype libvtkzlib
LOCAL_C_INCLUDES := $(LOCAL_PATH)/vtk-android/include/ $(LOCAL_PATH)/ves-android/include/ $(LOCAL_PATH)/ves-android/include/ves/kiwi $(LOCAL_PATH)/ves-android/include/ves/ves $(LOCAL_PATH)/ves-android/include/ves/shaders
LOCAL_MODULE := KiwiNative
LOCAL_SRC_FILES := KiwiNative.cpp
LOCAL_LDLIBS := -llog -lGLESv2
OPENGLES_DEF := -DUSE_OPENGL_ES_2_0
LOCAL_CFLAGS := -Wno-write-strings -Wno-psabi $(OPENGLES_DEF)
include $(BUILD_SHARED_LIBRARY)
—–See the bold lines. Those lines are related to OpenGL (obviously) and derived from the build.make file that we found.
With all these configurations your project is ready to be built by ndk-build of Android. Have fun. I might have missed some stuff or make mistakes please inform me in such conditions. Because I wrote this article after some time passed.
Whole Android.mk and Application.mk files: http://goo.gl/uyUPAF
I also thank my colleague David Lopez for his precious contribution.
Very cool! Many thanks to Candemir and Katie O. for this blog post.
Thanks a lot! Did you actually copy over the static .a libs and the header files from the VES build to your new Android project or did you create symlinks? I am on Windows, I don’t know of any way to create symlinks that a compiler would be able to follow…
Hi Sven,
I copied all the files its better that way in Windows.
Thanks, that’s what I found too. When I actually tried #include’ing the vesKiwiViewerApp.h in my own cpp file, build showed an error. I fixed it by adding $(LOCAL_PATH)/eigen to the LOCAL_C_INCLUDES. Will cross-post to the mailing list.
Nice, by the way I suggest you to disable the c++ code analysis on Eclipse. Sometimes it goes crazy =)
I had to add LOCAL_CPP_FEATURES += rtti to my module to in Android.mk and fix a few bugs in Eigen/src/core/Visitor.h for a successful build and launch.
We had the same issue at the time but I guess we fixed it in someother way. I guess our version of VES a little old now so thanks for the fix =)
Hi,
nice tutorial, the link to application.mk and android.mk is not working anymore. Could you post the file again?
Thanks!
Sorry my fault: http://goo.gl/uyUPAF
We have improved the CMake process for VES so you can build VES much easier now with just CMake. Here is a link to the blog: http://www.kitware.com/blog/home/post/642
Thanks I will check it out =)