C++ lib. deployment does not include all files

Hello I have generated the deployment c++ library but downloaded zip folder contains only

|_ edge-impulse-sdk
|_ model-parameters
|_ tflite-model
|_CMakeLists.txt

while below files/folder are missing, why is it so?
example-standalone-inferencing
|_ Makefile
|_ README.md
|_ build.sh
|_ source

-Vikas B

@vikas You need to combine the C++ Library export with https://github.com/edgeimpulse/example-standalone-inferencing . See the ‘Cloning the base repository’ section under https://docs.edgeimpulse.com/docs/running-your-impulse-locally#cloning-the-base-repository

How do I execute build.h shell script in windows environment with MinGW gcc compiler?

This works for me:

mingw32-make -f Makefile.tflite CC=gcc CXX=g++

edit: Actually, this lacks the porting layer (where to get timing info) on Windows… I’ll look at adding something here in the coming week.

edit 2: We’ll have a fix come in this week. In the meantime you can get around this by creating:

edge-impulse-sdk/porting/mingw32/debug_log.cpp

#include "../ei_classifier_porting.h"
#if EI_PORTING_MINGW32 == 1

#include "tensorflow/lite/micro/debug_log.h"
#include <stdio.h>
#include <stdarg.h>

// Redirect TFLite DebugLog to ei_printf
#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C"
#endif // defined(__cplusplus) && EI_C_LINKAGE == 1
void DebugLog(const char* s) {
    ei_printf("%s", s);
}

#endif // EI_PORTING_MINGW32 == 1

edge-impulse-sdk/porting/mingw32/ei_classifier_porting.cpp

#include "../ei_classifier_porting.h"
#if EI_PORTING_MINGW32 == 1

#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <chrono>
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

EI_IMPULSE_ERROR ei_run_impulse_check_canceled() {
    return EI_IMPULSE_OK;
}

/**
 * Cancelable sleep, can be triggered with signal from other thread
 */
EI_IMPULSE_ERROR ei_sleep(int32_t time_ms) {
    usleep(time_ms * 1000);
    return EI_IMPULSE_OK;
}

uint64_t ei_read_timer_ms() {
    auto now = std::chrono::system_clock::now();
    auto duration = now.time_since_epoch();
    auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
    return static_cast<uint64_t>(millis);
}

uint64_t ei_read_timer_us() {
    auto now = std::chrono::system_clock::now();
    auto duration = now.time_since_epoch();
    auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
    return static_cast<uint64_t>(micros);
}

void ei_printf(const char *format, ...) {
    va_list myargs;
    va_start(myargs, format);
    vprintf(format, myargs);
    va_end(myargs);
}

void ei_printf_float(float f) {
    ei_printf("%f", f);
}

void *ei_malloc(size_t size) {
    return malloc(size);
}

void *ei_calloc(size_t nitems, size_t size) {
    return calloc(nitems, size);
}

void ei_free(void *ptr) {
    free(ptr);
}

#endif // EI_PORTING_MINGW32 == 1

Then, update edge-impulse-sdk/porting/ei_classifier_porting.h to read:

#ifndef _EI_CLASSIFIER_PORTING_H_
#define _EI_CLASSIFIER_PORTING_H_

#include <stdint.h>
#include <stdlib.h>
#include "tensorflow/lite/micro/debug_log.h"

#if defined(__cplusplus) && EI_C_LINKAGE == 1
extern "C" {
#endif // defined(__cplusplus)

typedef enum {
    EI_IMPULSE_OK = 0,
    EI_IMPULSE_ERROR_SHAPES_DONT_MATCH = -1,
    EI_IMPULSE_CANCELED = -2,
    EI_IMPULSE_TFLITE_ERROR = -3,
    EI_IMPULSE_DSP_ERROR = -5,
    EI_IMPULSE_TFLITE_ARENA_ALLOC_FAILED = -6,
    EI_IMPULSE_CUBEAI_ERROR = -7,
    EI_IMPULSE_ALLOC_FAILED = -8,
    EI_IMPULSE_ONLY_SUPPORTED_FOR_IMAGES = -9,
    EI_IMPULSE_UNSUPPORTED_INFERENCING_ENGINE = -10,
    EI_IMPULSE_OUT_OF_MEMORY = -11
} EI_IMPULSE_ERROR;

/**
 * Cancelable sleep, can be triggered with signal from other thread
 */
EI_IMPULSE_ERROR ei_sleep(int32_t time_ms);

/**
 * Check if the sampler thread was canceled, use this in conjunction with
 * the same signaling mechanism as ei_sleep
 */
EI_IMPULSE_ERROR ei_run_impulse_check_canceled();

/**
 * Read the millisecond timer
 */
uint64_t ei_read_timer_ms();

/**
 * Read the microsecond timer
 */
uint64_t ei_read_timer_us();

/**
 * Print wrapper around printf()
 * This is used internally to print debug information.
 */
void ei_printf(const char *format, ...);

/**
 * Override this function if your target cannot properly print floating points
 * If not overriden, this will be sent through `ei_printf()`.
 */
void ei_printf_float(float f);

/**
 * Wrapper around malloc
 */
void *ei_malloc(size_t size);

/**
 * Wrapper around calloc
 */
void *ei_calloc(size_t nitems, size_t size);

/**
 * Wrapper around free
 */
void ei_free(void *ptr);

#if defined(__cplusplus) && EI_C_LINKAGE == 1
}
#endif // defined(__cplusplus) && EI_C_LINKAGE == 1

// Load porting layer depending on target
#ifndef EI_PORTING_ARDUINO
#ifdef ARDUINO
#define EI_PORTING_ARDUINO      1
#else
#define EI_PORTING_ARDUINO      0
#endif
#endif

