Issue including SPI.h in a library

Hey all!

I’m trying to create a small library to do a few useful things using the Arduino’s SPI interface, but for some reason, I can’t include SPI.h in my library file.
Whenever I do, and I try to compile, the compiler simply errors, saying “error: SPI.h: No such file or directory”. I can’t figure out why it’s doing this, since I’ve looked at several of the core libraries that include SPI.h, and they don’t do anything special for it, yet when I do the same thing, it says it cant find the lib.

I also just tried including SPI.h in my main sketch, but then my library errors out if I try to use any SPI functions inside it (because SPI is not declared in the library anywhere).

What can I do? I’ve attached a very basic example, which fails to compile with the following

In file included from test.cpp:2:
test.h:3:17: error: SPI.h: No such file or directory

As of Arduino 0019, the Ethernet library depends on the SPI library.
You appear to be using it or another library that depends on the SPI library

test.pde (60 Bytes)

test.h (19 Bytes)

Which version of the Arduino are you using? What platform?

Check if you can [u]compile[/u] one of the ethernet examples as these also include SPI.h if this doesn't work you probably need to reinstall the Arduino environment.

You can also check if the file SPI.h exists in the Arduino Library Path : Create a new sketch , Select skech menu -> Import Library -> SPI if SPI doesnot show up the lib is not there and you need to reinstall.

For some obscure reason (to do with the pre-processing of your source) you also need to include SPI.h in your main sketch. I came across this and was baffled for a while.

Yep, confirmed. I changed your sketch to read:

#include <SPI.h>
#include "test.h"

void loop(){
    }

void setup(){
    }

It now compiles OK.

robtillaart: Which version of the Arduino are you using? What platform?

I'm currently using IDE v0021, on Ubuntu Linux.

However...

