Code::Blocks + Android NDK

280
09 февраля 2020, 16:10

Как правильно скрестить Code::Blocks + Android NDK чтоб в том числе и дебаг работал (pass to ADB?). Возможно есть мануал, или готовый профайл настроек.
В поиске на эту тему крайне не много.. кроме упоминаний что это возможно.

P.S. поставить Android Studio пожалуйста не предлагать.

Answer 1

Начнем с малого, как прикрутить Android NDK к C::B

Есть два пути:

    1. прописать на каждую платформу свой профиль, с исполняемыми файлами согласно платформе. На мой взгляд утомительно, много всего и непонятно зачем. С учетом что если собирать одно и тоже под все платформы, то объем телодвижений с переключением конфигураций довольно велик. У меня по умолчанию собираются arm64-v8a, armeabi-v7a, x86, x86_64.
    1. использовать родную систему сборки ndk-build. Это самое простое и изящное решение, не вступающее в конфликты с большинством проверок C::B, но, в настройках C::B важна каждая деталь, схема довольно капризная, и при неточностях может легко ломаться.

Интеграция Android NDK

Идеология и манера сборки приложения с использованием тулчейна Android NDK максимально приближена к типовому поведению C::B, логика процессов:

  • сборка в режиме Release- этапы: всегда новая сборка приложения, копирование его на устройство, запуск приложения. Все действия отображаются в консоле C::B.

  • сборка в режиме Debug- этапы: всегда новая сборка приложения, копирование его на устройство, копирование NDK-парт файлов для отладки gdbserver, gdb.setup, запуск gdbserver на устройстве, ожидание подключения дебагера GDB для отладки.

  • режим запуска приложения- этапы: запуск на устройстве приложения с выводом результатов в консоль.

  • режим Отладка -> Старт - этапы: всегда новая сборка приложения, копирование его на устройство, копирование NDK-партфайлов для отладки gdbserv, gdb.setup, запуск gdbserv на устройстве, автоматическое подключение дебагера GDBи переход в режим отладки.

  • в режимах Debug, Отладка -> Старт, окно запускаемого gdbserver стартует в минимизированном состоянии и автоматически закрывается по окончани отладки.

Файлы шаблона:

Сам проект C::B, важные секции:

  • <Build><Option output> - указывает на скрипт дистанционного запуска приложения на устройстве - RunRemote.cmd. Скрипт генерируется автоматически.
  • <Build><Option compiler="android_ndk-build"> - это обработанное название компилятора в настройках C::B - Android NDK-Build. Как завести учетную запись нового компилятора, показано ниже.

В секции <Extensions><debugger><remote_debugging> находятся настройки дистанционной отладки, реализованной с помощью GDB:

  • options ip_address="127.0.0.1" ip_port="59999" extended_remote="0", если есть необходимость изменить номер порта, то это так-же необходимо сделать в Makefile. Если опция extended_remote будет отличной от нуля, окно дистанционно запущенного gdbserver не закроется автоматически после отладки.

AndroidNdkTemplate.cbp - файл проекта C::B:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
    <FileVersion major="1" minor="6" />
    <Project>
        <Option title="C::B Android Ndk project Template" />
        <Option makefile_is_custom="1" />
        <Option pch_mode="2" />
        <Option compiler="android_ndk-build" />
        <Option check_files="0" />
        <Build>
            <Target title="Release">
                <Option output="RunRemote.cmd" prefix_auto="0" extension_auto="0" />
                <Option type="1" />
                <Option compiler="android_ndk-build" />
            </Target>
            <Target title="Debug">
                <Option output="RunRemote.cmd" prefix_auto="0" extension_auto="0" />
                <Option type="1" />
                <Option compiler="android_ndk-build" />
            </Target>
        </Build>
        <Compiler>
            <Add option="-Wall" />
        </Compiler>
        <Unit filename="main.c">
            <Option compilerVar="CC" />
        </Unit>
        <Extensions>
            <code_completion />
            <envvars />
            <debugger>
                <search_path add="obj/local/armeabi-v7a" />
                <search_path add="obj/local/arm64-v8a" />
                <search_path add="obj/local/x86" />
                <search_path add="obj/local/x86_64" />
                <remote_debugging target="Debug">
                    <options conn_type="0" serial_baud="115200" ip_address="127.0.0.1" ip_port="59999" additional_cmds_before="set solib-search-path obj/local/armeabi-v7a&#x0A;file obj/local/armeabi-v7a/hello_world&#x0A;" />
                </remote_debugging>
            </debugger>
        </Extensions>
    </Project>
