在制作 ESP8266 项目时获取 C 函数的未定义引用

Getting undefined references for C functions while making ESP8266 project

我按照本教程将 Kaa 应用程序安装到 ESP8266 中,经过一些修改后它可以正常工作:https://kaaproject.github.io/kaa/docs/v0.10.0/Programming-guide/Using-Kaa-endpoint-SDKs/C/SDK-ESP8266/

我必须做的修改之一是在 eagle.app.v6.ld 中移动一行代码,因为字节溢出(箭头指向我所做的更改):

...

.irom0.text : ALIGN(4)
{
_irom0_text_start = ABSOLUTE(.);
*(.literal.* .text.*) --> moved from ".text : ALIGN(4){...}"

...

}

...

在我这样做之后我仍然有一些字节溢出,所以我修改了文档中的原始 cmake 命令以禁用正在占用的 cmake 扩展 space:

cmake \
-DCMAKE_TOOLCHAIN_FILE=../kaa/toolchains/esp8266.cmake \
-DKAA_PLATFORM=esp8266 \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DWITH_EXTENSION_CONFIGURATION=OFF \
-DWITH_EXTENSION_EVENT=OFF \
-DWITH_EXTENSION_LOGGING=OFF \
-DWITH_EXTENSION_NOTIFICATION=OFF \
-DWITH_EXTENSION_USER=OFF \
-DWITH_ENCRYPTION=OFF \
-DKAA_MAX_LOG_LEVEL=3 ..

最后,当我运行 make 命令。有效。然后我创建了二进制文件并将其闪存到我的 ESP 中。然后我用 GPIO0 高电平重置我的 ESP(这样它可以从闪存启动)并且 ESP 发送 "Hello, Kaa!" 到我连接的串口。

然而现在。我正在努力让我的 ESP8266 连接到我的 Kaa 服务器并生成一个端点配置文件,所以我需要代码来创建一个 t运行sport 频道来与 Bootstrap 服务器和操作服务器进行通信.

为此,我尝试使用您的第一个 Kaa 应用程序中的代码,该应用程序生成虚假的临时读数并接收配置模式并通过日志附加程序将数据推送到我的 Cassandra 服务器: https://kaaproject.github.io/kaa/docs/v0.10.0/Programming-guide/Your-first-Kaa-application/

所以在我尝试这样做时,我保留了相同的目录:

CMakeLists.txt
driver/
    uart.h
    uart.c
ld/
    eagle.app.v6.ld
    eagle.rom.addr.v6.ld
kaa/
    <put Kaa SDK here> --> replaced with new SDK with log and configuration schema
user/
    user_main.c
src/
    kaa_demo.c --> replaced with new code from "Your First Kaa Application"

然后我将此代码替换到我的 kaa_demo.c 文件中:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <kaa/kaa.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/kaa_error.h>
#include <extensions/configuration/kaa_configuration_manager.h>
#include <extensions/logging/kaa_logging.h>
#include <kaa/gen/kaa_logging_gen.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/utilities/kaa_log.h>
#include <kaa/platform-impl/common/ext_log_upload_strategies.h>

