Core: Disentangle SettingsDatabase access

There's nothing inherently tied to the main window here.

Change-Id: I48ae09777a4408fc4c955d23fdee3483d8a97dd0
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2023-09-14 17:00:11 +02:00
parent 5ec327d66d
commit 41856dd254
10 changed files with 114 additions and 141 deletions

View File

@@ -12,6 +12,7 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "modemanager.h" #include "modemanager.h"
#include "session.h" #include "session.h"
#include "settingsdatabase.h"
#include "themechooser.h" #include "themechooser.h"
#include "actionmanager/actionmanager.h" #include "actionmanager/actionmanager.h"
@@ -96,6 +97,7 @@ CorePlugin::~CorePlugin()
DesignMode::destroyModeIfRequired(); DesignMode::destroyModeIfRequired();
delete m_mainWindow; delete m_mainWindow;
SettingsDatabase::destroy();
setCreatorTheme(nullptr); setCreatorTheme(nullptr);
} }

View File

@@ -1201,7 +1201,7 @@ static QHash<QString, IEditorFactory *> fromMap(const QMap<QString, QVariant> &m
void EditorManagerPrivate::saveSettings() void EditorManagerPrivate::saveSettings()
{ {
ICore::settingsDatabase()->setValue(documentStatesKey, d->m_editorStates); SettingsDatabase::setValue(documentStatesKey, d->m_editorStates);
QtcSettings *qsettings = ICore::settings(); QtcSettings *qsettings = ICore::settings();
qsettings->setValueWithDefault(preferredEditorFactoriesKey, qsettings->setValueWithDefault(preferredEditorFactoriesKey,
@@ -1224,10 +1224,9 @@ void EditorManagerPrivate::readSettings()
qs->value(preferredEditorFactoriesKey).toMap()); qs->value(preferredEditorFactoriesKey).toMap());
setUserPreferredEditorTypes(preferredEditorFactories); setUserPreferredEditorTypes(preferredEditorFactories);
SettingsDatabase *settings = ICore::settingsDatabase(); if (SettingsDatabase::contains(documentStatesKey)) {
if (settings->contains(documentStatesKey)) { d->m_editorStates = SettingsDatabase::value(documentStatesKey)
d->m_editorStates = settings->value(documentStatesKey) .value<QMap<QString, QVariant>>();
.value<QMap<QString, QVariant> >();
} }
updateAutoSave(); updateAutoSave();

View File

@@ -362,21 +362,6 @@ QtcSettings *ICore::settings(QSettings::Scope scope)
return PluginManager::globalSettings(); return PluginManager::globalSettings();
} }
/*!
Returns the application's settings database.
The settings database is meant as an alternative to the regular settings
object. It is more suitable for storing large amounts of data. The settings
are application wide.
\sa SettingsDatabase
\sa settings()
*/
SettingsDatabase *ICore::settingsDatabase()
{
return m_mainwindow->settingsDatabase();
}
/*! /*!
Returns the application's printer object. Returns the application's printer object.

View File

@@ -28,7 +28,6 @@ namespace Utils { class InfoBar; }
namespace Core { namespace Core {
class Context; class Context;
class IWizardFactory; class IWizardFactory;
class SettingsDatabase;
namespace Internal { class MainWindow; } namespace Internal { class MainWindow; }
@@ -69,7 +68,6 @@ public:
QWidget *parent = nullptr); QWidget *parent = nullptr);
static Utils::QtcSettings *settings(QSettings::Scope scope = QSettings::UserScope); static Utils::QtcSettings *settings(QSettings::Scope scope = QSettings::UserScope);
static SettingsDatabase *settingsDatabase();
static QPrinter *printer(); static QPrinter *printer();
static QString userInterfaceLanguage(); static QString userInterfaceLanguage();

View File

@@ -155,26 +155,26 @@ void Locator::aboutToShutdown()
void Locator::loadSettings() void Locator::loadSettings()
{ {
SettingsDatabase *settings = ICore::settingsDatabase(); namespace DB = SettingsDatabase;
// check if we have to read old settings // check if we have to read old settings
// TOOD remove a few versions after 4.15 // TOOD remove a few versions after 4.15
const QString settingsGroup = settings->contains("Locator") ? QString("Locator") const QString settingsGroup = DB::contains("Locator") ? QString("Locator")
: QString("QuickOpen"); : QString("QuickOpen");
const Settings def; const Settings def;
settings->beginGroup(settingsGroup); DB::beginGroup(settingsGroup);
m_refreshTimer.setInterval(settings->value("RefreshInterval", 60).toInt() * 60000); m_refreshTimer.setInterval(DB::value("RefreshInterval", 60).toInt() * 60000);
m_settings.useCenteredPopup = settings->value(kUseCenteredPopup, def.useCenteredPopup).toBool(); m_settings.useCenteredPopup = DB::value(kUseCenteredPopup, def.useCenteredPopup).toBool();
for (ILocatorFilter *filter : std::as_const(m_filters)) { for (ILocatorFilter *filter : std::as_const(m_filters)) {
if (settings->contains(filter->id().toString())) { if (DB::contains(filter->id().toString())) {
const QByteArray state = settings->value(filter->id().toString()).toByteArray(); const QByteArray state = DB::value(filter->id().toString()).toByteArray();
if (!state.isEmpty()) if (!state.isEmpty())
filter->restoreState(state); filter->restoreState(state);
} }
} }
settings->beginGroup("CustomFilters"); DB::beginGroup("CustomFilters");
QList<ILocatorFilter *> customFilters; QList<ILocatorFilter *> customFilters;
const QStringList keys = settings->childKeys(); const QStringList keys = DB::childKeys();
int count = 0; int count = 0;
const Id directoryBaseId(Constants::CUSTOM_DIRECTORY_FILTER_BASEID); const Id directoryBaseId(Constants::CUSTOM_DIRECTORY_FILTER_BASEID);
const Id urlBaseId(Constants::CUSTOM_URL_FILTER_BASEID); const Id urlBaseId(Constants::CUSTOM_URL_FILTER_BASEID);
@@ -188,12 +188,12 @@ void Locator::loadSettings()
urlFilter->setIsCustomFilter(true); urlFilter->setIsCustomFilter(true);
filter = urlFilter; filter = urlFilter;
} }
filter->restoreState(settings->value(key).toByteArray()); filter->restoreState(DB::value(key).toByteArray());
customFilters.append(filter); customFilters.append(filter);
} }
setCustomFilters(customFilters); setCustomFilters(customFilters);
settings->endGroup(); DB::endGroup();
settings->endGroup(); DB::endGroup();
if (m_refreshTimer.interval() > 0) if (m_refreshTimer.interval() > 0)
m_refreshTimer.start(); m_refreshTimer.start();
@@ -288,19 +288,19 @@ void Locator::saveSettings() const
return; return;
const Settings def; const Settings def;
SettingsDatabase *s = ICore::settingsDatabase(); namespace DB = SettingsDatabase;
s->beginTransaction(); DB::beginTransaction();
s->beginGroup("Locator"); DB::beginGroup("Locator");
s->remove(QString()); DB::remove(QString());
s->setValue("RefreshInterval", refreshInterval()); DB::setValue("RefreshInterval", refreshInterval());
s->setValueWithDefault(kUseCenteredPopup, m_settings.useCenteredPopup, def.useCenteredPopup); DB::setValueWithDefault(kUseCenteredPopup, m_settings.useCenteredPopup, def.useCenteredPopup);
for (ILocatorFilter *filter : m_filters) { for (ILocatorFilter *filter : m_filters) {
if (!m_customFilters.contains(filter) && filter->id().isValid()) { if (!m_customFilters.contains(filter) && filter->id().isValid()) {
const QByteArray state = filter->saveState(); const QByteArray state = filter->saveState();
s->setValueWithDefault(filter->id().toString(), state); DB::setValueWithDefault(filter->id().toString(), state);
} }
} }
s->beginGroup("CustomFilters"); DB::beginGroup("CustomFilters");
int i = 0; int i = 0;
for (ILocatorFilter *filter : m_customFilters) { for (ILocatorFilter *filter : m_customFilters) {
const char *prefix = filter->id().name().startsWith( const char *prefix = filter->id().name().startsWith(
@@ -308,12 +308,12 @@ void Locator::saveSettings() const
? kDirectoryFilterPrefix ? kDirectoryFilterPrefix
: kUrlFilterPrefix; : kUrlFilterPrefix;
const QByteArray state = filter->saveState(); const QByteArray state = filter->saveState();
s->setValueWithDefault(prefix + QString::number(i), state); DB::setValueWithDefault(prefix + QString::number(i), state);
++i; ++i;
} }
s->endGroup(); DB::endGroup();
s->endGroup(); DB::endGroup();
s->endTransaction(); DB::endTransaction();
} }
/*! /*!

View File

@@ -39,7 +39,6 @@
#include "progressmanager/progressmanager_p.h" #include "progressmanager/progressmanager_p.h"
#include "progressmanager/progressview.h" #include "progressmanager/progressview.h"
#include "rightpane.h" #include "rightpane.h"
#include "settingsdatabase.h"
#include "statusbarmanager.h" #include "statusbarmanager.h"
#include "systemsettings.h" #include "systemsettings.h"
#include "vcsmanager.h" #include "vcsmanager.h"
@@ -73,7 +72,6 @@
#include <QComboBox> #include <QComboBox>
#include <QDebug> #include <QDebug>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QFileInfo>
#include <QMenu> #include <QMenu>
#include <QMenuBar> #include <QMenuBar>
#include <QMessageBox> #include <QMessageBox>
@@ -112,9 +110,6 @@ MainWindow::MainWindow()
: AppMainWindow() : AppMainWindow()
, m_coreImpl(new ICore(this)) , m_coreImpl(new ICore(this))
, m_lowPrioAdditionalContexts(Constants::C_GLOBAL) , m_lowPrioAdditionalContexts(Constants::C_GLOBAL)
, m_settingsDatabase(
new SettingsDatabase(QFileInfo(PluginManager::settings()->fileName()).path(),
QCoreApplication::applicationName()))
, m_progressManager(new ProgressManagerPrivate) , m_progressManager(new ProgressManagerPrivate)
, m_jsExpander(JsExpander::createGlobalJsExpander()) , m_jsExpander(JsExpander::createGlobalJsExpander())
, m_vcsManager(new VcsManager) , m_vcsManager(new VcsManager)
@@ -296,9 +291,6 @@ MainWindow::~MainWindow()
delete m_jsExpander; delete m_jsExpander;
m_jsExpander = nullptr; m_jsExpander = nullptr;
delete m_settingsDatabase;
m_settingsDatabase = nullptr;
} }
void MainWindow::init() void MainWindow::init()

View File

@@ -36,7 +36,6 @@ class ProgressManager;
class NavigationWidget; class NavigationWidget;
enum class Side; enum class Side;
class RightPaneWidget; class RightPaneWidget;
class SettingsDatabase;
class VcsManager; class VcsManager;
namespace Internal { namespace Internal {
@@ -71,7 +70,6 @@ public:
ICore::OpenFilesFlags flags, ICore::OpenFilesFlags flags,
const Utils::FilePath &workingDirectory = {}); const Utils::FilePath &workingDirectory = {});
inline SettingsDatabase *settingsDatabase() const { return m_settingsDatabase; }
virtual QPrinter *printer() const; virtual QPrinter *printer() const;
IContext * currentContextObject() const; IContext * currentContextObject() const;
QStatusBar *statusBar() const; QStatusBar *statusBar() const;
@@ -137,7 +135,6 @@ private:
QStringList m_aboutInformation; QStringList m_aboutInformation;
Context m_highPrioAdditionalContexts; Context m_highPrioAdditionalContexts;
Context m_lowPrioAdditionalContexts; Context m_lowPrioAdditionalContexts;
SettingsDatabase *m_settingsDatabase = nullptr;
mutable QPrinter *m_printer = nullptr; mutable QPrinter *m_printer = nullptr;
WindowSupport *m_windowSupport = nullptr; WindowSupport *m_windowSupport = nullptr;
EditorManager *m_editorManager = nullptr; EditorManager *m_editorManager = nullptr;

View File

@@ -3,6 +3,8 @@
#include "settingsdatabase.h" #include "settingsdatabase.h"
#include <extensionsystem/pluginmanager.h>
#include <QDir> #include <QDir>
#include <QMap> #include <QMap>
#include <QString> #include <QString>
@@ -13,13 +15,14 @@
#include <QSqlError> #include <QSqlError>
#include <QSqlQuery> #include <QSqlQuery>
#include <QDebug> #include <QDebug>
#include <QCoreApplication>
/*! /*!
\class Core::SettingsDatabase \namespace Core::SettingsDatabase
\inheaderfile coreplugin/settingsdatabase.h \inheaderfile coreplugin/settingsdatabase.h
\inmodule QtCreator \inmodule QtCreator
\brief The SettingsDatabase class offers an alternative to the \brief The SettingsDatabase namespace offers an alternative to the
application-wide QSettings that is more application-wide QSettings that is more
suitable for storing large amounts of data. suitable for storing large amounts of data.
@@ -28,19 +31,20 @@
rewriting the whole file each time one of the settings change. rewriting the whole file each time one of the settings change.
The SettingsDatabase API mimics that of QSettings. The SettingsDatabase API mimics that of QSettings.
\sa settings()
*/ */
using namespace Core; using namespace Core;
using namespace Core::Internal; using namespace ExtensionSystem;
enum { debug_settings = 0 }; enum { debug_settings = 0 };
namespace Core { namespace Core::SettingsDatabase {
namespace Internal {
using SettingsMap = QMap<QString, QVariant>; using SettingsMap = QMap<QString, QVariant>;
class SettingsDatabasePrivate class SettingsDatabaseImpl
{ {
public: public:
QString effectiveGroup() const QString effectiveGroup() const
@@ -65,12 +69,17 @@ public:
QSqlDatabase m_db; QSqlDatabase m_db;
}; };
} // namespace Internal static SettingsDatabaseImpl *d;
} // namespace Core
SettingsDatabase::SettingsDatabase(const QString &path, const QString &application) void ensureImpl()
: d(new SettingsDatabasePrivate)
{ {
if (d)
return;
d = new SettingsDatabaseImpl;
const QString path = QFileInfo(PluginManager::settings()->fileName()).path();
const QString application = QCoreApplication::applicationName();
const QLatin1Char slash('/'); const QLatin1Char slash('/');
// TODO: Don't rely on a path, but determine automatically // TODO: Don't rely on a path, but determine automatically
@@ -111,16 +120,21 @@ SettingsDatabase::SettingsDatabase(const QString &path, const QString &applicati
} }
} }
SettingsDatabase::~SettingsDatabase() void destroy()
{ {
sync(); if (!d)
return;
// TODO: Delay writing of dirty keys and save them here
delete d; delete d;
d = nullptr;
QSqlDatabase::removeDatabase(QLatin1String("settings")); QSqlDatabase::removeDatabase(QLatin1String("settings"));
} }
void SettingsDatabase::setValue(const QString &key, const QVariant &value) void setValue(const QString &key, const QVariant &value)
{ {
ensureImpl();
const QString effectiveKey = d->effectiveKey(key); const QString effectiveKey = d->effectiveKey(key);
// Add to cache // Add to cache
@@ -140,8 +154,9 @@ void SettingsDatabase::setValue(const QString &key, const QVariant &value)
qDebug() << "Stored:" << effectiveKey << "=" << value; qDebug() << "Stored:" << effectiveKey << "=" << value;
} }
QVariant SettingsDatabase::value(const QString &key, const QVariant &defaultValue) const QVariant value(const QString &key, const QVariant &defaultValue)
{ {
ensureImpl();
const QString effectiveKey = d->effectiveKey(key); const QString effectiveKey = d->effectiveKey(key);
QVariant value = defaultValue; QVariant value = defaultValue;
@@ -168,8 +183,9 @@ QVariant SettingsDatabase::value(const QString &key, const QVariant &defaultValu
return value; return value;
} }
bool SettingsDatabase::contains(const QString &key) const bool contains(const QString &key)
{ {
ensureImpl();
// check exact key // check exact key
// this already caches the value // this already caches the value
if (value(key).isValid()) if (value(key).isValid())
@@ -187,8 +203,9 @@ bool SettingsDatabase::contains(const QString &key) const
return false; return false;
} }
void SettingsDatabase::remove(const QString &key) void remove(const QString &key)
{ {
ensureImpl();
const QString effectiveKey = d->effectiveKey(key); const QString effectiveKey = d->effectiveKey(key);
// Remove keys from the cache // Remove keys from the cache
@@ -214,23 +231,27 @@ void SettingsDatabase::remove(const QString &key)
query.exec(); query.exec();
} }
void SettingsDatabase::beginGroup(const QString &prefix) void beginGroup(const QString &prefix)
{ {
ensureImpl();
d->m_groups.append(prefix); d->m_groups.append(prefix);
} }
void SettingsDatabase::endGroup() void endGroup()
{ {
ensureImpl();
d->m_groups.removeLast(); d->m_groups.removeLast();
} }
QString SettingsDatabase::group() const QString group()
{ {
ensureImpl();
return d->effectiveGroup(); return d->effectiveGroup();
} }
QStringList SettingsDatabase::childKeys() const QStringList childKeys()
{ {
ensureImpl();
QStringList children; QStringList children;
const QString g = group(); const QString g = group();
@@ -243,21 +264,20 @@ QStringList SettingsDatabase::childKeys() const
return children; return children;
} }
void SettingsDatabase::beginTransaction() void beginTransaction()
{ {
ensureImpl();
if (!d->m_db.isOpen()) if (!d->m_db.isOpen())
return; return;
d->m_db.transaction(); d->m_db.transaction();
} }
void SettingsDatabase::endTransaction() void endTransaction()
{ {
ensureImpl();
if (!d->m_db.isOpen()) if (!d->m_db.isOpen())
return; return;
d->m_db.commit(); d->m_db.commit();
} }
void SettingsDatabase::sync() } // Core::SettingsDatabase
{
// TODO: Delay writing of dirty keys and save them here
}

View File

@@ -5,48 +5,28 @@
#include "core_global.h" #include "core_global.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QVariant> #include <QVariant>
namespace Core { namespace Core::SettingsDatabase {
namespace Internal { class SettingsDatabasePrivate; } CORE_EXPORT void setValue(const QString &key, const QVariant &value);
CORE_EXPORT QVariant value(const QString &key, const QVariant &defaultValue = {});
class CORE_EXPORT SettingsDatabase final CORE_EXPORT bool contains(const QString &key);
{ CORE_EXPORT void remove(const QString &key);
public:
SettingsDatabase(const QString &path, const QString &application);
~SettingsDatabase();
void setValue(const QString &key, const QVariant &value); CORE_EXPORT void beginGroup(const QString &prefix);
QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; CORE_EXPORT void endGroup();
CORE_EXPORT QString group();
CORE_EXPORT QStringList childKeys();
template<typename T> CORE_EXPORT void beginTransaction();
void setValueWithDefault(const QString &key, const T &val, const T &defaultValue); CORE_EXPORT void endTransaction();
template<typename T>
void setValueWithDefault(const QString &key, const T &val);
bool contains(const QString &key) const; CORE_EXPORT void destroy();
void remove(const QString &key);
void beginGroup(const QString &prefix);
void endGroup();
QString group() const;
QStringList childKeys() const;
void beginTransaction();
void endTransaction();
void sync();
private:
Internal::SettingsDatabasePrivate *d;
};
template<typename T> template<typename T>
void SettingsDatabase::setValueWithDefault(const QString &key, const T &val, const T &defaultValue) void setValueWithDefault(const QString &key, const T &val, const T &defaultValue)
{ {
if (val == defaultValue) if (val == defaultValue)
remove(key); remove(key);
@@ -55,7 +35,7 @@ void SettingsDatabase::setValueWithDefault(const QString &key, const T &val, con
} }
template<typename T> template<typename T>
void SettingsDatabase::setValueWithDefault(const QString &key, const T &val) void setValueWithDefault(const QString &key, const T &val)
{ {
if (val == T()) if (val == T())
remove(key); remove(key);
@@ -63,4 +43,4 @@ void SettingsDatabase::setValueWithDefault(const QString &key, const T &val)
setValue(key, QVariant::fromValue(val)); setValue(key, QVariant::fromValue(val));
} }
} // namespace Core } // Core::SettingsDatabase

View File

@@ -36,11 +36,11 @@ static QString emSdkEnvOutput(const FilePath &sdkRoot)
return {}; return {};
const QDateTime ts = tsFile.lastModified(); const QDateTime ts = tsFile.lastModified();
Core::SettingsDatabase *db = Core::ICore::settingsDatabase(); namespace DB = Core::SettingsDatabase;
if (db->value(emSdkEnvTSKey).toDateTime() == ts if (DB::value(emSdkEnvTSKey).toDateTime() == ts
&& FilePath::fromVariant(db->value(emSdkEnvTSFileKey)) == tsFile && FilePath::fromVariant(DB::value(emSdkEnvTSFileKey)) == tsFile
&& db->contains(emSdkEnvOutputKey)) { && DB::contains(emSdkEnvOutputKey)) {
return db->value(emSdkEnvOutputKey).toString(); return DB::value(emSdkEnvOutputKey).toString();
} }
const bool isWindows = sdkRoot.osType() == OsTypeWindows; const bool isWindows = sdkRoot.osType() == OsTypeWindows;
@@ -55,9 +55,9 @@ static QString emSdkEnvOutput(const FilePath &sdkRoot)
} }
emSdkEnv.runBlocking(); emSdkEnv.runBlocking();
const QString result = emSdkEnv.allOutput(); const QString result = emSdkEnv.allOutput();
db->setValue(emSdkEnvTSFileKey, tsFile.toVariant()); DB::setValue(emSdkEnvTSFileKey, tsFile.toVariant());
db->setValue(emSdkEnvTSKey, ts); DB::setValue(emSdkEnvTSKey, ts);
db->setValue(emSdkEnvOutputKey, result); DB::setValue(emSdkEnvOutputKey, result);
return result; return result;
} }
@@ -103,11 +103,11 @@ QVersionNumber version(const FilePath &sdkRoot)
return {}; return {};
const QDateTime ts = tsFile.lastModified(); const QDateTime ts = tsFile.lastModified();
Core::SettingsDatabase *db = Core::ICore::settingsDatabase(); namespace DB = Core::SettingsDatabase;
if (db->value(emSdkVersionTSKey).toDateTime() == ts if (DB::value(emSdkVersionTSKey).toDateTime() == ts
&& FilePath::fromVariant(db->value(emSdkVersionTSFileKey)) == tsFile && FilePath::fromVariant(DB::value(emSdkVersionTSFileKey)) == tsFile
&& db->contains(emSdkVersionKey)) { && DB::contains(emSdkVersionKey)) {
return QVersionNumber::fromString(db->value(emSdkVersionKey).toString()); return QVersionNumber::fromString(DB::value(emSdkVersionKey).toString());
} }
Environment env = sdkRoot.deviceEnvironment(); Environment env = sdkRoot.deviceEnvironment();
@@ -121,21 +121,21 @@ QVersionNumber version(const FilePath &sdkRoot)
emcc.runBlocking(); emcc.runBlocking();
const QString versionStr = emcc.cleanedStdOut(); const QString versionStr = emcc.cleanedStdOut();
const QVersionNumber result = QVersionNumber::fromString(versionStr); const QVersionNumber result = QVersionNumber::fromString(versionStr);
db->setValue(emSdkVersionTSFileKey, tsFile.toVariant()); DB::setValue(emSdkVersionTSFileKey, tsFile.toVariant());
db->setValue(emSdkVersionTSKey, ts); DB::setValue(emSdkVersionTSKey, ts);
db->setValue(emSdkVersionKey, result.toString()); DB::setValue(emSdkVersionKey, result.toString());
return result; return result;
} }
void clearCaches() void clearCaches()
{ {
Core::SettingsDatabase *db = Core::ICore::settingsDatabase(); namespace DB = Core::SettingsDatabase;
db->remove(emSdkEnvTSFileKey); DB::remove(emSdkEnvTSFileKey);
db->remove(emSdkEnvTSKey); DB::remove(emSdkEnvTSKey);
db->remove(emSdkEnvOutputKey); DB::remove(emSdkEnvOutputKey);
db->remove(emSdkVersionTSFileKey); DB::remove(emSdkVersionTSFileKey);
db->remove(emSdkVersionTSKey); DB::remove(emSdkVersionTSKey);
db->remove(emSdkVersionKey); DB::remove(emSdkVersionKey);
} }
} // namespace WebAssembly::Internal::WebAssemblyEmSdk } // namespace WebAssembly::Internal::WebAssemblyEmSdk