</CodeBlocks_project_file>

Исходные файлы управления сборкой в директории NDK проекта:

Application.mk - установки параметров сборки:

APP_ABI := all
APP_STL := c++_static
APP_OPTIM := debug
APP_PLATFORM := android-22
APP_BUILD_SCRIPT := Android.mk

Android.mk - собственно и является мейк-файлом уникальным для каждого NDK проекта (приложения):

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := hello_world
LOCAL_SRC_FILES := ./main.c
LOCAL_C_INCLUDES := ./
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

Makefile - непосредственно запускается C::B:

PLATFORM := armeabi-v7a
NDKROOT  := C:\__BuildSource\__LIB__\android-ndk-r20-beta2
PROJECT  := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
BUILDTAG := $(filter-out $@,$(MAKECMDGOALS))
BUILDOPT := 
include Application.mk
include $(APP_BUILD_SCRIPT)
ifneq ($(APP_ABI),all)
    PLATFORM = $(APP_ABI)
endif
ifeq ($(BUILDTAG),Debug)
    BUILDOPT = V=1 NDK_DEBUG=1
else
    BUILDOPT = -j 4
endif
all: allndk
Debug: allndk adbsetup adbdebug buildscript rundebug
Release: allndk adbsetup adbexec buildscript
cleanDebug: clean
cleanRelease: clean
cleanall: clean
allndk:
    @echo '==== Build $(BUILDTAG) -> $(APP_ABI) platform -> active device: [ $(PLATFORM) ] ===='
    @Cmd.exe /C $(NDKROOT)\ndk-build.cmd NDK_APPLICATION_MK=$(PROJECT)Application.mk NDK_PROJECT_PATH=$(PROJECT) $(BUILDOPT)
clean:
    @echo '==== Clean ===='
    @Cmd.exe /C $(NDKROOT)\ndk-build.cmd NDK_APPLICATION_MK=$(PROJECT)Application.mk NDK_PROJECT_PATH=$(PROJECT) clean
    @Cmd.exe /C adb.exe shell rm -f /data/local/tmp/$(LOCAL_MODULE)
adbsetup:
    @echo '==== ADB SETUP: [ $(PLATFORM) ] ===='
    @Cmd.exe /C adb.exe push $(PROJECT)libs\$(PLATFORM)\$(LOCAL_MODULE) /data/local/tmp/$(LOCAL_MODULE)
    @Cmd.exe /C adb.exe shell /system/bin/chmod 0777 /data/local/tmp/$(LOCAL_MODULE)
adbexec:
    @echo '==== ADB RUN: [ $(PLATFORM) ] ===='
    @Cmd.exe /C adb.exe shell /data/local/tmp/$(LOCAL_MODULE)
adbdebug:
    @echo '==== GDB Debug: [ $(PLATFORM) ] ===='
    @Cmd.exe /C adb.exe push $(PROJECT)libs\$(PLATFORM)\gdb.setup /data/local/tmp/gdb.setup
    @Cmd.exe /C adb.exe push $(PROJECT)libs\$(PLATFORM)\gdbserver /data/local/tmp/gdbserver
    @Cmd.exe /C adb.exe shell /system/bin/chmod 0777 /data/local/tmp/gdbserver
rundebug:
    @Cmd.exe /C DebugRemote.cmd
buildscript:
ifeq (,$(wildcard ./RunRemote.cmd))
    @echo "adb.exe shell /data/local/tmp/$(LOCAL_MODULE)" >RunRemote.cmd
endif
ifeq (,$(wildcard ./DebugRemote.cmd))
    @echo "adb.exe forward tcp:59999 tcp:59999" >DebugRemote.cmd
    @echo "start \"$(PLATFORM) GDB server\" /MIN adb.exe shell /data/local/tmp/gdbserver :59999 /data/local/tmp/$(LOCAL_MODULE)" >>DebugRemote.cmd
    @echo "exit" >>DebugRemote.cmd
endif
.PHONY: clean all

Файлы Application.mk и Makefile являются универсальными для всех проектов собираемых с помощью NDK и не требуют правок.

Для понимания структуры где чего лежит в проекте NDK приложения, приведу дерево:

