Интеграция работы с нативным кодом на С/С++ для android в Eclipce (на примере, под Ubuntu). — часть 3

Настройка Eclipse для отладки нативного кода проекта.

Начало…

1) Устанавливаем breakepoint после загрузки библиотеки и перед вызовом нативной функции, запускаем проект на отладку и ждем его остановки на breakepoint. Если хотите можно переключится и Debag перспективу, это сейчас не важно.
2) Запускаем терминал переходим в директорию Вашего проекта и вводим команду ndk-gdb. Данная команда запустила скрипт который сгенерировал сервер gbd отладчика в папке obj/local/armearbi. Теперь можно выйти из него в терминале.
3) Собственно теперь нам необходимо перейти в директорию obj/local/armearb проекта(хотя вроде уже там) и создать копию файла gdb.setup назвав ее gdb2.setup.
4) Теперь необходимо отредактировать файл наш gdb2.setup. А именно в нем просто удалить последнюю строчку: «target remote :5039». Эти параметры мы укажем позже при настройке Eclipce, там требуется.
5) Переходим в директорию с ndk и создаем в ней опять копию файла ndk-gdb назвав к примеру его ndk-gdb-eclipse.
6) Редактируем файл ndk-gdb-eclipse, нам необходимо удалить или закомментировать последнюю 581 строку скрипта чтобы конец файла приобрел к примеру следующий вид:

echo "file `native_path $APP_PROCESS`" >> $GDBSETUP 
echo "target remote :$DEBUG_PORT" >> $GDBSETUP 
if [ -n "$OPTION_EXEC" ] ; then 
    cat $OPTION_EXEC >> $GDBSETUP 
fi 
##$GDBCLIENT -x `native_path $GDBSETUP`

7) Настройка проекта Eclipse для отладки. Создаем новую Debug configuration, назвав ее как нибудь осмысленно (например «NativeExample native debug»). Совет: переименуйте отладочную конфигурацию для андроида тоже в что нибудь осмысленное.
На закладке main в поле С/С++ Aplication указываем путь к сгенерированому gdb приложению в папке проекта obj/local/armearbi — «app_process».
Необходимо также выбрать Standard Create Process Launcher нажав на синюю ссылку внизу окна Select other… .

В закладке Debugger в поле Debugger указываем gdbserver. В поле Stop on startup название нативной функции при входе в которую отладчик остановится, в нашем случае это Java_com_example_NativeLib_function.
В поле GDB debugger указываем путь к gdb для андроида ${ndk_dir}/ toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gdb. В поле GDB command line нам необходимо указать путь к созданному нами файлу gdb2.setup.

В закладке Connection выставляем TCP localhost 5039.
И на всякий случай проверяем что бы в закладке Common у Вас стояла галочка в Debug конфигурации.

Отладка проекта в Eclipse.

1) Ставим точку в Java коде проекта перед вызовом нативной функции после загрузки библиотеки, запускаем АНДРОИД конфигурацию для отладки и ждем остановки на breakpoint’е, переходим в Debug перспективу Eclipse.
2) Из терминала в директории проекта выполняем команду ndk-gdb-eclipse, которая запускает gdb сервер для нашего проекта
3) Переходим в Eclipse запускаем нативную конфигурацию для отладки: Стрелочка возле жука вниз и выбираем нужную нам конфигурациюв нашем случае «NativeExample native debug»
4) И жмем кнопку Resume (зеленую стрелочку) в Debug перспективе.

Все 😉 Вас переключило в отладку нативного кода в самое начало функции как мы и хотели.
Теперь можно устанавливать в С/С++ breakpoint’ы и отлаживать нативный код.

Честно говоря когда была написана половина данной статьи нашел блог из которого почерпнул для себя много интересного. Часть этого вошло в статью 🙂 .

Интеграция работы с нативным кодом на С/С++ для android в Eclipce (на примере, под Ubuntu). — часть 2

Компиляция проекта.

Часть 1.

1)Заходим в свойства проекта и выбираем пункт С/С++ Build. Убираем галочку Use default build comand и вписываем команду для сборки С/С++ части — «ndk-build»

Переходим на закладку Behavior и выставляем следующие галочки:

Убираем галочку clean — ndk чистит проект автоматически и не поддерживает данную комманду, ndk-build также не поддерживает команду all, поэтому ее стираем.
Нажимаете кнопку Apply и вам выдает ошибку в коде С++, потому что Eclipce не видит необходимых библиотек.

2) Добавляем пути. В этом же окне в категории C/C++ General->Paths and Symbols в закладке Includes в категории С и С++ указываем пути к библиотекам необходимой таргет версии ${ndk_dir}/platforms/android-${target_version}/arch-arm/usr/include. Где ${ndk_dir} директория ndk, а ${target_version} — цифра таргет версии.
А в закладке С++ добавляем путь к заголовочным stdlib файлам {ndk_dir}/sources/cxx-stl/gnu-libstdc++/include

3)Нажимаем Apply и соглашаемся собрать проект, в консоли видим следующее:

**** Build of configuration Default for project NativeExample ****

ndk-build
Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libnative_lab.so => libs/armeabi/libnative_lab.so

