Problem to make a package of "mqtt_example.c" for OpenWrt + Paho

Hello all,

Remember I am a noobie.

I have a c program that is a simple "mqtt_example.c". It works fine in my pc and I am trying to make it into a package to install in OpenWrt.

I have already followed completely the helloworld tutorial: https://openwrt.org/docs/guide-developer/helloworld/chapter1 and know how to create a package and install it in openwrt - I was able to create a helloworld package and install it in an OpenWrt running in virtualbox.

My "mqtt_example.c" program uses the paho libraries (see it bellow).

I managed to create a package for paho using this: https://github.com/ngohaibac/openwrt-extra-packages/blob/master/paho.mqtt.c/Makefile

MY PROBLEM is that when I try to make a package with my "mqtt_example.c" program that uses the paho libs it cannot find these libs and issues an error!

How can I add this lib to my mqqt_example.c makefile?

Thank you for your help.

B

+++ This is the error:

~/Documents/myStuff/energiasolar.pt/dev/openwrt$ **make -j1 V=s package/mqtt_exemplo/compile**
WARNING: Makefile 'package/utils/busybox/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/busybox/Makefile' has a build dependency on 'libpam', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libgnutls', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libopenldap', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libidn2', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libssh2', which does not exist
WARNING: Makefile 'package/boot/kexec-tools/Makefile' has a dependency on 'liblzma', which does not exist
WARNING: Makefile 'package/network/services/lldpd/Makefile' has a dependency on 'libnetsnmp', which does not exist
WARNING: Makefile 'package/feeds/espt_packages/mqtt_exemplo/Makefile' has a dependency on 'libpaho-mqtt3c', which does not exist
make[1]: Entering directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt'
make[2]: Entering directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/package/libs/toolchain'
echo "libc" >> /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/pkginfo/toolchain.default.install
echo "libgcc" >> /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/pkginfo/toolchain.default.install
echo "libpthread" >> /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/pkginfo/toolchain.default.install
echo "librt" >> /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/pkginfo/toolchain.default.install
make[2]: Leaving directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/package/libs/toolchain'
time: package/libs/toolchain/compile#0.11#0.04#0.17
make[2]: Entering directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/espt_packages/examples/mqtt_exemplo'
rm -f /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0/.built
touch /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0/.built_check
make -C /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0 CC="x86_64-openwrt-linux-musl-gcc" CFLAGS="-Os -pipe -fno-caller-saves -fno-plt -fhonour-copts -Wno-error=unused-but-set-variable -Wno-error=unused-result  -Wformat -Werror=format-security -fstack-protector -D_FORTIFY_SOURCE=1 -Wl,-z,now -Wl,-z,relro" LDFLAGS="-L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/usr/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/toolchain-x86_64_gcc-7.3.0_musl/usr/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/toolchain-x86_64_gcc-7.3.0_musl/lib -znow -zrelro"
make[3]: Entering directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0'
x86_64-openwrt-linux-musl-gcc -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/usr/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/target-x86_64_musl/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/toolchain-x86_64_gcc-7.3.0_musl/usr/lib -L/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/staging_dir/toolchain-x86_64_gcc-7.3.0_musl/lib -znow -zrelro  mqtt_exemplo.o   -o mqtt_exemplo
mqtt_exemplo.o: In function `publish':
**mqtt_exemplo.c:(.text+0x53): undefined reference to `MQTTClient_publishMessage'**
**mqtt_exemplo.c:(.text+0x65): undefined reference to `MQTTClient_waitForCompletion'**
**mqtt_exemplo.o: In function `on_message':**
**mqtt_exemplo.c:(.text+0xac): undefined reference to `MQTTClient_freeMessage'**
**mqtt_exemplo.c:(.text+0xb5): undefined reference to `MQTTClient_free'**
**mqtt_exemplo.o: In function `main':**
**mqtt_exemplo.c:(.text.startup+0x2f): undefined reference to `MQTTClient_create'**
**mqtt_exemplo.c:(.text.startup+0x48): undefined reference to `MQTTClient_setCallbacks'**
**mqtt_exemplo.c:(.text.startup+0x58): undefined reference to `MQTTClient_connect'**
**mqtt_exemplo.c:(.text.startup+0x88): undefined reference to `MQTTClient_subscribe'**
**collect2: error: ld returned 1 exit status**
**make[3]: *** [<builtin>: mqtt_exemplo] Error 1**
make[3]: Leaving directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0'
make[2]: *** [Makefile:54: /home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/build_dir/target-x86_64_musl/mqtt_exemplo-1.0/.built] Error 2
make[2]: Leaving directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/espt_packages/examples/mqtt_exemplo'
time: package/feeds/espt_packages/mqtt_exemplo/compile#0.09#0.02#0.11
make[1]: *** [package/Makefile:109: package/feeds/espt_packages/mqtt_exemplo/compile] Error 2
make[1]: Leaving directory '/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt'
make: *** [/home/joao/Documents/myStuff/energiasolar.pt/dev/openwrt/include/toplevel.mk:218: package/mqtt_exemplo/compile] Error 2

+++ This is my makefile:

include $(TOPDIR)/rules.mk

#. Name, version and release number
#. The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)
PKG_NAME:=mqtt_exemplo
PKG_VERSION:=1.0
PKG_RELEASE:=1

#. Source settings (i.e. where to find the source codes)
#. This is a custom variable, used below
SOURCE_DIR:=/home/joao/Documents/myStuff/energiasolar.pt/dev/mqtt_exemplo

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/mqtt_exemplo
  SECTION:=examples
  CATEGORY:=Examples
  DEPENDS:=libpaho-mqtt3c
  TITLE:=exemplo de MQTT client
endef

#. Package description; a more verbose description on what our package does
define Package/mqtt_exemplo/description
  A simple "mqtt client" -application.
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 $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
	$(Build/Patch)
endef

#. Package build instructions; invoke the GNU make tool to build our package
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/mqtt_exemplo/install
	$(INSTALL_DIR) $(1)/usr/bin
	$(INSTALL_BIN) $(PKG_BUILD_DIR)/mqtt_exemplo $(1)/usr/bin
endef

#. This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,mqtt_exemplo))

-- This is my program "mqtt_example.c"

/*
*. Includes
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <MQTTClient.h>
 
/*
*. Defines
*/
/* Caso desejar utilizar outro broker MQTT, substitua o endereco abaixo */
#define MQTT_ADDRESS   "broker.mqttdashboard.com"
/* Substitua este por um ID unico em sua aplicacao */
#define CLIENTID       "MQTTCClientID"  
 
/* Substitua aqui os topicos de publish e subscribe por topicos exclusivos de sua aplicacao */
#define MQTT_PUBLISH_TOPIC     "MQTTCClientPubTopic"
#define MQTT_SUBSCRIBE_TOPIC   "MQTTCClientSubTopic"
 
/*
*.  Variaveis globais
*/
MQTTClient client;
 
/*
*. Prototipos de funcao
*/
void publish(MQTTClient client, char* topic, char* payload);
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message);
 
/*
*. Implementacoes
*/
 
/* Funcao: publicacao de mensagens MQTT
 *. Parametros: cleinte MQTT, topico MQTT and payload
 *. Retorno: nenhum
*/
void publish(MQTTClient client, char* topic, char* payload) {
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
 
    pubmsg.payload = payload;
    pubmsg.payloadlen = strlen(pubmsg.payload);
    pubmsg.qos = 2;
    pubmsg.retained = 0;
    MQTTClient_deliveryToken token;
    MQTTClient_publishMessage(client, topic, &pubmsg, &token);
    MQTTClient_waitForCompletion(client, token, 1000L);
}
 
/* Funcao: callback de mensagens MQTT recebidas e echo para o broker
 *. Parametros: contexto, ponteiro para nome do topico da mensagem recebida, tamanho do nome do topico e mensagem recebida
 *. Retorno : 1: sucesso (fixo / nao ha checagem de erro neste exemplo)
*/
int on_message(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    char* payload = message->payload;
 
    /* Mostra a mensagem recebida */
    printf("Mensagem recebida! \n\rTopico: %s Mensagem: %s\n", topicName, payload);
 
    /* Faz echo da mensagem recebida */
    publish(client, MQTT_PUBLISH_TOPIC, payload);
 
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}
 
int main(int argc, char *argv[])
{
   int rc;
   MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
 
   /* Inicializacao do MQTT (conexao & subscribe) */
   MQTTClient_create(&client, MQTT_ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
   MQTTClient_setCallbacks(client, NULL, NULL, on_message, NULL);
 
   rc = MQTTClient_connect(client, &conn_opts);
 
   if (rc != MQTTCLIENT_SUCCESS)
   {
       printf("\n\rFalha na conexao ao broker MQTT. Erro: %d\n", rc);
       exit(-1);
   }
 
   MQTTClient_subscribe(client, MQTT_SUBSCRIBE_TOPIC, 0);
 
   while(1)
   {
       /*
        *. o exemplo opera por "interrupcao" no callback de recepcao de 
        *. mensagens MQTT. Portanto, neste laco principal eh preciso fazer
        *. nada.
        */
   }
}

-- This is the makefile for the program "mqtt_example.c" that works in my pc

#. Global target; when 'make' is run without arguments, this is what it should do
all: mqtt_exemplo
 
#. These variables hold the name of the compilation tool, the compilation flags and the link flags
#. We make use of these variables in the package manifest
CC = gcc
CFLAGS = -lpaho-mqtt3c -Wall
LDFLAGS = 
LDLIBS = 
 
#. This variable identifies all header files in the directory; we use it to create a dependency chain between the object files and the source files
#. This approach will re-build your application whenever any header file changes. In a more complex application, such behavior is often undesirable
DEPS = $(wildcard *.h)
 
#. This variable holds all source files to consider for the build; we use a wildcard to pick all files
SRC = $(wildcard *.c)
 
#. This variable holds all object file names, constructed from the source file names using pattern substitution
OBJ = $(patsubst %.c, %.o, $(SRC))
 
#. This rule builds individual object files, and depends on the corresponding C source files and the header files
%.o: %.c $(DEPS)
	$(CC) -c -o $@ $< $(CFLAGS)
 
#. To build 'helloworld', we depend on the object files, and link them all into a single executable using the compilation tool
#. We use automatic variables to specify the final executable name 'helloworld', using '$@' and the '$^' will hold the names of all the
#. dependencies of this rule
helloworld: $(OBJ)
	$(CC) -o $@ $^ $(LDFLAGS)
 
#. To clean build artifacts, we specify a 'clean' rule, and use PHONY to indicate that this rule never matches with a potential file in the directory
.PHONY: clean
 
clean:
	rm -f mqtt_exemplo *.o

First make sure that your build environment is "initialized" properly. The dependency warnings early on suggest that you might not have run

./scripts/feeds update -a
./scripts/feeds install -a

The dependency problems related to missing symbols related to MQTT* may be either to a missing dependency for the paho library, or using the C++ versions, rather than the C versions, or vice versa (I don't recall which is which as its been a while since I worked with the libraries.)

Hi Jeff,

Thank you for your help.

Here is the output when I run the commands you suggested:

me@mypc:~/Documents/myStuff/energiasolar.pt/dev/openwrt$ ./scripts/feeds update -a
Updating feed 'espt_packages' from '/home/joao/Documents/myStuff/energiasolar.pt/dev/espt_packages' ...
Create index file './feeds/espt_packages.index' 
Collecting package info: done
me@mypc:~/Documents/myStuff/energiasolar.pt/dev/openwrt$ ./scripts/feeds install -a
WARNING: Makefile 'package/utils/busybox/Makefile' has a dependency on 'libpam', which does not exist
WARNING: Makefile 'package/utils/busybox/Makefile' has a build dependency on 'libpam', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libgnutls', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libopenldap', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libidn2', which does not exist
WARNING: Makefile 'package/network/utils/curl/Makefile' has a dependency on 'libssh2', which does not exist
WARNING: Makefile 'package/boot/kexec-tools/Makefile' has a dependency on 'liblzma', which does not exist
WARNING: Makefile 'package/network/services/lldpd/Makefile' has a dependency on 'libnetsnmp', which does not exist
WARNING: Makefile 'package/feeds/espt_packages/mqtt_exemplo/Makefile' has a dependency on 'libpaho-mqtt3c', which does not exist
Installing all packages from feed espt_packages.
me@mypc:~/Documents/myStuff/energiasolar.pt/dev/openwrt$ 

My end-game is use mqtt in a C application that I make into a package for OpenWrt. If there is an easier way to do this with Mosquitto instead of Paho, I can consider it. But I can't find a tutorial for this anywhere!

Can you guide me and provide a simple program/guidelines to do that?

Hi @azul I believe we have a similar problem and jeff link your post to mine, we can keep the discussion going here.

I Noticed that when you compile on your host machine you have a CFLAG to pahomqtt3c

CFLAGS = -lpaho-mqtt3c -Wall

that means that GCC is linking a library to compile your code. check this reference.

Your make file for openwrt doesn't have this flag so the compiler doesn't know where to look for pahomqtt libraries.

As jeff stated before you build environment is not "initialized" properly. Make sure you have the libraries installed and select on your .config file.

about the last warning

WARNING: Makefile 'package/feeds/espt_packages/mqtt_exemplo/Makefile' has a dependency on 'libpaho-mqtt3c', which does not exist

Make sure you compile the pahomqttc before trying to compile your package the toolchain is indicating that you didn't compile libpahomqtt yet, so it can't satisfy the dependencies on your Makefile

1 Like

@ joaohcca: Many thanks for the clear reply.