#ifndef EI_PORTING_ECM3532
#ifdef ECM3532
#define EI_PORTING_ECM3532      1
#else
#define EI_PORTING_ECM3532      0
#endif
#endif

#ifndef EI_PORTING_MBED
#ifdef __MBED__
#define EI_PORTING_MBED      1
#else
#define EI_PORTING_MBED      0
#endif
#endif

#ifndef EI_PORTING_POSIX
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#define EI_PORTING_POSIX      1
#else
#define EI_PORTING_POSIX      0
#endif
#endif

#ifndef EI_PORTING_SILABS
#if defined(EFR32MG12P332F1024GL125)
#define EI_PORTING_SILABS      1
#else
#define EI_PORTING_SILABS      0
#endif
#endif

#ifndef EI_PORTING_ZEPHYR
#if defined(__ZEPHYR__)
#define EI_PORTING_ZEPHYR      1
#else
#define EI_PORTING_ZEPHYR      0
#endif
#endif

#ifndef EI_PORTING_STM32_CUBEAI
#if defined(USE_HAL_DRIVER) && !defined(__MBED__) && EI_PORTING_ZEPHYR == 0
#define EI_PORTING_STM32_CUBEAI      1
#else
#define EI_PORTING_STM32_CUBEAI      0
#endif
#endif

#ifndef EI_PORTING_HIMAX
#ifdef CPU_ARC
#define EI_PORTING_HIMAX        1
#else
#define EI_PORTING_HIMAX        0
#endif
#endif

#ifndef EI_PORTING_MINGW32
#ifdef __MINGW32__
#define EI_PORTING_MINGW32      1
#else
#define EI_PORTING_MINGW32      0
#endif
#endif
// End load porting layer depending on target

#endif // _EI_CLASSIFIER_PORTING_H_

Then, update Makefile.tflite to read:

NAME = edge-impulse-standalone

CC = gcc
CXX = g++
CFLAGS ?= -Wall

MACROS += -DTF_LITE_DISABLE_X86_NEON
CXXFLAGS += -std=c++11
CFLAGS += -I.
CFLAGS += -Isource
CFLAGS += -Iedge-impulse-sdk/
CFLAGS += -Iedge-impulse-sdk/tensorflow
CFLAGS += -Iedge-impulse-sdk/third_party
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers/include
CFLAGS += -Iedge-impulse-sdk/third_party/flatbuffers/include/flatbuffers
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/fixedpoint
CFLAGS += -Iedge-impulse-sdk/third_party/gemmlowp/internal
CFLAGS += -Iedge-impulse-sdk/third_party/ruy
CFLAGS += -Imodel-parameters
CFLAGS += -Itflite-model
CFLAGS += -Iedge-impulse-sdk/anomaly
CFLAGS += -Iedge-impulse-sdk/classifier
CFLAGS += -Iedge-impulse-sdk/dsp
CFLAGS += -Iedge-impulse-sdk/dsp/kissfft
CFLAGS += -Iedge-impulse-sdk/porting
CFLAGS += -lstdc++
CFLAGS += -lm
CFLAGS += -Os
CFLAGS += -DNDEBUG
CFLAGS += -g

ifeq ($(OS),Windows_NT)
	MKDIR_BUILD = if not exist build mkdir build
else
	MKDIR_BUILD = mkdir -p build
endif

all: build

.PHONY: build clean

build:
	$(MKDIR_BUILD)
	$(CC) -c $(MACROS) $(CFLAGS) $(LFLAGS) edge-impulse-sdk/tensorflow/lite/c/common.c -o build/common.o
	$(CXX) $(MACROS) $(CXXFLAGS) $(CFLAGS) $(LFLAGS) source/*.cpp edge-impulse-sdk/dsp/kissfft/*.cpp edge-impulse-sdk/dsp/dct/*.cpp edge-impulse-sdk/tensorflow/lite/kernels/*.cc edge-impulse-sdk/tensorflow/lite/kernels/internal/*.cc edge-impulse-sdk/tensorflow/lite/micro/kernels/*.cc edge-impulse-sdk/tensorflow/lite/micro/*.cc edge-impulse-sdk/tensorflow/lite/micro/memory_planner/*.cc edge-impulse-sdk/tensorflow/lite/core/api/*.cc ./edge-impulse-sdk/dsp/memory.cpp edge-impulse-sdk/porting/posix/*.c* edge-impulse-sdk/porting/mingw32/*.c* tflite-model/*.cpp build/common.o -o build/$(NAME)

clean:
	rm $(NAME)

Thanks for sharing detailed instruction to execute lib into window environment.
After following al above instruction I got below warning do I need to fix it or leave as it is?

source/main.cpp: In function ‘int main(int, char**)’:
source/main.cpp:53:16: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘std::vector::size_type’ {aka ‘unsigned int’} [-Wformat=]
printf(“The size of your ‘features’ array is not correct. Expected %d items, but had %lu\n”,
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, raw_features.size());
~~~~~~~~~~~~~~~~~~~
source/main.cpp:53:16: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 3 has type ‘std::vector::size_type’ {aka ‘unsigned int’} [-Wformat=]
edge-impulse-sdk/tensorflow/lite/micro/micro_string.cc: In function ‘char* {anonymous}::FastFloatToBufferLeft(float, char*)’:
edge-impulse-sdk/tensorflow/lite/micro/micro_string.cc:128:23: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
const uint32_t u = reinterpret_cast<uint32_t>(&f);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Just leave the warnings as-is.

Note this has now been released and all examples have been updated.

1 Like