│   Android.mk
│   AndroidNdkTemplate.cbp
│   Application.mk
│   main.c
│   Makefile
│   
├───libs
│   ├───arm64-v8a
│   │       gdb.setup
│   │       gdbserver
│   │       hello_world
│   ├───armeabi-v7a
│   │       gdb.setup
│   │       gdbserver
│   │       hello_world
│   ├───x86
│   │       gdb.setup
│   │       gdbserver
│   │       hello_world
│   └───x86_64
│           gdb.setup
│           gdbserver
│           hello_world
│           
└───obj
    └───local
        ├───arm64-v8a
        │   │   hello_world
        │   ├───objs
        │   │   └───hello_world
        │   └───objs-debug
        │       └───hello_world
        │               main.o
        │               main.o.d
        ├───armeabi-v7a
        │   │   hello_world
        │   │   
        │   ├───objs
        │   │   └───hello_world
        │   └───objs-debug
        │       └───hello_world
        │               main.o
        │               main.o.d
        ├───x86
        │   │   hello_world
        │   │   
        │   ├───objs
        │   │   └───hello_world
        │   └───objs-debug
        │       └───hello_world
        │               main.o
        │               main.o.d
        └───x86_64
            │   hello_world
            │   
            ├───objs
            │   └───hello_world
            └───objs-debug
                └───hello_world
                        main.o
                        main.o.d

Вид настроек проекта из GUI C::B:

Обязательно указать возможные пути где расположены объектные файлы с отладочными символами:

  • obj/local/armeabi-v7a

  • obj/local//arm64-v8a

  • obj/local/x86

  • obj/local/x86_64

Необходимо добавить команды GDB передающие информацию о нахождении отладочных символов для платформы подключенного устройства:

  • set solib-search-path obj/local/armeabi-v7a - расположение отладочных символов для активного устройста.
  • file obj/local/armeabi-v7a/<имя приложения> - имя отлаживаемого приложения.

Вид настроек компилятора в C::B:

Дополнительное меню отладки NDK приложения:

Оба используемых в меню скрипта имеют фиксированное имя и генерируются автоматически, во время исполнения Makefile, для удобства разумно добавить их в меню:

Метод отладки приложения состоит из типовых действий, например через F8 или меню Отладка -> Старт. Как только запустился дебагер, вам надо вызвать из созданного меню пункт ADB Debug Remote server, этой командой вы запустите GDB сервер на устройстве, который запустит ваше приложение. Вы подключаетесь к GDB серверу дистанционно и можете проводить сеанс отладки.
В режиме Debug запуск дистанционного сервера происходит автоматически и не требует вызова данного пункта меню.
Смотрите скриншот настроек дебагера в проекте выше.

Данная схема запуска отладки поддерживает и не рутированные устройства.

Глобальные настройки дебагера для NDK выглядят так:

Отладка на устройстве:

Результат сборки приложения толчейном NDK:

Преимущества использования NDK:

В отличии от статической сборки под определенную платформу:

  • Не нужно компилировать двоичные файлы статически, поэтому размер выходного двоичного файла будет меньше.

  • Можно использовать android C/C++ библиотеки, такие как liblog, чтобы иметь возможность иметь вывод в logcat из аппликации.

Возможности данного решения:

  • не требуется рутированного устройства

  • полноценная отладка сборки, без дополнительных инструментов (набор инструментов NDK)

  • полноценная сборка в Debug/Release режимах

  • полноценный запуск приложения (с устройства)

  • авто запуск/остановка gdbserver с устройства

  • не требуется оберток из Gradle/Java кода, работает напрямую с устройством

Полный код HOWTO NDK C::B template разместил на github

READ ALSO
undefined reference для Poco::Data::MySQL::Connector::registerConnector()

undefined reference для Poco::Data::MySQL::Connector::registerConnector()

Библиотеки Poco ставились при помощи conan и cmake, IDE может перейти к коду библиотеки, но у линковщика с ней проблемыОсновные причины данной проблемы...

286
Создать вектор потоков

Создать вектор потоков

В зависимости от количества доступных системе потоков, надо использовать эти потокиХочу сделать это всё вектором

272
Линковка .dll имея .h MinGW C++

Линковка .dll имея .h MinGW C++

есть в наличии динамическая библиотека (dll) и ее заголовок (

276
Socks4 работа с локальной сетью с++

Socks4 работа с локальной сетью с++

Решил разработать локальный прокси сервер, для просмотра и контроля трафикаПрочитал документацию, реализовал как там описано

255