[quote author=Nick Gammon link=topic=54345.msg389569#msg389569 date=1299366288] For some obscure reason (to do with the pre-processing of your source) you also need to include SPI.h in your main sketch. I came across this and was baffled for a while. [/quote]

I've also now confirmed this. Very strange, but at least now I've got the answer as to why this wasn't working! Should this be reported as a bug, or is this the way this is intended to work? I read a little traffic on the developer mailing list from after the change for how the Ethernet library handles the SPI library, and I get the impression that this is the intended behavior...

[EDIT]

Unfortunately, even though my simplistic example now compiles, my real code still won't work. Whenever I compile it, I no longer get the errors about the missing library, but I am still having other issues (ones I originally thought would be resolved by fixing the missing lib issue... sorry for not mentioning earlier).

Whenever I try to compile, i get this error:

In file included from EncoderInterface.c:23:
/home/andrew/arduino-0022/libraries/SPI/SPI.h:36: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘SPIClass’
/home/andrew/arduino-0022/libraries/SPI/SPI.h:53: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘SPI’
/home/andrew/arduino-0022/libraries/SPI/SPI.h:55: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘:’ token
/home/andrew/arduino-0022/libraries/SPI/SPI.h:62: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘:’ token
/home/andrew/arduino-0022/libraries/SPI/SPI.h:66: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘:’ token
EncoderInterface.c: In function ‘Test_encoder_SPI_link’:
EncoderInterface.c:63: error: ‘SPI’ undeclared (first use in this function)
EncoderInterface.c:63: error: (Each undeclared identifier is reported only once
EncoderInterface.c:63: error: for each function it appears in.)
EncoderInterface.c: In function ‘Flush_encoder_cache’:
EncoderInterface.c:131: error: ‘SPI’ undeclared (first use in this function)
EncoderInterface.c: In function ‘Encoder_read_angle’:
EncoderInterface.c:183: error: ‘SPI’ undeclared (first use in this function)
EncoderInterface.c: In function ‘Encoder_setup’:
EncoderInterface.c:263: error: ‘SPI’ undeclared (first use in this function)

It still looks like it's getting mad about something in the SPI library, but I don't understand why. I tried upgrading to Arduino 0022 to see if it would help, but it won't run on my system, and I also tried reinstalling 0021, but that didn't help either.

Im including links my full sketch and source... the forum wouldnt let me upload them for some reason. Can anybody see what in the world is wrong here? http://pastebin.com/YdfKkhLm -- MegaEncoder.pde http://pastebin.com/z0ngcECh -- EncoderInterface.h http://pastebin.com/M39J491z -- EncoderInterface.c

Should this be reported as a bug, or is this the way this is intended to work?

The way that the IDE figures out what to compile is based on what is included in the main sketch. It is not a bug that things not included in the sketch are not compiled. Why should the Ethernet library, for instance, be compiled every time I compile a sketch, if I am not using it?

PaulS:
The way that the IDE figures out what to compile is based on what is included in the main sketch. It is not a bug that things not included in the sketch are not compiled. Why should the Ethernet library, for instance, be compiled every time I compile a sketch, if I am not using it?

I understand this, but in order for the program to run, any libraries your main sketch depend on must also be compiled, including other libraries that the ones you include depend on. This is obvious both when building programs to run on a computer, or on the Arduino.
What is not obvious though, is why I should have to include SPI.h in my main sketch if it’s already included in my library, and at the same time I could pull in any number of other libs into my library, yet I don’t have to put any of them into my main sketch. The only library I’ve seen that does this is the SPI library. For example, if I pull in the EEPROM library in my lib, I don’t also have to inttypes.h (which is pulled in by the EEPROM library) to use it, so why should I have to do this sort of thing if I use SPI.h in my lib?

This defeats one of the purposes of using libraries anyway… hiding implementation. The person using my library shouldn’t have to know how the thing works, only that it does work when used as directed. If they don’t use it as directed, then they either need to know what they’re doing, or understand the consequences if they dont.

Upon further reading, the only actual justification I’ve seen for this behavior was a message citing that people were using the SPI library with the Ethernet shield, then hooking things up to the SPI pins, and complaining that things didn’t work like they expected. This ‘change’ is supposedly intended to keep people from doing that by ‘reminding’ them that the SPI pins are taken by making them include the SPI lib in their main sketch. However the change appears to have been made in the SPI library, not the Ethernet library, so the side effect is that any lib that depends in SPI is subject to this questionable behavior.

What is not obvious though, is why I should have to include SPI.h in my main sketch if it's already included in my library, and at the same time I could pull in any number of other libs into my library, yet I don't have to put any of them into my main sketch. The only library I've seen that does this is the SPI library.

This isn't true. The compiler makes a list of file that need to be compiled, based in the includes in the sketch. Nothing else gets compiled.

If your library includes LiquidCrystal.h, but your sketch does not, the LiquidCrystal source code will not be compiled, and your library will end up with a bunch of undefined external references.

But, Paul …

His main sketch includes test.h. And the IDE knows to compile that, because there is an include there. So it goes to compile test.h. And this is all it has in it:

#include <SPI.h>

Line 3 is the include for SPI.h. Then he gets the error message:

In file included from test.cpp:2:
test.h:3:17: error: SPI.h: No such file or directory

In what way, when compiling test.h, does SPI.h not exist?

This isn’t an issue of deciding what to link, or whether or not to compile test.h. It is compiling test.h and reporting that file, which in fact exists, does not exist. When I got that message I spent an hour looking at other code, which also included SPI.h, and worked, to try to find in what way SPI.h didn’t exist in this test case.

Just to amplify … When compiling the test program, which is this:

#include "test.h"

void loop(){
    }

void setup(){
    }

This is the full error message:

In file included from test.cpp:2:
test.h:3:17: error: SPI.h: No such file or directory

As of Arduino 0019, the Ethernet library depends on the SPI library.
You appear to be using it or another library that depends on the SPI library

That’s plain wrong. It says “You appear to be using [the Ethernet library] or another library”. No, I’m not. I’m using the SPI library. Surely an include that specifically loads the SPI library, shouldn’t be rejected with a message that implies that I have forgotten to load the SPI library. Why, including the SPI library is all that test.h does!

I must admit that if I change

#include <SPI.h>

to:

#include <EEPROM.h>

I now get an error message about EEPROM.h missing.

Hmmm - I’m starting to see what is happening here. Compiling with and without the include for EEPROM.h in the main sketch (and with the shift key held down) reveals one major difference:

avr-g++ -c -g -Os -w -fno-exceptions ... yaddayadda ... -I/Applications/Arduino.app/Contents/Resources/Java/libraries/EEPROM

So I see now what is happening. It isn’t working which files to compile (well, it probably is), but more importantly it is modifying the include path to add them to the include path for avr-gcc for this particular file.

I think this behaviour is a tiny bit obscure. It means that to use a library like the liquid crystal one, you have to open it up yourself and see what it includes (eg. SPI.h or Wire.h) and then manually also add those includes into your main sketch, or the sketch won’t compile. But this takes away the “black box” functionality of the libraries.

A couple of suggested changes:

  • The IDE could scan libraries and add the paths for any includes they use into the -I (include file path) part of the compilation. This won’t add to code size, it just tells the compiler where an include file is.
  • Or, the default libraries which are included anyway could be automatically added to the compile include-file path. Again, this doesn’t change code size, as if the include file isn’t called for it isn’t loaded.

flyindragon1: It still looks like it's getting mad about something in the SPI library, but I don't understand why. I tried upgrading to Arduino 0022 to see if it would help, but it won't run on my system, and I also tried reinstalling 0021, but that didn't help either.

Im including links my full sketch and source... the forum wouldnt let me upload them for some reason. Can anybody see what in the world is wrong here? http://pastebin.com/YdfKkhLm -- MegaEncoder.pde http://pastebin.com/z0ngcECh -- EncoderInterface.h http://pastebin.com/M39J491z -- EncoderInterface.c

  • Change EncoderInterface.c to EncoderInterface.cpp. The SPI library uses C++, and won't compile under a C program.

  • Don't include EncoderInterface.c in MegaEncoder.pde - you don't "include" C code normally. Make another tab in the IDE and put it there, so it knows to compile it.

  • In MegaEncoder.pde put an include for EncoderInterface.h

Then it compiles OK apart from a problem with an "if" statement.