Code::Blocks + Android NDK

How to cross properly Code::Blocks + Android NDK so that the debag also works (pass to ADB?). Perhaps there is a manual, or a ready-made profile of settings.
In the search on this topic, there is very little.. except to mention that it's possible.

P.S. please do not offer to install Android Studio.

Author: NewView, 2019-04-22

1 answers

Let's start small, how to fasten Android NDK to C::B

There are two ways:

    1. register your own profile for each platform, with executable files according to the platform. In my opinion, it is tedious, a lot of things and it is not clear why. Taking into account that if you collect the same thing for all platforms, then the volume of body movements with switching configurations is quite large. I have a default collection of arm64-v8a, armeabi-v7a, x86, x86_64.
    1. use native build system ndk-build. This is the simplest and most elegant solution, which does not conflict with most checks C::B, but, in the settings C::B, every detail is important, the scheme is quite capricious, and with inaccuracies it can easily break.

Android NDK integration


The ideology and manner of building an application using the tulchain Android NDK is as close as possible to the typical behavior C::B, the logic of the processes:

  • Build in Release mode-stages: always new build the app, copy it to the device, and launch the app. All actions are displayed in the console C::B.

  • Build in Debug mode-steps: always build the app again, copy it to the device, copy NDK-парт files for debugging gdbserver, gdb.setup, running gdbserver on the device, waiting for the debugger to connect GDB.

  • Mode запуска приложения - steps: launch the application on the device with the output of the results in the console.

  • Mode Отладка -> Старт - stages: always build the app again, copy it to the device, copy NDK-партfiles for debugging gdbserv, gdb.setup, start gdbserv on the device, automatically connect the debugger GDB, and switch to debug mode.

  • In the modes Debug, Отладка -> Старт, the window of the startup gdbserver starts in the minimized state and closes automatically at the end of debugging.

Template files:

The project itself C::B, important sections:

  • <Build><Option output> - indicates the remote app launch script on the device - RunRemote.cmd. The script is generated automatically.
  • <Build><Option compiler="android_ndk-build"> is the processed compiler name in the settings C::B - Android NDK-Build. How to create a new compiler account is shown below.

The <Extensions><debugger><remote_debugging> section contains settings for remote debugging implemented with GDB:

  • options ip_address="127.0.0.1" ip_port="59999" extended_remote="0", if there is a need to change the number port, then this must also be done in Makefile. If the option extended_remote will be non-zero, the window of the remotely launched gdbserver will not close automatically after debugging.

AndroidNdkTemplate. cbp - project file 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>

Source files of the build management in the project directory NDK:


Application.mk - setting build parameters:

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

Android.mk - in fact, it is a make-file unique for each NDK project (application):

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 - directly runs 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

The Application.mk and Makefile files are universal for all projects built with NDK and do not require edits.

To understand the structure of where what lies in the project NDK of the application, I will give a tree:

│   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

Project settings view from GUI C::B:


enter a description of the image here

enter a description of the image here

enter a description of the image here

enter a description of the image here

Be sure to specify the possible paths where the object files with debugging symbols are located:

  • obj/local/armeabi-v7a

  • obj/local//arm64-v8a

  • obj/local/x86

  • obj/local/x86_64

enter a description of the image here

You need to add the GDB commands that transmit information about finding debug symbols for the platform of the connected device:

  • set solib-search-path obj/local/armeabi-v7a - location of debug symbols for the active device.
  • file obj/local/armeabi-v7a/<имя приложения> - name of the application being debugged.

View of the compiler settings in C::B:


enter a description of the image here

enter a description of the image here

enter a description of the image here

Additional debug menu NDK of the application:


Both used in the menu the scripts have a fixed name and are generated automatically during execution Makefile, for convenience, it is reasonable to add them to the menu:

enter a description of the image here

enter a description of the image here

The application debugging method consists of typical actions, for example, via F8 or the Отладка -> Старт menu. As soon as the debugger is started, you need to call the ADB Debug Remote server item from the created menu, with this command you will launch GDB сервер on the device that will launch your application. You are connecting to GDB серверу remotely and can conduct a debugging session.
In the Debug mode, the remote server is started automatically and does not require calling this menu item.
See the screenshot of the debugger settings in the project above.

This debug startup scheme also supports non-rooted devices.

The global debugger settings for NDK look like this:


enter a description of the image here

Debugging on on the device:


enter a description of the image here

The result of building the application by the tolchein NDK:


enter a description of the image here

Advantages of using NDK:

In contrast to a static build for a specific platform:

  • No need to compile binaries statically, so the output binary file size will be smaller.

  • You can use android C/C++ libraries, such as liblog, to be able to have output in logcat from the application.

Features of this solution:

  • No rooted device required

  • Full-fledged debugging of the assembly, without additional tools (NDK toolset)

  • Full build in Debug/Release modes

  • Full launch of the app (from the device)

  • Auto start / stop gdbserver with devices

  • No wrappers from the Gradle/Java code required, works directly with the

    {[83 device]}

Full code of HOWTO NDK C::B template posted on github

 3
Author: NewView, 2019-04-25 04:22:36