Двойное подключение h файла

Есть сторонняя библиотека IRRemote для Arduino с таким заголовочным файлом IRremote.h

#ifndef IRremote_h
#define IRremote_h
.........
#include "IRremoteInt.h"

/*
 * Include the sources here to enable compilation with macro values set by user program.
 */
#include "irReceive.cpp.h"
#include "irSend.cpp.h"
#include "IRremote.cpp.h"

#endif // IRremote_h

#pragma once

В irReceive.cpp.h есть такой код

IRrecv IrReceiver;

IRrecv::IRrecv() {
    irparams.recvpin = 0;  // 44 строка
    irparams.blinkflag = false;
}

Теперь использование.

В своем main.cpp пишу

#include <IRremote.h>

#include "Controller.h"

......

Все компилируется без ошибок. Но если я в Controller.h тоже добавлю инклуд

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <IRremote.h>
#include "Settings.h"

class Controller {
.....
}

#endif //CONTROLLER_H

То получаю каскад ошибок линковки

CMakeFiles\Controller.dir\src\main.cpp.obj: In function IRrecv::IRrecv():
C:\PROGRA~2\Arduino\LIBRAR~1\IRremote\src/irReceive.cpp.h:44: multiple definition of IRrecv::IRrecv()
CMakeFiles\Controller.dir\src\Controller.cpp.obj:C:\PROGRA~2\Arduino\LIBRAR~1\IRremote\src/irReceive.cpp.h:44: first defined here
.........
CMakeFiles\Controller.dir\src\controller.cpp.obj: In function IRrecv::IRrecv():
C:\PROGRA~2\Arduino\LIBRAR~1\IRremote\src/irReceive.cpp.h:44: multiple definition of IRrecv::decode()
CMakeFiles\Controller.dir\src\AirConditionController.cpp.obj:C:\PROGRA~2\Arduino\LIBRAR~1\IRremote\src/irReceive.cpp.h:44: first defined here

Ошибок очень много, но все они ссылаются на одно место irReceive.cpp.h:44

Controller.h также инклудится в файл Controller.cpp, где находится реализация класса Controller

Как с этим бороться и откуда возникает эта ошибка? Ведь IRremote.h содержит include guard. Да, include guard не содержит файл irReceive.cpp.h, но он инклудится в одном месте в IRremote.h


Ответы (2 шт):

Автор решения: Harry

Вот этот код, о котором вы пишете -

IRrecv IrReceiver;

IRrecv::IRrecv() {
    irparams.recvpin = 0;  // 44 строка
    irparams.blinkflag = false;
}

оказавшись дважды в разных .cpp-файлах, приводит к появлению объекта IrReceiver и конструктора в двух файлах. Линковщик не знает, какой выбрать.

Если у вас С++ не очень старый - вас спасет просто добавление слова inline перед каждым из них.

Если старый - то лучше не заморачиваться, а перенести это все в отдельный .cpp-файл в проекте. Это самое разумное решение - чтобы каждый занимался своим делом: заголовочный файл содержал заголовки-объявления, а файл реализации - содержал реализацию.

→ Ссылка
Автор решения: Anton Shchyrov

Оформил я баг-репорт. Если кто еще столкнется с этим багом в этой библиотеке, а баг все еще не закроют, то есть такой обходной путь:

  1. Вместо IRremote.h нужно везде инклудить IRremoteInt.h. В этом файле описаны все описания классов.
  2. Ровно в одном cpp файле проекта пишем #include <IRremote.h>. Тогда реализация подтягивается только один раз и проект компилируется.
→ Ссылка