Using a library from a library

I am working on a project that makes use of a library. The project is in a folder called TelescopeController. This contains TelescopeController.pde and a libraries folder. In the libraries folder I have four folders, each of which contains a library : CommandDetector, CommandProcessor, StepperMotor and StringSplitter. So far so good. Now the problem comes because I want to use the StringSplitter library in the code for the CommandProcessor library. At the head of CommandProcessor.cpp, which is in the CommandProcessor folder I have:

#include "..\StringSplitter\StringSplitter.h"		// for splitting Strings into sections

which seems to work, but when I try and compile the whole thing I get this message :

CommandProcessor\CommandProcessor.cpp.o: In function `CommandProcessor::Process(String)':
C:\Programming\Arduino\TelescopeController\libraries\CommandProcessor/CommandProcessor.cpp:31: undefined reference to `StringSplitter::Split(String, int, String*, int)'

For some reason, although the CommandProcessor.cpp file has all the definitions for StringSplitter it cannot see the Split method. How come?
Here is CommandProcessor.cpp :

/*
 * SOURCE FILE : CommandProcessor.cpp
 *
 * Class for processing incoming commands sent from another
 * computer somehow, typically from a serial port.
 *
 */

#include "..\StringSplitter\StringSplitter.h"		// for splitting Strings into sections
#include "CommandProcessor.h"	// this module's prototypes
 
/***************/
/* CONSTRUCTOR */
/***************/

CommandProcessor::CommandProcessor() {
}

/****************************/
/* PROCESS A COMMAND STRING */
/****************************/

// Pass command string in command parameter.

void CommandProcessor::Process( String command ) {
	// Transmit back command.
	Serial.print( '<' );
	Serial.print( command );
	Serial.println( '>' );
	// Split command into sections separated by commas.
	int count = StringSplitter::Split( command, ',', commandSections, maxSections );
	// Transmit sections found.
	for( int i = 0; i < count; ++i ) {
		Serial.print( i );
		Serial.print( " : <" );
		Serial.print( commandSections[ i ] );
		Serial.println( '>' );
	}
}

and here is StringSplitter.h :

/*
 * SOURCE FILE : StringSplitter.h
 *
 * Splits strings into sections.
 *
 */

#ifndef StringSplitterIncluded

#define StringSplitterIncluded

#include "WProgram.h"		// Arduino stuff - needed for String class

class StringSplitter {

public :

	/********************************/
	/* SPLIT A STRING INTO SECTIONS */
	/********************************/

	// Pass string to be split in s parameter.
	// Pass character used to separate sections in separator parameter.
	// Pass array of strings to accept sections in sections parameter.
	// Pass length of the sections array in maxSections parameter.
	// Returns number of sections extracted.
	static int Split( String s, int separator, String sections[], int maxSections );
	
};

#endif

// END of StringSplitter.h

and StringSplitter.cpp :

/*
 * SOURCE FILE : StringSplitter.cpp
 *
 * Splits strings into sections.
 *
 */

#include "StringSplitter.h"		// this module's prototypes

/********************************/
/* SPLIT A STRING INTO SECTIONS */
/********************************/

// Pass string to be split in s parameter.
// Pass character used to separate sections in separator parameter.
// Pass array of strings to accept sections in sections parameter.
// Pass length of the sections array in maxSections parameter.
// Returns number of sections extracted.
static int StringSplitter::Split( String s, int separator, String sections[], int maxSections ) {
	sections[ 0 ] = s;
	return 1;
}

Now I don't think there are any syntax errors in the code. I think it is a linking error. Any ideas?

To be honest, if I was working in any other environment I would just put all the cpp and h files in the same folder as TelescopeController.pde, but then it won't link at all, hence the proliferation of folders. Is there a better way?

Try just doing #include <StringSplitter.h>, the Arduino IDE may be changing your include paths.

By the way, it looks like you're just using it to split strings - in that case, why not use strtok?

I think I tried #include <StringSplitter.h> with no luck, but I will give it another try. However, I'm not getting an error suggesting that StringSplitter.h cannot be found, just an error saying that the Split method cannot be found.

I could use strtok, but this operates on char arrays rather than String objects and I was trying to get away from char arrays and use the String methods. It is mainly a choice of style and I prefer to do things in an object orientated way. I had hoped the String class would have a Split method to do this (much like the C# String class). Also, strtok modifies the string it is splitting (inserts zero chars). Having said that, if I can't get it to work any other way then strtok will have to do.

As far as I can tell, when you use library A from within library B, the sketch which uses library B needs to ALSO #include <A.h>. That's how Arduino knows to tell the linker to go get library A.

Brilliant! One addition of #include <StringSplitter.h> to the pde file and everything works fine. Thanks maniacbug.

Just to explain a little:

#include "xyz"

means look relative to the current directory (the one the sourcefile is in)

#include <xyz>

means look in the "system includes path" - ie where includes are deemed to live for that system. This is typically a list of directories, not just one.

So any code from a separate library - use <>, any .h file you've written, use "" (unless you are writing a library!!)

Yes. Typically when programming in C++ I use #include <stdio.h> for stuff from the standard C++ libraries or libraries from elsewhere and #include "myclass.h" for something I have written myself. But then I normally put all my source code in a single folder and if I do this in the Arduino environment it won't work. If I have understood it correctly (and I probably have not) if you want to declare a class in a separate source file you have to make it a library in a folder inside a "libraries" folder with a .h and a .cpp file. This means when using library A from inside the source code of library B you need to do #include "..\A\A.h" unless you put every single library folder you use in the system includes path and life is just too short.

Frankly, I would really like to put all my source code in one folder like I normally do but I haven't figured out a way of doing this. If I try I find that when compiling the pde file the .h files cannot be found even though they are in the same folder. If anyone has managed this please let me know how. I think you might be able to do it by writing all your code as pde files but I think that approach also has problems. I think what happens is that all the pde files (and possibly files without a suffix) are just glued together into one big source file which seems to break all the rules regarding encapsulation. I have yet to find an example program that uses more than a single (pde) source file and libraries. I really like breaking my programs down into lots of little classes all in their own source files and this seems a bit tough with Arduino.

Still, pretty impressive given the price.

You CAN put header files (.h), source files (.cpp) and sketch files (.pde/.ino) in the same directory. All files will be opened, in separate tabs.

There can be multiple sketch files in the directory, but only one can contain the setup() and loop() functions.

If you are not successful doing this, create a zip file of the collection of source files, and post it, so we can see the relative position of the files on your system.

Errm. How embarrassing. It seems to work. Not sure where I went wrong. Maybe I hadn't set the sketch folder in preferences. I also had to change some #includes in the pde file to use inverted commas rather than angle brackets, but it does work now. Thanks a lot.

Not making excuses, but most C++ compilers I have used will still search the current directory for include files even if you use angle brackets. Is there no hard-and-fast rule as to how this works?

That's because the build system told the compiler to look there with "-I." For whatever reason, the Arduino IDE chooses not to.