Pages: [1]   Go Down
Author Topic: Compiler weirdness with include files in ino file  (Read 701 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a a simple project with three files.  myreader.cpp and myreader.h that define a simple ooPinChangeInt (http://code.google.com/p/oopinchangeint) CallBackInterface-derived class.  Then I have my main file, called readpwm1.ino.  I have attached a zip file with them (absolute minimum to demonstrate the problem).  Basically in the ino file if I comment out the ooPinChangeInt.h include, then arduino cannot compile myreader.cpp; the compiler does not recognize CallBackInterface, which is defined in a header file that is in included by myreader.cpp.  I am mystified as to why g++ cannot see it.

If I add the ooPinChangeInt.h to the main ino file, then the myreader.cpp file compiles just fine.  However now readpwm1.ino will not compile and it claims that ooPinChangeInt.h is redefining a bunch of things.

Here are the files inline:
Code:
/* uncomment next line and myreader.cpp will compile,
   but arduino complains about redefinitions.  without
   it, myreader.cpp says it can't find
   CallBackInterface or PCintPort.*/
//#include <ooPinChangeInt.h>
#include "myreader.h"

MyReader p(2);

void setup()
{
        Serial.begin(9600);
}

void loop()
{
        delay(500);
}

myreader.h
Code:
#ifndef __MYREADER_H__
#define __MYREADER_H__

#include <Arduino.h>
#include <ooPinChangeInt.h>
#include <cbiface.h>


class MyReader : public CallBackInterface
{
public:
        unsigned char count;
        unsigned long time;
        unsigned long ticksperminute;
        uint8_t pin;
        unsigned long total_ticks;

        MyReader(uint8_t _pin);
        void cbmethod();
private:
        void init ();
};

#endif

And myreader.cpp:
Code:
#include <limits.h>
#include "myreader.h"
#include <ooPinChangeInt.h>
//#include <cbiface.h>
//#include <Arduino.h>

inline unsigned long elapsed_time(unsigned long now, unsigned long then) {
        if (now < then) {
                /* number wrapped around; do some math */
                return ULONG_MAX - then + now + 1;
        } else {
                /* straight-forward difference */
                return now - then;
        }
}

#define MAX_TICKS_PER_CALC 255
#define TICKS_PER_CALC 10

static const double coeff = 0.10;

MyReader::MyReader (uint8_t _pin): pin(_pin)
{
        init();
};

void MyReader::cbmethod() {
        unsigned long now;
        unsigned long delta;
        unsigned long tpm;

        count++;
        total_ticks++;

        if(count >= TICKS_PER_CALC) {

                now = micros();

                if (now == time)
                        return;

                tpm = (unsigned long)(  TICKS_PER_CALC / (double) (elapsed_time(now, time)) * 1000000 * 60 );

                ticksperminute = tpm * coeff + ticksperminute * (1 - coeff);
                count=0;
                time = micros();
        }
}

void MyReader::init () {
        ticksperminute=0;
        pinMode(pin, INPUT);
        digitalWrite(pin, LOW);
        PCintPort::attachInterrupt(pin, this, RISING);
        time = micros();
        total_ticks = 0;
}


I've read about how the ino preprocessor is broken when it comes to certain # statements.  Is this a case of Arduino's broken preprocessor biting me?

Is there any way to get arduino to compile my little project as it is layed out? I cannot add the class to the main arduino file because that seems to break compiling of other classes I have added in.

As an aside, I am finding Arduino's build system to be rather cumbersome and very fragile.  Are there any good recipes for building using other tools like cmake?

* readpwm1.zip (3.18 KB - downloaded 6 times.)
« Last Edit: February 01, 2013, 01:20:54 am by torriem » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your files are copied to a temporary directory. The #include directives inform the copying process which ones to copy. If your main sketch does not include a .h file it isn't copied. Annoying perhaps, but that's the way it works.

So your main sketch has to include files which it may not personally use.
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2037
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have included Arduino.h in the wrong places, perhaps.

And if your myReader.cpp  includes  myReader.h,  which includes the ooPinChange.h,     then it doesn't need to include ooPinChange.h again,   particularly in a different order.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
As an aside, I am finding Arduino's build system to be rather cumbersome and very fragile.  

I haven't found that. Once you get used to a couple of idiosyncrasies like the above, and all systems have some problems, it works pretty smoothly.
Logged

Offline Offline
Edison Member
*
Karma: 28
Posts: 2037
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So why,  every time I recompile my sketch,  does it take ages,  and recompiles a whole bunch of stuff I never use, never edit, afaik never reference,   and get a whole bunch of compiler warnings ?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You have included Arduino.h in the wrong places, perhaps.

And if your myReader.cpp  includes  myReader.h,  which includes the ooPinChange.h,     then it doesn't need to include ooPinChange.h again,   particularly in a different order.
Yes those includes aren't necessary, bit they certainly won't break g++.  Each include file has pound defined guards. So it doesn't explain why what should compile doesn't. And why Arduino complains about redefinition in the oopinchangeint.h file.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your files are copied to a temporary directory. The #include directives inform the copying process which ones to copy. If your main sketch does not include a .h file it isn't copied. Annoying perhaps, but that's the way it works.

So your main sketch has to include files which it may not personally use.

Yes I am aware of this. It's too bad they didn't use some macros to let Arduino know what libraries you are using instead of using real includes. That does give me an idea to try though.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So why,  every time I recompile my sketch,  does it take ages,  and recompiles a whole bunch of stuff I never use, never edit, afaik never reference,   and get a whole bunch of compiler warnings ?

What warnings?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 549
Posts: 46090
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What version of the IDE are you using, on what operating system? From the sounds of it, you aren't using a recent version.

Or, are you not using the IDE at all? Are you using some other method to compile your code?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What version of the IDE are you using, on what operating system? From the sounds of it, you aren't using a recent version.

Or, are you not using the IDE at all? Are you using some other method to compile your code?

Yes I'm sorry I neglected to give this information.  I'm using the IDE to build, Arduino 1.0.3.  It's the latest version, as far as I can tell.

I am strongly considering not using the IDE and using one of the cmake systems I've found (and not using .ino files at all), since Arduino's built-in build is acting so strange.  I've managed to make some pretty complicated C++ classes work up til now, but this one has me completely stuck.  I have posted a simple example in my first post on how to replicate my problem, though you have to install the ooPinChangeInt library from google code which is pretty easy. 

I'm still messing with the ino file.  I've moved all my code out of it into a cpp file, and now just have an empty .ino file with the includes so it knows what libraries to stick in, but it's still having the same errors about things being redefined in the ooPinChangeInt.h file.  Which is really really odd because it doesn't matter how many times you include that file, the #define guards in it prevent redefinition.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Actually it's not a compiler error.  This is a linker error. And it's pointing to a problem in the ooPinChangeInt library itself.  I believe it's a bug in that library.  Essentially there is code defined in the .h file (which I was always taught was a big no no).  So in the main ino file when I include the header file it's actually building the class and it's methods.  Then in my cpp file I include the .h file again, and it builds the class and it's methods again, and then the linker finds duplicate symbols.  Had the library been made with a separate .cpp and .h file, then the cpp file would build the class methods and they'd end up in only one .o file, and the other places that needed the .h file would be just happy.

So arduino's build is not at fault here.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How bizarre.  The library author decided to put everything in the .h file, but knowing that if you included the file in two different .cpp files you'd get duplicate symbols, he placed all the C++ definition code in #ifndef LIBCALL_OOPINCHANGEINT barriers.  So in one file you include it normally.  And in all other .cpp files, you have to #define LIBCALL_OOPINCHANGEINT.

This is a style of C++ I have never seen before.  Please library authors, do not do this! Just stick your implementation code in a .cpp file.  It will be much easier to debug, less prone to conflicts, and will just work when someone uses your .h file in a usual fashion.  I'm not sure where this trend to put everything in the .h file is coming from (I see on stackexchange it's becoming common), but it's not a good idea. For one it breaks make systems.  If a method call's implementation is tweaked, if you stick to a separate .cpp file then a rebuild is a matter of compiling one cpp file and a re-link.  If you keep the code in the .h file (even if it is inside of #define implementation barriers), build systems will rebuild possibly all your cpp files.  Obviously build time isn't an issue here in Arduino, but in the real world, that could be hours!  Rant finished now.
Logged

Pages: [1]   Go Up
Jump to: