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 ==========
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.