qmlls: add option to disable cmake-calls

Add option to disable cmake calls via commandline arguments, environment
variable and settings file.
Also fix the qmlls.ini generation script to include a line with
no-cmake-calls=false.

Picking back to 6.7 because the cmake call feature introduced in 6.7
might break stuff, so it should be easily disableable.

Fixes: QTBUG-119953
Fixes: QTBUG-119565
Change-Id: Ic3f2e369172aef430c52a98c1713e46b598a4f21
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
(cherry picked from commit d976ddc5b1)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Sami Shalayel 2023-11-15 17:53:44 +01:00
parent 7ef31a5763
commit 2f4b7e8f8a
5 changed files with 62 additions and 16 deletions

View File

@ -763,7 +763,7 @@ function(_qt_internal_write_deferred_qmlls_ini_file)
# cmake list separator and windows path separator are both ';', so no replacement needed
set(concatenated_build_dirs "${_qmlls_ini_build_folders}")
endif()
set(file_content "[General]\nbuildDir=${concatenated_build_dirs}\n")
set(file_content "[General]\nbuildDir=${concatenated_build_dirs}\nno-cmake-calls=false\n")
file(CONFIGURE OUTPUT "${qmlls_ini_file}" CONTENT "${file_content}")
endfunction()

View File

@ -90,8 +90,17 @@ QQmlCodeModel::QQmlCodeModel(QObject *parent, QQmlToolingSettings *settings)
DomEnvironment::Option::SingleThreaded)),
m_settings(settings)
{
QObject::connect(&m_cppFileWatcher, &QFileSystemWatcher::fileChanged, this,
&QQmlCodeModel::onCppFileChanged);
}
/*!
\internal
Disable the functionality that uses CMake, and remove the already watched paths if there are some.
*/
void QQmlCodeModel::disableCMakeCalls()
{
m_cmakeStatus = DoesNotHaveCMake;
m_cppFileWatcher.removePaths(m_cppFileWatcher.files());
QObject::disconnect(&m_cppFileWatcher, &QFileSystemWatcher::fileChanged, nullptr, nullptr);
}
QQmlCodeModel::~QQmlCodeModel()
@ -419,17 +428,34 @@ void QQmlCodeModel::openUpdateEnd()
/*!
\internal
Test for CMake on the current system, and save result in m_cmakeStatus.
Performs initialization for m_cmakeStatus, including testing for CMake on the current system.
*/
QQmlCodeModel::CMakeStatus QQmlCodeModel::testCMakeStatus()
void QQmlCodeModel::initializeCMakeStatus(const QString &pathForSettings)
{
if (m_settings) {
const QString cmakeCalls = u"no-cmake-calls"_s;
m_settings->search(pathForSettings);
if (m_settings->isSet(cmakeCalls) && m_settings->value(cmakeCalls).toBool()) {
qWarning() << "Disabling CMake calls via .qmlls.ini setting.";
m_cmakeStatus = DoesNotHaveCMake;
return;
}
}
QProcess process;
process.setProgram(u"cmake"_s);
process.setArguments({ u"--version"_s });
process.start();
process.waitForFinished();
m_cmakeStatus = process.exitCode() == 0 ? HasCMake : DoesNotHaveCMake;
return m_cmakeStatus;
if (m_cmakeStatus == DoesNotHaveCMake) {
qWarning() << "Disabling CMake calls because CMake was not found.";
return;
}
QObject::connect(&m_cppFileWatcher, &QFileSystemWatcher::fileChanged, this,
&QQmlCodeModel::onCppFileChanged);
}
/*!
@ -547,13 +573,14 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &url, int version, const
{
qCDebug(codeModelLog) << "updating doc" << url << "to version" << version << "("
<< docText.size() << "chars)";
const QString fPath = url2Path(url, UrlLookup::ForceLookup);
if (m_cmakeStatus == RequiresInitialization)
initializeCMakeStatus(fPath);
DomItem newCurrent = m_currentEnv.makeCopy(DomItem::CopyOption::EnvConnected).item();
QStringList loadPaths = buildPathsForFileUrl(url);
if (m_cmakeStatus == ToTest) {
m_cmakeStatus = testCMakeStatus();
}
if (m_cmakeStatus == HasCMake && !loadPaths.isEmpty() && m_rebuildRequired) {
callCMakeBuild(loadPaths);
m_rebuildRequired = false;
@ -563,7 +590,6 @@ void QQmlCodeModel::newDocForOpenFile(const QByteArray &url, int version, const
if (std::shared_ptr<DomEnvironment> newCurrentPtr = newCurrent.ownerAs<DomEnvironment>()) {
newCurrentPtr->setLoadPaths(loadPaths);
}
QString fPath = url2Path(url, UrlLookup::ForceLookup);
Path p;
DomCreationOptions options;
options.setFlag(DomCreationOption::WithScriptExpressions);

View File

@ -104,6 +104,7 @@ public:
QQmlToolingSettings *settings();
QStringList findFilePathsFromFileNames(const QStringList &fileNames) const;
static QStringList fileNamesToWatch(const QQmlJS::Dom::DomItem &qmlFile);
void disableCMakeCalls();
Q_SIGNALS:
void updatedSnapshot(const QByteArray &url);
private:
@ -122,8 +123,8 @@ private:
static bool callCMakeBuild(const QStringList &buildPaths);
void addFileWatches(const QQmlJS::Dom::DomItem &qmlFile);
enum CMakeStatus { ToTest, HasCMake, DoesNotHaveCMake };
CMakeStatus testCMakeStatus();
enum CMakeStatus { RequiresInitialization, HasCMake, DoesNotHaveCMake };
void initializeCMakeStatus(const QString &);
mutable QMutex m_mutex;
State m_state = State::Running;
@ -145,7 +146,7 @@ private:
QQmlToolingSettings *m_settings;
QFileSystemWatcher m_cppFileWatcher;
bool m_rebuildRequired = true; // always trigger a rebuild on start
CMakeStatus m_cmakeStatus = ToTest;
CMakeStatus m_cmakeStatus = RequiresInitialization;
private slots:
void onCppFileChanged(const QString &);
};

View File

@ -41,7 +41,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
auto secondFolder = QDir(build.absolutePath().append(u"/qml/hello/subfolders"_s));
QVERIFY(secondFolder.exists());
QCOMPARE(fileContent,
u"[General]\nbuildDir=%1%2%3\n"_s.arg(build.absolutePath(), QDir::listSeparator(),
u"[General]\nbuildDir=%1%2%3\nno-cmake-calls=false\n"_s.arg(build.absolutePath(), QDir::listSeparator(),
secondFolder.absolutePath()));
}
@ -54,7 +54,7 @@ void tst_generate_qmlls_ini::qmllsIniAreCorrect()
QVERIFY(file.open(QFile::ReadOnly | QFile::Text));
const auto fileContent = QString::fromUtf8(file.readAll());
QCOMPARE(fileContent,
u"[General]\nbuildDir=%1\n"_s.arg(buildSubfolder.absolutePath()));
u"[General]\nbuildDir=%1\nno-cmake-calls=false\n"_s.arg(buildSubfolder.absolutePath()));
}
}

View File

@ -175,6 +175,12 @@ int main(int argv, char *argc[])
"command line options into consideration"));
parser.addOption(ignoreSettings);
QCommandLineOption noCMakeCallsOption(
QStringList() << "no-cmake-calls",
QLatin1String("Disables automatic CMake rebuilds and C++ file watching."));
parser.addOption(noCMakeCallsOption);
settings.addOption("no-cmake-calls", "false");
parser.process(app);
if (parser.isSet(writeDefaultsOption)) {
@ -213,6 +219,19 @@ int main(int argv, char *argc[])
},
(parser.isSet(ignoreSettings) ? nullptr : &settings));
const bool disableCMakeCallsViaEnvironment =
qmlGetConfigOption<bool, qmlConvertBoolConfigOption>("QMLLS_NO_CMAKE_CALLS");
if (disableCMakeCallsViaEnvironment || parser.isSet(noCMakeCallsOption)) {
if (disableCMakeCallsViaEnvironment) {
qWarning() << "Disabling CMake calls via QMLLS_NO_CMAKE_CALLS environment variable.";
} else {
qWarning() << "Disabling CMake calls via command line switch.";
}
qmlServer.codeModel()->disableCMakeCalls();
}
const QStringList envPaths =
qEnvironmentVariable("QMLLS_BUILD_DIRS").split(u',', Qt::SkipEmptyParts);
for (const QString &envPath : envPaths) {