embeddedavratmelstudio

AtmelStudio recipe for target *.elf failed


I have separated the code into files (*.c and *.h) and included them. I have guard headers and all the separated files were reported to being build:

Finished building: .././test.c

But my project build results in this error:

recipe for target 'Midi.elf' failed

, because of

undefined reference to 'some_test()'

(all calls to functions) defined within these separated files. And I don't know how to debug this. I inserted compiler warnings and can proof the function definition and declaration to be processed. Maybe avr-g++.exe and avr-gcc.exe build output cannot be linked?

Sketch.cpp:

#include "test.h"
void setup() {
   some_test();
}

void loop() {
}

test.h:

#ifndef TEST_H
#define TEST_H

void some_test(void);
#warning "processing test.h"

#endif //TEST_H

test.c:

#include "test.h"

void some_test(void){
    #warning "processing test.c"
}

Output (project relevant section):

...
Done building project "ArduinoCore.cppproj".

Build succeeded.
------ Build started: Project: Midi, Configuration: Debug AVR ------
Build started.
Project "Midi.cppproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files\Atmel\Studio\7.0\Vs\Compiler.targets" from project "D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\Midi\Midi.cppproj" (target "Build" depends on it):
    Task "RunCompilerTask"
        Shell Utils Path C:\Program Files\Atmel\Studio\7.0\shellUtils
        C:\Program Files\Atmel\Studio\7.0\shellUtils\make.exe all --jobs 4 --output-sync 
        Building file: .././Sketch.cpp
        Invoking: AVR8/GNU C Compiler : 4.9.2
        "C:\Program Files\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe" -funsigned-char -funsigned-bitfields -DDEBUG -DF_CPU=16000000L -DARDUINO=108013 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x0010 -DUSB_MANUFACTURER="\"Arduino LLC\""  -I"C:\Program Files\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\include" -I"..\\..\ArduinoCore\include\core" -I"..\\..\ArduinoCore\include\variants\mega"  -Os -fno-threadsafe-statics -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mrelax -g2 -Wall -w -mmcu=atmega2560 -B "C:\Program Files\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega2560" -c -std=gnu++11 -MD -MP -MF "Sketch.d" -MT"Sketch.d" -MT"Sketch.o"   -o "Sketch.o" ".././Sketch.cpp" 
        Finished building: .././Sketch.cpp
        Building file: .././test.c
        Invoking: AVR8/GNU C Compiler : 4.9.2
        "C:\Program Files\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-gcc.exe"  -x c -funsigned-char -funsigned-bitfields -DDEBUG -DF_CPU=16000000L -DARDUINO=108013 -DARDUINO_AVR_MEGA2560 -DARDUINO_ARCH_AVR -DUSB_VID=0x2341 -DUSB_PID=0x0010 -DUSB_MANUFACTURER="\"Arduino LLC\""  -I"C:\Program Files\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\include" -I"..\\..\ArduinoCore\include\core" -I"..\\..\ArduinoCore\include\variants\mega"  -Os -fno-threadsafe-statics -ffunction-sections -fdata-sections -fpack-struct -fshort-enums -mrelax -g2 -Wall -mmcu=atmega2560 -B "C:\Program Files\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega2560" -c -std=gnu99 -std=gnu11 -MD -MP -MF "test.d" -MT"test.d" -MT"test.o"   -o "test.o" ".././test.c" 
        Finished building: .././test.c
cc1.exe(0,0): warning: command line option '-fno-threadsafe-statics' is valid for C++/ObjC++ but not for C
        In file included from .././test.c:1:0:
D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\Midi\test.h(5,2): warning: #warning "processing test.h" [-Wcpp]
         #warning "processing test.h"
          ^
        .././test.c: In function 'some_test':
D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\Midi\test.c(4,3): warning: #warning "processing test.c" [-Wcpp]
          #warning "processing test.c"
           ^
        Building target: Midi.elf
        Invoking: AVR8/GNU Linker : 4.9.2
        "C:\Program Files\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe" -o Midi.elf  Sketch.o test.o   -Wl,-Map="Midi.map" -Wl,--start-group -Wl,-lm -Wl,-lArduinoCore  -Wl,--end-group -Wl,-L"D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\ArduinoCore\Debug"  -Wl,--gc-sections -mrelax -mmcu=atmega2560 -B "C:\Program Files\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega2560" -Os  
        Sketch.o: In function `setup':
D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\Midi\Sketch.cpp(20,1): error: undefined reference to `some_test()'
collect2.exe(0,0): error: ld returned 1 exit status
        make: *** [Midi.elf] Error 1
D:\Mirror\Anwendungen\AVRStudio\Arduino\MIDIout\MIDIout\MIDIout\Midi\Debug\Makefile(123,1): error: recipe for target 'Midi.elf' failed
        The command exited with code 2.
    Done executing task "RunCompilerTask" -- FAILED.
Done building target "CoreBuild" in project "Midi.cppproj" -- FAILED.
Done building project "Midi.cppproj" -- FAILED.

Build FAILED.
========== Build: 1 succeeded or up-to-date, 1 failed, 0 skipped ==========

Solution

  • Sketch.cpp is compiled as as C++, including test.h. In order to support function overloading, class membership etc, C++ uses name mangling to encode these C++ features in the symbol name. As such the symbol name for some_test in Sketch.cpp is not the same as that in test.c which is compiled as C and no name mabgling is applied..

    The solution is to prevent name mangling for this symbol when the header is C++ compiled by specifying that the symbol has C linkage:

    #ifndef TEST_H
    #define TEST_H
    
    #if defined __cplusplus
    extern "C"
    {
        #warning Using C linkage in C++ for test.h
    #endif
    
    void some_test(void);
    #warning "processing test.h"
    
    #if defined __cplusplus
    }
    #endif
    
    
    #endif //TEST_H
    

    The braces ({...}) in the extern "C" declaration mean that all the enclosed symbols declarations have C linkage. For C / C++ interoperability all your C code headers should include this wrapper.

    Another solution of course is simply to compile test.c as C++ (most simply by renaming it text.cpp). Note that Arduino Sketch code and libraries are C++ code. It is normally better to stick to C++ compilation throughout to allow access to the Arduino library which will have C++ linkage and would require a lot of wrapper code to access from C.

    Unhelpfully the build log states "Invoking: AVR8/GNU C Compiler" when clearly it is using C++ compilation. I think that is just an Atmel Studio thing, not generated by the compiler itself.