Skip to main content
juliuscaesar
Associate III
March 14, 2018
Solved

stm32 c++ Linker error

  • March 14, 2018
  • 4 replies
  • 1542 views
Posted on March 14, 2018 at 22:47

hey guys

I have an stm32f4 discovery board and used stm32 cube to generate a SW4STM32 project with freertos.

SW4STM32 is able to convert a c project to c++ project.

I have read about the problem when mixing c and c++ code and i know about the mangling of the c++ compiler.

There are lots of extern C header guards in the header files.

However i'm still getting a linker error

Building target: Cpp_Test.elf

Invoking: MCU G++ Linker

arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nosys.specs -specs=nano.specs -T'../STM32F429ZITx_FLASH.ld' -Wl,-Map=output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o 'Cpp_Test.elf' @'objects.list'   -lm

Src/freertos.o: In function `StartDefaultTask':

xxxx\Cpp_Test\Debug/../Src/freertos.c:131: undefined reference to `calc_values'

collect2.exe: error: ld returned 1 exit status

makefile:59: recipe for target 'Cpp_Test.elf' failed

make: *** [Cpp_Test.elf] Error 1

my test_cpp.h file looks like this

#ifndef USER_TEST_CPLUS_H_

#define USER_TEST_CPLUS_H_

#include 'stdint.h'

int calc_values();

#endif /* USER_TEST_CPLUS_H_ */

my test_cpp.cpp file looks like this

#include 'test_cplus.h'

#include <iostream>

using namespace std;

class Rectangle {

    int width, height;

  public:

    void set_values (int,int);

    int area() {return width*height;}

};

void Rectangle::set_values (int x, int y) {

  width = x;

  height = y;

}

int calc_values()

{

    Rectangle rect;

    rect.set_values(1,2);

    int area = rect.area();

    return area;

}

the calc_values() function is called from the freertos default task in freertos.c

/* Includes ------------------------------------------------------------------*/

#include 'FreeRTOS.h'

#include 'task.h'

#include 'cmsis_os.h'

/* USER CODE BEGIN Includes */     

#include 'test_file.h'

#include 'test_cplus.h'

/* USER CODE END Includes */

/* Variables -----------------------------------------------------------------*/

osThreadId defaultTaskHandle;

/* USER CODE BEGIN Variables */

/* USER CODE END Variables */

/* Function prototypes -------------------------------------------------------*/

void StartDefaultTask(void const * argument);

extern void MX_USB_DEVICE_Init(void);

extern void MX_FATFS_Init(void);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

/* Hook prototypes */

/* Init FreeRTOS */

void MX_FREERTOS_Init(void) {

  /* USER CODE BEGIN Init */

       

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */

  /* add mutexes, ... */

  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */

  /* add semaphores, ... */

  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */

  /* start timers, add new ones, ... */

  /* USER CODE END RTOS_TIMERS */

  /* Create the thread(s) */

  /* definition and creation of defaultTask */

  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */

  /* add threads, ... */

  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */

  /* add queues, ... */

  /* USER CODE END RTOS_QUEUES */

}

/* StartDefaultTask function */

void StartDefaultTask(void const * argument)

{

  /* init code for USB_DEVICE */

  MX_USB_DEVICE_Init();

  /* init code for FATFS */

  MX_FATFS_Init();

  /* USER CODE BEGIN StartDefaultTask */

  /* Infinite loop */

  for(;;)

  {

      run_test();

      calc_values(); //=> this causes the linker error

    osDelay(100);

  }

  /* USER CODE END StartDefaultTask */

}

/* USER CODE BEGIN Application */

/* USER CODE END Application */

could you give me a hint why this is not working?

    This topic has been closed for replies.
    Best answer by Pavel A.
    Posted on March 14, 2018 at 23:14

    There are lots of extern C header guards in the header files.

    But none in the code you've posted. So go add the 

    extern 'C' guards  around your C++ functions exported to C.

    - pa

    4 replies

    Pavel A.
    Pavel A.Best answer
    March 14, 2018
    Posted on March 14, 2018 at 23:14

    There are lots of extern C header guards in the header files.

    But none in the code you've posted. So go add the 

    extern 'C' guards  around your C++ functions exported to C.

    - pa

    Andrew Neil
    Super User
    March 14, 2018
    Posted on March 14, 2018 at 23:19

    Hopefully this is just a typo in your post; you say:

    my

    test_cpp.h

    file looks like this

    But everywhere that #includes it calls it 

    'test_cplus.h'

    A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
    Tesla DeLorean
    Guru
    March 14, 2018
    Posted on March 14, 2018 at 23:35

    Name mangling?

    extern 'C' int calc_values()

    {

        Rectangle rect;

        rect.set_values(1,2);

        int area = rect.area();

        return area;

    }

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    juliuscaesar
    Associate III
    March 14, 2018
    Posted on March 14, 2018 at 23:39

    @andrew this was a typo

    :)

    ^^

    @pavel That did work.

    I thought i only needed the extern c guards when implementing c code in c++ functions, not the other way around.

    @clive: according the wikipedia the c++ compiler uses the function name and the arguments the generate unique names. The C compiler only uses the names. Thats why overloading is only possible in C++.

    And this process is called name mangling. (at least that's what i understood, feel free to correct me if i'm wrong )

    Thx for your quick help guys