Problem with using .h file

Hello All,

Sorry for writing in “Bad” English, I’m living in the Flemish speaking part of Belgium :wink:

I have a problem using a dot h file, I want to create clean, readable code using different cpp an h files.
Problem is that I have to use the “compass” and “tft” variables in different cpp files (in the example below in SetupAll.cpp and main.cpp)

My simplified test code:
8<------------------------------------------------------------

// main.cpp
#include <Arduino.h>
#include "SetupAll.h"

void setup(){
  setupDebug();       // Serialport for debugging
  setupCompass();  // Setup the Compass
  setupTFT();           // Setup the TFT Screen
}

void loop(){
  // Read compass values
  compass.read();

  // Draw something on the TFT Screen 
  tft.drawChar(65,10,10);

  delay(500);
}

8<------------------------------------------------------------

// SetupAll.h

#pragma once

#include <Arduino.h>
#include <TFT_eSPI.h>
#include <QMC5883LCompass.h>

// Instantiations
QMC5883LCompass compass;   // compass
TFT_eSPI tft = TFT_eSPI();         // tft

void setupDebug();      // Serialport for debugging
void setupCompass();  // Setup the Compass
void setupTFT();           // Setup the TFT Screen

8<------------------------------------------------------------

//SetupAll.cpp

#include "SetupAll.h"

void setupDebug(){
  Serial.begin(115200);
}

void setupCompass(){
  compass.init();
}

void setupTFT(){
  tft.init();
  tft.setRotation(0);
}

8<------------------------------------------------------------

I’m getting multiple definition of compass' and multiple definition of tft’ in the linker
I tried making the Instantiations “extern” but then I get “undefined” errors.

Can somebody point me in the right direction?

When learning C++/Arduino I skipped the whole part of dealing with those kind of issues.

My approach is:

  1. Do NOT make global vars. I only have one, no more. And I could get rid of it with Singleton (anti)pattern, but that would also be a global, just hidden, so I skip it.
  2. OOP. Other files contain classes. Classes are just functions with their encapsulated data → great, no need for globals to exchange state between functions – just use the state within the class :wink: Example.
  3. App class is the “glue” for everything. It contains no logic. Just initialization of objects and throwing them into The Arduino Loop. My goal is to have something looking like a “dependency injection container”. Will work on that, I’m not entirely satisfied with the design yet. Anyway, the point is: do NOT make globals, declare all app state in one isolated place.
  4. [optional] Skip the CPP files – use just header files :smiley: No globals, no problem :smiley: You think it makes build times longer? Hey, it is so effin long anyway, who cares? :smiley:

Are you familiar with the ‘extern’ keyword? If not, this is probably what you are looking for. You declare it suing ‘extern’ in the .h file and define in one of the .c files with no ‘extern’.

Do not instantiate variables in the header files, they must only appear as extern here to inform the linker they exist. You instantiate the variable in one .cpp file.

So if you change above to

// Declarations
extern QMC5883LCompass compass;   // compass
extern TFT_eSPI tft;  // tft

and add the original snippet above in main.cpp as

// main.cpp
#include <Arduino.h>
#include "SetupAll.h"

// Instantiations
QMC5883LCompass compass;   // compass
TFT_eSPI tft = TFT_eSPI();         // tft

the error should be resolved.

Hello All,

Thanks for the help.

After digging a bit deeper in how instantiation does work and exploring the exact purpose of “extern”, I came to the same, error free, result as "maxgerhardt’s solution.

I’m always struggling with the concept of instantiations and classes, also the “user defined variable type” is something “strange” to me.

But no problem, I’m only 62, so still got a lot of years to learn :wink:

Thanks again,
Michel

You also need to understand the usage of extern.