static int32_t sample_period;
static time_t  last_sample_time;
extern kaa_error_t ext_unlimited_log_storage_create(void **log_storage_context_p, kaa_logger_t *logger);
/* Retrieves current temperature. */
static int32_t get_temperature_sample(void)
{
    /* For the sake of example, random data is used */
    return rand() % 10 + 25;
}
/* Periodically called by Kaa SDK. */
static void example_callback(void *context)
{
    time_t current_time = time(NULL);
    /* Respect sample period */
    if (difftime(current_time, last_sample_time) >= sample_period) {
        int32_t temperature = get_temperature_sample();
        printf("Sampled temperature: %i\n", temperature);
        last_sample_time = current_time;
        kaa_user_log_record_t *log_record = kaa_logging_data_collection_create();
        log_record->temperature = temperature;
        kaa_logging_add_record(kaa_client_get_context(context)->log_collector, log_record, NULL);
    }
}
/* Receives new configuration data. */
static kaa_error_t on_configuration_updated(void *context, const kaa_root_configuration_t *conf)
{
    (void) context;
    printf("Received configuration data. New sample period: %i seconds\n", conf->sample_period);
    sample_period = conf->sample_period;
    return KAA_ERR_NONE;
}
int main(void)
{
    /* Init random generator used to generate temperature */
    srand(time(NULL));
    /* Prepare Kaa client. */
    kaa_client_t *kaa_client = NULL;
    kaa_error_t error = kaa_client_create(&kaa_client, NULL);
    if (error) {
        return EXIT_FAILURE;
    }
    /* Configure notification manager. */
    kaa_configuration_root_receiver_t receiver = {
        .context = NULL,
        .on_configuration_updated = on_configuration_updated
    };
    error = kaa_configuration_manager_set_root_receiver(
        kaa_client_get_context(kaa_client)->configuration_manager,
        &receiver);
    if (error) {
        return EXIT_FAILURE;
    }
    /* Obtain default configuration shipped within SDK. */
    const kaa_root_configuration_t *dflt = kaa_configuration_manager_get_configuration(
        kaa_client_get_context(kaa_client)->configuration_manager);
    printf("Default sample period: %i seconds\n", dflt->sample_period);
    sample_period = dflt->sample_period;

    /* Configure data collection. */
    void *log_storage_context         = NULL;
    void *log_upload_strategy_context = NULL;
    /* The internal memory log storage distributed with Kaa SDK. */
    error = ext_unlimited_log_storage_create(&log_storage_context,
        kaa_client_get_context(kaa_client)->logger);
    if (error) {
        return EXIT_FAILURE;
    }
    /* Create a strategy based on timeout. */
    error = ext_log_upload_strategy_create(
        kaa_client_get_context(kaa_client), &log_upload_strategy_context,
        KAA_LOG_UPLOAD_BY_TIMEOUT_STRATEGY);
    if (error) {
        return EXIT_FAILURE;
    }
    /* Strategy will upload logs every 5 seconds. */
    error = ext_log_upload_strategy_set_upload_timeout(log_upload_strategy_context, 5);
    if (error) {
        return EXIT_FAILURE;
    }
    /* Specify log bucket size constraints. */
    kaa_log_bucket_constraints_t bucket_sizes = {
         .max_bucket_size       = 32,   /* Bucket size in bytes. */
         .max_bucket_log_count  = 2,    /* Maximum log count in one bucket. */
    };
    /* Initialize the log storage and strategy (by default, they are not set). */
    error = kaa_logging_init(kaa_client_get_context(kaa_client)->log_collector,
        log_storage_context, log_upload_strategy_context, &bucket_sizes);
    if (error) {
        return EXIT_FAILURE;
    }

    /* Start Kaa SDK's main loop. example_callback is called once per second. */
    error = kaa_client_start(kaa_client, example_callback, kaa_client, 1);
    /* Should get here only after Kaa stops. */
    kaa_client_destroy(kaa_client);

    if (error) {
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

我保留了 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.0.2)

project(kaa_demo C)

# Add Kaa SDK directory
add_subdirectory(kaa)

# Add source files
add_library(kaa_demo_s STATIC user/user_main.c driver/uart.c src/kaa_demo.c)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")

if(NOT DEFINED ESP_RTOS_SDK)
    set(ESP_RTOS_SDK /opt/Espressif/esp-rtos-sdk)
endif()

# specify include directories
target_include_directories(kaa_demo_s PUBLIC driver)
target_include_directories(kaa_demo_s PUBLIC .)
target_include_directories(kaa_demo_s PUBLIC
                           ${ESP_RTOS_SDK}/extra_include
                           ${ESP_RTOS_SDK}/include
                           ${ESP_RTOS_SDK}/include/lwip
                           ${ESP_RTOS_SDK}/include/lwip/ipv4
                           ${ESP_RTOS_SDK}/include/lwip/ipv6
                           ${ESP_RTOS_SDK}/include/espressif/
                           )

exec_program(xtensa-lx106-elf-gcc .
            ARGS -print-libgcc-file-name
            OUTPUT_VARIABLE ESP8266_LIBGCC
            )

link_directories(${CMAKE_CURRENT_SOURCE_DIR}/ld)

target_link_libraries(kaa_demo_s PUBLIC
                      kaac
                      ${ESP_RTOS_SDK}/lib/libfreertos.a
                      ${ESP_RTOS_SDK}/lib/libhal.a
                      ${ESP_RTOS_SDK}/lib/libpp.a
                      ${ESP_RTOS_SDK}/lib/libphy.a
                      ${ESP_RTOS_SDK}/lib/libnet80211.a
                      ${ESP_RTOS_SDK}/lib/libwpa.a
                      ${ESP_RTOS_SDK}/lib/liblwip.a
                      ${ESP_RTOS_SDK}/lib/libmain.a
                      ${ESP_RTOS_SDK}/lib/libssl.a
                      ${ESP_RTOS_SDK}/lib/libhal.a
                      ${ESP8266_LIBGCC}
                      -Teagle.app.v6.ld
                      )

file(WRITE ${CMAKE_BINARY_DIR}/blank.c "")
add_executable(kaa_demo ${CMAKE_BINARY_DIR}/blank.c)

target_link_libraries(kaa_demo kaa_demo_s)

我保留了 user_main.c 文件:

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#include "uart.h"

extern int main(void);

static void main_task(void *pvParameters)
{
    (void)pvParameters;
    main();
    for (;;);
}

void user_init(void)
{
    uart_init_new();
    UART_SetBaudrate(UART0, 115200);
    UART_SetPrintPort(UART0);

    portBASE_TYPE error = xTaskCreate(main_task, "main_task", 512, NULL, 2, NULL );
    if (error < 0) {
        printf("Error creating main_task! Error code: %ld\r\n", error);
    }
}

我把eagle.app.v6.ld(除了开头描述的修改)和eagle.rom.addr.ld、uart.h、uart.c一样(从 github)

获得

所以当我切换到构建目录并运行这个cmake命令时:

cmake \
-DCMAKE_TOOLCHAIN_FILE=../kaa/toolchains/esp8266.cmake \
-DKAA_PLATFORM=esp8266 \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DWITH_EXTENSION_CONFIGURATION=OFF \
-DWITH_EXTENSION_EVENT=OFF \
-DWITH_EXTENSION_LOGGING=OFF \
-DWITH_EXTENSION_NOTIFICATION=OFF \
-DWITH_EXTENSION_USER=OFF \
-DWITH_ENCRYPTION=OFF \
-DKAA_MAX_LOG_LEVEL=3 ..

我明白了:(esp8266 是我的用户名,kaa-app 是主目录,其中包含:CMakeLists.txt、构建、驱动程序等)

-- Default SDK location will be used: /opt/Espressif/esp-rtos-sdk
-- Toolchain path: /opt/Espressif/crosstool-NG/builds/xtensa-lx106-elf
-- ESP8266 SDK path: /opt/Espressif/esp-rtos-sdk
==================================
BUILD_TYPE = MinSizeRel
KAA_PLATFORM = esp8266
KAA_MAX_LOG_LEVEL = 3
==================================
BOOTSTRAP ENABLED
PROFILE ENABLED
KAA WILL BE INSTALLED TO /usr/local
-- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE)
-- Configuring done
-- Generating done
-- Build files have been written to: /home/esp8266/Documents/kaa-app/build

