Using .h and .cpp files in same directory as sketch

I'm trying to figure out how to use .cpp and .h files in the same directory as my sketch, but I'm getting compile errors. I created a simple sketch with 3 files all in the same folder: Include_Lib_Test.ino, MyLib.h & MyLib.cpp. They use a button library, Button.h which is in my libraries folder

Here's the code for the 3 files

// Include_Lib_Test.ino
#include "MyLib.h"
#include <Button.h>
void setup() { }
void loop() {
  readbutton();
}
// MyLib.h
#ifndef _MYLIB_H
#define _MYLIB_H
#include <Button.h>
Button helloButton = Button(2, LOW);
void readbutton();
#endif
// MyLib.cpp
#include "MyLib.h"
void readbutton() {
  helloButton.listen();
}

I get this compile error:

MyLib.cpp.o: In function __static_initialization_and_destruction_0': MyLib.h:5: multiple definition of helloButton'
Include_Lib_Test.cpp.o:/Applications/Include_Lib_Test.ino:4: first defined here

I attached Button.h and .cpp for reference

Button.h (2.91 KB)

Button.cpp (10.2 KB)

The Arduino software scans the files for function prototyping and include files before compiling.
There is an error with that, it doesn't look at the "#ifndef", so you end up declaring "hello button" twice.

Could you try to remove the includes from all files.
Use only this in the *.ino file:

#include <Button.h>
#include "MyLib.h"

If you get an error, perhaps you have to include one more in a file.

You probably don't need to do the prototyping in the *.h file. But it's okay, so you don't have to remove it.

Please declare the helloButton in the *.ino file.
Creating a class in a *.h file could easily cause problems, I try to avoid that.

If you are making a libary, you have to include specifically what is used.

The Arduino software scans the files for function prototyping and include files before compiling.
There is an error with that, it doesn't look at the "#ifndef", so you end up declaring "hello button" twice.

Not exactly. What happens is that the .ino file is converted to a .cpp file, and compiled. That compilation unit references the header file, so an instance of the Button class is created.

Then, the source file is compiled. It references the header file, so another instance of the Button class is created.

Then, the two compilation units are linked, and there are two instances of the Button class.

Your solution is correct, though the reason for the correction being needed is wrong. Creating is the wrong word to use. Defining a class in a header file is necessary. Instancing it in a header file is not good.

Thanks for the clarification.

Variables should be defined in .cpp files. The definition means, in effect: allocate some memory to hold a Button, name it helloButton and initialise it to this value ...

Button helloButton = Button(2, LOW);

If you need to access a variable from other files, you should add an external declaration in a header file and include that wherever you need to access it. The external declaration means, in effect: the symbol helloButton refers to a Button which is defined in some other file ...

extern Button helloButton;

In this case you don't refer to helloButton from outside MyLib.cpp so you don't actually need the external declaration.

PeterH:
Variables should be defined in .cpp files. The definition means, in effect: allocate some memory to hold a Button, name it helloButton and initialise it to this value ...

Button helloButton = Button(2, LOW);

If you need to access a variable from other files, you should add an external declaration in a header file and include that wherever you need to access it. The external declaration means, in effect: the symbol helloButton refers to a Button which is defined in some other file ...

extern Button helloButton;

In this case you don't refer to helloButton from outside MyLib.cpp so you don't actually need the external declaration.

That's a big help. Because I moved

Button helloButton = Button(2, LOW);

to the .ino file per the previous suggestion. But I got this compile error:
MyLip.cpp: In function 'void readbutton()':
MyLip.cpp:5: error: 'helloButton' was not declared in this scope

So if I add to MyLip.cpp this:

extern Button helloButton;

Then it compiles fine.