Embedded linux development and remote debugging using Eclipse IDE. Part 2. Makefile application

In previous chapter we used Eclipse for Embedded linux development and remote debugging of simple application for embedded linux. Now we are getting one step closer to OpenWrt – we will use Eclipse for development and remote debugging of application represented as OpenWrt package (Makefile based application, in fact). But this article might be useful for any other Embedded linux build system.

Hello World package

In previous chapter we created simple Hello World application containing just one single C source file:

$ mkdir package/helloworld/src
$ touch package/helloworld/helloworld.c
$ cd package/helloworld/src

with following content:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char **argv) {
fprintf(stdout, “Hello world! \r\n”);
return 0;
}

Now we will transform it to OpenWrt package:

$ touch Makefile

open it with any text editor and enter:

all: helloworld

CFLAGS = -O0 -g3 -Wall -c -fmessage-length=0

LDFLAGS =

DEPS = $(wildcard *.h)

SRC = $(wildcard *.c)

OBJ = $(patsubst %.c, %.o, $(SRC))

%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)

helloworld: $(OBJ)
$(CC) -o $@ $^ $(LDFLAGS)

.PHONY: clean

clean:
rm -f helloworld *.o

There is pretty simple Makefile to build simple application.

Then we need to create package’s Makefile:

$ cd ..
$ touch Makefile

Again open it with editor and enter:

include $(TOPDIR)/rules.mk

PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1

PKG_BUILD_DIR:=$(BUILD_DIR)/helloworld-$(PKG_VERSION)

include $(INCLUDE_DIR)/package.mk

# Package definition; instructs on how and where our package will appear in the overall configuration menu (‘make menuconfig’)
define Package/helloworld
SECTION:=examples
CATEGORY:=Examples
TITLE:=helloworld example
endef

# Package description; a more verbose description on what our package does
define Package/helloworld/description
GPIO input/output driving example
endef

# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
endef

# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR) CC=”$(TARGET_CC)” CFLAGS=”$(TARGET_CFLAGS)” LDFLAGS=”$(TARGET_LDFLAGS)”
endef

# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
$(INSTALL_DIR) $(1)/etc
endef

$(eval $(call BuildPackage,helloworld))

Looks completely different from typical Makefile’s content. There is package manifest file describing steps to be passed before, during and after compilation.

So as a result you should get following structure in package/helloworld folder:

Makefile
/src
Makefile

Time to compile it. Go back to the root and start package building process:

$ cd ../../
$ make V=s package/helloworld/compile

The output generated by V=s helps you to understand build process flow.
As a result you may find following:

$ ls -l build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/helloworld-1.0/
helloworld
helloworld.c
helloworld.o
ipkg-arm_cortex-a7_neon-vfpv4
Makefile

there is content of src folder we created before (helloworld.c and Makefile) and few resulted output files including application executable. You can open helloworld.c and/or Makefile and make sure that there are files we created before. Switch back to package manifest file and find following definition:

define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp ./src/* $(PKG_BUILD_DIR)/
$(Build/Patch)
endef

that responsible for such source code copying. There is one of peculiarity of OpenWrt – building of sources happens in separate folder.
Because of that it looks quite difficult use initial sources (./package/helloworld) folder for experiments with Eclipse. Especially in a case of more compicated packages having bunch of patches to be applied on original sources. So we will try to use resulted folder (./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/helloworld-1.0/) as an existing Makefile project to be imported to Eclipse.

Import Makefile project to eclipse

Open Eclipse and File –> New –> Project:

Then select C/C++ –> Makefile Project with Existing Code:

and navigate to your resulted package folder generated on OpenWrt package build. But in general you may point to any Makefile based application for embedded linux:

Here how imported project looks:

As you see it includes Host headers so we need replace them with headers from our toolchain and make few additional changes similar for changes we made in previous chapter for application built without Makefile.
Right mouse click on project –> Properties –> C/C++ Build –> Environment and add two additional environment varialbes:

STAGING_DIR = /home/al/imx6ull/imx6ull-openwrt/staging_dir/
CC = arm-openwrt-linux-muslgnueabi-gcc

and modify existing PATH variable by inserting following to the start of variable value:

/home/al/imx6ull/imx6ull-openwrt/staging_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/host/bin:/home/al/imx6ull/imx6ull-openwrt/staging_dir/hostpkg/bin:/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/bin:/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/bin:/home/al/imx6ull/imx6ull-openwrt/staging_dir/host/bin:/home/al/imx6ull/imx6ull-openwrt/staging_dir/host/bin:

Here four folders from our toolchain splitted with and endings with colon symbol:

/home/al/imx6ull/imx6ull-openwrt/staging_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/host/bin
/home/al/imx6ull/imx6ull-openwrt/staging_dir/hostpkg/bin
/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/bin
/home/al/imx6ull/imx6ull-openwrt/staging_dir/host/bin

click to Apply button and switch to C/C++ General –>Preprocessor Include Path, Macros etc. –> Providers¬†and uncheck CDT Cross GCC Built-in Compiler Settings:

click to Apply button and navigate to C/C++ General –> Paths and Symbols –> Includes –> GNU C. Here add paths to headers from our toolchain:

/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/arm-openwrt-linux-muslgnueabi/include/
/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/include/
/home/al/imx6ull/imx6ull-openwrt/staging_dir/toolchain-arm_cortex-a7+neon-vfpv4_gcc-7.5.0_musl_eabi/lib/gcc/arm-openwrt-linux-muslgnueabi/7.5.0/include/

Click to Apply and Close button.

Time to build project:
Then create Run (Run –> Run Configurations) and Debug (Run –> Debug Configurations) configurations as we did it in previous post for Makefile-less project. No any difference:

Try to run:

And debug:

So we got opportunity of debugging real OpenWrt applications.