然后我 运行 make,我得到这个错误:

libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0x8): undefined reference to `time'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0xc): undefined reference to `difftime'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.example_callback+0x20): undefined reference to `kaa_logging_add_record'
libkaa_demo_s.a(kaa_demo2.c.obj): In function `example_callback':
kaa_demo2.c:(.text.example_callback+0x35): undefined reference to `time'
kaa_demo2.c:(.text.example_callback+0x42): undefined reference to `difftime'
kaa_demo2.c:(.text.example_callback+0x9e): undefined reference to `kaa_logging_add_record'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x10): undefined reference to `srand'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x14): undefined reference to `kaa_configuration_manager_set_root_receiver'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x18): undefined reference to `kaa_configuration_manager_get_configuration'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x1c): undefined reference to `ext_unlimited_log_storage_create'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x20): undefined reference to `ext_log_upload_strategy_create'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x24): undefined reference to `ext_log_upload_strategy_set_upload_timeout'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x28): undefined reference to `kaa_logging_init'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x3a): undefined reference to `time'
libkaa_demo_s.a(kaa_demo2.c.obj):(.text.startup.main+0x40): undefined reference to `srand'
libkaa_demo_s.a(kaa_demo2.c.obj): In function `main':
kaa_demo2.c:(.text.startup.main+0x69): undefined reference to `kaa_configuration_manager_set_root_receiver'
kaa_demo2.c:(.text.startup.main+0x7b): undefined reference to `kaa_configuration_manager_get_configuration'
kaa_demo2.c:(.text.startup.main+0xa5): undefined reference to `ext_unlimited_log_storage_create'
kaa_demo2.c:(.text.startup.main+0xb8): undefined reference to `ext_log_upload_strategy_create'
kaa_demo2.c:(.text.startup.main+0xc5): undefined reference to `ext_log_upload_strategy_set_upload_timeout'
kaa_demo2.c:(.text.startup.main+0xe6): undefined reference to `kaa_logging_init'
collect2: error: ld returned 1 exit status
CMakeFiles/kaa_demo.dir/build.make:120: recipe for target 'kaa_demo' failed
make[2]: *** [kaa_demo] Error 1
CMakeFiles/Makefile2:107: recipe for target 'CMakeFiles/kaa_demo.dir/all' failed
make[1]: *** [CMakeFiles/kaa_demo.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2

所以它似乎在尝试链接文件时找不到我包含的新 headers:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <kaa/kaa.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/kaa_error.h>
#include <extensions/configuration/kaa_configuration_manager.h>
#include <extensions/logging/kaa_logging.h>
#include <kaa/gen/kaa_logging_gen.h>
#include <kaa/platform/kaa_client.h>
#include <kaa/utilities/kaa_log.h>
#include <kaa/platform-impl/common/ext_log_upload_strategies.h>

但是,CMakeLists.txt 中包含的目标目录包含我需要的 header 文件(对于 C headers):

${ESP_RTOS_SDK}/extra_include

所以我真的不知道我需要添加或修改什么,我完全卡住了。任何帮助将非常感激!谢谢!

对于 data_collection 你必须设置 -DWITH_EXTENSION_LOGGING=ON

对于 esp8266,你有一个不同的 "time.h" 库 /kaa/src/kaa/platform-impl/esp8266/platform,它不支持功能 time(NULL),但支持

kaa_time_t kaa_esp8266_get_time(void);