Что сигнализирует нам что нативная библиотека скомпилировалась и собралась удачно. В проекте при этом появилась папка obj в которую поместили нашу скомпилированную библиотеку libnative_lab.so

4)Помещаем вызов нашей библиотеки например в метод onCreate вашей активити:

String string="blablabla";
NativeLib lib = new NativeLib();
String result = lib.function(string.getBytes());
Log.i("NativeExample", result);

И нажимаем кнопку Run. И опять продолжение следует… 😉

Интеграция работы с нативным кодом на С/С++ для android в Eclipce (на примере, под Ubuntu). — часть 1

Создание проекта.

1)Необходимо добавить путь к директории с ndk в переменные среды, без этого все дальнейшее бесполезно.
2)Для создания андроид проекта с нативным кодом на С и С++ необходимо учесть несколько важных следующих замечаний (в качестве рекомендаций, можно и без них, но будет сложнее):

Расположение папки workspace для Eclipce должно быть таким, чтобы ndk имел права записи в эту папку и мог изменять свойства файлов расположенных в этой папке. То есть например чтобы папка с ndk и папка  workspace находились в домашней директории пользователя, а не на смонтированном носителе.
Крайне желательно чтобы пути к SDK, NDK и проекту содержали только латинские символы без пробелов.
Версия ndk желательна выше 5. В этом случае вы без особого труда сможете использовать stdlib

В случае если Вы собираетесь отлаживать нативный код:

Target SDK версия для проекта должна быть не меньше 9

 android:minSdkVersion="9"

В AndroidManifest.xml должен быть установлен флаг

 android:debuggable="true"

3)Необходимо установить CDT(C and C++ Development Tools) для Eclipce. Help->Install New Software выбираем репозиторий Вашей версии Eclipce(например Helios — http://download.eclipse.org/releases/helios) в ней Programming Languages и в ней C and C++ Development Tools.

4) Следующим шагом нам необходимо сконвертировать Ваш уже созданый андроид проект в совместный проект Java и C++. Нажимаем на проекте правой кнопкой New->Other (или Ctrl+n) и в открывшемся окне выбираем Convert to C/C++ Project жмем Next

на втором шаге выбираем Makefile project->—Other Toolchain—

Жмем Finish и в консоли Eclipce видим ошибку: «**** Build of configuration Default for project NativeExample **** make all make: *** Нет правила для сборки цели `all’. Останов.»
Все правильно — среда не видит ни правил сборки нативного кода ни самого кода.

5)Работа с JNI: Создадим класс- обертку для вызова наших нативных функций.

package com.example;
public class NativeLib {
	static{
		System.loadLibrary("native_lab");
	}
	public native String function(byte[] string);
}

Создаем папке проекта папку jni. В ней будет находится весь код на С и С++ и правила сборки. Переходим в деррикторию bin нашего проекта и выполняем из терминала следующую команду javah -jni com.example.NativeLib, которая генерирует заголовочный файл вызова Ваших нативных функций для С в соответствии с правилами JNI.

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_NativeLib */

#ifndef _Included_com_example_NativeLib
#define _Included_com_example_NativeLib
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_example_NativeLib
 * Method:    function
 * Signature: ([B)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_example_NativeLib_function
  (JNIEnv *, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif

Переносим сгенерированный h файл в директорию jni. Осталось добавить только реализацию на С нашей функции в новом файле (например native.cpp):

#include <cstdlib>
#include "android_log.h"
#include "com_example_NativeLib.h"

jstring JNICALL Java_com_example_NativeLib_function
  (JNIEnv * env, jobject obj, jbyteArray string){

	// get "string" from JVM
	const size_t STRING_LENGTH = env->GetArrayLength(string);
	char * buffer = new char[STRING_LENGTH];
	env->GetByteArrayRegion(string, 0, STRING_LENGTH, (jbyte*) buffer);
	env->ReleaseByteArrayElements(string, (jbyte*) buffer, 0);

	LOGI(buffer);

	jstring result = env->NewStringUTF("done");
	return result;
}

6)Создаем правила сборки С/С++ библиотеки, для этого необходимо создать два мейкфайла Application.mk Android.mk в папке jni. Первый отвечает за общую сборку, второй за сборку модулей.

Application.mk:

# как будет оптимизироватся библиотека
#APP_OPTIM := debug

# подключение stllib 
#only if you platform upper then 2.2
#APP_STL :=gnustl_static 
# platform 1.6
APP_STL :=stlport_static

# библиотека которую собираем
APP_MODULES := native_lab

Android.mk:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
# библиотека которую собираем
LOCAL_MODULE    := native_lab
# исходные файлы через пробел
LOCAL_SRC_FILES := native.cpp
# библиотека для работы с логом андроида 
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)

7)Пишем в лог андроида. Для удобства создадим заголовочный файл android_log.h следующего вида:

#include <android/log.h>

#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "NativeExample native",__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG  , "NativeExample native",__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO   , "NativeExample native",__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN   , "NativeExample native",__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "NativeExample native",__VA_ARGS__)

Пример использования виден выше в native.cpp.

Продолжение следует… 😉

О чем….

Собственно данный блог будет посвящен моему увлечению программированием (А теперь уже и моей профессии).

А именно проектам на Android’e.