ezieragabriel / arduino

Automatically exported from code.google.com/p/arduino
Other
0 stars 0 forks source link

Document process for using .c / .cpp / .h files in a sketch. #993

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
The Arduino environment has ways to split a sketch into multiple files but I 
had difficulties splitting a long sketch, after searches there were numerous 
reports of failure, and recommendations not to do it , since it didn't work. 

I thought it useful to reduce it to its simplest set of errors to see if its 
really a bug. It seems the simplest set that causes a bug is definition of a 
variable and a function in a seperate file. 

What steps will reproduce the problem?
1. Create sketch below
2. Verify it

What is the expected output? What do you see instead?

sketch.cpp.o:(.data.foo+0x0): multiple definition of `foo'
test.c.o:(.data.foo+0x0): first defined here
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/
gcc/avr/4.3.2/../../../../avr/bin/ld: Disabling relaxation: it will not work 
with multiple definitions

So delete the "#include test.c" line 

sketch_jul28b.cpp.o: In function `loop':
/Applications/sketch_jul28b.ino:5: undefined reference to `bar()'

What version of the Arduino software are you using? 1.0.1 
On what operating system?  MacOX
Which Arduino board are you using? Uno

Please provide any additional information below.

Sample sketch to illustrate the problem
-----sketch-------
#include "test.h"
void setup() {
// Do nothing
}
void loop() {
   bar();
}
#include "test.c";
-----test.h -----
void bar();
-----test.c-----
#include <WProgram.h>
int foo = 1;
void bar() {
  // Do nothing
}

Original issue reported on code.google.com by mitra.ar...@gmail.com on 28 Jul 2012 at 9:36

GoogleCodeExporter commented 9 years ago
Further investigation shows this can be forced to work by either renaming 
test.c as test.cpp (even though its a C file) or by wrapping the definiton in 
test.h with 
extern "C" {  .... } 

If the intention is to hide that you are working in CPP, then it should just 
work ... if the intention is to expose it, then neither of these fixes are 
obvious - since the documentation on splitting sketches doesnt point out that 
most people won't get it to work if they add a .c file 

i.e. I content this is either a bug in the Arduino environment, or a bug in its 
documentation.

Original comment by mitra.ar...@gmail.com on 28 Jul 2012 at 9:55

GoogleCodeExporter commented 9 years ago
Marking this as a documentation issue and redirecting to Tom.

The Arduino environment specifically doesn't do any pre-processing of .c / .cpp 
/ .h files in your sketch (only .ino files), so you need to do #ifdef 
__cplusplus in your header if you want to share a function between .c and .cpp 
(or .ino) files.

Original comment by dmel...@gmail.com on 28 Jul 2012 at 10:00

GoogleCodeExporter commented 9 years ago
Umm, not sure I understand the problem, Dave.  Where exactly does this issue 
come up?  Can you explain in more depth,so I can figure out where in the docs 
something like this might go?  Never seen the problem before.

Original comment by tom.i...@gmail.com on 13 Aug 2012 at 7:15

GoogleCodeExporter commented 9 years ago
Hmm, I've been thinking about writing something like "A Guide to Arduino for C 
and C++ Programmers"; so maybe it makes sense for me to handle this there?

Basically, the problem is that if you want to use a C function in a C++ file 
(or your regular sketch .ino files), you need to wrap its prototype (in the 
header file) in:

#ifdef __cplusplus
extern "C" {
#endif

void foo();

#ifdef __cplusplus
}
#endif

This is because C++ slightly changes ("mangles") the names of function when 
compiling, but C doesn't (or mangles them differently). So for a C++ file to 
find a C function, it needs to know that the function's name wasn't mangled 
when it was compiled (as a C function). That's what the "extern "C" {" does. 
Except that in C, you can't use "extern "C" {", so you need to wrap it in the 
"#ifdef __cplusplus", so it's only included when compiling the C++ file that 
includes the header (and not when compiling the C file that includes the 
header). 

Confusing as this is, it's standard practice (AFAIK) when using C functions 
from C++ code. My expectation (which may or may not be appropriate) is that if 
you're using .c / .cpp / .h files in your sketch (as opposed to just one or 
more .ino files), you're doing so because you know C and/or C++. These files 
are not pre-processed in any way, and so you have to use extern "C" as you 
would in any other C/C++ code.

All of which feels like it could be explained in a document targeting C and C++ 
programmers. I'm also imagining that it would discuss the pre-processing of the 
.ino files and explain the implications of the auto-generation of function 
prototypes, etc.

Original comment by dmel...@gmail.com on 13 Aug 2012 at 8:42