SuperHouse / esp-open-rtos

Open source FreeRTOS-based ESP8266 software framework
BSD 3-Clause "New" or "Revised" License
1.53k stars 491 forks source link

Build System -- fails to link POSIX basename() from <libgen.h> #569

Closed jeffsf closed 6 years ago

jeffsf commented 6 years ago

Although basename is defined in <libgen.h> and code is present in newlib, the build system fails to properly link, even with a trivial example.

[jeff@miniup /Volumes/esp-build/esp-open-rtos/local/basename-link-failure-libgen]$ make V=1
xtensa-lx106-elf-gcc -nostdlib -Wl,--no-check-sections -L./build/sdklib -L../../lib -u call_user_start -Wl,-static -Wl,-Map=./build/basename_libgen.map  -Wl,-gc-sections -g -O2 -T../../ld/program.ld -T../../ld/rom.ld -L../../libc/xtensa-lx106-elf/lib -u _printf_float -u _scanf_float -Wl,--whole-archive  ./build/open_esplibs_libmain.a ./build/open_esplibs_libnet80211.a ./build/open_esplibs_libphy.a ./build/open_esplibs_libpp.a ./build/open_esplibs_libwpa.a -Wl,--no-whole-archive -Wl,--start-group  ./build/program.a ./build/freertos.a ./build/lwip.a ./build/core.a ./build/open_esplibs.a ./build/libgcc.a ./build/libc.a -lhal -lmain -lnet80211 -lphy -lpp -lwpa -Wl,--end-group -o build/basename_libgen.out
./build/program.a(basename-libgen.o):(.text.testTask+0x10): undefined reference to `basename'
./build/program.a(basename-libgen.o): In function `testTask':
/Volumes/esp-build/esp-open-rtos/local/basename-link-failure-libgen/basename-libgen.c:50: undefined reference to `basename'
collect2: error: ld returned 1 exit status
make: *** [build/basename_libgen.out] Error 1

This is a recent pull and build of esp-open-sdk and a recent pull of esp-open-rtos. esp-open-sdk was built using the instructions found at https://github.com/SuperHouse/esp-open-rtos on a case-sensitive volume.

To replicate:

/*
 * Tests of ability to link to basename() using <libgen.h>
 * 
 */

/* There are two common basename variants.  If you do NOT #include <libgen.h>
   and you do

     #define _GNU_SOURCE
     #include <string.h>

   you get the GNU version.  Otherwise you get the POSIX versionfor which you
   should #include <libgen.h>i for the function prototype.  POSIX requires that
   #undef basename will still let you invoke the underlying function.  However,
   this also implies that the POSIX version is used in this case.  That's made
   sure here. */

#include <libgen.h>

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

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

#include <espressif/esp_common.h>
#include <espressif/esp_wifi.h>

#include <esp8266.h>
#include <esp/uart.h>

#define BLUE_LED 2
#define LED_ON 0
#define LED_OFF 1

#define WAIT_FOR_UART_SECS 5  // 2 might be OK

// For sdk_system_restart_in_nmi()
#include <esplibs/libmain.h>

// Not defined in espressif/esp_wifi.h
extern bool
sdk_wifi_set_opmode_current(uint8_t opmode);

void
testTask(void *pvParameters)
{
    gpio_enable(BLUE_LED, GPIO_OUTPUT);
    gpio_write(BLUE_LED, LED_OFF);

    vTaskDelay(WAIT_FOR_UART_SECS * 1000 / portTICK_PERIOD_MS);

    gpio_write(BLUE_LED, LED_ON);

    printf("basename() test; expect somefile.name\n");
    printf("basename(\"path/to/somefile.name\") returned '%s'\n",
           basename("path/to/somefile.name"));

    printf("\n");
    printf("All done\n");

    gpio_write(BLUE_LED, LED_OFF);

    sdk_system_restart_in_nmi();
}

void user_init(void)
{
    uart_set_baud(0, 115200);
    sdk_wifi_set_opmode_current(NULL_MODE);  // Temporarily disable
    xTaskCreate(testTask, "testTask", 512, NULL, 2, NULL);
}
PROGRAM=basename_libgen

include ../../common.mk

The same program and Makefile link with the GNU version as described using

#define _GNU_SOURCE
#include <string.h>

Unfortunately, GNU licensing requirements do not make this a viable alternative.

Looking at what is built with nm

lib_a-gnu_basename.o:
00000000 T __gnu_basename
         U strrchr

It appears that the POSIX version is not included in libc

[jeff@miniup /Volumes/esp-build/esp-open-rtos/local/basename-link-failure-libgen]$ nm build/libc.a | fgrep basename
lib_a-gnu_basename.o:
00000000 T __gnu_basename
jeffsf commented 6 years ago

For anyone looking to resolve this prior to any possible patch or recompilation of newlib, the newlib source code for basename() may be found at

https://github.com/projectgus/newlib-xtensa/

at newlib/libc/unix/basename.c

/* Copyright 2005 Shaun Jackman
 * Permission to use, copy, modify, and distribute this software
 * is freely granted, provided that this notice is preserved.
 */
ourairquality commented 6 years ago

See https://github.com/SuperHouse/esp-open-rtos/pull/571 for a newlib update that includes some of the code from libc/unix such as basename.

jeffsf commented 6 years ago

Confirmed resolved and both cases now compile and link

Thanks @ourairquality