Я пытаюсь перекомпилировать проект, который имеет две зависимости: Qt и X11.
X11 определяют следующие символы в глобальном пространстве имен:
// Xlib.h
#define Bool int
#define Status int
#define True 1
#define False 0
// X.h
#define None 0L
Однако эти символы (а может и больше) также используются в Qt (например, в перечислениях). Как мы видим в qcoreevent.h:
enum Type {
/*
If you get a strange compiler error on the line with None,
it's probably because you're also including X11 headers,
which #define the symbol None. Put the X11 includes after
the Qt includes to solve this problem.
*/
None = 0,
...
Решение, предоставляемое Qt, простое: наконец, включите X11. Но у меня возникла проблема со следующей ситуацией:
Файл1.hpp
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
Файл2.hpp
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h> // Ok, X11 is included after Qt
... some classes ...
Но тогда некоторые файлы выглядят так:
Файл3.hpp
#include "File1.hpp"
#include "File2.hpp"
Итак, в какой-то момент во время предварительной обработки я предполагаю, что он преобразуется в
// #include "File1.hpp" ->
#include <SomeQtHeader.h>
#include <SomeX11Header.h> // X11 ends up included before Qt
// #include "File2.hpp" ->
#include <SomeOtherQtHeader.h>
#include <SomeX11Header.h>
Я думал об использовании упреждающего объявления, но некоторые структуры и классы не используются в качестве указателей, и многие из них даже имеют typedef, поэтому я в конечном итоге объявляю исходную внутреннюю структуру, которую пользователь не должен использовать, и в целом это большой беспорядок.
Как я должен эффективно решать эту проблему, не злоупотребляя предварительным объявлением и использованием указателей?
Решение этой проблемы, скорее всего, проходит через исправление debB.h
, поэтому не требует определенного порядка включения. Для получения дополнительной помощи объясните более подробно, что в этом заголовке приводит к зависимости заказа.
У вас есть два варианта: обернуть зависимости вашим кодом (таким образом, обе зависимости никогда не сойдутся в единице перевода) или предоставить подробности, чтобы мы могли помочь вам решить проблему, вызванную одной из зависимостей. Например, у меня была проблема с библиотекой fmt
в macOS (коллизия макросов с определением функции), и я нашел хороший обходной путь.
Чтобы дать более подробную информацию: depA в моем случае — это Qt, а depB — это X11. Похоже, что X11 переопределяет некоторые символы, такие как None, которые вызывают проблемы в qcoreevent.h. Разработчики Qt знают, и в комментарии говорится, что нужно включать заголовки, связанные с X11, после всех заголовков Qt, однако проект, который я пытаюсь перекомпилировать, везде смешивает заголовки Qt и X11.
@IgorTandetnik depB вот X11, к сожалению, я не уверен, что смогу исправить это сам. Он переопределяет такие символы, как None, в глобальном пространстве имен.
Используйте #pragma once
в начале каждого файла, чтобы избежать дублирования файлов заголовков. Подробнее читайте это
Xlib.h содержит следующие строки: #define Bool int, #define Status int, #define True 1, #define False 0. Я предполагаю, что он предназначен для библиотеки C. Это символы, которые вызывают проблемы.
@GHOSTHUNT проблема не в этом. Проблема в порядке включения. Здесь ничего не включается больше одного раза (вторая #include <debB.h>
ничего не даст).
это xy проблема. X имеет дело с порядком включения (что не является хорошим решением), в то время как реальная проблема заключается в наличии некоторых странных макросов. Лучше объясните свою настоящую проблему.
@largest_prime_is_463035818 Спасибо, вы правы. Уточню в исходном посте.
о, я только что понял, что у вас уже есть эта информация в вопросе, но она теряется в остальном. Я понял, с чем вы имеете дело, только прочитав ваши комментарии....
Вы должны иметь дело со злыми МАКРОСами, вы можете обернуть библиотеку X11 во что-то вроде
// X11wrapper.h
#ifndef X11Wrapper_H
#define X11Wrapper_H
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#endif
и используйте этот заголовок оболочки вместо официального.
Спасибо, это самый чистый и быстрый способ решения моих проблем! Мне пришлось добавить и другие undef, я опубликую их в отдельном ответе.
После ответа @Jarod42, вот моя полная оболочка со всеми определениями, которые мне пришлось отменить и правильно переопределить, в том порядке, в котором они появились в журнале ошибок компилятора:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
#include <X11/Xlib.h>
#undef None
constexpr auto None = 0L;
#undef KeyPress
constexpr auto KeyPress = 2;
#undef KeyRelease
constexpr auto KeyRelease = 2;
#undef FocusIn
constexpr auto FocusIn = 9;
#undef FocusOut
constexpr auto FocusOut = 10;
#undef FontChange
constexpr auto FontChange = 255;
#undef Expose
constexpr auto Expose = 12;
#undef False
constexpr auto False = 0;
#undef True
constexpr auto True = 1;
#undef Status
typedef int Status;
#undef Unsorted
constexpr auto Unsorted = 0;
#undef Bool
typedef int Bool;
#endif // WRAPPER_HPP
Вы решаете не ту проблему, избавьтесь от зависимости порядка в своих включениях. Возможно, это требует абстрагирования некоторых общих символов в общую библиотеку/ресурс.