Приветствую. Уже голову сломал, перепробовал все варианты, но так и не нашел решения. Проект для ESP32 в Visual Studio Code. Проект собирается без ошибок, но директивы препроцессора работают некорректно. Прошу помощи. Начало main.cpp. Перед включением заголовков библиотеки BMP280.h создаю два макроопределения PIN_I2C_SDA и PIN_I2C_SCL для переопределения пинов шины I2C Код (C++): #include <Arduino.h> #define PIN_I2C_SDA 22 #define PIN_I2C_SCL 23 #include "../lib/BMP280/BMP280.h" В BMP280.h делаю проверку макроопределений PIN_I2C_SDA и PIN_I2C_SCL. Если они не определены, то определяю их -1 (для wire.begin() это признак использования стандартного пина). Код (C++): #ifndef PIN_I2C_SDA #define PIN_I2C_SDA -1 #endif #ifndef PIN_I2C_SCL #define PIN_I2C_SCL -1 #endif При этом среда разработки подсказывает, что макроопределения присутствуют и #define затемнены. это последние строки BMP280.h И вот начало BMP280.cpp Код (C++): #include "BMP280.h" bool BMP280::init(void) { Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); if(bmp280Read8(BMP280_REG_CHIPID) != 0x58) return false; ........ И вот здесь вот PIN_I2C_SDA и PIN_I2C_SCL имеют значения -1 И, соответственно, шина работает на дефолтных пинах. Реально работает. Какого черта??? Запись Wire.begin(22, 23); Переназначает пины, и тоже все работает нормально. Но хочется сделать библиотеку в которую лазать для переназначения шины не нужно. Что я делаю не так, почему в BMP280.h и BMP280.cpp значения макроопределений разные? И еще немного информации. Если в BMP280.h сделаю полное комментирование проверки определений. Код (C++): //#ifndef PIN_I2C_SDA // #define PIN_I2C_SDA -1 //#endif //#ifndef PIN_I2C_SCL // #define PIN_I2C_SCL -1 //#endif , то компилятор выдает ошибку Код (C++): Compiling .pio\build\nodemcu-32s\lib406\BMP280\BMP280.cpp.o lib\BMP280\BMP280.cpp: In member function 'bool BMP280::init()': lib\BMP280\BMP280.cpp:6:14: error: 'PIN_I2C_SDA' was not declared in this scope Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); ^ lib\BMP280\BMP280.cpp:6:27: error: 'PIN_I2C_SCL' was not declared in this scope Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); ^ *** [.pio\build\nodemcu-32s\lib406\BMP280\BMP280.cpp.o] Error 1 И кросс-референс по макроопределениям Я догадываюсь из-за чего это происходит. (библиотека компилится до компиляции кода программы и на момент сборки библиотеки макроопределений нет). Но как выйти из этой ситуации???
Всё правильно, так и должно быть. Что именно тебя смущает? Ты ведь свои определения вставил в основном файле. А в файле BMP280.cpp ты их не вставлял. Так откуда им там взяться? Прости, я просто не понял проблемы.
вставить свои дефайны не в скетч, а в файл BMP280.h нет, не поэтому. Определения в коде и в библиотеке независимы друг от друга. Подгружается только то, что явно указано во включаемых файлах. Поэтому не важно в каком порядке компилится скетч и библиотеки, определения из скетча все равно в библиотеку не попадут, если их непосредственно туда не вставить
Но они есть в BMP280.h Да, я уже понял в чем ошибка. Меня ввела в заблуждение одна из статей и я повелся. Если найду дам ссылку. Буду переписывать либу с параметрами для функции.
Ты просто запутался. Давай-ка я расскажу тебе, как на самом деле устроена эта жизнь. Тебе нужно твёрдо знать две вещи: №1. Каждый файл «.cpp» («.c», «.ino» и т.п.) компилируется сам по себе, независимо от других. Компилятор вообще не знает ничего о других файлах. Их можно компилировать в любом порядке. В одно целое код собирается позже, и этим занимается не компилятор, а компоновщик. Итак, запомни, каждый файл компилируется сам по себе и ничего не знает о других. №2. Директива #include означает «вставить в это место содержимое указанного файла». Всё. Больше никакой мистики. Это ровно тоже самое, как вставить это содержимое туда руками. А теперь, когда ты это знаешь, проанализируй свою ситуацию и ты легко поймёшь, что всё у тебя работает правильно. Если ты вставил свои определения в .ino файле, то они коснуться только включения .h файла в этот .ino, и никаким боком не коснутся включения в другом .cpp файле.
это другие дефайны, хоть и называются так же. У дефайнов также есть область видимости, как и у переменных вас же не удивляет, что две переменные int a, описанные в разных функциях - независимы друг от друга?
в описанном случае этого будет недостаточно, автор хочет внедрить свои определения в чужую библиотеку,
Не вариант. Задача стоит сделать библиотечный класс, вообще не зависящий от прикладной задачи, не требующий изменений внутри библиотечных файлов и храниться на Git. И что будет выдавать компилятор, если в библиотеку будет включен неизвестный *.h-файл. Все верно, хочу сделать ее более функциональной. Если в BMP280.cpp есть #include BMP280.h и где дифы прописаны, то это будут одни и те же дифы. Со второй частью полностью согласен. Если файлы входят в дерево сборки и имеют наследования, то знает. main.h Код (C++): #define PIN_I2C_SDA 22 #define PIN_I2C_SCL 23 BMP280.h Код (C++): #include main.h #ifndef PIN_I2C_SDA #define PIN_I2C_SDA -1 #endif #ifndef PIN_I2C_SCL #define PIN_I2C_SCL -1 #endif BMP280.ccp Код (C++): #include "BMP280.h" bool BMP280::init(void) { Wire.begin(PIN_I2C_SDA, PIN_I2C_SCL); } Будет работать правильно, и сборка BMP280.ccp будет зависеть от макроопределений в main.h. Но как я сказал выше это не вариант
Почему неизвестный? Вариантов, когда Настройки выносятся в отдельный файл, полно. Компилятор ничего не скажет - он включит этот файл везде, где есть на него инклюды. У меня был случай, когда дефайны первого файла ссылались на инклюды второго файла, а те на первый. Получался замкнутый круг. Без стороннего файла эту задачу не решить в принципе.
Переделал под параметры функции инициализации. Осталась проблема монопольного занятия шины I2C, но это уже совсем другая история, и направление в котором копать так же понятно. Закрыто.
Если не смущают накладные расходы на дополнительные вызовы (например для получения параметров), можете использовать в библиотеке "слабые" функции, а в конкретном проекте реализовать эти функции. Т.о. библиотека будет использовать реализацию из проекта если она есть, если её нет, использовать свои "слабые" функции, и никаких дефайнов и инклюдов зависимых от проекта.
Может проще пронаследоваться от класса библиотеки и заменить что нужно? Тогда хоть от обновления библиотек зависеть не будешь.
проще - но редко получается. Чаще всего как раз те переменные и методы. что хочется подправить - описаны как приватные.