Allow generating deprecated header files cross-module

If some header files were moved to another module within same repo it
makes sense to allow deprecating them. 'syncqt' now is able to detect
this kind of header files if the 'foreign' module is specified in
qt_deprecates pragma as part of the deprecated header name.

Pick-to: 6.5 6.6
Task-number: QTBUG-116483
Change-Id: I479ea60e71de112b67c281722600cd818aac7762
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Alexey Edelev 2023-08-25 18:57:52 +02:00
parent ac8fe3e645
commit 7e84a04563

View File

@ -738,7 +738,16 @@ public:
std::filesystem::recursive_directory_iterator(outputDirectory)) {
if (m_producedHeaders.find(entry.path().filename().generic_string())
== m_producedHeaders.end()) {
std::filesystem::remove(entry.path());
// Check if header file came from another module as result of the cross-module
// deprecation before removing it.
std::ifstream input(entry.path(), std::ifstream::in);
std::string firstLine;
std::getline(input, firstLine);
if (firstLine.find("#ifndef DEPRECATED_HEADER_"
+ m_commandLineArgs->moduleName())
== 0
|| firstLine.find("#ifndef DEPRECATED_HEADER_") != 0)
std::filesystem::remove(entry.path());
}
}
}
@ -1050,12 +1059,14 @@ public:
// - 'qt_class(<symbol>)' manually declares the 'symbol' that should be used to generate
// the CaMeL case header alias.
//
// - 'qt_deprecates(<deprecated header file>[,<major.minor>])' indicates that this header
// file replaces the 'deprecated header file'. syncqt will create the deprecated header
// file' with the special deprecation content. Pragma optionally accepts the Qt version
// where file should be removed. If the current Qt version is higher than the
// deprecation version, syncqt displays deprecation warning and skips generating the
// deprecated header.
// - 'qt_deprecates([module/]<deprecated header file>[,<major.minor>])' indicates that
// this header file replaces the 'deprecated header file'. syncqt will create the
// deprecated header file' with the special deprecation content. Pragma optionally
// accepts the Qt version where file should be removed. If the current Qt version is
// higher than the deprecation version, syncqt displays deprecation warning and skips
// generating the deprecated header. If the module is specified and is different from
// the one this header file belongs to, syncqt attempts to generate header files
// for the specified module. Cross-module deprecation only works within the same repo.
// See the 'generateDeprecatedHeaders' function for details.
//
// - 'qt_no_master_include' indicates that syncqt should avoid including this header
@ -1493,7 +1504,7 @@ public:
const std::string &replacement = it->second;
const auto separatorPos = descriptor.find(',');
std::string headerName = descriptor.substr(0, separatorPos);
std::string headerPath = descriptor.substr(0, separatorPos);
std::string versionDisclaimer;
if (separatorPos != std::string::npos) {
std::string version = descriptor.substr(separatorPos + 1);
@ -1503,7 +1514,7 @@ public:
if (!utils::parseVersion(version, major, minor)) {
std::cerr << ErrorMessagePreamble
<< "Invalid version format specified for the deprecated header file "
<< headerName << ": '" << version
<< headerPath << ": '" << version
<< "'. Expected format: 'major.minor'.\n";
result = false;
continue;
@ -1511,7 +1522,7 @@ public:
if (QT_VERSION_MAJOR > major
|| (QT_VERSION_MAJOR == major && QT_VERSION_MINOR >= minor)) {
std::cerr << WarningMessagePreamble << headerName
std::cerr << WarningMessagePreamble << headerPath
<< " is marked as deprecated and will not be generated in Qt "
<< QT_VERSION_STR
<< ". The respective qt_deprecates pragma needs to be removed.\n";
@ -1519,12 +1530,21 @@ public:
}
}
const auto moduleSeparatorPos = headerPath.find('/');
std::string headerName = moduleSeparatorPos != std::string::npos
? headerPath.substr(moduleSeparatorPos + 1)
: headerPath;
const std::string moduleName = moduleSeparatorPos != std::string::npos
? headerPath.substr(0, moduleSeparatorPos)
: m_commandLineArgs->moduleName();
bool isCrossModuleDeprecation = moduleName != m_commandLineArgs->moduleName();
std::string qualifiedHeaderName =
std::regex_replace(headerName, cIdentifierSymbolsRegex, "_");
std::string guard = guard_base + "_" + qualifiedHeaderName;
std::string warningText = "Header <" + m_commandLineArgs->moduleName() + "/"
+ headerName + "> is deprecated" + versionDisclaimer + ". Please include <"
+ replacement + "> instead.";
std::string warningText = "Header <" + moduleName + "/" + headerName + "> is deprecated"
+ versionDisclaimer + ". Please include <" + replacement + "> instead.";
std::stringstream buffer;
buffer << "#ifndef " << guard << "\n"
<< "#define " << guard << "\n"
@ -1535,7 +1555,15 @@ public:
<< "#endif\n"
<< "#include <" << replacement << ">\n"
<< "#endif\n";
writeIfDifferent(m_commandLineArgs->includeDir() + '/' + headerName, buffer.str());
const std::string outputDir = isCrossModuleDeprecation
? m_commandLineArgs->includeDir() + "/../" + moduleName
: m_commandLineArgs->includeDir();
writeIfDifferent(outputDir + '/' + headerName, buffer.str());
// Add header file to staging installation directory for cross-module deprecation case.
if (isCrossModuleDeprecation)
writeIfDifferent(outputDir + "/.syncqt_staging/" + headerName, buffer.str());
m_producedHeaders.insert(headerName);
}
return result;