Arduino IDE and header files Getting Multiple Definitions

I am trying to compile a sketch with a main.ino and several .cpp files. I clearly don't understand the rules. I have this header file mqtt.h with guards that is included in main.ino because it has two function prototypes I need there and in mqtt.cpp.

IN writing this and researching the posts I may have actually understood something new. Am I understanding this correctly that if I have my main.ino and maybe some other .ino's and several .cpp files that each .cpp will be compiled separately and all the code in the .ino files will be combined into one file and compiled. So any guard #defines are reset for each .cpp file compiled.

I posted the code below incase I am wrong but I think I understand the problem if what I said above is true.

What is the advantage of having .cpp and .h files over .ino and .h files?

#pragma once
#ifndef _MQTT_H
#define _MQTT_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClient.h>
WiFiClient        wifiClient;                                     // 
#include <ArduinoJson.h>

#include "esp_task_wdt.h"
#include <MQTT.h>                                                 // https://github.com/256dpi/arduino-mqtt
#include <time.h>

#include <ArduinoJson.h>
#include <ArduinoTimer.h>                                         // https://www.megunolink.com/documentation/arduino-libraries/arduino-timer/
#include <ESPmDNS.h>
#include <WiFiUdp.h>
                                   

#define MQTT_HOST "threadripper"                                  // Host running MQTT
#define DEFAULT_HOST "192.168.1.15"                               // host for to use if resolve host fails

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static MQTTClient mqttClient(1024);                               // create the mqttClient
String clientId;                                                  // save ClientID

bool      StarUpdate = false;                                     // MQTT Star indi-allsky message received
bool      MQTTwebReConnect = false;                               // flag to process reconnect outside of messageReceived
uint64_t  millisecondsSinceEpochLastPoint;                        // milliseconds since the time epoch of last pint in buffer
bool      publish_ok;                                             // publish any error 

String MQTT_HostIP = "";                                          // place to save ip after resolution  

static String lastLogText;                                        // error log message 
static String lastErrorText;                                      // last error message

bool serviceMQTT(void);                                           // function prototype
void parseWeatherJSON(DynamicJsonDocument& jsonDoc);              // function prototype
bool MQTTsetup(void);                                             // function prototype

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The String Literal jsonMQTTConfigurationString defines the mapping from JSON key-value pairs in the MQTT Broker Supplied JSON
// to the values used in the ASCOM/Alpaca Observing Conditions Monitor.
// the JSON key in String Literal jsonMQTTConfigurationString is the value that will be parsed from the incomming JSON. You are free to change this.
// This JSON can also be dynamically changed by publishing a JSON.
// the JSON value in this literal is the target value in the ASCOM/Alpaca Observing Conditions Monitor this value is hardcoded in the parser parseWeatherJSON
// and cannot be changed it is used in this manner:
// sensorPtr->temperature => "temperature"
// sensorPtr->sky_temperature => "uranus_sky_temperature"
// ...and so on for each mapping

// The JSON object supplied from the MQTT topic containing either weather information or jsonMQTTConfigurationString key-values may contain one or more key-value pairs
// The jsonMQTTConfigurationString key-values are parsed first and any modifications to the mapping will be applied to weather information key-values pairs regardless of their order
// in the JSON Object

const char* jsonMQTTConfigurationString = R"({
    "temperature": "temperature_value",                       
    "uranus_sky_temperature": "sky_temperature_value",        
    "uranus_pressure": "pressure_value",                      
    "uranus_relative_pressure": "sl_pressure_value",          
    "humidity": "rh_value",                                   
    "precipitation": "rain_intensity_value",                  
    "wind_speed": "wind_speed_value",                         
    "wind_direction": "wind_direction_value",                 
    "wind_gust": "wind_gust_value",                           
    "illuminance": "lux_value",                               
    "uranus_SQM": "msas_value",                               
    "uranus_nelm": "nelm_value",                              
    "uranus_cloud_coverage": "cloud_cover_value",              
    "uranus_dew_point": "dew_point_value",                     
    "wind_speed_average": "averagewindspeed120s",             
    "PARK": "park",                                           
    "ROOFOPEN": "ROOFOPEN",                                   
    "RAIN": "RG11rain",                                       
    "PWRFAIL": "pwrfail",                                     
    "BATTERYOK": "battery_ok",                                
    "openweathermap_cloud_coverage": "openweathercloudcover",  
    "openweathermap_visibility": "openweathermap_visibility",  
    "lightning_average_distance": "lightning_average_distance",
    "precipitation_type": "precipitation_type",                
    "wind_chill": "windchillfactor"                            
})"; 

#endif

I am encountering these errors:

/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:34: multiple definition of `MQTT_HostIP'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:34: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:27: multiple definition of `clientId'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:27: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:32: multiple definition of `publish_ok'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:32: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:8: multiple definition of `wifiClient'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:8: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:58: multiple definition of `jsonMQTTConfigurationString'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:58: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:31: multiple definition of `millisecondsSinceEpochLastPoint'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:31: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:30: multiple definition of `MQTTwebReConnect'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:30: first defined here
c:/users/kurt/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(mqtt.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:29: multiple definition of `StarUpdate'; C:\Users\Kurt\AppData\Local\Temp\arduino\sketches\8462C14A1194FE792B98DC3BBB3A585A\sketch\objs.a(Alpaca_MQTT_copy_20240105112310_adding-MQTT.ino.cpp.o):C:\Users\Kurt\Documents\Arduino\Alpaca_MQTT_copy_20240105112310_adding-MQTT/mqtt.h:29: first defined here
collect2.exe: error: ld returned 1 exit status

Kurt

You should not have variable definitions (nor function implementations) in the .h file. Otherwise you'll encounter exactly these errors. The .h file should only contain variable extern declarations, function prototypes, class declarations, templates, etc. See My Post #5 in this Thread for a basic guide to breaking up large projects into separate .h / .cpp files.

Thanks this is helpful. One other question. I ran into an issue where the IDE did not know what a uint16_t was and I needed to include <stdint.h>. How does this happen?

<stdint.h>, along with many other definitions, gets included through Arduino.h. When compiling a .ino file, Arduino.h is included automatically. That's not the case for a .cpp file. So the easiest thing to do is to put '#include <Arduino.h>' where the .cpp can see it. That could be in a .h or the .cpp itself.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.