aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexis Jeandet <alexis.jeandet@member.fsf.org>2020-05-01 18:20:56 +0200
committerAlexis Jeandet <alexis.jeandet@member.fsf.org>2020-06-08 09:55:17 +0000
commit77d7bb5014a79db539f82d95392d07c6bda9d6a8 (patch)
tree8249ab051adc2962203355c8ec59abde420106d8
parenta8f38f8aab5303bb6e0c6575508661b51b7aebc3 (diff)
Meson build plugin initial support
Most basic project management is implemented: - Project config/build - Build options accessible to user - Lists most build targets - Meson and Ninja added to kit setup - Basic project file tree with files known by Meson - Some basic meson and ninja process output parsing - Some project templates Missing features, that will come later: - Configurable project tree layout - Locators for Meson - Build importer - Access to Machine files for better user fine tuning - ... Fixes: QTCREATORBUG-18117 Change-Id: I2811e71562c113fb0fc6b6177bcf0698fa71ef63 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
-rw-r--r--share/qtcreator/templates/wizards/projects/consoleapp/meson.build11
-rw-r--r--share/qtcreator/templates/wizards/projects/consoleapp/wizard.json18
-rw-r--r--share/qtcreator/templates/wizards/projects/cpplibrary/meson.build56
-rw-r--r--share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json17
-rw-r--r--share/qtcreator/templates/wizards/projects/plainc/meson.build3
-rw-r--r--share/qtcreator/templates/wizards/projects/plainc/wizard.json15
-rw-r--r--share/qtcreator/templates/wizards/projects/plaincpp/meson.build3
-rw-r--r--share/qtcreator/templates/wizards/projects/plaincpp/wizard.json15
-rw-r--r--share/qtcreator/templates/wizards/projects/qtwidgetsapplication/meson.build23
-rw-r--r--share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json17
-rw-r--r--src/plugins/CMakeLists.txt1
-rw-r--r--src/plugins/mesonprojectmanager/CMakeLists.txt162
-rw-r--r--src/plugins/mesonprojectmanager/MesonProjectManager.json.in21
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/mesontools.cpp112
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/mesontools.h118
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.cpp96
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.h128
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/ninjawrapper.h64
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp84
-rw-r--r--src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h108
-rw-r--r--src/plugins/mesonprojectmanager/icons/README.txt3
-rw-r--r--src/plugins/mesonprojectmanager/icons/meson_bw_logo.pngbin0 -> 277 bytes
-rw-r--r--src/plugins/mesonprojectmanager/icons/meson_bw_logo@2x.pngbin0 -> 542 bytes
-rw-r--r--src/plugins/mesonprojectmanager/icons/meson_logo.png1
-rw-r--r--src/plugins/mesonprojectmanager/kithelper/kitdata.h41
-rw-r--r--src/plugins/mesonprojectmanager/kithelper/kithelper.h100
-rw-r--r--src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp137
-rw-r--r--src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.h50
-rw-r--r--src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.cpp62
-rw-r--r--src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.h39
-rw-r--r--src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.cpp112
-rw-r--r--src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.h46
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/buildoptions.h266
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfo.h34
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfoparser.h85
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildoptionsparser.h117
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildsystemfilesparser.h79
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/parsers/common.h114
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/parsers/infoparser.h69
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/parsers/targetparser.h105
-rw-r--r--src/plugins/mesonprojectmanager/mesoninfoparser/target.h140
-rw-r--r--src/plugins/mesonprojectmanager/mesonpluginconstants.h97
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectmanager.pro102
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectmanager.qbs197
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectmanager_dependencies.pri12
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectplugin.cpp121
-rw-r--r--src/plugins/mesonprojectmanager/mesonprojectplugin.h54
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp138
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.h59
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.ui147
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.cpp102
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.h53
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.ui89
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.cpp88
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.h60
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.cpp227
-rw-r--r--src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.h190
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp177
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.h129
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp217
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonbuildsystem.h76
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprocess.cpp223
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprocess.h87
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonproject.cpp89
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonproject.h56
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprojectimporter.cpp81
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprojectimporter.h54
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprojectparser.cpp356
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonprojectparser.h131
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp101
-rw-r--r--src/plugins/mesonprojectmanager/project/mesonrunconfiguration.h48
-rw-r--r--src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp186
-rw-r--r--src/plugins/mesonprojectmanager/project/ninjabuildstep.h69
-rw-r--r--src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.cpp146
-rw-r--r--src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.h72
-rw-r--r--src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.cpp68
-rw-r--r--src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.h49
-rw-r--r--src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp83
-rw-r--r--src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.h61
-rw-r--r--src/plugins/mesonprojectmanager/project/projecttree/projecttree.cpp95
-rw-r--r--src/plugins/mesonprojectmanager/project/projecttree/projecttree.h41
-rw-r--r--src/plugins/mesonprojectmanager/resources.qrc7
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp52
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h41
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp52
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h52
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui60
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/settings.cpp33
-rw-r--r--src/plugins/mesonprojectmanager/settings/general/settings.h89
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.cpp97
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.h62
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.cpp97
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.h61
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp144
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h80
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.cpp74
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.h57
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.ui49
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolsmodel.cpp117
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolsmodel.h58
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp100
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.h42
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.cpp42
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.h40
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.cpp93
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.h64
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.ui96
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.cpp135
-rw-r--r--src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.h70
-rw-r--r--src/plugins/mesonprojectmanager/tests/resources/simplecproject/main.c4
-rw-r--r--src/plugins/mesonprojectmanager/tests/resources/simplecproject/meson.build7
-rw-r--r--src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp115
-rw-r--r--src/plugins/mesonprojectmanager/tests/testmesonparser.cpp299
-rw-r--r--src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp109
-rw-r--r--src/plugins/mesonprojectmanager/tests/testninjaparser.cpp110
-rw-r--r--src/plugins/mesonprojectmanager/versionhelper.h72
-rw-r--r--src/plugins/plugins.pro1
-rw-r--r--src/plugins/plugins.qbs1
-rw-r--r--src/tools/icons/qtcreatoricons.svg18
-rw-r--r--tests/manual/meson/mesonsampleproject/main.cpp39
-rw-r--r--tests/manual/meson/mesonsampleproject/meson.build19
-rw-r--r--tests/manual/meson/mesonsampleproject/mesonsampleproject.cpp39
-rw-r--r--tests/manual/meson/mesonsampleproject/mesonsampleproject.h45
-rw-r--r--tests/manual/meson/mesonsampleproject/mesonsampleproject.ui67
-rw-r--r--tests/manual/meson/mesonsampleproject/mesonsampleproject_fr_FR.ts17
125 files changed, 10016 insertions, 13 deletions
diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/meson.build b/share/qtcreator/templates/wizards/projects/consoleapp/meson.build
new file mode 100644
index 0000000000..55090dea93
--- /dev/null
+++ b/share/qtcreator/templates/wizards/projects/consoleapp/meson.build
@@ -0,0 +1,11 @@
+project('%{ProjectName}', 'cpp',default_options : ['cpp_std=c++11'], meson_version:'>=0.44')
+
+# Documentation: https://mesonbuild.com/Qt5-module.html
+qt5 = import('qt5')
+qt5core = dependency('qt5', modules : 'Core')
+
+@if %{HasTranslation}
+translations = qt5.compile_translations(ts_files : '%{TsFileName}', build_by_default : true)
+@endif
+
+executable('%{ProjectName}', '%{CppFileName}', dependencies : [qt5core])
diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json
index b54e769d66..1bc8554c8b 100644
--- a/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/consoleapp/wizard.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
+ "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
"id": "E.QtCore",
"category": "D.ApplicationQt",
"trDescription": "Creates a project containing a single main.cpp file with a stub implementation.\n\nPreselects a desktop Qt for building the application if available.",
@@ -8,14 +8,15 @@
"trDisplayCategory": "Application (Qt)",
"icon": "../../global/consoleapplication.png",
"featuresRequired": [ "QtSupport.Wizards.FeatureQt" ],
- "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0}",
+ "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0}",
"options":
[
- { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : (value('BuildSystem') === 'cmake' ? value('CMakeFile') : value('QbsFile'))}" },
+ { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : (value('BuildSystem') === 'cmake' ? value('CMakeFile') : (value('BuildSystem') === 'meson' ? value('MesonFile') : value('QbsFile')))}" },
{ "key": "ProFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" },
{ "key": "QbsFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'qbs')}" },
{ "key": "CMakeFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
+ { "key": "MesonFile", "value": "%{ProjectDirectory}/meson.build" },
{ "key": "HasTranslation", "value": "%{JS: value('TsFileName') !== ''}" },
{ "key": "CppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" }
],
@@ -59,6 +60,11 @@
"trKey": "Qbs",
"value": "qbs",
"condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}"
+ },
+ {
+ "trKey": "Meson",
+ "value": "meson",
+ "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}"
}
]
}
@@ -107,6 +113,12 @@
"condition": "%{JS: value('BuildSystem') === 'qbs'}"
},
{
+ "source": "meson.build",
+ "target": "%{MesonFile}",
+ "openAsProject": true,
+ "condition": "%{JS: value('BuildSystem') === 'meson'}"
+ },
+ {
"source": "main.cpp",
"target": "%{CppFileName}",
"openInEditor": true
diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/meson.build b/share/qtcreator/templates/wizards/projects/cpplibrary/meson.build
new file mode 100644
index 0000000000..73b1e67fbc
--- /dev/null
+++ b/share/qtcreator/templates/wizards/projects/cpplibrary/meson.build
@@ -0,0 +1,56 @@
+project('%{ProjectName}', 'cpp',
+@if %{IsStatic}
+ default_options : ['cpp_std=c++11', 'default_library=static'],
+@else
+ default_options : ['cpp_std=c++11', 'default_library=shared'],
+@endif
+ meson_version:'>=0.48')
+
+@if '%{QtModule}' != 'none'
+# Documentation: https://mesonbuild.com/Qt5-module.html
+qt5 = import('qt5')
+
+@if '%{QtModule}' == 'core'
+qt5dep = dependency('qt5', modules : ['Core'])
+@endif
+@if '%{QtModule}' == 'gui'
+qt5dep = dependency('qt5', modules : ['Core', 'Gui'])
+@endif
+@if '%{QtModule}' == 'widgets'
+qt5dep = dependency('qt5', modules : ['Core', 'Gui', 'Widgets'])
+@endif
+
+@if %{HasTranslation}
+translations = qt5.compile_translations(ts_files : '%{TsFileName}', build_by_default : true)
+@endif
+
+cpp_args = [
+@if %{IsShared}
+ '-D%{LibraryDefine}'
+ @if %{IsQtPlugin}
+ ,'-DQT_PLUGIN'
+ @endif
+@else
+ @if %{IsQtPlugin}
+ '-DQT_STATICPLUGIN'
+ @endif
+@endif
+]
+
+moc_files = qt5.preprocess(moc_headers : [
+ @if '%{Type}' === 'shared'
+ '%{GlobalHdrFileName}',
+ @endif
+ '%{HdrFileName}'],
+ moc_extra_arguments : cpp_args,
+ dependencies: [qt5dep])
+@endif
+
+
+library('%{ProjectName}', '%{SrcFileName}'
+@if '%{QtModule}' != 'none'
+ , moc_files
+ , dependencies : [qt5dep]
+ , cpp_args : cpp_args
+@endif
+ , install : true)
diff --git a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json
index 0b12fd67e1..217a5c1a73 100644
--- a/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/cpplibrary/wizard.json
@@ -1,19 +1,20 @@
{
"version": 1,
- "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
+ "supportedProjectTypes": [ "MesonProjectManager.MesonProject", "CMakeProjectManager.CMakeProject", "Qbs.QbsProject", "Qt4ProjectManager.Qt4Project" ],
"id": "H.CppLibrary",
"category": "G.Library",
"trDescription": "Creates a C++ library. This can be used to create:<ul><li>a shared C++ library for use with <tt>QPluginLoader</tt> and runtime (Plugins)</li><li>a shared or static C++ library for use with another project at linktime</li></ul>",
"trDisplayName": "C++ Library",
"trDisplayCategory": "Library",
"icon": "../../global/lib.png",
- "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0)}",
+ "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}",
"options":
[
- { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'cmake' ? value('CMakeFile') : value('ProFile')}" },
+ { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'cmake' ? value('CMakeFile') : ( value('BuildSystem') === 'meson' ? value('MesonFile') : value('ProFile') )}" },
{ "key": "ProFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), value('BuildSystem') === 'qmake' ? 'pro' : 'qbs')}" },
{ "key": "CMakeFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
+ { "key": "MesonFile", "value": "%{ProjectDirectory}/meson.build" },
{ "key": "PluginJsonFile", "value": "%{JS: Util.fileName(value('ProjectName'), 'json')}" },
{ "key": "IsShared", "value": "%{JS: value('Type') === 'shared'}" },
{ "key": "IsStatic", "value": "%{JS: value('Type') === 'static'}" },
@@ -74,6 +75,11 @@
"trKey": "Qbs",
"value": "qbs",
"condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}"
+ },
+ {
+ "trKey": "Meson",
+ "value": "meson",
+ "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}"
}
]
}
@@ -316,6 +322,11 @@
"condition": "%{JS: value('BuildSystem') === 'cmake'}"
},
{
+ "source": "meson.build",
+ "openAsProject": true,
+ "condition": "%{JS: value('BuildSystem') === 'meson'}"
+ },
+ {
"source": "lib.cpp",
"target": "%{SrcFileName}",
"openInEditor": true
diff --git a/share/qtcreator/templates/wizards/projects/plainc/meson.build b/share/qtcreator/templates/wizards/projects/plainc/meson.build
new file mode 100644
index 0000000000..d88b2c110e
--- /dev/null
+++ b/share/qtcreator/templates/wizards/projects/plainc/meson.build
@@ -0,0 +1,3 @@
+project('%{ProjectName}', 'c')
+
+executable('%{ProjectName}', '%{CFileName}')
diff --git a/share/qtcreator/templates/wizards/projects/plainc/wizard.json b/share/qtcreator/templates/wizards/projects/plainc/wizard.json
index 205e02c379..2f6d8bf5ca 100644
--- a/share/qtcreator/templates/wizards/projects/plainc/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/plainc/wizard.json
@@ -7,14 +7,15 @@
"trDisplayName": "Plain C Application",
"trDisplayCategory": "Non-Qt Project",
"icon": "../../global/consoleapplication.png",
- "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0)}",
+ "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}",
"options":
[
- { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : (value('BuildSystem') === 'cmake' ? value('CMakeFile') : value('QbsFile'))}" },
+ { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : (value('BuildSystem') === 'cmake' ? value('CMakeFile') : ( value('BuildSystem') === 'meson' ? value('MesonFile') : value('QbsFile')))}" },
{ "key": "ProFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" },
{ "key": "QbsFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'qbs')}" },
{ "key": "CMakeFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
+ { "key": "MesonFile", "value": "%{ProjectDirectory}/meson.build" },
{ "key": "CFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-csrc')}" }
],
@@ -56,6 +57,11 @@
"trKey": "Qbs",
"value": "qbs",
"condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}"
+ },
+ {
+ "trKey": "Meson",
+ "value": "meson",
+ "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}"
}
]
}
@@ -99,6 +105,11 @@
"condition": "%{JS: value('BuildSystem') === 'qbs'}"
},
{
+ "source": "meson.build",
+ "openAsProject": true,
+ "condition": "%{JS: value('BuildSystem') === 'meson'}"
+ },
+ {
"source": "main.c",
"target": "%{CFileName}",
"openInEditor": true
diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/meson.build b/share/qtcreator/templates/wizards/projects/plaincpp/meson.build
new file mode 100644
index 0000000000..4625e042c1
--- /dev/null
+++ b/share/qtcreator/templates/wizards/projects/plaincpp/meson.build
@@ -0,0 +1,3 @@
+project('%{ProjectName}', 'cpp', default_options : ['cpp_std=c++11'])
+
+executable('%{ProjectName}', '%{CppFileName}')
diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json b/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json
index 496f2f41c1..3475d27207 100644
--- a/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/plaincpp/wizard.json
@@ -7,14 +7,15 @@
"trDisplayName": "Plain C++ Application",
"trDisplayCategory": "Non-Qt Project",
"icon": "../../global/consoleapplication.png",
- "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0)}",
+ "enabled": "%{JS: value('Plugins').indexOf('CppEditor') >= 0 && (value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0)}",
"options":
[
- { "key": "ProjectFile", "value": "%{JS: '%{BuildSystem}' === 'qmake' ? '%{ProFile}' : ('%{BuildSystem}' === 'cmake' ? '%{CMakeFile}' : '%{QbsFile}')}" },
+ { "key": "ProjectFile", "value": "%{JS: '%{BuildSystem}' === 'qmake' ? '%{ProFile}' : ('%{BuildSystem}' === 'cmake' ? '%{CMakeFile}' : ( '%{BuildSystem}' === 'meson' ? '%{MesonFile}' : '%{QbsFile}'))}" },
{ "key": "ProFile", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'pro')}" },
{ "key": "QbsFile", "value": "%{JS: Util.fileName('%{ProjectDirectory}/%{ProjectName}', 'qbs')}" },
{ "key": "CMakeFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
+ { "key": "MesonFile", "value": "%{ProjectDirectory}/meson.build" },
{ "key": "CppFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" }
],
@@ -56,6 +57,11 @@
"trKey": "Qbs",
"value": "qbs",
"condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}"
+ },
+ {
+ "trKey": "Meson",
+ "value": "meson",
+ "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}"
}
]
}
@@ -99,6 +105,11 @@
"condition": "%{JS: '%{BuildSystem}' === 'qbs'}"
},
{
+ "source": "meson.build",
+ "openAsProject": true,
+ "condition": "%{JS: '%{BuildSystem}' === 'meson'}"
+ },
+ {
"source": "main.cpp",
"target": "%{CppFileName}",
"openInEditor": true
diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/meson.build b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/meson.build
new file mode 100644
index 0000000000..c7a3ffd8e0
--- /dev/null
+++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/meson.build
@@ -0,0 +1,23 @@
+project('%{ProjectName}', 'cpp',default_options : ['cpp_std=c++11'])
+
+# Documentation: https://mesonbuild.com/Qt5-module.html
+qt5 = import('qt5')
+qt5dep = dependency('qt5', modules : ['Core', 'Widgets'])
+
+@if %{HasTranslation}
+translations = qt5.compile_translations(ts_files : '%{TsFileName}', build_by_default : true)
+@endif
+
+generated_files = qt5.preprocess(
+ moc_headers : '%{HdrFileName}',
+ @if %{GenerateForm}
+ ui_files : '%{FormFileName}',
+ @endif
+ dependencies: [qt5dep])
+
+executable('%{ProjectName}'
+ , '%{MainFileName}'
+ , '%{SrcFileName}'
+ , generated_files
+ , dependencies : [qt5dep]
+ , install : true)
diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json
index a33f0cb563..baa5d860e1 100644
--- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json
+++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/wizard.json
@@ -1,6 +1,6 @@
{
"version": 1,
- "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject", "Qt4ProjectManager.Qt4Project", "Qbs.QbsProject" ],
+ "supportedProjectTypes": [ "MesonProjectManager.MesonProject","CMakeProjectManager.CMakeProject", "Qt4ProjectManager.Qt4Project", "Qbs.QbsProject" ],
"id": "C.QtWidgets",
"category": "D.ApplicationQt",
"trDescription": "Creates a Qt application for the desktop. Includes a Qt Designer-based main window.\n\nPreselects a desktop Qt for building the application if available.",
@@ -8,13 +8,14 @@
"trDisplayCategory": "Application (Qt)",
"icon": "../../global/guiapplication.png",
"featuresRequired": [ "QtSupport.Wizards.FeatureQt" ],
- "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0}",
+ "enabled": "%{JS: value('Plugins').indexOf('QmakeProjectManager') >= 0 || value('Plugins').indexOf('CMakeProjectManager') >= 0 || value('Plugins').indexOf('QbsProjectManager') >= 0 || value('Plugins').indexOf('MesonProjectManager') >= 0}",
"options":
[
- { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : value('BuildSystem') === 'cmake' ? value('CMakeFile') : value('QbsFile')}" },
+ { "key": "ProjectFile", "value": "%{JS: value('BuildSystem') === 'qmake' ? value('ProFile') : value('BuildSystem') === 'cmake' ? value('CMakeFile') : value('BuildSystem') === 'meson' ? value('MesonFile') : value('QbsFile')}" },
{ "key": "ProFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'pro')}" },
{ "key": "CMakeFile", "value": "%{ProjectDirectory}/CMakeLists.txt" },
+ { "key": "MesonFile", "value": "%{ProjectDirectory}/meson.build" },
{ "key": "QbsFile", "value": "%{JS: Util.fileName(value('ProjectDirectory') + '/' + value('ProjectName'), 'qbs')}" },
{ "key": "MainFileName", "value": "%{JS: 'main.' + Util.preferredSuffix('text/x-c++src')}" },
{ "key": "UiHdrFileName", "value": "%{JS: (value('BuildSystem') === 'cmake' ? (Util.path(value('FormFileName')) + '/') : '') + 'ui_' + Util.completeBaseName(value('FormFileName')) + '.h'}" },
@@ -59,6 +60,11 @@
"condition": "%{JS: value('Plugins').indexOf('CMakeProjectManager') >= 0}"
},
{
+ "trKey": "Meson",
+ "value": "meson",
+ "condition": "%{JS: value('Plugins').indexOf('MesonProjectManager') >= 0}"
+ },
+ {
"trKey": "Qbs",
"value": "qbs",
"condition": "%{JS: value('Plugins').indexOf('QbsProjectManager') >= 0}"
@@ -183,6 +189,11 @@
"condition": "%{JS: value('BuildSystem') === 'qbs'}"
},
{
+ "source": "meson.build",
+ "openAsProject": true,
+ "condition": "%{JS: value('BuildSystem') === 'meson'}"
+ },
+ {
"source": "main.cpp",
"target": "%{MainFileName}",
"openInEditor": true
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 85aa9991e6..05f97fde95 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -51,6 +51,7 @@ add_subdirectory(fakevim)
add_subdirectory(genericprojectmanager)
add_subdirectory(git)
add_subdirectory(mercurial)
+add_subdirectory(mesonprojectmanager)
add_subdirectory(perforce)
add_subdirectory(qmakeprojectmanager)
add_subdirectory(qmljstools)
diff --git a/src/plugins/mesonprojectmanager/CMakeLists.txt b/src/plugins/mesonprojectmanager/CMakeLists.txt
new file mode 100644
index 0000000000..972fab6473
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/CMakeLists.txt
@@ -0,0 +1,162 @@
+add_qtc_plugin(MesonProjectManager
+ DEPENDS QmlJS
+ PLUGIN_DEPENDS Core CppTools ProjectExplorer TextEditor QtSupport
+ PLUGIN_RECOMMENDS Designer
+ SOURCES
+ mesonprojectplugin.cpp
+ mesonprojectplugin.h
+ versionhelper.h
+ mesonactionsmanager/mesonactionsmanager.h
+ mesonactionsmanager/mesonactionsmanager.cpp
+ settings/tools/toolsmodel.cpp
+ settings/tools/toolssettingswidget.h
+ settings/tools/toolssettingswidget.ui
+ settings/tools/toolssettingswidget.cpp
+ settings/tools/toolssettingspage.cpp
+ settings/tools/toolssettingspage.h
+ settings/tools/toolitemsettings.ui
+ settings/tools/toolitemsettings.cpp
+ settings/tools/toolitemsettings.h
+ settings/tools/tooltreeitem.cpp
+ settings/tools/tooltreeitem.h
+ settings/tools/toolsmodel.h
+ settings/tools/kitaspect/ninjatoolkitaspect.cpp
+ settings/tools/kitaspect/ninjatoolkitaspect.h
+ settings/tools/kitaspect/toolkitaspectwidget.h
+ settings/tools/kitaspect/toolkitaspectwidget.cpp
+ settings/tools/kitaspect/mesontoolkitaspect.cpp
+ settings/tools/kitaspect/mesontoolkitaspect.h
+ settings/tools/toolssettingsaccessor.h
+ settings/tools/toolssettingsaccessor.cpp
+ settings/general/generalsettingswidget.ui
+ settings/general/generalsettingswidget.cpp
+ settings/general/generalsettingswidget.h
+ settings/general/generalsettingspage.h
+ settings/general/generalsettingspage.cpp
+ settings/general/settings.h
+ settings/general/settings.cpp
+ exewrappers/mesonwrapper.cpp
+ exewrappers/mesonwrapper.h
+ exewrappers/ninjawrapper.h
+ exewrappers/toolwrapper.h
+ exewrappers/toolwrapper.cpp
+ exewrappers/mesontools.h
+ exewrappers/mesontools.cpp
+ mesoninfoparser/mesoninfoparser.h
+ mesoninfoparser/buildoptions.h
+ mesoninfoparser/target.h
+ mesoninfoparser/mesoninfo.h
+ mesoninfoparser/parsers/common.h
+ mesoninfoparser/parsers/buildoptionsparser.h
+ mesoninfoparser/parsers/buildsystemfilesparser.h
+ mesoninfoparser/parsers/infoparser.h
+ mesoninfoparser/parsers/targetparser.h
+ kithelper/kitdata.h
+ kithelper/kithelper.h
+ project/mesonproject.h
+ project/mesonproject.cpp
+ project/mesonprojectimporter.h
+ project/mesonprojectimporter.cpp
+ project/mesonbuildsystem.h
+ project/mesonbuildsystem.cpp
+ project/mesonprojectparser.h
+ project/mesonprojectparser.cpp
+ project/mesonbuildconfiguration.h
+ project/mesonbuildconfiguration.cpp
+ project/ninjabuildstep.h
+ project/ninjabuildstep.cpp
+ project/buildoptions/mesonbuildstepconfigwidget.ui
+ project/buildoptions/mesonbuildstepconfigwidget.h
+ project/buildoptions/mesonbuildstepconfigwidget.cpp
+ project/buildoptions/mesonbuildsettingswidget.ui
+ project/buildoptions/mesonbuildsettingswidget.h
+ project/buildoptions/mesonbuildsettingswidget.cpp
+ project/buildoptions/optionsmodel/buildoptionsmodel.h
+ project/buildoptions/optionsmodel/buildoptionsmodel.cpp
+ project/buildoptions/optionsmodel/arrayoptionlineedit.cpp
+ project/buildoptions/optionsmodel/arrayoptionlineedit.h
+ project/mesonprocess.h
+ project/mesonprocess.cpp
+ project/outputparsers/mesonoutputparser.h
+ project/outputparsers/mesonoutputparser.cpp
+ project/outputparsers/ninjaparser.h
+ project/outputparsers/ninjaparser.cpp
+ project/mesonrunconfiguration.h
+ project/mesonrunconfiguration.cpp
+ project/projecttree/projecttree.h
+ project/projecttree/projecttree.cpp
+ project/projecttree/mesonprojectnodes.h
+ project/projecttree/mesonprojectnodes.cpp
+ machinefiles/machinefilemanager.h
+ machinefiles/machinefilemanager.cpp
+ machinefiles/nativefilegenerator.h
+ machinefiles/nativefilegenerator.cpp
+ resources.qrc
+)
+
+if(WITH_TESTS)
+add_qtc_test(tst_mesonwrapper
+ INCLUDES
+ BEFORE "."
+ DEPENDS
+ Qt5::Core Qt5::Test Core
+ Utils
+ DEFINES
+ MESON_SAMPLES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/resources"
+ MESON_SAMPLES_BUILD_DIR="${CMAKE_CURRENT_BINARY_DIR}"
+ SOURCES
+ tests/testmesonwrapper.cpp
+ exewrappers/mesonwrapper.cpp
+ exewrappers/mesonwrapper.h
+ exewrappers/ninjawrapper.h
+ exewrappers/toolwrapper.h
+ exewrappers/toolwrapper.cpp
+ exewrappers/mesontools.h
+)
+
+add_qtc_test(tst_mesoninfoparser
+ INCLUDES
+ BEFORE "."
+ DEPENDS
+ Qt5::Core Qt5::Test Core
+ Utils
+ DEFINES
+ MESON_SAMPLES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/tests/resources"
+ MESON_SAMPLES_BUILD_DIR="${CMAKE_CURRENT_BINARY_DIR}"
+ SOURCES
+ tests/testmesoninfoparser.cpp
+ exewrappers/mesonwrapper.cpp
+ exewrappers/mesonwrapper.h
+ exewrappers/ninjawrapper.h
+ exewrappers/toolwrapper.h
+ exewrappers/toolwrapper.cpp
+ exewrappers/mesontools.h
+ mesoninfoparser/mesoninfoparser.h
+)
+
+add_qtc_test(tst_ninjaparser
+ INCLUDES
+ BEFORE "."
+ DEPENDS
+ Qt5::Core Qt5::Test Core
+ Utils ProjectExplorer
+ SOURCES
+ tests/testninjaparser.cpp
+ project/outputparsers/ninjaparser.cpp
+)
+
+add_qtc_test(tst_mesonparser
+ INCLUDES
+ BEFORE "."
+ DEFINES
+ MESONPARSER_DISABLE_TASKS_FOR_TESTS
+ DEPENDS
+ Qt5::Core Qt5::Test Core
+ Utils ProjectExplorer
+ SOURCES
+ tests/testmesonparser.cpp
+ project/outputparsers/mesonoutputparser.cpp
+)
+
+
+endif(WITH_TESTS)
diff --git a/src/plugins/mesonprojectmanager/MesonProjectManager.json.in b/src/plugins/mesonprojectmanager/MesonProjectManager.json.in
new file mode 100644
index 0000000000..27a0bfda7d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/MesonProjectManager.json.in
@@ -0,0 +1,21 @@
+{
+ \"Name\" : \"MesonProjectManager\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Vendor\" : \"Laboratory of Plasma Physics\",
+ \"Experimental\" : true,
+ \"DisabledByDefault\" : true,
+ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR Laboratory of Plasma Physics\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html.\"
+ ],
+ \"Category\" : \"Build Systems\",
+ \"Description\" : \"Meson support.\",
+ \"Url\" : \"http://www.mesonbuild.com\",
+ $$dependencyList
+}
diff --git a/src/plugins/mesonprojectmanager/exewrappers/mesontools.cpp b/src/plugins/mesonprojectmanager/exewrappers/mesontools.cpp
new file mode 100644
index 0000000000..9c773818c8
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/mesontools.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesontools.h"
+namespace MesonProjectManager {
+namespace Internal {
+
+template<typename T>
+inline bool is(const MesonTools::Tool_t &tool)
+{
+ return bool(std::dynamic_pointer_cast<T>(tool));
+}
+
+template<typename T>
+std::shared_ptr<T> tool(const Core::Id &id, const std::vector<MesonTools::Tool_t> &tools)
+{
+ static_assert(std::is_base_of<ToolWrapper, T>::value, "Type must derive from ToolWrapper");
+ const auto tool = std::find_if(std::cbegin(tools),
+ std::cend(tools),
+ [&id](const MesonTools::Tool_t &tool) {
+ return tool->id() == id;
+ });
+ if (tool != std::cend(tools) && is<T>(*tool))
+ return std::dynamic_pointer_cast<T>(*tool);
+ return nullptr;
+}
+
+template<typename T>
+std::shared_ptr<T> autoDetected(const std::vector<MesonTools::Tool_t> &tools)
+{
+ static_assert(std::is_base_of<ToolWrapper, T>::value, "Type must derive from ToolWrapper");
+ for (const auto &tool : tools) {
+ if (tool->autoDetected() && is<T>(tool)) {
+ return std::dynamic_pointer_cast<T>(tool);
+ }
+ }
+ return nullptr;
+}
+
+template<typename T>
+void fixAutoDetected(std::vector<MesonTools::Tool_t> &tools)
+{
+ auto autoDetectedTool = autoDetected<T>(tools);
+ if (!autoDetectedTool) {
+ auto path = T::find();
+ if (path)
+ tools.emplace_back(std::make_shared<T>(
+ QString("System %1 at %2").arg(T::toolName()).arg(path->toString()), *path, true));
+ }
+}
+
+bool MesonTools::isMesonWrapper(const MesonTools::Tool_t &tool)
+{
+ return is<MesonWrapper>(tool);
+}
+
+bool MesonTools::isNinjaWrapper(const MesonTools::Tool_t &tool)
+{
+ return is<NinjaWrapper>(tool);
+}
+
+void MesonTools::setTools(std::vector<MesonTools::Tool_t> &&tools)
+{
+ auto self = instance();
+ std::swap(self->m_tools, tools);
+ fixAutoDetected<MesonWrapper>(self->m_tools);
+ fixAutoDetected<NinjaWrapper>(self->m_tools);
+}
+
+std::shared_ptr<NinjaWrapper> MesonTools::ninjaWrapper(const Core::Id &id)
+{
+ return tool<NinjaWrapper>(id, MesonTools::instance()->m_tools);
+}
+std::shared_ptr<MesonWrapper> MesonTools::mesonWrapper(const Core::Id &id)
+{
+ return tool<MesonWrapper>(id, MesonTools::instance()->m_tools);
+}
+
+std::shared_ptr<NinjaWrapper> MesonTools::ninjaWrapper()
+{
+ return autoDetected<NinjaWrapper>(MesonTools::instance()->m_tools);
+}
+
+std::shared_ptr<MesonWrapper> MesonTools::mesonWrapper()
+{
+ return autoDetected<MesonWrapper>(MesonTools::instance()->m_tools);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/mesontools.h b/src/plugins/mesonprojectmanager/exewrappers/mesontools.h
new file mode 100644
index 0000000000..35337d4fc4
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/mesontools.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "mesonwrapper.h"
+#include "ninjawrapper.h"
+#include "toolwrapper.h"
+#include <mesonpluginconstants.h>
+
+#include <utils/algorithm.h>
+
+#include <QObject>
+
+#include <memory>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class MesonTools : public QObject
+{
+ Q_OBJECT
+ MesonTools() {}
+ ~MesonTools() {}
+
+public:
+ using Tool_t = std::shared_ptr<ToolWrapper>;
+
+
+ static bool isMesonWrapper(const Tool_t &tool);
+ static bool isNinjaWrapper(const Tool_t &tool);
+
+ static inline void addTool(const Core::Id &itemId,
+ const QString &name,
+ const Utils::FilePath &exe)
+ {
+ // TODO improve this
+ if (exe.fileName().contains("ninja"))
+ addTool(std::make_shared<NinjaWrapper>(name, exe, itemId));
+ else
+ addTool(std::make_shared<MesonWrapper>(name, exe, itemId));
+ }
+
+ static inline void addTool(Tool_t meson)
+ {
+ auto self = instance();
+ self->m_tools.emplace_back(std::move(meson));
+ emit self->toolAdded(self->m_tools.back());
+ }
+
+ static void setTools(std::vector<Tool_t> &&tools);
+
+ static inline const std::vector<Tool_t> &tools() { return instance()->m_tools; }
+
+ static inline void updateTool(const Core::Id &itemId,
+ const QString &name,
+ const Utils::FilePath &exe)
+ {
+ auto self = instance();
+ auto item = std::find_if(std::begin(self->m_tools),
+ std::end(self->m_tools),
+ [&itemId](const Tool_t &tool) { return tool->id() == itemId; });
+ if (item != std::end(self->m_tools)) {
+ (*item)->setExe(exe);
+ (*item)->setName(name);
+ } else {
+ addTool(itemId, name, exe);
+ }
+ }
+ static void removeTool(const Core::Id &id)
+ {
+ auto self = instance();
+ auto item = Utils::take(self->m_tools, [&id](const auto &item) { return item->id() == id; });
+ QTC_ASSERT(item, return );
+ emit self->toolRemoved(*item);
+ }
+
+ static std::shared_ptr<NinjaWrapper> ninjaWrapper(const Core::Id &id);
+ static std::shared_ptr<MesonWrapper> mesonWrapper(const Core::Id &id);
+
+ static std::shared_ptr<NinjaWrapper> ninjaWrapper();
+ static std::shared_ptr<MesonWrapper> mesonWrapper();
+
+ Q_SIGNAL void toolAdded(const Tool_t &tool);
+ Q_SIGNAL void toolRemoved(const Tool_t &tool);
+
+ static MesonTools *instance()
+ {
+ static MesonTools inst;
+ return &inst;
+ }
+
+private:
+ std::vector<Tool_t> m_tools;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.cpp b/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.cpp
new file mode 100644
index 0000000000..cfc30dc954
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonwrapper.h"
+#include "utils/algorithm.h"
+#include "utils/qtcassert.h"
+#include <QUuid>
+
+namespace {
+template<typename First>
+void impl_option_cat(QStringList &list, const First &first)
+{
+ list.append(first);
+}
+
+template<typename First, typename... T>
+void impl_option_cat(QStringList &list, const First &first, const T &... args)
+{
+ impl_option_cat(list, first);
+ impl_option_cat(list, args...);
+}
+
+template<typename... T>
+QStringList options_cat(const T &... args)
+{
+ QStringList result;
+ impl_option_cat(result, args...);
+ return result;
+}
+
+} // namespace
+namespace MesonProjectManager {
+namespace Internal {
+
+Command MesonWrapper::setup(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory,
+ const QStringList &options) const
+{
+ return {m_exe,
+ sourceDirectory,
+ options_cat("setup", options, sourceDirectory.toString(), buildDirectory.toString())};
+}
+
+Command MesonWrapper::configure(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory,
+ const QStringList &options) const
+{
+ if (!isSetup(buildDirectory))
+ return setup(sourceDirectory, buildDirectory, options);
+ return {m_exe, buildDirectory, options_cat("configure", options, buildDirectory.toString())};
+}
+
+Command MesonWrapper::regenerate(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory) const
+{
+ return {m_exe,
+ buildDirectory,
+ options_cat("--internal",
+ "regenerate",
+ sourceDirectory.toString(),
+ buildDirectory.toString(),
+ "--backend",
+ "ninja")};
+}
+
+Command MesonWrapper::introspect(const Utils::FilePath &sourceDirectory) const
+{
+ return {m_exe,
+ sourceDirectory,
+ {"introspect", "--all", QString("%1/meson.build").arg(sourceDirectory.toString())}};
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.h b/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.h
new file mode 100644
index 0000000000..8423b58d2b
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/mesonwrapper.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include "../mesonpluginconstants.h"
+#include "toolwrapper.h"
+#include "utils/environment.h"
+#include "utils/fileutils.h"
+#include "utils/optional.h"
+#include <coreplugin/id.h>
+#include <tuple>
+#include <QFile>
+#include <QFileInfo>
+#include <QObject>
+#include <QProcess>
+#include <QTemporaryFile>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+template<typename File_t>
+bool containsFiles(const QString &path, const File_t &file)
+{
+ return QFile::exists(QString("%1/%2").arg(path).arg(file));
+}
+
+template<typename File_t, typename... T>
+bool containsFiles(const QString &path, const File_t &file, const T &... files)
+{
+ return containsFiles(path, file) && containsFiles(path, files...);
+}
+
+inline bool run_meson(const Command &command, QIODevice *output = nullptr)
+{
+ QProcess process;
+ process.setWorkingDirectory(command.workDir().toString());
+ process.start(command.executable().toString(), command.arguments());
+ if (!process.waitForFinished())
+ return false;
+ if (output) {
+ output->write(process.readAllStandardOutput());
+ }
+ return process.exitCode() == 0;
+}
+
+inline bool isSetup(const Utils::FilePath &buildPath)
+{
+ using namespace Utils;
+ return containsFiles(buildPath.pathAppended(Constants::MESON_INFO_DIR).toString(),
+ Constants::MESON_INTRO_TESTS,
+ Constants::MESON_INTRO_TARGETS,
+ Constants::MESON_INTRO_INSTALLED,
+ Constants::MESON_INTRO_BENCHMARKS,
+ Constants::MESON_INTRO_BUIDOPTIONS,
+ Constants::MESON_INTRO_PROJECTINFO,
+ Constants::MESON_INTRO_DEPENDENCIES,
+ Constants::MESON_INTRO_BUILDSYSTEM_FILES);
+}
+
+class MesonWrapper final : public ToolWrapper
+{
+public:
+ using ToolWrapper::ToolWrapper;
+
+ Command setup(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory,
+ const QStringList &options = {}) const;
+ Command configure(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory,
+ const QStringList &options = {}) const;
+
+ Command regenerate(const Utils::FilePath &sourceDirectory,
+ const Utils::FilePath &buildDirectory)const;
+
+ Command introspect(const Utils::FilePath &sourceDirectory) const;
+
+ static inline Utils::optional<Utils::FilePath> find()
+ {
+ return ToolWrapper::findTool({"meson.py","meson"});
+ }
+
+ static inline QString toolName() { return "Meson"; };
+};
+
+template<>
+inline QVariantMap toVariantMap<MesonWrapper>(const MesonWrapper &meson)
+{
+ QVariantMap data;
+ data.insert(Constants::ToolsSettings::NAME_KEY, meson.m_name);
+ data.insert(Constants::ToolsSettings::EXE_KEY, meson.m_exe.toVariant());
+ data.insert(Constants::ToolsSettings::AUTO_DETECTED_KEY, meson.m_autoDetected);
+ data.insert(Constants::ToolsSettings::ID_KEY, meson.m_id.toSetting());
+ data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_MESON);
+ return data;
+}
+template<>
+inline MesonWrapper *fromVariantMap<MesonWrapper *>(const QVariantMap &data)
+{
+ return new MesonWrapper(data[Constants::ToolsSettings::NAME_KEY].toString(),
+ Utils::FilePath::fromVariant(data[Constants::ToolsSettings::EXE_KEY]),
+ Core::Id::fromSetting(data[Constants::ToolsSettings::ID_KEY]),
+ data[Constants::ToolsSettings::AUTO_DETECTED_KEY].toBool());
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/ninjawrapper.h b/src/plugins/mesonprojectmanager/exewrappers/ninjawrapper.h
new file mode 100644
index 0000000000..85f6476587
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/ninjawrapper.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../mesonpluginconstants.h"
+#include "toolwrapper.h"
+namespace MesonProjectManager {
+namespace Internal {
+
+class NinjaWrapper final : public ToolWrapper
+{
+public:
+ using ToolWrapper::ToolWrapper;
+
+ static inline Utils::optional<Utils::FilePath> find()
+ {
+ return ToolWrapper::findTool({"ninja", "ninja-build"});
+ }
+ static inline QString toolName() { return "Ninja"; };
+};
+
+template<>
+inline QVariantMap toVariantMap<NinjaWrapper>(const NinjaWrapper &meson)
+{
+ QVariantMap data;
+ data.insert(Constants::ToolsSettings::NAME_KEY, meson.m_name);
+ data.insert(Constants::ToolsSettings::EXE_KEY, meson.m_exe.toVariant());
+ data.insert(Constants::ToolsSettings::AUTO_DETECTED_KEY, meson.m_autoDetected);
+ data.insert(Constants::ToolsSettings::ID_KEY, meson.m_id.toSetting());
+ data.insert(Constants::ToolsSettings::TOOL_TYPE_KEY, Constants::ToolsSettings::TOOL_TYPE_NINJA);
+ return data;
+}
+template<>
+inline NinjaWrapper *fromVariantMap<NinjaWrapper *>(const QVariantMap &data)
+{
+ return new NinjaWrapper(data[Constants::ToolsSettings::NAME_KEY].toString(),
+ Utils::FilePath::fromVariant(data[Constants::ToolsSettings::EXE_KEY]),
+ Core::Id::fromSetting(data[Constants::ToolsSettings::ID_KEY]),
+ data[Constants::ToolsSettings::AUTO_DETECTED_KEY].toBool());
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp
new file mode 100644
index 0000000000..a89d2bf336
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "toolwrapper.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+
+ToolWrapper::ToolWrapper(const QString &name, const Utils::FilePath &path, bool autoDetected)
+ : m_version(read_version(path))
+ , m_isValid{path.exists() && m_version.isValid}
+ , m_autoDetected{autoDetected}
+ , m_id{Core::Id::fromString(QUuid::createUuid().toString())}
+ , m_exe{path}
+ , m_name{name}
+{}
+
+ToolWrapper::ToolWrapper(const QString &name,
+ const Utils::FilePath &path,
+ const Core::Id &id,
+ bool autoDetected)
+ : m_version(read_version(path))
+ , m_isValid{path.exists() && m_version.isValid}
+ , m_autoDetected{autoDetected}
+ , m_id{id}
+ , m_exe{path}
+ , m_name{name}
+{
+ QTC_ASSERT(m_id.isValid(), m_id = Core::Id::fromString(QUuid::createUuid().toString()));
+}
+
+void ToolWrapper::setExe(const Utils::FilePath &newExe)
+{
+ m_exe = newExe;
+ m_version = read_version(m_exe);
+}
+
+Version ToolWrapper::read_version(const Utils::FilePath &toolPath)
+{
+ if (toolPath.toFileInfo().isExecutable()) {
+ QProcess process;
+ process.start(toolPath.toString(), {"--version"});
+ if (process.waitForFinished()) {
+ return Version::fromString(QString::fromUtf8(process.readLine()));
+ }
+ }
+ return {};
+}
+
+Utils::optional<Utils::FilePath> ToolWrapper::findTool(const QStringList &exeNames)
+{
+ using namespace Utils;
+ Environment systemEnvironment = Environment::systemEnvironment();
+ for (const auto &exe : exeNames) {
+ const FilePath exe_path = systemEnvironment.searchInPath(exe);
+ if (exe_path.exists())
+ return exe_path;
+ }
+ return Utils::nullopt;
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h
new file mode 100644
index 0000000000..717b38e4c1
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <coreplugin/id.h>
+#include <utils/environment.h>
+#include <utils/fileutils.h>
+#include <utils/qtcassert.h>
+#include <versionhelper.h>
+#include <QFileInfo>
+#include <QProcess>
+#include <QString>
+#include <QUuid>
+#include <QVariant>
+#include <QVariantMap>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class Command
+{
+ Utils::CommandLine m_cmd;
+ Utils::FilePath m_workDir;
+
+public:
+ Command() = default;
+ Command(const Utils::FilePath &exe, const Utils::FilePath &workDir, const QStringList &args)
+ : m_cmd{exe, args}
+ , m_workDir{workDir}
+ {}
+ inline const Utils::CommandLine &cmdLine() const { return m_cmd; }
+ inline const Utils::FilePath &workDir() const { return m_workDir; }
+ inline Utils::FilePath executable() const { return m_cmd.executable(); }
+ inline QStringList arguments() const { return m_cmd.splitArguments(); }
+ inline QString toUserOutput() const { return m_cmd.toUserOutput(); };
+};
+
+class ToolWrapper
+{
+public:
+ virtual ~ToolWrapper(){};
+ ToolWrapper() = delete;
+ ToolWrapper(const QString &name, const Utils::FilePath &path, bool autoDetected = false);
+ ToolWrapper(const QString &name,
+ const Utils::FilePath &path,
+ const Core::Id &id,
+ bool autoDetected = false);
+ ToolWrapper(const ToolWrapper &other) = default;
+ ToolWrapper(ToolWrapper &&other) = default;
+ ToolWrapper &operator=(const ToolWrapper &other) = default;
+ ToolWrapper &operator=(ToolWrapper &&other) = default;
+
+ inline const Version &version() const noexcept { return m_version; };
+ inline bool isValid() const noexcept { return m_isValid; };
+ inline bool autoDetected() const noexcept { return m_autoDetected; };
+ inline Core::Id id() const noexcept { return m_id; };
+ inline Utils::FilePath exe() const noexcept { return m_exe; };
+ inline QString name() const noexcept { return m_name; };
+
+ inline void setName(const QString &newName) { m_name = newName; }
+ virtual void setExe(const Utils::FilePath &newExe);
+
+ static Version read_version(const Utils::FilePath &toolPath);
+
+ static Utils::optional<Utils::FilePath> findTool(const QStringList &exeNames);
+
+ template<typename T>
+ friend QVariantMap toVariantMap(const T &);
+ template<typename T>
+ friend T fromVariantMap(const QVariantMap &);
+
+protected:
+ Version m_version;
+ bool m_isValid;
+ bool m_autoDetected;
+ Core::Id m_id;
+ Utils::FilePath m_exe;
+ QString m_name;
+};
+
+template<typename T>
+QVariantMap toVariantMap(const T &);
+template<typename T>
+T fromVariantMap(const QVariantMap &);
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/icons/README.txt b/src/plugins/mesonprojectmanager/icons/README.txt
new file mode 100644
index 0000000000..e21aaaa049
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/icons/README.txt
@@ -0,0 +1,3 @@
+These pictures are place holders for real Meson logo until license issue is resolved, see here for more details:
+https://codereview.qt-project.org/c/qt-creator/qt-creator/+/298968/23
+
diff --git a/src/plugins/mesonprojectmanager/icons/meson_bw_logo.png b/src/plugins/mesonprojectmanager/icons/meson_bw_logo.png
new file mode 100644
index 0000000000..57e017af71
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/icons/meson_bw_logo.png
Binary files differ
diff --git a/src/plugins/mesonprojectmanager/icons/meson_bw_logo@2x.png b/src/plugins/mesonprojectmanager/icons/meson_bw_logo@2x.png
new file mode 100644
index 0000000000..51ecb6665d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/icons/meson_bw_logo@2x.png
Binary files differ
diff --git a/src/plugins/mesonprojectmanager/icons/meson_logo.png b/src/plugins/mesonprojectmanager/icons/meson_logo.png
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/icons/meson_logo.png
@@ -0,0 +1 @@
+
diff --git a/src/plugins/mesonprojectmanager/kithelper/kitdata.h b/src/plugins/mesonprojectmanager/kithelper/kitdata.h
new file mode 100644
index 0000000000..a4463a6640
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/kithelper/kitdata.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <utils/cpplanguage_details.h>
+#include <QString>
+namespace MesonProjectManager {
+namespace Internal {
+struct KitData
+{
+ QString cCompilerPath;
+ QString cxxCompilerPath;
+ QString cmakePath;
+ QString qmakePath;
+ QString qtVersionStr;
+ Utils::QtVersion qtVersion;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/kithelper/kithelper.h b/src/plugins/mesonprojectmanager/kithelper/kithelper.h
new file mode 100644
index 0000000000..9f0f8295e3
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/kithelper/kithelper.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "kitdata.h"
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitinformation.h>
+#include <utils/macroexpander.h>
+#include <utils/qtcassert.h>
+#include <versionhelper.h>
+#include <QString>
+#pragma once
+namespace MesonProjectManager {
+namespace Internal {
+namespace KitHelper {
+namespace details {
+inline QString expand(const ProjectExplorer::Kit *kit, const QString &macro)
+{
+ return kit->macroExpander()->expand(macro);
+}
+} // namespace details
+
+inline QString cCompilerPath(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return "");
+ return details::expand(kit, "%{Compiler:Executable:C}");
+}
+
+inline QString cxxCompilerPath(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return "");
+ return details::expand(kit, "%{Compiler:Executable:Cxx}");
+}
+
+inline QString qmakePath(const ProjectExplorer::Kit *kit)
+{
+ return details::expand(kit, "%{Qt:qmakeExecutable}");
+}
+
+inline QString cmakePath(const ProjectExplorer::Kit *kit)
+{
+ return details::expand(kit, "%{CMake:Executable:FilePath}");
+}
+
+inline QString qtVersion(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return "");
+ return details::expand(kit, "%{Qt:Version}");
+}
+
+inline KitData kitData(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return {});
+ KitData data;
+ data.cCompilerPath = cCompilerPath(kit);
+ data.cxxCompilerPath = cxxCompilerPath(kit);
+ data.cmakePath = cmakePath(kit);
+ data.qmakePath = qmakePath(kit);
+ data.qtVersionStr = qtVersion(kit);
+ data.qtVersion = Utils::QtVersion::None;
+ auto version = Version::fromString(data.qtVersionStr);
+ if (version.isValid) {
+ switch (version.major) {
+ case 4:
+ data.qtVersion = Utils::QtVersion::Qt4;
+ break;
+ case 5:
+ data.qtVersion = Utils::QtVersion::Qt5;
+ break;
+ default:
+ data.qtVersion = Utils::QtVersion::Unknown;
+ }
+ }
+ return data;
+}
+
+} // namespace KitHelper
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp
new file mode 100644
index 0000000000..b4bffabd0b
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "machinefilemanager.h"
+#include "nativefilegenerator.h"
+#include <kithelper/kitdata.h>
+#include <kithelper/kithelper.h>
+#include <coreplugin/icore.h>
+#include <utils/optional.h>
+#include <utils/qtcassert.h>
+#include <QDir>
+#include <QFile>
+#include <QRegularExpression>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+const char MACHINE_FILE_PREFIX[] = "Meson-MachineFile-";
+const char MACHINE_FILE_EXT[] = ".ini";
+
+template<typename F>
+bool withFile(const Utils::FilePath &path, const F &f)
+{
+ QFile file(path.toString());
+ if (file.open(QIODevice::WriteOnly)) {
+ f(&file);
+ return file.flush();
+ }
+ return false;
+}
+
+Utils::FilePath MachineFilesDir()
+{
+ return Utils::FilePath::fromString(Core::ICore::userResourcePath())
+ .pathAppended("Meson-machine-files");
+}
+
+MachineFileManager::MachineFileManager()
+{
+ using namespace ProjectExplorer;
+ connect(KitManager::instance(),
+ &KitManager::kitAdded,
+ this,
+ &MachineFileManager::addMachineFile);
+ connect(KitManager::instance(),
+ &KitManager::kitUpdated,
+ this,
+ &MachineFileManager::updateMachineFile);
+ connect(KitManager::instance(),
+ &KitManager::kitRemoved,
+ this,
+ &MachineFileManager::removeMachineFile);
+ connect(KitManager::instance(),
+ &KitManager::kitsLoaded,
+ this,
+ &MachineFileManager::cleanupMachineFiles);
+}
+
+Utils::FilePath MachineFileManager::machineFile(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return {});
+ auto baseName
+ = QString("%1%2%3").arg(MACHINE_FILE_PREFIX).arg(kit->id().toString()).arg(MACHINE_FILE_EXT);
+ baseName = baseName.remove('{').remove('}');
+ return MachineFilesDir().pathAppended(baseName);
+}
+
+void MachineFileManager::addMachineFile(const ProjectExplorer::Kit *kit)
+{
+ auto filePath = machineFile(kit);
+ QTC_ASSERT(!filePath.isEmpty(), return );
+ auto data = KitHelper::kitData(kit);
+ QTC_ASSERT(withFile(filePath,
+ [&data](QFile *file) { NativeFileGenerator::makeNativeFile(file, data); }),
+ return );
+}
+
+void MachineFileManager::removeMachineFile(const ProjectExplorer::Kit *kit)
+{
+ auto filePath = machineFile(kit);
+ if (filePath.exists())
+ QFile::remove(filePath.toString());
+}
+
+void MachineFileManager::updateMachineFile(const ProjectExplorer::Kit *kit)
+{
+ addMachineFile(kit);
+}
+
+void MachineFileManager::cleanupMachineFiles()
+{
+ const auto kits = ProjectExplorer::KitManager::kits();
+ auto machineFilesDir = QDir(MachineFilesDir().toString());
+ if (!machineFilesDir.exists()) {
+ machineFilesDir.mkdir(machineFilesDir.path());
+ }
+ auto machineFiles = QDir(MachineFilesDir().toString())
+ .entryList(
+ {QString("%1*%2").arg(MACHINE_FILE_PREFIX).arg(MACHINE_FILE_EXT)});
+ QStringList expected;
+ for (auto const *kit : kits) {
+ QString fname = machineFile(kit).toString();
+ expected.push_back(fname);
+ if (!machineFiles.contains(fname))
+ addMachineFile(kit);
+ }
+
+ for (const auto &file : machineFiles) {
+ if (!expected.contains(file))
+ QFile::remove(file);
+ }
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.h b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.h
new file mode 100644
index 0000000000..e4fe27b6bc
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/machinefiles/machinefilemanager.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitmanager.h>
+#include <utils/fileutils.h>
+#include <QObject>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class MachineFileManager final : public QObject
+{
+ Q_OBJECT
+public:
+ MachineFileManager();
+
+ static Utils::FilePath machineFile(const ProjectExplorer::Kit *kit);
+
+private:
+ void addMachineFile(const ProjectExplorer::Kit *kit);
+ void removeMachineFile(const ProjectExplorer::Kit *kit);
+ void updateMachineFile(const ProjectExplorer::Kit *kit);
+ void cleanupMachineFiles();
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.cpp b/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.cpp
new file mode 100644
index 0000000000..249c96809f
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "nativefilegenerator.h"
+#include <kithelper/kithelper.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/toolchain.h>
+#include <utils/macroexpander.h>
+#include <utils/qtcassert.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+NativeFileGenerator::NativeFileGenerator() {}
+
+inline void addEntry(QIODevice *nativeFile, const QString &key, const QString &value)
+{
+ nativeFile->write(QString("%1 = '%2'\n").arg(key).arg(value).toUtf8());
+}
+
+void writeBinariesSection(QIODevice *nativeFile, const KitData &kitData)
+{
+ nativeFile->write("[binaries]\n");
+ addEntry(nativeFile, "c", kitData.cCompilerPath);
+ addEntry(nativeFile, "cpp", kitData.cxxCompilerPath);
+ addEntry(nativeFile, "qmake", kitData.qmakePath);
+ if (kitData.qtVersion == Utils::QtVersion::Qt4)
+ addEntry(nativeFile, QString{"qmake-qt4"}, kitData.qmakePath);
+ else if (kitData.qtVersion == Utils::QtVersion::Qt5)
+ addEntry(nativeFile, QString{"qmake-qt5"}, kitData.qmakePath);
+ addEntry(nativeFile, "cmake", kitData.cmakePath);
+}
+
+void NativeFileGenerator::makeNativeFile(QIODevice *nativeFile, const KitData &kitData)
+{
+ QTC_ASSERT(nativeFile, return );
+ writeBinariesSection(nativeFile, kitData);
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.h b/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.h
new file mode 100644
index 0000000000..fab2472333
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/machinefiles/nativefilegenerator.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <kithelper/kitdata.h>
+#include <projectexplorer/kit.h>
+#include <QIODevice>
+namespace MesonProjectManager {
+namespace Internal {
+class NativeFileGenerator
+{
+ NativeFileGenerator();
+
+public:
+ static void makeNativeFile(QIODevice *nativeFile, const KitData &kitData);
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.cpp b/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.cpp
new file mode 100644
index 0000000000..521b0ba865
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.cpp
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonactionsmanager.h"
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <project/mesonbuildsystem.h>
+#include <project/projecttree/mesonprojectnodes.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projecttree.h>
+#include <utils/parameteraction.h>
+namespace MesonProjectManager {
+namespace Internal {
+
+MesonActionsManager::MesonActionsManager()
+ : configureActionMenu(tr("Configure"))
+ , configureActionContextMenu(tr("Configure"))
+{
+ const Core::Context globalContext(Core::Constants::C_GLOBAL);
+ const Core::Context projectContext{Constants::Project::ID};
+ Core::ActionContainer *mproject = Core::ActionManager::actionContainer(
+ ProjectExplorer::Constants::M_PROJECTCONTEXT);
+ Core::ActionContainer *msubproject = Core::ActionManager::actionContainer(
+ ProjectExplorer::Constants::M_SUBPROJECTCONTEXT);
+
+ Core::Command *command;
+
+ {
+ command = Core::ActionManager::registerAction(&configureActionMenu,
+ "MesonProject.Configure",
+ projectContext);
+ mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ connect(&configureActionMenu,
+ &QAction::triggered,
+ this,
+ &MesonActionsManager::configureCurrentProject);
+ }
+
+ {
+ command = Core::ActionManager::registerAction(&buildTargetContextAction,
+ "Meson.BuildTargetContextMenu",
+ projectContext);
+ command->setAttribute(Core::Command::CA_Hide);
+ command->setAttribute(Core::Command::CA_UpdateText);
+ command->setDescription(buildTargetContextAction.text());
+
+ Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT)
+ ->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD);
+ // Wire up context menu updates:
+ connect(ProjectExplorer::ProjectTree::instance(),
+ &ProjectExplorer::ProjectTree::currentNodeChanged,
+ this,
+ &MesonActionsManager::updateContextActions);
+
+ connect(&buildTargetContextAction, &Utils::ParameterAction::triggered, this, [] {
+ auto bs = qobject_cast<MesonBuildSystem *>(
+ ProjectExplorer::ProjectTree::currentBuildSystem());
+ if (bs) {
+ auto targetNode = dynamic_cast<MesonTargetNode *>(
+ ProjectExplorer::ProjectTree::currentNode());
+ targetNode->build();
+ }
+ });
+ }
+}
+
+void MesonActionsManager::configureCurrentProject()
+{
+ auto bs = dynamic_cast<MesonBuildSystem *>(ProjectExplorer::ProjectTree::currentBuildSystem());
+ QTC_ASSERT(bs, return );
+ if (ProjectExplorer::ProjectExplorerPlugin::saveModifiedFiles())
+ bs->configure();
+}
+
+void MesonActionsManager::updateContextActions()
+{
+ auto targetNode = dynamic_cast<const MesonTargetNode *>(
+ ProjectExplorer::ProjectTree::currentNode());
+ const QString targetDisplayName = targetNode ? targetNode->displayName() : QString();
+
+ // Build Target:
+ buildTargetContextAction.setParameter(targetDisplayName);
+ buildTargetContextAction.setEnabled(targetNode);
+ buildTargetContextAction.setVisible(targetNode);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.h b/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.h
new file mode 100644
index 0000000000..34bf2eb444
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonactionsmanager/mesonactionsmanager.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <utils/parameteraction.h>
+#include <QAction>
+#include <QObject>
+namespace MesonProjectManager {
+namespace Internal {
+class MesonActionsManager : public QObject
+{
+ Q_OBJECT
+ Utils::ParameterAction buildTargetContextAction{
+ tr("Build"), tr("Build \"%1\""), Utils::ParameterAction::AlwaysEnabled /*handled manually*/
+ };
+ QAction configureActionMenu;
+ QAction configureActionContextMenu;
+ void configureCurrentProject();
+ void updateContextActions();
+
+public:
+ MesonActionsManager();
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/buildoptions.h b/src/plugins/mesonprojectmanager/mesoninfoparser/buildoptions.h
new file mode 100644
index 0000000000..74b33b72cc
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/buildoptions.h
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <utils/fileutils.h>
+#include <utils/optional.h>
+#include <QCheckBox>
+#include <QComboBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QSpinBox>
+#include <QString>
+#include <QVariant>
+#include <QWidget>
+namespace MesonProjectManager {
+namespace Internal {
+
+struct ComboData
+{
+ QString value() const { return m_choices.at(m_currentIndex != -1 ? m_currentIndex : 0); }
+ void setValue(const QString &value) { m_currentIndex = m_choices.indexOf(value); }
+ ComboData(const QStringList &choices, const QString &value)
+ : m_choices{choices}
+ {
+ setValue(value);
+ }
+ ComboData() = default;
+ const QStringList &choices() const { return m_choices; }
+ int currentIndex() const { return m_currentIndex; }
+
+private:
+ QStringList m_choices;
+ int m_currentIndex = 0;
+};
+
+struct FeatureData : ComboData
+{
+ FeatureData()
+ : ComboData({"enabled", "disabled", "auto"}, "disabled")
+ {}
+ FeatureData(const QString &value)
+ : ComboData({"enabled", "disabled", "auto"}, value)
+ {}
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
+Q_DECLARE_METATYPE(MesonProjectManager::Internal::FeatureData);
+Q_DECLARE_METATYPE(MesonProjectManager::Internal::ComboData);
+
+namespace MesonProjectManager {
+namespace Internal {
+
+struct BuildOption
+{
+ enum class Type { integer, string, feature, combo, array, boolean, unknown };
+ const QString name;
+ const QString section;
+ const QString description;
+ const Utils::optional<QString> subproject;
+ virtual ~BuildOption() {}
+ virtual QVariant value() const = 0;
+ virtual QString valueStr() const = 0;
+ virtual void setValue(const QVariant &) = 0;
+ virtual Type type() const = 0;
+ virtual BuildOption *copy() const = 0;
+ inline QString fullName() const
+ {
+ if (subproject)
+ return QString("%1:%2").arg(*subproject).arg(name);
+ return name;
+ }
+ inline virtual QString mesonArg() const
+ {
+ return QString("-D%1=%2").arg(fullName()).arg(valueStr());
+ }
+ BuildOption(const QString &name, const QString &section, const QString &description)
+ : name{name.contains(":") ? name.split(":").last() : name}
+ , section{section}
+ , description{description}
+ , subproject{name.contains(":") ? Utils::optional<QString>(name.split(":").first())
+ : Utils::nullopt}
+ {}
+}; // namespace Internal
+
+struct IntegerBuildOption final : BuildOption
+{
+ QVariant value() const override { return m_currentValue; }
+ QString valueStr() const override { return QString::number(m_currentValue); }
+ void setValue(const QVariant &value) override { m_currentValue = value.toInt(); }
+ Type type() const override { return Type::integer; }
+ BuildOption *copy() const override { return new IntegerBuildOption{*this}; }
+ IntegerBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ , m_currentValue{value.toInt()}
+ {}
+
+protected:
+ int m_currentValue;
+};
+
+struct StringBuildOption : BuildOption
+{
+ QVariant value() const override { return m_currentValue; }
+ QString valueStr() const override { return m_currentValue; }
+ void setValue(const QVariant &value) override { m_currentValue = value.toString(); }
+ Type type() const override { return Type::string; }
+ BuildOption *copy() const override { return new StringBuildOption{*this}; }
+
+ StringBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ , m_currentValue{value.toString()}
+ {}
+
+protected:
+ QString m_currentValue;
+};
+
+struct FeatureBuildOption : BuildOption
+{
+ QVariant value() const override { return QVariant::fromValue(m_currentValue); }
+ QString valueStr() const override { return m_currentValue.value(); }
+ void setValue(const QVariant &value) override { m_currentValue.setValue(value.toString()); }
+ Type type() const override { return Type::feature; }
+ BuildOption *copy() const override { return new FeatureBuildOption{*this}; }
+ FeatureBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ {
+ setValue(value);
+ }
+
+protected:
+ FeatureData m_currentValue;
+};
+
+struct ComboBuildOption : BuildOption
+{
+ const QStringList &choices() const { return m_currentValue.choices(); }
+ QVariant value() const override { return QVariant::fromValue(m_currentValue); }
+ QString valueStr() const override { return m_currentValue.value(); }
+ void setValue(const QVariant &value) override { m_currentValue.setValue(value.toString()); }
+ Type type() const override { return Type::combo; }
+ BuildOption *copy() const override { return new ComboBuildOption{*this}; }
+ ComboBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QStringList &choices,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ , m_currentValue{choices, value.toString()}
+ {}
+
+protected:
+ ComboData m_currentValue;
+};
+
+static inline QStringList quoteAll(const QStringList &values)
+{
+ QStringList quoted;
+ std::transform(std::cbegin(values),
+ std::cend(values),
+ std::back_inserter(quoted),
+ [](const QString &v) {
+ if (v.front() == '\'' && v.back() == '\'')
+ return v;
+ return QString("\'%1\'").arg(v);
+ });
+ return quoted;
+}
+struct ArrayBuildOption : BuildOption
+{
+ QVariant value() const override { return m_currentValue; }
+ QString valueStr() const override { return m_currentValue.join(" "); }
+ void setValue(const QVariant &value) override
+ {
+ m_currentValue = quoteAll(value.toStringList());
+ }
+ Type type() const override { return Type::array; }
+ BuildOption *copy() const override { return new ArrayBuildOption{*this}; }
+ inline virtual QString mesonArg() const override
+ {
+ return QString("-D%1=[%2]").arg(fullName()).arg(quoteAll(m_currentValue).join(','));
+ }
+ ArrayBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ , m_currentValue{quoteAll(value.toStringList())}
+ {}
+
+protected:
+ QStringList m_currentValue;
+};
+
+struct BooleanBuildOption : BuildOption
+{
+ QVariant value() const override { return m_currentValue; }
+ QString valueStr() const override
+ {
+ return m_currentValue ? QString{"true"} : QString{"false"};
+ }
+ void setValue(const QVariant &value) override { m_currentValue = value.toBool(); }
+ Type type() const override { return Type::boolean; }
+ BuildOption *copy() const override { return new BooleanBuildOption{*this}; }
+
+ BooleanBuildOption(const QString &name,
+ const QString &section,
+ const QString &description,
+ const QVariant &value)
+ : BuildOption(name, section, description)
+ {
+ setValue(value);
+ }
+
+protected:
+ bool m_currentValue;
+};
+
+struct UnknownBuildOption : BuildOption
+{
+ QVariant value() const override { return "Unknown option"; }
+ QString valueStr() const override { return "Unknown option"; }
+ void setValue(const QVariant &) override {}
+ Type type() const override { return Type::unknown; }
+ BuildOption *copy() const override { return new UnknownBuildOption{*this}; }
+
+ UnknownBuildOption(const QString &name, const QString &section, const QString &description)
+ : BuildOption(name, section, description)
+ {}
+};
+
+using BuildOptionsList = std::vector<std::unique_ptr<BuildOption>>;
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfo.h b/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfo.h
new file mode 100644
index 0000000000..258c01a6dd
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfo.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <versionhelper.h>
+namespace MesonProjectManager {
+namespace Internal {
+struct MesonInfo
+{
+ Version mesonVersion;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfoparser.h b/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfoparser.h
new file mode 100644
index 0000000000..7db6d96acf
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/mesoninfoparser.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "buildoptions.h"
+#include "mesoninfo.h"
+#include "parsers/buildoptionsparser.h"
+#include "parsers/buildsystemfilesparser.h"
+#include "parsers/infoparser.h"
+#include "parsers/targetparser.h"
+#include "target.h"
+#include <utils/fileutils.h>
+#include <utils/optional.h>
+#include <QString>
+#include <QVariant>
+namespace MesonProjectManager {
+namespace Internal {
+class MesonInfoParserPrivate;
+
+namespace MesonInfoParser {
+struct Result
+{
+ TargetsList targets;
+ BuildOptionsList buildOptions;
+ std::vector<Utils::FilePath> buildSystemFiles;
+ Utils::optional<MesonInfo> mesonInfo;
+};
+
+inline Result parse(const QString &buildDir)
+{
+ return {TargetParser{buildDir}.targetList(),
+ BuildOptionsParser{buildDir}.takeBuildOptions(),
+ BuildSystemFilesParser{buildDir}.files(),
+ InfoParser{buildDir}.info()};
+}
+
+inline Result parse(const QByteArray &data)
+{
+ auto json = QJsonDocument::fromJson(data);
+ return {TargetParser{json}.targetList(),
+ BuildOptionsParser{json}.takeBuildOptions(),
+ BuildSystemFilesParser{json}.files(),
+ Utils::nullopt};
+}
+
+inline Result parse(QIODevice *introFile)
+{
+ if (introFile) {
+ if (!introFile->isOpen())
+ introFile->open(QIODevice::ReadOnly | QIODevice::Text);
+ introFile->seek(0);
+ auto data = introFile->readAll();
+ return parse(data);
+ }
+ return {};
+}
+inline Utils::optional<MesonInfo> mesonInfo(const QString &buildDir)
+{
+ return InfoParser{buildDir}.info();
+}
+
+} // namespace MesonInfoParser
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildoptionsparser.h b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildoptionsparser.h
new file mode 100644
index 0000000000..bbceb83a57
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildoptionsparser.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../../mesonpluginconstants.h"
+#include "../buildoptions.h"
+#include "./common.h"
+
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+#include <memory>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class BuildOptionsParser
+{
+ static inline std::unique_ptr<BuildOption> load_option(const QJsonObject &option)
+ {
+ const auto type = option["type"].toString();
+ if (type == "string")
+ return std::make_unique<StringBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["value"]);
+ if (type == "boolean")
+ return std::make_unique<BooleanBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["value"]);
+ if (type == "combo")
+ return std::make_unique<ComboBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["choices"].toVariant().toStringList(),
+ option["value"]);
+ if (type == "integer")
+ return std::make_unique<IntegerBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["value"]);
+ if (type == "array")
+ return std::make_unique<ArrayBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["value"].toVariant());
+ if (type == "feature")
+ return std::make_unique<FeatureBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString(),
+ option["value"]);
+ return std::make_unique<UnknownBuildOption>(option["name"].toString(),
+ option["section"].toString(),
+ option["description"].toString());
+ }
+
+ static inline std::vector<std::unique_ptr<BuildOption>> load_options(const QJsonArray &arr)
+ {
+ std::vector<std::unique_ptr<BuildOption>> buildOptions;
+ std::transform(std::cbegin(arr),
+ std::cend(arr),
+ std::back_inserter(buildOptions),
+ [](const auto &option) { return load_option(option.toObject()); });
+ return buildOptions;
+ }
+
+ std::vector<std::unique_ptr<BuildOption>> m_buildOptions;
+
+public:
+ BuildOptionsParser(const QString &buildDir)
+ {
+ auto arr = load<QJsonArray>(QString("%1/%2/%3")
+ .arg(buildDir)
+ .arg(Constants::MESON_INFO_DIR)
+ .arg(Constants::MESON_INTRO_BUIDOPTIONS));
+ if (arr)
+ m_buildOptions = load_options(*arr);
+ }
+ BuildOptionsParser(const QJsonDocument &js)
+ {
+ auto obj = get<QJsonArray>(js.object(), "buildoptions");
+ if (obj)
+ m_buildOptions = load_options(*obj);
+ }
+
+ inline std::vector<std::unique_ptr<BuildOption>> takeBuildOptions()
+ {
+ return std::move(m_buildOptions);
+ }
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildsystemfilesparser.h b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildsystemfilesparser.h
new file mode 100644
index 0000000000..6d6fd80dd7
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/buildsystemfilesparser.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../../mesonpluginconstants.h"
+#include "./common.h"
+#include "utils/fileutils.h"
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class BuildSystemFilesParser
+{
+ std::vector<Utils::FilePath> m_files;
+ static void appendFiles(const Utils::optional<QJsonArray> &arr,
+ std::vector<Utils::FilePath> &dest)
+ {
+ if (arr)
+ std::transform(std::cbegin(*arr),
+ std::cend(*arr),
+ std::back_inserter(dest),
+ [](const auto &file) {
+ return Utils::FilePath::fromString(file.toString());
+ });
+ }
+
+public:
+ BuildSystemFilesParser(const QString &buildDir)
+ {
+ auto arr = load<QJsonArray>(QString("%1/%2/%3")
+ .arg(buildDir)
+ .arg(Constants::MESON_INFO_DIR)
+ .arg(Constants::MESON_INTRO_BUILDSYSTEM_FILES));
+ appendFiles(arr, m_files);
+ }
+
+ BuildSystemFilesParser(const QJsonDocument &js)
+ {
+ auto arr = get<QJsonArray>(js.object(), "projectinfo", "buildsystem_files");
+ appendFiles(arr, m_files);
+ auto subprojects = get<QJsonArray>(js.object(), "projectinfo", "subprojects");
+ std::for_each(std::cbegin(*subprojects),
+ std::cend(*subprojects),
+ [this](const auto &subproject) {
+ auto arr = get<QJsonArray>(subproject.toObject(), "buildsystem_files");
+ appendFiles(arr, m_files);
+ });
+ }
+
+ std::vector<Utils::FilePath> files() { return m_files; };
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/common.h b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/common.h
new file mode 100644
index 0000000000..a5113a7700
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/common.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <utils/optional.h>
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+template<typename T>
+inline T load(QJsonDocument &&doc);
+
+template<>
+inline QJsonArray load<QJsonArray>(QJsonDocument &&doc)
+{
+ return doc.array();
+}
+
+template<>
+inline QJsonObject load<QJsonObject>(QJsonDocument &&doc)
+{
+ return doc.object();
+}
+
+template<typename T>
+inline T load(const QJsonValueRef &ref);
+
+template<>
+inline QJsonArray load<QJsonArray>(const QJsonValueRef &ref)
+{
+ return ref.toArray();
+}
+
+template<>
+inline QJsonObject load<QJsonObject>(const QJsonValueRef &ref)
+{
+ return ref.toObject();
+}
+
+template<typename T>
+inline Utils::optional<T> load(const QString &jsonFile)
+{
+ QFile js(jsonFile);
+ js.open(QIODevice::ReadOnly | QIODevice::Text);
+ if (js.isOpen()) {
+ auto data = js.readAll();
+ return load<T>(QJsonDocument::fromJson(data));
+ }
+ return Utils::nullopt;
+}
+
+template<typename T>
+inline Utils::optional<T> get(const QJsonObject &obj, const QString &name);
+
+template<>
+inline Utils::optional<QJsonArray> get<QJsonArray>(const QJsonObject &obj, const QString &name)
+{
+ if (obj.contains(name)) {
+ auto child = obj[name];
+ if (child.isArray())
+ return child.toArray();
+ }
+ return Utils::nullopt;
+}
+
+template<>
+inline Utils::optional<QJsonObject> get<QJsonObject>(const QJsonObject &obj, const QString &name)
+{
+ if (obj.contains(name)) {
+ auto child = obj[name];
+ if (child.isObject())
+ return child.toObject();
+ }
+ return Utils::nullopt;
+}
+
+template<typename T, typename... Strings>
+inline Utils::optional<T> get(const QJsonObject &obj,
+ const QString &firstPath,
+ const Strings &... path)
+{
+ if (obj.contains(firstPath))
+ return get<T>(obj[firstPath].toObject(), path...);
+ return Utils::nullopt;
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/infoparser.h b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/infoparser.h
new file mode 100644
index 0000000000..883102a6e3
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/infoparser.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../../mesonpluginconstants.h"
+#include "../mesoninfo.h"
+#include "./common.h"
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class InfoParser
+{
+ static inline MesonInfo load_info(const QJsonObject &obj)
+ {
+ MesonInfo info;
+ auto version = obj["meson_version"].toObject();
+ info.mesonVersion = Version{version["major"].toInt(),
+ version["minor"].toInt(),
+ version["patch"].toInt()};
+ return info;
+ }
+ MesonInfo m_info;
+
+public:
+ InfoParser(const QString &buildDir)
+ /*: AbstractParser(jsonFile(buildDir))*/
+ {
+ auto obj = load<QJsonObject>(jsonFile(buildDir));
+ if (obj)
+ m_info = load_info(*obj);
+ }
+ static inline QString jsonFile(const QString &buildDir)
+ {
+ return QString("%1/%2/%3")
+ .arg(buildDir)
+ .arg(Constants::MESON_INFO_DIR)
+ .arg(Constants::MESON_INFO);
+ }
+ MesonInfo info() { return m_info; }
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/targetparser.h b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/targetparser.h
new file mode 100644
index 0000000000..41e1c83629
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/parsers/targetparser.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../../mesonpluginconstants.h"
+#include "../target.h"
+#include "./common.h"
+#include <QFile>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class TargetParser
+{
+ TargetsList m_targets;
+ static inline Target::SourceGroup extract_source(const QJsonValue &source)
+ {
+ const auto srcObj = source.toObject();
+ return {srcObj["language"].toString(),
+ srcObj["compiler"].toVariant().toStringList(),
+ srcObj["parameters"].toVariant().toStringList(),
+ srcObj["sources"].toVariant().toStringList(),
+ srcObj["generated_sources"].toVariant().toStringList()};
+ }
+
+ static inline Target::SourceGroupList extract_sources(const QJsonArray &sources)
+ {
+ Target::SourceGroupList res;
+ std::transform(std::cbegin(sources),
+ std::cend(sources),
+ std::back_inserter(res),
+ extract_source);
+ return res;
+ }
+
+ static inline Target extract_target(const QJsonValue &target)
+ {
+ auto targetObj = target.toObject();
+ Target t{targetObj["type"].toString(),
+ targetObj["name"].toString(),
+ targetObj["id"].toString(),
+ targetObj["defined_in"].toString(),
+ targetObj["filename"].toVariant().toStringList(),
+ targetObj["subproject"].toString(),
+ extract_sources(targetObj["target_sources"].toArray())};
+ return t;
+ }
+
+ static inline TargetsList load_targets(const QJsonArray &arr)
+ {
+ TargetsList targets;
+ std::transform(std::cbegin(arr),
+ std::cend(arr),
+ std::back_inserter(targets),
+ extract_target);
+ return targets;
+ }
+
+public:
+ TargetParser(const QString &buildDir)
+ {
+ auto arr = load<QJsonArray>(QString("%1/%2/%3")
+ .arg(buildDir)
+ .arg(Constants::MESON_INFO_DIR)
+ .arg(Constants::MESON_INTRO_TARGETS));
+ if (arr)
+ m_targets = load_targets(*arr);
+ }
+
+ TargetParser(const QJsonDocument &js)
+ {
+ auto obj = get<QJsonArray>(js.object(), "targets");
+ if (obj)
+ m_targets = load_targets(*obj);
+ }
+
+ inline TargetsList targetList() { return m_targets; }
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesoninfoparser/target.h b/src/plugins/mesonprojectmanager/mesoninfoparser/target.h
new file mode 100644
index 0000000000..a0cbaaef66
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesoninfoparser/target.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <utils/fileutils.h>
+#include <utils/optional.h>
+#include <QString>
+#include <QVariant>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+struct Target
+{
+ enum class Type {
+ executable,
+ run,
+ custom,
+ sharedLibrary,
+ sharedModule,
+ staticLibrary,
+ jar,
+ unknown
+ };
+ struct SourceGroup
+ {
+ const QString language;
+ const QStringList compiler;
+ const QStringList parameters;
+ const QStringList sources;
+ const QStringList generatedSources;
+ SourceGroup(QString &&language,
+ QStringList &&compiler,
+ QStringList &&parameters,
+ QStringList &&sources,
+ QStringList &&generatedSources)
+ : language{std::move(language)}
+ , compiler{std::move(compiler)}
+ , parameters{std::move(parameters)}
+ , sources{std::move(sources)}
+ , generatedSources{std::move(generatedSources)}
+ {}
+ };
+ using SourceGroupList = std::vector<SourceGroup>;
+ const Type type;
+ const QString name;
+ const QString id;
+ const QString definedIn;
+ const QStringList fileName;
+ const Utils::optional<QString> subproject;
+ const SourceGroupList sources;
+
+ static inline QString fullName(const Target &target)
+ {
+ // TODO, this is bad, might be moved in a place where src dir is known
+ if (target.fileName.first().startsWith("/")) {
+ auto fname = target.fileName.first().split('/');
+ auto definedIn = target.definedIn.split('/');
+ definedIn.pop_back();
+ int i = std::min(definedIn.length(), fname.length()) - 1;
+ for (; i >= 0 && fname[i] == definedIn[i]; --i)
+ ;
+ return fname.mid(i + 1).join("/");
+ } else {
+ return target.fileName.first();
+ }
+ }
+
+ static Type toType(const QString &typeStr)
+ {
+ if (typeStr == "executable")
+ return Type::executable;
+ if (typeStr == "static library")
+ return Type::staticLibrary;
+ if (typeStr == "shared library")
+ return Type::sharedLibrary;
+ if (typeStr == "shared module")
+ return Type::sharedModule;
+ if (typeStr == "custom")
+ return Type::custom;
+ if (typeStr == "run")
+ return Type::run;
+ if (typeStr == "jar")
+ return Type::jar;
+ return Type::unknown;
+ }
+
+ Target(const QString &type,
+ QString &&name,
+ QString &&id,
+ QString &&definedIn,
+ QStringList &&fileName,
+ QString &&subproject,
+ SourceGroupList &&sources)
+ : type{toType(type)}
+ , name{std::move(name)}
+ , id{std::move(id)}
+ , definedIn{std::move(definedIn)}
+ , fileName{std::move(fileName)}
+ , subproject{subproject.isNull() ? Utils::nullopt
+ : Utils::optional<QString>{std::move(subproject)}}
+ , sources{std::move(sources)}
+ {}
+};
+
+using TargetsList = std::vector<Target>;
+
+template<class function>
+void for_each_source_group(const TargetsList &targets, const function &f)
+{
+ for (const Target &target : targets) {
+ for (const Target::SourceGroup &group : target.sources) {
+ f(target, group);
+ }
+ }
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesonpluginconstants.h b/src/plugins/mesonprojectmanager/mesonpluginconstants.h
new file mode 100644
index 0000000000..4329ae987d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonpluginconstants.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+namespace MesonProjectManager {
+namespace Constants {
+
+namespace Project {
+const char MIMETYPE[] = "text/x-meson";
+const char ID[] = "MesonProjectManager.MesonProject";
+} // namespace Project
+
+namespace BuildConfiguration {
+const char BUILD_TYPE_KEY[] = "MesonProjectManager.BuildConfig.Type";
+}
+
+// Settings page
+namespace SettingsPage {
+const char GENERAL_ID[] = "A.MesonProjectManager.SettingsPage.General";
+const char TOOLS_ID[] = "Z.MesonProjectManager.SettingsPage.Tools";
+const char CATEGORY[] = "Z.Meson";
+} // namespace SettingsPage
+
+namespace ToolsSettings {
+const char FILENAME[] = "mesontools.xml";
+const char ENTRY_KEY[] = "Tool.";
+const char ENTRY_COUNT[] = "Tools.Count";
+const char TOOL_TYPE_KEY[] = "type";
+const char TOOL_TYPE_MESON[] = "meson";
+const char TOOL_TYPE_NINJA[] = "ninja";
+const char EXE_KEY[] = "exe";
+const char AUTO_DETECTED_KEY[] = "autodetected";
+const char NAME_KEY[] = "name";
+const char ID_KEY[] = "uuid";
+} // namespace ToolsSettings
+
+namespace GeneralSettings {
+const char SECTION[] = "MesonProjectManager";
+const char AUTORUN_MESON_KEY[] = "meson.autorun";
+const char VERBOSE_NINJA_KEY[] = "ninja.verbose";
+} // namespace GeneralSettings
+
+namespace Icons {
+const char MESON[] = ":/mesonproject/icons/meson_logo.png";
+const char MESON_BW[] = ":/mesonproject/icons/meson_bw_logo.png";
+} // namespace Icons
+
+const char MESON_INFO_DIR[] = "meson-info";
+const char MESON_INTRO_BENCHMARKS[] = "intro-benchmarks.json";
+const char MESON_INTRO_BUIDOPTIONS[] = "intro-buildoptions.json";
+const char MESON_INTRO_BUILDSYSTEM_FILES[] = "intro-buildsystem_files.json";
+const char MESON_INTRO_DEPENDENCIES[] = "intro-dependencies.json";
+const char MESON_INTRO_INSTALLED[] = "intro-installed.json";
+const char MESON_INTRO_PROJECTINFO[] = "intro-projectinfo.json";
+const char MESON_INTRO_TARGETS[] = "intro-targets.json";
+const char MESON_INTRO_TESTS[] = "intro-tests.json";
+const char MESON_INFO[] = "meson-info.json";
+
+const char MESON_TOOL_MANAGER[] = "MesonProjectManager.Tools";
+const char MESON_BUILD_STEP_ID[] = "MesonProjectManager.BuildStep";
+
+namespace Targets {
+const char all[] = "all";
+const char clean[] = "clean";
+const char install[] = "install";
+const char tests[] = "test";
+const char benchmark[] = "benchmark";
+const char clang_format[] = "clang-format";
+const char scan_build[] = "scan-build";
+} // namespace Targets
+const char MESON_BUILD_CONFIG_ID[] = "MesonProjectManager.BuildConfiguration";
+
+} // namespace Constants
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.pro b/src/plugins/mesonprojectmanager/mesonprojectmanager.pro
new file mode 100644
index 0000000000..71a7b25818
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.pro
@@ -0,0 +1,102 @@
+include(../../qtcreatorplugin.pri)
+
+INCLUDEPATH += $$PWD
+
+HEADERS = \
+ exewrappers/mesontools.h \
+ exewrappers/mesonwrapper.h \
+ exewrappers/ninjawrapper.h \
+ exewrappers/toolwrapper.h \
+ kithelper/kitdata.h \
+ kithelper/kithelper.h \
+ machinefiles/machinefilemanager.h \
+ machinefiles/nativefilegenerator.h \
+ mesonactionsmanager/mesonactionsmanager.h \
+ mesoninfoparser/buildoptions.h \
+ mesoninfoparser/mesoninfo.h \
+ mesoninfoparser/mesoninfoparser.h \
+ mesoninfoparser/parsers/buildoptionsparser.h \
+ mesoninfoparser/parsers/buildsystemfilesparser.h \
+ mesoninfoparser/parsers/common.h \
+ mesoninfoparser/parsers/infoparser.h \
+ mesoninfoparser/parsers/targetparser.h \
+ mesoninfoparser/target.h \
+ project/buildoptions/optionsmodel/arrayoptionlineedit.h \
+ project/buildoptions/optionsmodel/buildoptionsmodel.h \
+ project/buildoptions/mesonbuildsettingswidget.h \
+ project/buildoptions/mesonbuildstepconfigwidget.h \
+ project/outputparsers/mesonoutputparser.h \
+ project/outputparsers/ninjaparser.h \
+ project/projecttree/mesonprojectnodes.h \
+ project/projecttree/projecttree.h \
+ project/mesonbuildconfiguration.h \
+ project/mesonbuildsystem.h \
+ project/mesonprocess.h \
+ project/mesonproject.h \
+ project/mesonprojectimporter.h \
+ project/mesonprojectparser.h \
+ project/mesonrunconfiguration.h \
+ project/ninjabuildstep.h \
+ settings/general/generalsettingspage.h \
+ settings/general/generalsettingswidget.h \
+ settings/general/settings.h \
+ settings/tools/kitaspect/mesontoolkitaspect.h \
+ settings/tools/kitaspect/ninjatoolkitaspect.h \
+ settings/tools/kitaspect/toolkitaspectwidget.h \
+ settings/tools/toolitemsettings.h \
+ settings/tools/toolsmodel.h \
+ settings/tools/toolssettingsaccessor.h \
+ settings/tools/toolssettingspage.h \
+ settings/tools/toolssettingswidget.h \
+ settings/tools/tooltreeitem.h \
+ mesonpluginconstants.h \
+ mesonprojectplugin.h \
+ versionhelper.h
+
+
+SOURCES = \
+ exewrappers/mesonwrapper.cpp \
+ exewrappers/toolwrapper.cpp \
+ exewrappers/mesontools.cpp \
+ machinefiles/machinefilemanager.cpp \
+ machinefiles/nativefilegenerator.cpp \
+ mesonactionsmanager/mesonactionsmanager.cpp \
+ project/buildoptions/optionsmodel/arrayoptionlineedit.cpp \
+ project/buildoptions/optionsmodel/buildoptionsmodel.cpp \
+ project/buildoptions/mesonbuildsettingswidget.cpp \
+ project/buildoptions/mesonbuildstepconfigwidget.cpp \
+ project/outputparsers/mesonoutputparser.cpp \
+ project/outputparsers/ninjaparser.cpp \
+ project/projecttree/mesonprojectnodes.cpp \
+ project/projecttree/projecttree.cpp \
+ project/mesonbuildconfiguration.cpp \
+ project/mesonbuildsystem.cpp \
+ project/mesonprocess.cpp \
+ project/mesonproject.cpp \
+ project/mesonprojectimporter.cpp \
+ project/mesonprojectparser.cpp \
+ project/mesonrunconfiguration.cpp \
+ project/ninjabuildstep.cpp \
+ settings/general/generalsettingspage.cpp \
+ settings/general/generalsettingswidget.cpp \
+ settings/general/settings.cpp \
+ settings/tools/kitaspect/mesontoolkitaspect.cpp \
+ settings/tools/kitaspect/ninjatoolkitaspect.cpp \
+ settings/tools/kitaspect/toolkitaspectwidget.cpp \
+ settings/tools/toolitemsettings.cpp \
+ settings/tools/toolsmodel.cpp \
+ settings/tools/toolssettingsaccessor.cpp \
+ settings/tools/toolssettingspage.cpp \
+ settings/tools/toolssettingswidget.cpp \
+ settings/tools/tooltreeitem.cpp \
+ mesonprojectplugin.cpp
+
+RESOURCES += resources.qrc
+
+FORMS += \
+ project/buildoptions/mesonbuildsettingswidget.ui \
+ project/buildoptions/mesonbuildstepconfigwidget.ui \
+ settings/general/generalsettingswidget.ui \
+ settings/tools/toolitemsettings.ui \
+ settings/tools/toolssettingswidget.ui
+
diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs
new file mode 100644
index 0000000000..42b86ba029
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonprojectmanager.qbs
@@ -0,0 +1,197 @@
+import qbs.FileInfo
+
+Project {
+ name: "MesonProjectManager"
+
+ property stringList testDefines: [
+ 'MESON_SAMPLES_DIR="' + FileInfo.joinPaths(sourceDirectory, "tests", "resources") + '"',
+ ]
+
+ QtcPlugin {
+ Depends { name: "Qt.widgets" }
+ Depends { name: "Utils" }
+
+ Depends { name: "Core" }
+ Depends { name: "CppTools" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "QtSupport" }
+ Depends { name: "app_version_header" }
+
+ pluginRecommends: [
+ "Designer"
+ ]
+
+ cpp.includePaths: "."
+
+ files: [
+ "exewrappers/mesontools.cpp",
+ "exewrappers/mesontools.h",
+ "exewrappers/mesonwrapper.cpp",
+ "exewrappers/mesonwrapper.h",
+ "exewrappers/ninjawrapper.h",
+ "exewrappers/toolwrapper.cpp",
+ "exewrappers/toolwrapper.h",
+ "kithelper/kitdata.h",
+ "kithelper/kithelper.h",
+ "machinefiles/machinefilemanager.cpp",
+ "machinefiles/machinefilemanager.h",
+ "machinefiles/nativefilegenerator.cpp",
+ "machinefiles/nativefilegenerator.h",
+ "mesonactionsmanager/mesonactionsmanager.cpp",
+ "mesonactionsmanager/mesonactionsmanager.h",
+ "mesoninfoparser/buildoptions.h",
+ "mesoninfoparser/mesoninfo.h",
+ "mesoninfoparser/mesoninfoparser.h",
+ "mesoninfoparser/parsers/buildoptionsparser.h",
+ "mesoninfoparser/parsers/buildsystemfilesparser.h",
+ "mesoninfoparser/parsers/common.h",
+ "mesoninfoparser/parsers/infoparser.h",
+ "mesoninfoparser/parsers/targetparser.h",
+ "mesoninfoparser/target.h",
+ "mesonpluginconstants.h",
+ "mesonprojectplugin.cpp",
+ "mesonprojectplugin.h",
+ "project/buildoptions/mesonbuildsettingswidget.cpp",
+ "project/buildoptions/mesonbuildsettingswidget.h",
+ "project/buildoptions/mesonbuildsettingswidget.ui",
+ "project/buildoptions/mesonbuildstepconfigwidget.cpp",
+ "project/buildoptions/mesonbuildstepconfigwidget.h",
+ "project/buildoptions/mesonbuildstepconfigwidget.ui",
+ "project/buildoptions/optionsmodel/arrayoptionlineedit.cpp",
+ "project/buildoptions/optionsmodel/arrayoptionlineedit.h",
+ "project/buildoptions/optionsmodel/buildoptionsmodel.cpp",
+ "project/buildoptions/optionsmodel/buildoptionsmodel.h",
+ "project/mesonbuildconfiguration.cpp",
+ "project/mesonbuildconfiguration.h",
+ "project/mesonbuildsystem.cpp",
+ "project/mesonbuildsystem.h",
+ "project/mesonprocess.cpp",
+ "project/mesonprocess.h",
+ "project/mesonproject.cpp",
+ "project/mesonproject.h",
+ "project/mesonprojectimporter.cpp",
+ "project/mesonprojectimporter.h",
+ "project/mesonprojectparser.cpp",
+ "project/mesonprojectparser.h",
+ "project/mesonrunconfiguration.cpp",
+ "project/mesonrunconfiguration.h",
+ "project/ninjabuildstep.cpp",
+ "project/ninjabuildstep.h",
+ "project/outputparsers/mesonoutputparser.cpp",
+ "project/outputparsers/mesonoutputparser.h",
+ "project/outputparsers/ninjaparser.cpp",
+ "project/outputparsers/ninjaparser.h",
+ "project/projecttree/mesonprojectnodes.cpp",
+ "project/projecttree/mesonprojectnodes.h",
+ "project/projecttree/projecttree.cpp",
+ "project/projecttree/projecttree.h",
+ "settings/general/generalsettingspage.cpp",
+ "settings/general/generalsettingspage.h",
+ "settings/general/generalsettingswidget.cpp",
+ "settings/general/generalsettingswidget.h",
+ "settings/general/generalsettingswidget.ui",
+ "settings/general/settings.cpp",
+ "settings/general/settings.h",
+ "settings/tools/kitaspect/mesontoolkitaspect.cpp",
+ "settings/tools/kitaspect/mesontoolkitaspect.h",
+ "settings/tools/kitaspect/ninjatoolkitaspect.cpp",
+ "settings/tools/kitaspect/ninjatoolkitaspect.h",
+ "settings/tools/kitaspect/toolkitaspectwidget.cpp",
+ "settings/tools/kitaspect/toolkitaspectwidget.h",
+ "settings/tools/toolitemsettings.cpp",
+ "settings/tools/toolitemsettings.h",
+ "settings/tools/toolitemsettings.ui",
+ "settings/tools/toolsmodel.cpp",
+ "settings/tools/toolsmodel.h",
+ "settings/tools/toolssettingsaccessor.cpp",
+ "settings/tools/toolssettingsaccessor.h",
+ "settings/tools/toolssettingspage.cpp",
+ "settings/tools/toolssettingspage.h",
+ "settings/tools/toolssettingswidget.cpp",
+ "settings/tools/toolssettingswidget.h",
+ "settings/tools/toolssettingswidget.ui",
+ "settings/tools/tooltreeitem.cpp",
+ "settings/tools/tooltreeitem.h",
+ "versionhelper.h",
+ ]
+ }
+
+ QtcAutotest {
+ name: "tst_mesonwrapper"
+ condition: project.withAutotests
+
+ Depends { name: "Core" }
+ Depends { name: "Utils" }
+
+ cpp.defines: project.testDefines
+ cpp.includePaths: "."
+
+ files: [
+ "exewrappers/mesonwrapper.cpp",
+ "exewrappers/mesonwrapper.h",
+ "exewrappers/ninjawrapper.h",
+ "exewrappers/toolwrapper.h",
+ "exewrappers/toolwrapper.cpp",
+ "exewrappers/mesontools.h",
+ "tests/testmesonwrapper.cpp",
+ ]
+ }
+
+ QtcAutotest {
+ name: "tst_mesoninfoparser"
+ condition: project.withAutotests
+
+ Depends { name: "Core" }
+ Depends { name: "Utils" }
+
+ cpp.defines: project.testDefines
+ cpp.includePaths: "."
+
+ files: [
+ "exewrappers/mesonwrapper.cpp",
+ "exewrappers/mesonwrapper.h",
+ "exewrappers/ninjawrapper.h",
+ "exewrappers/toolwrapper.h",
+ "exewrappers/toolwrapper.cpp",
+ "exewrappers/mesontools.h",
+ "mesoninfoparser/mesoninfoparser.h",
+ "tests/testmesoninfoparser.cpp",
+ ]
+ }
+
+ QtcAutotest {
+ name: "tst_ninjaparser"
+ condition: project.withAutotests
+
+ Depends { name: "Core" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "Utils" }
+
+ cpp.includePaths: "."
+
+ files: [
+ "project/outputparsers/ninjaparser.cpp",
+ "project/outputparsers/ninjaparser.h",
+ "mesoninfoparser/mesoninfoparser.h",
+ "tests/testninjaparser.cpp",
+ ]
+ }
+
+ QtcAutotest {
+ name: "tst_mesonparser"
+ condition: project.withAutotests
+
+ Depends { name: "Core" }
+ Depends { name: "ProjectExplorer" }
+ Depends { name: "Utils" }
+
+ cpp.defines: "MESONPARSER_DISABLE_TASKS_FOR_TESTS"
+ cpp.includePaths: "."
+
+ files: [
+ "project/outputparsers/mesonoutputparser.h",
+ "project/outputparsers/mesonoutputparser.cpp",
+ "tests/testmesonparser.cpp",
+ ]
+ }
+}
diff --git a/src/plugins/mesonprojectmanager/mesonprojectmanager_dependencies.pri b/src/plugins/mesonprojectmanager/mesonprojectmanager_dependencies.pri
new file mode 100644
index 0000000000..08c8f220bb
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonprojectmanager_dependencies.pri
@@ -0,0 +1,12 @@
+QTC_PLUGIN_NAME = MesonProjectManager
+QTC_LIB_DEPENDS += \
+ extensionsystem \
+ utils
+QTC_PLUGIN_DEPENDS += \
+ coreplugin \
+ projectexplorer \
+ cpptools \
+ qtsupport
+QTC_PLUGIN_RECOMMENDS += \
+ designer
+
diff --git a/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp
new file mode 100644
index 0000000000..a48e2b6a8a
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonprojectplugin.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonprojectplugin.h"
+#include "exewrappers/mesonwrapper.h"
+#include "machinefiles/machinefilemanager.h"
+#include "mesonactionsmanager/mesonactionsmanager.h"
+#include "project/mesonbuildconfiguration.h"
+#include "project/mesonbuildsystem.h"
+#include "project/mesonproject.h"
+#include "project/mesonrunconfiguration.h"
+#include "project/ninjabuildstep.h"
+#include "settings/general/generalsettingspage.h"
+#include "settings/tools/kitaspect/mesontoolkitaspect.h"
+#include "settings/tools/kitaspect/ninjatoolkitaspect.h"
+#include "settings/tools/toolssettingsaccessor.h"
+#include "settings/tools/toolssettingspage.h"
+
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/icore.h>
+
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectmanager.h>
+#include <projectexplorer/runcontrol.h>
+
+#include <extensionsystem/pluginmanager.h>
+
+#include <utils/parameteraction.h>
+
+#include <QObject>
+
+using namespace Core;
+using namespace ProjectExplorer;
+using namespace Utils;
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class MesonProjectPluginPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ MesonProjectPluginPrivate()
+ {
+ MesonTools::setTools(m_toolsSettings.loadMesonTools(ICore::dialogParent()));
+ connect(ICore::instance(),
+ &ICore::saveSettingsRequested,
+ this,
+ &MesonProjectPluginPrivate::saveAll);
+ }
+
+ ~MesonProjectPluginPrivate() {}
+
+private:
+ GeneralSettingsPage m_generalSettingsPage;
+ ToolsSettingsPage m_toolslSettingsPage;
+ ToolsSettingsAccessor m_toolsSettings;
+ MesonToolKitAspect m_mesonKitAspect;
+ NinjaToolKitAspect m_ninjaKitAspect;
+ MesonBuildStepFactory m_buildStepFactory;
+ MesonBuildConfigurationFactory m_buildConfigurationFactory;
+ MesonRunConfigurationFactory m_runConfigurationFactory;
+ MesonActionsManager m_actions;
+ MachineFileManager m_machineFilesManager;
+ RunWorkerFactory
+ m_mesonRunWorkerFactory{RunWorkerFactory::make<ProjectExplorer::SimpleTargetRunner>(),
+ {ProjectExplorer::Constants::NORMAL_RUN_MODE},
+ {m_runConfigurationFactory.id()}};
+ void saveAll()
+ {
+ m_toolsSettings.saveMesonTools(MesonTools::tools(), ICore::dialogParent());
+ m_generalSettingsPage.saveAll();
+ }
+};
+
+MesonProjectPlugin::~MesonProjectPlugin()
+{
+ delete d;
+}
+
+bool MesonProjectPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ Q_UNUSED(errorMessage)
+
+ d = new MesonProjectPluginPrivate;
+
+ ProjectManager::registerProjectType<MesonProject>(Constants::Project::MIMETYPE);
+ FileIconProvider::registerIconOverlayForFilename(Constants::Icons::MESON, "meson.build");
+ FileIconProvider::registerIconOverlayForFilename(Constants::Icons::MESON, "meson_options.txt");
+ return true;
+}
+
+void MesonProjectPlugin::extensionsInitialized() {}
+
+} // namespace Internal
+} // namespace MesonProjectManager
+
+#include "mesonprojectplugin.moc"
diff --git a/src/plugins/mesonprojectmanager/mesonprojectplugin.h b/src/plugins/mesonprojectmanager/mesonprojectplugin.h
new file mode 100644
index 0000000000..8cbcfa10ba
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/mesonprojectplugin.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <extensionsystem/iplugin.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class MesonProjectPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "MesonProjectManager.json")
+
+public:
+ ~MesonProjectPlugin() override;
+
+#ifdef WITH_TESTS
+private slots:
+
+#endif
+
+private:
+ bool initialize(const QStringList &arguments, QString *errorMessage) override;
+ void extensionsInitialized() override;
+
+ class MesonProjectPluginPrivate *d = nullptr;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp
new file mode 100644
index 0000000000..df91c285fa
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include <coreplugin/find/itemviewfind.h>
+#include <projectexplorer/buildaspects.h>
+#include <projectexplorer/projectconfiguration.h>
+#include <utils/detailswidget.h>
+#include <utils/headerviewstretcher.h>
+
+#include "../mesonbuildconfiguration.h"
+#include "../mesonbuildsystem.h"
+#include "mesonbuildsettingswidget.h"
+#include "ui_mesonbuildsettingswidget.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+MesonBuildSettingsWidget::MesonBuildSettingsWidget(MesonBuildConfiguration *buildCfg)
+ : ProjectExplorer::NamedWidget{tr("Meson")}
+ , ui{new Ui::MesonBuildSettingsWidget}
+ , m_progressIndicator(Utils::ProgressIndicatorSize::Large)
+{
+ ui->setupUi(this);
+ ui->container->setState(Utils::DetailsWidget::NoSummary);
+ ui->container->setWidget(ui->details);
+ ProjectExplorer::LayoutBuilder buildDirWBuilder{ui->buildDirWidget};
+ auto buildDirAspect = buildCfg->buildDirectoryAspect();
+ buildDirAspect->addToLayout(buildDirWBuilder);
+
+ ui->optionsFilterLineEdit->setFiltering(true);
+
+ ui->optionsTreeView->sortByColumn(0, Qt::AscendingOrder);
+
+ QFrame *findWrapper
+ = Core::ItemViewFind::createSearchableWrapper(ui->optionsTreeView,
+ Core::ItemViewFind::LightColored);
+ findWrapper->setFrameStyle(QFrame::StyledPanel);
+ m_progressIndicator.attachToWidget(findWrapper);
+ m_progressIndicator.raise();
+ m_progressIndicator.hide();
+ ui->details->layout()->addWidget(findWrapper);
+
+ m_showProgressTimer.setSingleShot(true);
+ m_showProgressTimer.setInterval(50); // don't show progress for < 50ms tasks
+ connect(&m_showProgressTimer, &QTimer::timeout, [this]() { m_progressIndicator.show(); });
+ connect(&m_optionsModel, &BuidOptionsModel::configurationChanged, this, [this]() {
+ ui->configureButton->setEnabled(true);
+ });
+ m_optionsFilter.setSourceModel(&m_optionsModel);
+ m_optionsFilter.setSortRole(Qt::DisplayRole);
+ m_optionsFilter.setFilterKeyColumn(-1);
+ m_optionsFilter.setFilterCaseSensitivity(Qt::CaseInsensitive);
+
+ ui->optionsTreeView->setModel(&m_optionsFilter);
+
+ ui->optionsTreeView->setItemDelegate(new BuildOptionDelegate{ui->optionsTreeView});
+ MesonBuildSystem *bs = static_cast<MesonBuildSystem *>(buildCfg->buildSystem());
+ connect(buildCfg->target(),
+ &ProjectExplorer::Target::parsingFinished,
+ this,
+ [this, bs](bool success) {
+ if (success) {
+ m_optionsModel.setConfiguration(bs->buildOptions());
+ } else {
+ m_optionsModel.clear();
+ }
+ ui->optionsTreeView->expandAll();
+ ui->optionsTreeView->resizeColumnToContents(0);
+ ui->optionsTreeView->setEnabled(true);
+ m_showProgressTimer.stop();
+ m_progressIndicator.hide();
+ });
+
+ connect(bs, &MesonBuildSystem::parsingStarted, this, [this]() {
+ if (!m_showProgressTimer.isActive()) {
+ ui->optionsTreeView->setEnabled(false);
+ m_showProgressTimer.start();
+ }
+ });
+
+ connect(&m_optionsModel, &BuidOptionsModel::dataChanged, this, [bs, this]() {
+ bs->setMesonConfigArgs(this->m_optionsModel.changesAsMesonArgs());
+ });
+
+ connect(&m_optionsFilter, &QAbstractItemModel::modelReset, this, [this]() {
+ ui->optionsTreeView->expandAll();
+ ui->optionsTreeView->resizeColumnToContents(0);
+ });
+ connect(ui->optionsFilterLineEdit,
+ &QLineEdit::textChanged,
+ &m_optionsFilter,
+ &QSortFilterProxyModel::setFilterFixedString);
+ connect(ui->optionsTreeView,
+ &Utils::TreeView::activated,
+ ui->optionsTreeView,
+ [tree = ui->optionsTreeView](const QModelIndex &idx) { tree->edit(idx); });
+ connect(ui->configureButton, &QPushButton::clicked, [bs, this]() {
+ ui->optionsTreeView->setEnabled(false);
+ ui->configureButton->setEnabled(false);
+ m_showProgressTimer.start();
+ bs->configure();
+ });
+ connect(ui->wipeButton, &QPushButton::clicked, [bs, this]() {
+ ui->optionsTreeView->setEnabled(false);
+ ui->configureButton->setEnabled(false);
+ m_showProgressTimer.start();
+ bs->wipe();
+ });
+ bs->triggerParsing();
+}
+
+MesonBuildSettingsWidget::~MesonBuildSettingsWidget()
+{
+ delete ui;
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.h b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.h
new file mode 100644
index 0000000000..d3b9ab5118
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "optionsmodel/buildoptionsmodel.h"
+
+#include <utils/categorysortfiltermodel.h>
+#include <utils/progressindicator.h>
+#include <projectexplorer/namedwidget.h>
+
+#include <QTimer>
+#include <QWidget>
+
+namespace Ui {
+class MesonBuildSettingsWidget;
+}
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonBuildConfiguration;
+class MesonBuildSettingsWidget : public ProjectExplorer::NamedWidget
+{
+ Q_OBJECT
+
+public:
+ explicit MesonBuildSettingsWidget(MesonBuildConfiguration *buildCfg);
+ ~MesonBuildSettingsWidget();
+
+private:
+ Ui::MesonBuildSettingsWidget *ui;
+ BuidOptionsModel m_optionsModel;
+ Utils::CategorySortFilterModel m_optionsFilter;
+ Utils::ProgressIndicator m_progressIndicator;
+ QTimer m_showProgressTimer;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.ui b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.ui
new file mode 100644
index 0000000000..69671323e1
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildsettingswidget.ui
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MesonBuildSettingsWidget</class>
+ <widget class="QWidget" name="MesonBuildSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="configureButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Apply configuration changes</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="wipeButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Wipe build directory and reconfigure using previous command line options.
+Userful when build directory got corrupted, or when rebuilding with a newer version of meson.</string>
+ </property>
+ <property name="text">
+ <string>Wipe project</string>
+ </property>
+ <property name="icon">
+ <iconset theme=":/utils/images/warning.png"/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="Utils::DetailsWidget" name="container" native="true">
+ <widget class="QWidget" name="details" native="true">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>20</y>
+ <width>371</width>
+ <height>211</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="buildDirWidget" native="true"/>
+ </item>
+ <item>
+ <widget class="Utils::FancyLineEdit" name="optionsFilterLineEdit">
+ <property name="placeholderText">
+ <string>Filter</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Utils::TreeView" name="optionsTreeView">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>300</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectItems</enum>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::DetailsWidget</class>
+ <extends>QWidget</extends>
+ <header>utils/detailswidget.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Utils::FancyLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>utils/fancylineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Utils::TreeView</class>
+ <extends>QTreeView</extends>
+ <header>utils/itemviews.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.cpp b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.cpp
new file mode 100644
index 0000000000..2417a9e3b3
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonbuildstepconfigwidget.h"
+#include "ui_mesonbuildstepconfigwidget.h"
+#include <coreplugin/find/itemviewfind.h>
+#include <mesonpluginconstants.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/processparameters.h>
+#include <QCheckBox>
+#include <QRadioButton>
+namespace MesonProjectManager {
+namespace Internal {
+MesonBuildStepConfigWidget::MesonBuildStepConfigWidget(NinjaBuildStep *step)
+ : ProjectExplorer::BuildStepConfigWidget{step}
+ , ui(new Ui::MesonBuildStepConfigWidget)
+ , m_buildTargetsList{new QListWidget}
+{
+ setDisplayName(tr("Build", "MesonProjectManager::MesonBuildStepConfigWidget display name."));
+ ui->setupUi(this);
+ m_buildTargetsList->setFrameStyle(QFrame::NoFrame);
+ m_buildTargetsList->setMinimumHeight(200);
+ ui->frame->layout()->addWidget(
+ Core::ItemViewFind::createSearchableWrapper(m_buildTargetsList,
+ Core::ItemViewFind::LightColored));
+ updateDetails();
+ updateTargetList();
+ connect(step, &NinjaBuildStep::commandChanged, this, &MesonBuildStepConfigWidget::updateDetails);
+ connect(step,
+ &NinjaBuildStep::targetListChanged,
+ this,
+ &MesonBuildStepConfigWidget::updateTargetList);
+ connect(ui->m_toolArguments, &QLineEdit::textEdited, this, [this](const QString &text) {
+ auto mesonBuildStep = static_cast<NinjaBuildStep *>(this->step());
+ mesonBuildStep->setCommandArgs(text);
+ updateDetails();
+ });
+ connect(m_buildTargetsList, &QListWidget::itemChanged, this, [this](QListWidgetItem *item) {
+ if (item->checkState() == Qt::Checked) {
+ mesonBuildStep()->setBuildTarget(item->data(Qt::UserRole).toString());
+ updateDetails();
+ }
+ });
+}
+
+MesonBuildStepConfigWidget::~MesonBuildStepConfigWidget()
+{
+ delete ui;
+}
+
+void MesonBuildStepConfigWidget::updateDetails()
+{
+ auto mesonBuildStep = static_cast<NinjaBuildStep *>(step());
+ ProjectExplorer::ProcessParameters param;
+ param.setMacroExpander(mesonBuildStep->macroExpander());
+ param.setEnvironment(mesonBuildStep->buildEnvironment());
+ param.setWorkingDirectory(mesonBuildStep->buildDirectory());
+ param.setCommandLine(mesonBuildStep->command());
+ setSummaryText(param.summary(displayName()));
+}
+
+void MesonBuildStepConfigWidget::updateTargetList()
+{
+ m_buildTargetsList->clear();
+ for (const auto &target : mesonBuildStep()->projectTargets()) {
+ auto item = new QListWidgetItem(m_buildTargetsList);
+ auto button = new QRadioButton(target);
+ connect(button, &QRadioButton::toggled, this, [this, target](bool toggled) {
+ if (toggled) {
+ mesonBuildStep()->setBuildTarget(target);
+ updateDetails();
+ }
+ });
+ button->setChecked(mesonBuildStep()->targetName() == target);
+ m_buildTargetsList->setItemWidget(item, button);
+ item->setData(Qt::UserRole, target);
+ }
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.h b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.h
new file mode 100644
index 0000000000..b0cc6fb9d8
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "../ninjabuildstep.h"
+#include "projectexplorer/buildstep.h"
+#include <QListWidget>
+#include <QWidget>
+
+namespace Ui {
+class MesonBuildStepConfigWidget;
+}
+namespace MesonProjectManager {
+namespace Internal {
+class MesonBuildStepConfigWidget final : public ProjectExplorer::BuildStepConfigWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::MesonBuildStepConfigWidget)
+
+public:
+ explicit MesonBuildStepConfigWidget(NinjaBuildStep *step);
+ ~MesonBuildStepConfigWidget();
+
+private:
+ void updateDetails();
+ void updateTargetList();
+ inline NinjaBuildStep *mesonBuildStep() { return static_cast<NinjaBuildStep *>(step()); }
+ Ui::MesonBuildStepConfigWidget *ui;
+ QListWidget *m_buildTargetsList;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.ui b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.ui
new file mode 100644
index 0000000000..1212227fb7
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/mesonbuildstepconfigwidget.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MesonBuildStepConfigWidget</class>
+ <widget class="QWidget" name="MesonBuildStepConfigWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Tool arguments:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="m_toolArguments"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Targets:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QFrame" name="frame">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.cpp b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.cpp
new file mode 100644
index 0000000000..3391a972d0
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "arrayoptionlineedit.h"
+namespace MesonProjectManager {
+namespace Internal {
+ArrayOptionLineEdit::ArrayOptionLineEdit(QWidget *parent)
+ : QPlainTextEdit(parent)
+{
+ m_highLighter = new RegexHighlighter(this);
+ m_highLighter->setDocument(this->document());
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setLineWrapMode(QPlainTextEdit::NoWrap);
+ QFontMetrics metrics(this->font());
+ int lineHeight = metrics.lineSpacing();
+ this->setFixedHeight(lineHeight * 1.5);
+}
+
+QStringList ArrayOptionLineEdit::options()
+{
+ return m_highLighter->options(this->toPlainText());
+}
+
+void ArrayOptionLineEdit::keyPressEvent(QKeyEvent *e)
+{
+ if (e->key() != Qt::Key_Return)
+ return QPlainTextEdit::keyPressEvent(e);
+ e->accept();
+}
+
+RegexHighlighter::RegexHighlighter(QWidget *parent)
+ : QSyntaxHighlighter(parent)
+{
+ m_format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
+ m_format.setUnderlineColor(QColor(180, 180, 180));
+ m_format.setBackground(QBrush(QColor(180, 180, 230, 80)));
+}
+
+QStringList RegexHighlighter::options(const QString &text)
+{
+ QRegularExpressionMatchIterator i = m_regex.globalMatch(text);
+ QStringList op;
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ for (int j = 1; j <= match.lastCapturedIndex(); j++) {
+ auto str = match.captured(j);
+ if (!str.isEmpty())
+ op.push_back(str);
+ }
+ }
+ return op;
+}
+
+void RegexHighlighter::highlightBlock(const QString &text)
+{
+ QRegularExpressionMatchIterator i = m_regex.globalMatch(text);
+ while (i.hasNext()) {
+ QRegularExpressionMatch match = i.next();
+ for (int j = 1; j <= match.lastCapturedIndex(); j++) {
+ setFormat(match.capturedStart(j), match.capturedLength(j), m_format);
+ }
+ }
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.h b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.h
new file mode 100644
index 0000000000..5107ffee7e
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/arrayoptionlineedit.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <QColor>
+#include <QPlainTextEdit>
+#include <QRegularExpression>
+#include <QSyntaxHighlighter>
+#include <QWidget>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class RegexHighlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+ const QRegularExpression m_regex{R"('([^']+)'+|([^', ]+)[, ]*)"};
+ QTextCharFormat m_format;
+
+public:
+ RegexHighlighter(QWidget *parent);
+ void highlightBlock(const QString &text) override;
+ QStringList options(const QString &text);
+};
+
+class ArrayOptionLineEdit : public QPlainTextEdit
+{
+ Q_OBJECT
+ RegexHighlighter *m_highLighter;
+
+public:
+ ArrayOptionLineEdit(QWidget *parent = nullptr);
+ QStringList options();
+
+protected:
+ void keyPressEvent(QKeyEvent *e) override;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.cpp b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.cpp
new file mode 100644
index 0000000000..707b5eed0c
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "buildoptionsmodel.h"
+#include "arrayoptionlineedit.h"
+#include <QComboBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QMap>
+#include <QStyledItemDelegate>
+#include <QTextEdit>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+// this could be relaxed once we have something able to link reliably meson build type
+// to QTC build type and update it, this must not break any features like tests/debug/profiling...
+static const QStringList lockedOptions = {"buildtype", "debug", "backend", "optimization"};
+
+inline Utils::TreeItem *makeBuildOptionTreeItem(CancellableOption *buildOption)
+{
+ return new BuildOptionTreeItem(buildOption);
+}
+
+BuidOptionsModel::BuidOptionsModel(QObject *parent)
+ : Utils::TreeModel<>(parent)
+{
+ setHeader({tr("Key"), tr("Value")});
+}
+
+inline void groupPerSubprojectAndSection(
+ const CancellableOptionsList &options,
+ QMap<QString, QMap<QString, std::vector<CancellableOption *>>> &subprojectOptions,
+ QMap<QString, std::vector<CancellableOption *>> &perSectionOptions)
+{
+ std::for_each(std::cbegin(options),
+ std::cend(options),
+ [&subprojectOptions,
+ &perSectionOptions](const std::unique_ptr<CancellableOption> &option) {
+ if (option->subproject()) {
+ subprojectOptions[*option->subproject()][option->section()].push_back(
+ option.get());
+ } else {
+ perSectionOptions[option->section()].push_back(option.get());
+ }
+ });
+}
+
+void makeTree(Utils::TreeItem *root,
+ const QMap<QString, std::vector<CancellableOption *>> &perSectioOptions)
+{
+ std::for_each(perSectioOptions.constKeyValueBegin(),
+ perSectioOptions.constKeyValueEnd(),
+ [root](const std::pair<QString, std::vector<CancellableOption *>> kv) {
+ const auto &options = kv.second;
+ auto sectionNode = new Utils::StaticTreeItem(kv.first);
+ std::for_each(std::cbegin(options),
+ std::cend(options),
+ [sectionNode](CancellableOption *option) {
+ sectionNode->appendChild(makeBuildOptionTreeItem(option));
+ });
+ root->appendChild(sectionNode);
+ });
+}
+
+void BuidOptionsModel::setConfiguration(const BuildOptionsList &options)
+{
+ clear();
+ m_options = decltype(m_options)();
+ std::for_each(std::cbegin(options),
+ std::cend(options),
+ [this](const BuildOptionsList::value_type &option) {
+ m_options.emplace_back(
+ std::make_unique<CancellableOption>(option.get(),
+ lockedOptions.contains(option->name)));
+ });
+ {
+ QMap<QString, QMap<QString, std::vector<CancellableOption *>>> subprojectOptions;
+ QMap<QString, std::vector<CancellableOption *>> perSectionOptions;
+ groupPerSubprojectAndSection(m_options, subprojectOptions, perSectionOptions);
+ auto root = new Utils::TreeItem;
+ makeTree(root, perSectionOptions);
+ auto subProjects = new Utils::StaticTreeItem{"Subprojects"};
+ std::for_each(subprojectOptions.constKeyValueBegin(),
+ subprojectOptions.constKeyValueEnd(),
+ [subProjects](
+ const std::pair<QString, QMap<QString, std::vector<CancellableOption *>>>
+ kv) {
+ auto subProject = new Utils::StaticTreeItem{kv.first};
+ makeTree(subProject, kv.second);
+ subProjects->appendChild(subProject);
+ });
+ root->appendChild(subProjects);
+ setRootItem(root);
+ }
+}
+
+bool BuidOptionsModel::setData(const QModelIndex &idx, const QVariant &data, int role)
+{
+ bool result = Utils::TreeModel<>::setData(idx, data, role);
+ if (hasChanges())
+ emit configurationChanged();
+ return result;
+}
+
+QStringList BuidOptionsModel::changesAsMesonArgs()
+{
+ QStringList args;
+ std::for_each(std::cbegin(m_options),
+ std::cend(m_options),
+ [&](const std::unique_ptr<CancellableOption> &option) {
+ if (option->hasChanged()) {
+ args.push_back(option->mesonArg());
+ }
+ });
+ return args;
+}
+
+bool BuidOptionsModel::hasChanges() const
+{
+ for (const std::unique_ptr<CancellableOption> &option : m_options) {
+ if (option->hasChanged())
+ return true;
+ }
+ return false;
+}
+
+QWidget *BuildOptionDelegate::makeWidget(QWidget *parent, const QVariant &data)
+{
+ auto type = data.userType();
+ switch (type) {
+ case QVariant::Int: {
+ auto w = new QSpinBox{parent};
+ w->setValue(data.toInt());
+ return w;
+ }
+ case QVariant::Bool: {
+ auto w = new QComboBox{parent};
+ w->addItems({"false", "true"});
+ w->setCurrentIndex(data.toBool());
+ return w;
+ }
+ case QVariant::StringList: {
+ auto w = new ArrayOptionLineEdit{parent};
+ w->setPlainText(data.toStringList().join(" "));
+ return w;
+ }
+ case QVariant::String: {
+ auto w = new QLineEdit{parent};
+ w->setText(data.toString());
+ return w;
+ }
+ default: {
+ if (type == qMetaTypeId<ComboData>()) {
+ auto w = new QComboBox{parent};
+ auto value = data.value<ComboData>();
+ w->addItems(value.choices());
+ w->setCurrentIndex(value.currentIndex());
+ return w;
+ }
+ if (type == qMetaTypeId<FeatureData>()) {
+ auto w = new QComboBox{parent};
+ auto value = data.value<FeatureData>();
+ w->addItems(value.choices());
+ w->setCurrentIndex(value.currentIndex());
+ return w;
+ }
+ return nullptr;
+ }
+ }
+}
+
+BuildOptionDelegate::BuildOptionDelegate(QObject *parent)
+ : QStyledItemDelegate{parent}
+{}
+
+QWidget *BuildOptionDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ auto data = index.data(Qt::EditRole);
+ bool readOnly = index.data(Qt::UserRole).toBool();
+ auto widget = makeWidget(parent, data);
+ if (widget) {
+ widget->setFocusPolicy(Qt::StrongFocus);
+ widget->setDisabled(readOnly);
+ return widget;
+ }
+ return QStyledItemDelegate::createEditor(parent, option, index);
+}
+
+void BuildOptionDelegate::setModelData(QWidget *editor,
+ QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ ArrayOptionLineEdit *arrayWidget = qobject_cast<ArrayOptionLineEdit *>(editor);
+ if (arrayWidget) {
+ model->setData(index, QVariant::fromValue(arrayWidget->options()));
+ } else {
+ QStyledItemDelegate::setModelData(editor, model, index);
+ }
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.h b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.h
new file mode 100644
index 0000000000..c196571cc3
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/buildoptions/optionsmodel/buildoptionsmodel.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "mesoninfoparser/mesoninfoparser.h"
+
+#include <utils/qtcassert.h>
+#include <utils/treemodel.h>
+
+#include <QAbstractTableModel>
+#include <QFont>
+#include <QItemEditorFactory>
+#include <QObject>
+#include <QStyledItemDelegate>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class CancellableOption
+{
+ std::unique_ptr<BuildOption> m_savedValue;
+ std::unique_ptr<BuildOption> m_currentValue;
+ bool m_changed = false;
+ bool m_locked = false;
+
+public:
+ CancellableOption(BuildOption *option, bool locked = false)
+ : m_savedValue{option->copy()}
+ , m_currentValue{option->copy()}
+ , m_locked{locked}
+ {}
+ inline bool isLocked() { return m_locked; }
+ inline bool hasChanged() { return m_changed; }
+ inline void apply()
+ {
+ if (m_changed) {
+ m_savedValue = std::unique_ptr<BuildOption>(m_currentValue->copy());
+ m_changed = false;
+ }
+ }
+ inline void cancel()
+ {
+ if (m_changed) {
+ m_currentValue = std::unique_ptr<BuildOption>(m_savedValue->copy());
+ m_changed = false;
+ }
+ }
+
+ inline const QString &name() const { return m_currentValue->name; }
+ inline const QString &section() const { return m_currentValue->section; }
+ inline const QString &description() const { return m_currentValue->description; }
+ inline const Utils::optional<QString> &subproject() const
+ {
+ return m_currentValue->subproject;
+ };
+ inline QVariant value() { return m_currentValue->value(); }
+ inline QString valueStr() { return m_currentValue->valueStr(); };
+ inline QString savedValueStr() { return m_savedValue->valueStr(); };
+ inline QString mesonArg() { return m_currentValue->mesonArg(); }
+ inline void setValue(const QVariant &v)
+ {
+ if (!m_locked) {
+ m_currentValue->setValue(v);
+ m_changed = m_currentValue->valueStr() != m_savedValue->valueStr();
+ }
+ }
+ inline BuildOption::Type type() { return m_currentValue->type(); }
+};
+using CancellableOptionsList = std::vector<std::unique_ptr<CancellableOption>>;
+class BuidOptionsModel final : public Utils::TreeModel<>
+{
+ Q_OBJECT
+public:
+ explicit BuidOptionsModel(QObject *parent = nullptr);
+
+ void setConfiguration(const BuildOptionsList &options);
+ bool setData(const QModelIndex &idx, const QVariant &data, int role) override;
+
+ QStringList changesAsMesonArgs();
+
+ Q_SIGNAL void configurationChanged();
+
+private:
+ bool hasChanges() const;
+ CancellableOptionsList m_options;
+};
+
+class BuildOptionTreeItem final : public Utils::TreeItem
+{
+ CancellableOption *m_option;
+
+public:
+ BuildOptionTreeItem(CancellableOption *option) { m_option = option; }
+ QVariant data(int column, int role) const final
+ {
+ QTC_ASSERT(column >= 0 && column < 2, return {});
+ QTC_ASSERT(m_option, return {});
+ if (column == 0) {
+ switch (role) {
+ case Qt::DisplayRole:
+ return m_option->name();
+ case Qt::ToolTipRole:
+ return toolTip();
+ case Qt::FontRole:
+ QFont font;
+ font.setBold(m_option->hasChanged());
+ return font;
+ }
+ }
+ if (column == 1) {
+ switch (role) {
+ case Qt::DisplayRole:
+ return m_option->valueStr();
+ case Qt::EditRole:
+ return m_option->value();
+ case Qt::UserRole:
+ return m_option->isLocked();
+ case Qt::ToolTipRole:
+ if (m_option->hasChanged())
+ return QString("%1<br>Initial value was <b>%2</b>")
+ .arg(toolTip())
+ .arg(m_option->savedValueStr());
+ else
+ return toolTip();
+ case Qt::FontRole:
+ QFont font;
+ font.setBold(m_option->hasChanged());
+ return font;
+ }
+ }
+ return {};
+ };
+ bool setData(int column, const QVariant &data, int role) final
+ {
+ Q_UNUSED(role);
+ QTC_ASSERT(column == 1, return false);
+ m_option->setValue(data);
+ return true;
+ };
+ Qt::ItemFlags flags(int column) const final
+ {
+ QTC_ASSERT(column >= 0 && column < 2, return Qt::NoItemFlags);
+ if (column == 0)
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+ if (column == 1)
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
+ return Qt::NoItemFlags;
+ }
+ BuildOption::Type type() const { return m_option->type(); }
+ QString toolTip() const { return m_option->description(); }
+};
+
+class BuildOptionDelegate final : public QStyledItemDelegate
+{
+ Q_OBJECT
+ static QWidget *makeWidget(QWidget *parent, const QVariant &data);
+
+public:
+ BuildOptionDelegate(QObject *parent = nullptr);
+ QWidget *createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+ void setModelData(QWidget *editor,
+ QAbstractItemModel *model,
+ const QModelIndex &index) const override;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp
new file mode 100644
index 0000000000..a76e54590e
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include <projectexplorer/buildinfo.h>
+#include <projectexplorer/buildmanager.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectmacroexpander.h>
+#include <utils/fileutils.h>
+
+#include <QDir>
+
+#include "buildoptions/mesonbuildsettingswidget.h"
+#include "mesonbuildconfiguration.h"
+#include "mesonbuildsystem.h"
+#include "mesonpluginconstants.h"
+#include "ninjabuildstep.h"
+#include <exewrappers/mesonwrapper.h>
+#include <mesonpluginconstants.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+MesonBuildConfiguration::MesonBuildConfiguration(ProjectExplorer::Target *target, Core::Id id)
+ : ProjectExplorer::BuildConfiguration{target, id}
+{
+ appendInitialBuildStep(Constants::MESON_BUILD_STEP_ID);
+ appendInitialCleanStep(Constants::MESON_BUILD_STEP_ID);
+ setInitializer([this, target](const ProjectExplorer::BuildInfo &info) {
+ m_buildType = mesonBuildType(info.typeName);
+ auto k = target->kit();
+ if (info.buildDirectory.isEmpty()) {
+ setBuildDirectory(shadowBuildDirectory(target->project()->projectFilePath(),
+ k,
+ info.displayName,
+ info.buildType));
+ }
+ m_buildSystem = new MesonBuildSystem{this};
+ });
+}
+
+MesonBuildConfiguration::~MesonBuildConfiguration()
+{
+ delete m_buildSystem;
+}
+
+Utils::FilePath MesonBuildConfiguration::shadowBuildDirectory(
+ const Utils::FilePath &projectFilePath,
+ const ProjectExplorer::Kit *k,
+ const QString &bcName,
+ ProjectExplorer::BuildConfiguration::BuildType buildType)
+{
+ if (projectFilePath.isEmpty())
+ return Utils::FilePath();
+
+ const QString projectName = projectFilePath.parentDir().fileName();
+ ProjectExplorer::ProjectMacroExpander expander(projectFilePath,
+ projectName,
+ k,
+ bcName,
+ buildType);
+ QDir projectDir = QDir(ProjectExplorer::Project::projectDirectory(projectFilePath).toString());
+ QString buildPath = expander.expand(
+ ProjectExplorer::ProjectExplorerPlugin::buildDirectoryTemplate());
+ buildPath.replace(" ", "-");
+ return Utils::FilePath::fromUserInput(projectDir.absoluteFilePath(buildPath));
+}
+
+ProjectExplorer::BuildSystem *MesonBuildConfiguration::buildSystem() const
+{
+ return m_buildSystem;
+}
+
+void MesonBuildConfiguration::build(const QString &target)
+{
+ auto mesonBuildStep = qobject_cast<NinjaBuildStep *>(
+ Utils::findOrDefault(buildSteps()->steps(), [](const ProjectExplorer::BuildStep *bs) {
+ return bs->id() == Constants::MESON_BUILD_STEP_ID;
+ }));
+
+ QString originalBuildTarget;
+ if (mesonBuildStep) {
+ originalBuildTarget = mesonBuildStep->targetName();
+ mesonBuildStep->setBuildTarget(target);
+ }
+
+ ProjectExplorer::BuildManager::buildList(buildSteps());
+
+ if (mesonBuildStep)
+ mesonBuildStep->setBuildTarget(originalBuildTarget);
+}
+
+QVariantMap MesonBuildConfiguration::toMap() const
+{
+ auto data = ProjectExplorer::BuildConfiguration::toMap();
+ data[Constants::BuildConfiguration::BUILD_TYPE_KEY] = mesonBuildTypeName(m_buildType);
+ return data;
+}
+
+bool MesonBuildConfiguration::fromMap(const QVariantMap &map)
+{
+ auto res = ProjectExplorer::BuildConfiguration::fromMap(map);
+ m_buildSystem = new MesonBuildSystem{this};
+ m_buildType = mesonBuildType(
+ map.value(Constants::BuildConfiguration::BUILD_TYPE_KEY).toString());
+ return res;
+}
+
+ProjectExplorer::NamedWidget *MesonBuildConfiguration::createConfigWidget()
+{
+ return new MesonBuildSettingsWidget{this};
+}
+
+ProjectExplorer::BuildInfo createBuildInfo(MesonBuildType type)
+{
+ ProjectExplorer::BuildInfo bInfo;
+ bInfo.typeName = mesonBuildTypeName(type);
+ bInfo.displayName = mesonBuildTypeDisplayName(type);
+ bInfo.buildType = buildType(type);
+ return bInfo;
+}
+
+MesonBuildConfigurationFactory::MesonBuildConfigurationFactory()
+{
+ registerBuildConfiguration<MesonBuildConfiguration>(Constants::MESON_BUILD_CONFIG_ID);
+ setSupportedProjectType(Constants::Project::ID);
+ setSupportedProjectMimeTypeName(Constants::Project::MIMETYPE);
+ setBuildGenerator(
+ [](const ProjectExplorer::Kit *k, const Utils::FilePath &projectPath, bool forSetup) {
+ QList<ProjectExplorer::BuildInfo> result;
+
+ Utils::FilePath path = forSetup
+ ? ProjectExplorer::Project::projectDirectory(projectPath)
+ : projectPath;
+ for (const auto &bType : {MesonBuildType::debug,
+ MesonBuildType::release,
+ MesonBuildType::debugoptimized,
+ MesonBuildType::minsize}) {
+ auto bInfo = createBuildInfo(bType);
+ if (forSetup)
+ bInfo.buildDirectory
+ = MesonBuildConfiguration::shadowBuildDirectory(projectPath,
+ k,
+ bInfo.typeName,
+ bInfo.buildType);
+ result << bInfo;
+ }
+ return result;
+ });
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.h b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.h
new file mode 100644
index 0000000000..e60bba50cc
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildconfiguration.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "coreplugin/id.h"
+#include "projectexplorer/buildconfiguration.h"
+#include "projectexplorer/target.h"
+#include "utils/fileutils.h"
+#include <QString>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+enum class MesonBuildType { plain, debug, debugoptimized, release, minsize, custom };
+
+const QHash<QString, MesonBuildType> buildTypesByName = {{"plain", MesonBuildType::plain},
+ {"debug", MesonBuildType::debug},
+ {"debugoptimized",
+ MesonBuildType::debugoptimized},
+ {"release", MesonBuildType::release},
+ {"minsize", MesonBuildType::minsize},
+ {"custom", MesonBuildType::custom}};
+
+inline QString mesonBuildTypeName(MesonBuildType type)
+{
+ return buildTypesByName.key(type, "custom");
+}
+
+inline QString mesonBuildTypeDisplayName(MesonBuildType type)
+{
+ switch (type) {
+ case MesonBuildType::plain:
+ return "Plain";
+ case MesonBuildType::debug:
+ return "Debug";
+ case MesonBuildType::debugoptimized:
+ return "Debug With Optimizations";
+ case MesonBuildType::release:
+ return "Release";
+ case MesonBuildType::minsize:
+ return "Minimum Size";
+ default:
+ return "Custom";
+ }
+}
+
+inline MesonBuildType mesonBuildType(const QString &typeName)
+{
+ return buildTypesByName.value(typeName, MesonBuildType::custom);
+}
+
+inline ProjectExplorer::BuildConfiguration::BuildType buildType(MesonBuildType type)
+{
+ switch (type) {
+ case MesonBuildType::plain:
+ return ProjectExplorer::BuildConfiguration::Unknown;
+ case MesonBuildType::debug:
+ return ProjectExplorer::BuildConfiguration::Debug;
+ case MesonBuildType::debugoptimized:
+ return ProjectExplorer::BuildConfiguration::Profile;
+ case MesonBuildType::release:
+ return ProjectExplorer::BuildConfiguration::Release;
+ case MesonBuildType::minsize:
+ return ProjectExplorer::BuildConfiguration::Release;
+ default:
+ return ProjectExplorer::BuildConfiguration::Unknown;
+ }
+}
+
+class MesonBuildSystem;
+class MesonTools;
+
+class MesonBuildConfiguration final : public ProjectExplorer::BuildConfiguration
+{
+ Q_OBJECT
+public:
+ MesonBuildConfiguration(ProjectExplorer::Target *target, Core::Id id);
+ ~MesonBuildConfiguration() final;
+
+ static Utils::FilePath shadowBuildDirectory(
+ const Utils::FilePath &projectFilePath,
+ const ProjectExplorer::Kit *k,
+ const QString &bcName,
+ ProjectExplorer::BuildConfiguration::BuildType buildType);
+
+ ProjectExplorer::BuildSystem *buildSystem() const final;
+ void build(const QString &target);
+
+ QStringList mesonConfigArgs()
+ {
+ return {QString("-Dbuildtype=%1").arg(mesonBuildTypeName(m_buildType))};
+ }
+
+private:
+ QVariantMap toMap() const override;
+ bool fromMap(const QVariantMap &map) override;
+ MesonBuildType m_buildType;
+ ProjectExplorer::NamedWidget *createConfigWidget() final;
+ MesonBuildSystem *m_buildSystem;
+};
+
+class MesonBuildConfigurationFactory final : public ProjectExplorer::BuildConfigurationFactory
+{
+public:
+ MesonBuildConfigurationFactory();
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp
new file mode 100644
index 0000000000..dace993fe0
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonbuildsystem.h"
+#include "mesonbuildconfiguration.h"
+#include <kithelper/kithelper.h>
+#include <machinefiles/machinefilemanager.h>
+#include <settings/general/settings.h>
+#include <settings/tools/kitaspect/mesontoolkitaspect.h>
+#include <projectexplorer/buildconfiguration.h>
+
+#include <QDir>
+#include <QLoggingCategory>
+#include <qtsupport/qtcppkitinfo.h>
+#include <qtsupport/qtkitinformation.h>
+
+#define LEAVE_IF_BUSY() \
+ { \
+ if (m_parseGuard.guardsProject()) \
+ return false; \
+ }
+#define LOCK() \
+ { \
+ m_parseGuard = guardParsingRun(); \
+ }
+
+#define UNLOCK(success) \
+ { \
+ if (success) \
+ m_parseGuard.markAsSuccess(); \
+ m_parseGuard = {}; \
+ };
+
+namespace MesonProjectManager {
+namespace Internal {
+static Q_LOGGING_CATEGORY(mesonBuildSystemLog, "qtc.meson.buildsystem", QtDebugMsg);
+
+MesonBuildSystem::MesonBuildSystem(MesonBuildConfiguration *bc)
+ : ProjectExplorer::BuildSystem{bc}
+ , m_parser{MesonToolKitAspect::mesonToolId(bc->target()->kit()),
+ bc->environment(),
+ project()}
+{
+ init();
+}
+
+MesonBuildSystem::~MesonBuildSystem()
+{
+ qCDebug(mesonBuildSystemLog) << "dtor";
+}
+
+void MesonBuildSystem::triggerParsing()
+{
+ qCDebug(mesonBuildSystemLog) << "Trigger parsing";
+ parseProject();
+}
+
+bool MesonBuildSystem::needsSetup()
+{
+ const Utils::FilePath &buildDir = buildConfiguration()->buildDirectory();
+ return (!isSetup(buildDir) || !m_parser.usesSameMesonVersion(buildDir)
+ || !m_parser.matchesKit(m_kitData));
+}
+
+void MesonBuildSystem::parsingCompleted(bool success)
+{
+ if (success) {
+ setRootProjectNode(m_parser.takeProjectNode());
+ if (kit() && buildConfiguration()) {
+ ProjectExplorer::KitInfo kitInfo{kit()};
+ m_cppCodeModelUpdater.update(
+ {project(),
+ QtSupport::CppKitInfo(kit()),
+ buildConfiguration()->environment(),
+ m_parser.buildProjectParts(kitInfo.cxxToolChain, kitInfo.cToolChain)});
+ }
+ setApplicationTargets(m_parser.appsTargets());
+ UNLOCK(true);
+ emitBuildSystemUpdated();
+ } else {
+ UNLOCK(false);
+ emitBuildSystemUpdated();
+ }
+}
+
+ProjectExplorer::Kit *MesonBuildSystem::MesonBuildSystem::kit()
+{
+ return buildConfiguration()->target()->kit();
+}
+
+QStringList MesonBuildSystem::configArgs(bool isSetup)
+{
+ if (!isSetup)
+ return m_pendingConfigArgs + mesonBuildConfiguration()->mesonConfigArgs();
+ else {
+ return QStringList{QString("--native-file=%1")
+ .arg(MachineFileManager::machineFile(kit()).toString())}
+ + m_pendingConfigArgs + mesonBuildConfiguration()->mesonConfigArgs();
+ }
+}
+
+bool MesonBuildSystem::configure()
+{
+ LEAVE_IF_BUSY();
+ qCDebug(mesonBuildSystemLog) << "Configure";
+ if (needsSetup())
+ return setup();
+ LOCK();
+ if (m_parser.configure(projectDirectory(),
+ buildConfiguration()->buildDirectory(),
+ configArgs(false))) {
+ return true;
+ }
+ UNLOCK(false);
+ return false;
+}
+
+bool MesonBuildSystem::setup()
+{
+ LEAVE_IF_BUSY();
+ LOCK();
+ qCDebug(mesonBuildSystemLog) << "Setup";
+ if (m_parser.setup(projectDirectory(), buildConfiguration()->buildDirectory(), configArgs(true)))
+ return true;
+ UNLOCK(false);
+ return false;
+}
+
+bool MesonBuildSystem::wipe()
+{
+ LEAVE_IF_BUSY();
+ LOCK();
+ qCDebug(mesonBuildSystemLog) << "Wipe";
+ if (m_parser.wipe(projectDirectory(), buildConfiguration()->buildDirectory(), configArgs(true)))
+ return true;
+ UNLOCK(false);
+ return false;
+}
+
+MesonBuildConfiguration *MesonBuildSystem::mesonBuildConfiguration()
+{
+ return static_cast<MesonBuildConfiguration *>(buildConfiguration());
+}
+
+void MesonBuildSystem::init()
+{
+ qCDebug(mesonBuildSystemLog) << "Init";
+ connect(buildConfiguration()->target(), &ProjectExplorer::Target::kitChanged, this, [this] {
+ updateKit(kit());
+ });
+ connect(mesonBuildConfiguration(),
+ &MesonBuildConfiguration::buildDirectoryChanged,
+ this,
+ [this]() {
+ updateKit(kit());
+ this->triggerParsing();
+ });
+ connect(mesonBuildConfiguration(), &MesonBuildConfiguration::environmentChanged, this, [this]() {
+ m_parser.setEnvironment(buildConfiguration()->environment());
+ });
+
+ connect(project(), &ProjectExplorer::Project::projectFileIsDirty, this, [this]() {
+ if (buildConfiguration()->isActive())
+ parseProject();
+ });
+ connect(&m_parser,
+ &MesonProjectParser::parsingCompleted,
+ this,
+ &MesonBuildSystem::parsingCompleted);
+ updateKit(kit());
+}
+
+bool MesonBuildSystem::parseProject()
+{
+ QTC_ASSERT(buildConfiguration(), return false);
+ if (!isSetup(buildConfiguration()->buildDirectory()) && Settings::autorunMeson())
+ return configure();
+ LEAVE_IF_BUSY();
+ LOCK();
+ qCDebug(mesonBuildSystemLog) << "Starting parser";
+ if (m_parser.parse(projectDirectory(), buildConfiguration()->buildDirectory()))
+ return true;
+ UNLOCK(false);
+ return false;
+}
+
+void MesonBuildSystem::updateKit(ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return );
+ m_kitData = KitHelper::kitData(kit);
+ m_parser.setQtVersion(m_kitData.qtVersion);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonbuildsystem.h b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.h
new file mode 100644
index 0000000000..3f266c88a7
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonbuildsystem.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "mesonprojectparser.h"
+#include <exewrappers/mesonwrapper.h>
+#include <kithelper/kitdata.h>
+
+#include <cpptools/cppprojectupdater.h>
+#include <projectexplorer/buildsystem.h>
+#include <projectexplorer/target.h>
+#include <utils/filesystemwatcher.h>
+#include <QObject>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonBuildConfiguration;
+class MesonBuildSystem final : public ProjectExplorer::BuildSystem
+{
+ Q_OBJECT
+public:
+ MesonBuildSystem(MesonBuildConfiguration *bc);
+ ~MesonBuildSystem() final;
+
+ void triggerParsing() final;
+
+ inline const BuildOptionsList &buildOptions() const { return m_parser.buildOptions(); }
+ inline const TargetsList &targets() const { return m_parser.targets(); }
+
+ bool configure();
+ bool setup();
+ bool wipe();
+
+ MesonBuildConfiguration *mesonBuildConfiguration();
+
+ const QStringList &targetList() const { return m_parser.targetsNames(); }
+
+ void setMesonConfigArgs(const QStringList &args) { m_pendingConfigArgs = args; }
+
+private:
+ void init();
+ bool parseProject();
+ void updateKit(ProjectExplorer::Kit *kit);
+ bool needsSetup();
+ void parsingCompleted(bool success);
+ ProjectExplorer::Kit *kit();
+ QStringList configArgs(bool isSetup);
+ ProjectExplorer::BuildSystem::ParseGuard m_parseGuard;
+ MesonProjectParser m_parser;
+ CppTools::CppProjectUpdater m_cppCodeModelUpdater;
+ QStringList m_pendingConfigArgs;
+ KitData m_kitData;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprocess.cpp b/src/plugins/mesonprojectmanager/project/mesonprocess.cpp
new file mode 100644
index 0000000000..5daf3d227f
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprocess.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonprocess.h"
+#include "outputparsers/mesonoutputparser.h"
+
+#include <coreplugin/messagemanager.h>
+#include <coreplugin/progressmanager/progressmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/taskhub.h>
+#include <utils/stringutils.h>
+
+#include <QLoggingCategory>
+
+namespace MesonProjectManager {
+namespace Internal {
+static Q_LOGGING_CATEGORY(mesonProcessLog, "qtc.meson.buildsystem", QtDebugMsg);
+
+MesonProcess::MesonProcess()
+{
+ connect(&m_cancelTimer, &QTimer::timeout, this, &MesonProcess::checkForCancelled);
+ m_cancelTimer.setInterval(500);
+}
+
+bool MesonProcess::run(const Command &command,
+ const Utils::Environment env,
+ const QString &projectName,
+ bool captureStdo)
+{
+ if (!sanityCheck(command))
+ return false;
+ m_currentCommand = command;
+ m_stdo.clear();
+ m_processWasCanceled = false;
+ m_future = decltype(m_future){};
+ ProjectExplorer::TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
+ setupProcess(command, env, captureStdo);
+ m_future.setProgressRange(0, 1);
+ Core::ProgressManager::addTimedTask(m_future,
+ tr("Configuring \"%1\".").arg(projectName),
+ "Meson.Configure",
+ 10);
+ emit started();
+ m_elapsed.start();
+ m_process->start();
+ m_cancelTimer.start(500);
+ qCDebug(mesonProcessLog()) << "Starting:" << command.toUserOutput();
+ return true;
+}
+
+QProcess::ProcessState MesonProcess::state() const
+{
+ return m_process->state();
+}
+
+void MesonProcess::reportCanceled()
+{
+ m_future.reportCanceled();
+}
+
+void MesonProcess::reportFinished()
+{
+ m_future.reportFinished();
+}
+
+void MesonProcess::setProgressValue(int p)
+{
+ m_future.setProgressValue(p);
+}
+
+void MesonProcess::handleProcessFinished(int code, QProcess::ExitStatus status)
+{
+ m_cancelTimer.stop();
+ m_stdo = m_process->readAllStandardOutput();
+ m_stderr = m_process->readAllStandardError();
+ if (status == QProcess::NormalExit) {
+ m_future.setProgressValue(1);
+ m_future.reportFinished();
+ } else {
+ m_future.reportCanceled();
+ m_future.reportFinished();
+ }
+ const QString elapsedTime = Utils::formatElapsedTime(m_elapsed.elapsed());
+ Core::MessageManager::write(elapsedTime);
+ emit finished(code, status);
+}
+
+void MesonProcess::handleProcessError(QProcess::ProcessError error)
+{
+ QString message;
+ QString commandStr = m_currentCommand.toUserOutput();
+ switch (error) {
+ case QProcess::ProcessError::FailedToStart:
+ message = tr("The process failed to start.")
+ + tr("Either the "
+ "invoked program \"%1\" is missing, or you may have insufficient "
+ "permissions to invoke the program.")
+ .arg(m_currentCommand.executable().toUserOutput());
+ break;
+ case QProcess::ProcessError::Crashed:
+ message = tr("The process was ended forcefully.");
+ break;
+ case QProcess::ProcessError::Timedout:
+ message = tr("Process timed out.");
+ break;
+ case QProcess::ProcessError::WriteError:
+ message = tr("An error occurred when attempting to write "
+ "to the process. For example, the process may not be running, "
+ "or it may have closed its input channel.");
+ break;
+ case QProcess::ProcessError::ReadError:
+ message = tr("An error occurred when attempting to read from "
+ "the process. For example, the process may not be running.");
+ break;
+ case QProcess::ProcessError::UnknownError:
+ message = tr("An unknown error in the process occurred.");
+ break;
+ }
+ ProjectExplorer::TaskHub::addTask(
+ ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
+ QString("%1\n%2").arg(message).arg(commandStr)});
+ handleProcessFinished(-1, QProcess::CrashExit);
+}
+
+void MesonProcess::checkForCancelled()
+{
+ if (m_future.isCanceled()) {
+ m_cancelTimer.stop();
+ m_processWasCanceled = true;
+ m_process->close();
+ }
+}
+
+void MesonProcess::setupProcess(const Command &command,
+ const Utils::Environment env,
+ bool captureStdo)
+{
+ if (m_process)
+ disconnect(m_process.get());
+ m_process = std::make_unique<Utils::QtcProcess>();
+ connect(m_process.get(),
+ QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
+ this,
+ &MesonProcess::handleProcessFinished);
+ connect(m_process.get(), &QProcess::errorOccurred, this, &MesonProcess::handleProcessError);
+ if (!captureStdo) {
+ connect(m_process.get(),
+ &QProcess::readyReadStandardOutput,
+ this,
+ &MesonProcess::processStandardOutput);
+
+ connect(m_process.get(),
+ &QProcess::readyReadStandardError,
+ this,
+ &MesonProcess::processStandardError);
+ }
+
+ m_process->setWorkingDirectory(command.workDir().toString());
+ m_process->setEnvironment(env);
+ Core::MessageManager::write(
+ tr("Running %1 in %2.").arg(command.toUserOutput()).arg(command.workDir().toUserOutput()));
+ m_process->setCommand(command.cmdLine());
+}
+
+bool MesonProcess::sanityCheck(const Command &command) const
+{
+ const auto &exe = command.cmdLine().executable();
+ if (!exe.exists()) {
+ //Should only reach this point if Meson exe is removed while a Meson project is opened
+ ProjectExplorer::TaskHub::addTask(
+ ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
+ tr("Executable does not exist: %1")
+ .arg(exe.toUserOutput())});
+ return false;
+ }
+ if (!exe.toFileInfo().isExecutable()) {
+ ProjectExplorer::TaskHub::addTask(
+ ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error,
+ tr("Command is not executable: %1")
+ .arg(exe.toUserOutput())});
+ return false;
+ }
+ return true;
+}
+
+void MesonProcess::processStandardOutput()
+{
+ QTC_ASSERT(m_process, return );
+ auto data = m_process->readAllStandardOutput();
+ Core::MessageManager::write(QString::fromLocal8Bit(data));
+ emit readyReadStandardOutput(data);
+}
+
+void MesonProcess::processStandardError()
+{
+ QTC_ASSERT(m_process, return );
+
+ Core::MessageManager::write(QString::fromLocal8Bit(m_process->readAllStandardError()));
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprocess.h b/src/plugins/mesonprojectmanager/project/mesonprocess.h
new file mode 100644
index 0000000000..235dffc80f
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprocess.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <exewrappers/mesonwrapper.h>
+
+#include <utils/qtcprocess.h>
+
+#include <QBuffer>
+#include <QByteArray>
+#include <QElapsedTimer>
+#include <QFutureInterface>
+#include <QObject>
+#include <QProcess>
+#include <QTimer>
+
+#include <memory>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonProcess final : public QObject
+{
+ Q_OBJECT
+public:
+ MesonProcess();
+ bool run(const Command &command,
+ const Utils::Environment env,
+ const QString &projectName,
+ bool captureStdo = false);
+
+ QProcess::ProcessState state() const;
+
+ // Update progress information:
+ void reportCanceled();
+ void reportFinished();
+ void setProgressValue(int p);
+
+ const QByteArray &stdOut() const { return m_stdo; }
+ const QByteArray &stdErr() const { return m_stderr; }
+signals:
+ void started();
+ void finished(int exitCode, QProcess::ExitStatus exitStatus);
+ void readyReadStandardOutput(const QByteArray &data);
+
+private:
+ void handleProcessFinished(int code, QProcess::ExitStatus status);
+ void handleProcessError(QProcess::ProcessError error);
+ void checkForCancelled();
+ void setupProcess(const Command &command, const Utils::Environment env, bool captureStdo);
+
+ bool sanityCheck(const Command &command) const;
+
+ void processStandardOutput();
+ void processStandardError();
+
+ std::unique_ptr<Utils::QtcProcess> m_process;
+ QFutureInterface<void> m_future;
+ bool m_processWasCanceled = false;
+ QTimer m_cancelTimer;
+ QElapsedTimer m_elapsed;
+ QByteArray m_stdo;
+ QByteArray m_stderr;
+ Command m_currentCommand;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonproject.cpp b/src/plugins/mesonprojectmanager/project/mesonproject.cpp
new file mode 100644
index 0000000000..5398a75d55
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonproject.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonproject.h"
+#include "mesonbuildsystem.h"
+#include "mesonpluginconstants.h"
+#include <exewrappers/mesontools.h>
+#include <settings/tools/kitaspect/mesontoolkitaspect.h>
+#include <settings/tools/kitaspect/ninjatoolkitaspect.h>
+#include <coreplugin/icontext.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+MesonProject::MesonProject(const Utils::FilePath &path)
+ : ProjectExplorer::Project{Constants::Project::MIMETYPE, path}
+{
+ setId(Constants::Project::ID);
+ setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID));
+ setDisplayName(projectDirectory().fileName());
+ setCanBuildProducts();
+ setKnowsAllBuildExecutables(true);
+ setHasMakeInstallEquivalent(true);
+}
+
+ProjectExplorer::Tasks MesonProject::projectIssues(const ProjectExplorer::Kit *k) const
+{
+ ProjectExplorer::Tasks result = Project::projectIssues(k);
+
+ if (!MesonToolKitAspect::isValid(k))
+ result.append(
+ createProjectTask(ProjectExplorer::Task::TaskType::Error, tr("No Meson tool set.")));
+ if (!NinjaToolKitAspect::isValid(k))
+ result.append(
+ createProjectTask(ProjectExplorer::Task::TaskType::Error, tr("No Ninja tool set.")));
+ if (ProjectExplorer::ToolChainKitAspect::toolChains(k).isEmpty())
+ result.append(createProjectTask(ProjectExplorer::Task::TaskType::Warning,
+ tr("No compilers set in kit.")));
+ return result;
+}
+
+ProjectExplorer::ProjectImporter *MesonProject::projectImporter() const
+{
+ if (m_projectImporter)
+ m_projectImporter = std::make_unique<MesonProjectImporter>(projectFilePath());
+ return m_projectImporter.get();
+}
+
+ProjectExplorer::DeploymentKnowledge MesonProject::deploymentKnowledge() const
+{
+ // TODO in next releases
+ return ProjectExplorer::DeploymentKnowledge::Bad;
+}
+
+ProjectExplorer::MakeInstallCommand MesonProject::makeInstallCommand(
+ const ProjectExplorer::Target *target, const QString &installRoot)
+{
+ Q_UNUSED(target)
+ Q_UNUSED(installRoot)
+ // TODO in next releases
+ return {};
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonproject.h b/src/plugins/mesonprojectmanager/project/mesonproject.h
new file mode 100644
index 0000000000..bffbb5f043
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonproject.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "exewrappers/mesonwrapper.h"
+#include "mesonprojectimporter.h"
+
+#include "projectexplorer/project.h"
+#include "projectexplorer/projectimporter.h"
+#include "projectexplorer/task.h"
+#include "utils/fileutils.h"
+#include <QObject>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonProject final : public ProjectExplorer::Project
+{
+ Q_OBJECT
+public:
+ explicit MesonProject(const Utils::FilePath &path);
+ ~MesonProject() final = default;
+
+ ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
+ ProjectExplorer::ProjectImporter *projectImporter() const final;
+
+private:
+ ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override;
+ ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target,
+ const QString &installRoot) override;
+
+ mutable std::unique_ptr<MesonProjectImporter> m_projectImporter;
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprojectimporter.cpp b/src/plugins/mesonprojectmanager/project/mesonprojectimporter.cpp
new file mode 100644
index 0000000000..60f1b26c3a
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprojectimporter.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonprojectimporter.h"
+
+#include <QLoggingCategory>
+
+namespace {
+static Q_LOGGING_CATEGORY(mInputLog, "qtc.meson.import", QtWarningMsg);
+}
+
+namespace MesonProjectManager {
+namespace Internal {
+MesonProjectImporter::MesonProjectImporter(const Utils::FilePath &path)
+ : QtSupport::QtProjectImporter{path}
+{}
+
+QStringList MesonProjectImporter::importCandidates()
+{
+ //TODO, this can be done later
+ return {};
+}
+
+QList<void *> MesonProjectImporter::examineDirectory(const Utils::FilePath &importPath) const
+{
+ //TODO, this can be done later
+ qCDebug(mInputLog()) << "examining build directory" << importPath.toUserOutput();
+ QList<void *> data;
+ return data;
+}
+
+bool MesonProjectImporter::matchKit(void *directoryData, const ProjectExplorer::Kit *k) const
+{
+ Q_UNUSED(directoryData)
+ Q_UNUSED(k)
+ //TODO, this can be done later
+ return false;
+}
+
+ProjectExplorer::Kit *MesonProjectImporter::createKit(void *directoryData) const
+{
+ Q_UNUSED(directoryData)
+ //TODO, this can be done later
+ return nullptr;
+}
+
+const QList<ProjectExplorer::BuildInfo> MesonProjectImporter::buildInfoList(void *directoryData) const
+{
+ Q_UNUSED(directoryData)
+ //TODO, this can be done later
+ return {};
+}
+
+void MesonProjectImporter::deleteDirectoryData(void *directoryData) const
+{
+ Q_UNUSED(directoryData)
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprojectimporter.h b/src/plugins/mesonprojectmanager/project/mesonprojectimporter.h
new file mode 100644
index 0000000000..2ae3c36dd9
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprojectimporter.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "exewrappers/mesonwrapper.h"
+
+#include "projectexplorer/buildinfo.h"
+#include "projectexplorer/kit.h"
+#include "qtsupport/qtprojectimporter.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonProjectImporter final : public QtSupport::QtProjectImporter
+{
+public:
+ MesonProjectImporter(const Utils::FilePath &path);
+ QStringList importCandidates() final;
+
+private:
+ // importPath is an existing directory at this point!
+ QList<void *> examineDirectory(const Utils::FilePath &importPath) const final;
+ // will get one of the results from examineDirectory
+ bool matchKit(void *directoryData, const ProjectExplorer::Kit *k) const final;
+ // will get one of the results from examineDirectory
+ ProjectExplorer::Kit *createKit(void *directoryData) const final;
+ // will get one of the results from examineDirectory
+ const QList<ProjectExplorer::BuildInfo> buildInfoList(void *directoryData) const final;
+
+ virtual void deleteDirectoryData(void *directoryData) const final;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprojectparser.cpp b/src/plugins/mesonprojectmanager/project/mesonprojectparser.cpp
new file mode 100644
index 0000000000..a084e337b7
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprojectparser.cpp
@@ -0,0 +1,356 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonprojectparser.h"
+#include "projecttree/mesonprojectnodes.h"
+#include "projecttree/projecttree.h"
+#include <exewrappers/mesontools.h>
+#include <mesoninfoparser/mesoninfoparser.h>
+
+#include <coreplugin/messagemanager.h>
+#include <projectexplorer/projectexplorer.h>
+#include <utils/fileinprojectfinder.h>
+#include <utils/optional.h>
+#include <utils/runextensions.h>
+
+#include <QStringList>
+#include <QTextStream>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+struct CompilerArgs
+{
+ QStringList args;
+ QStringList includePaths;
+ ProjectExplorer::Macros macros;
+};
+
+inline Utils::optional<QString> extractValueIfMatches(const QString &arg,
+ const QStringList &candidates)
+{
+ for (const auto &flag : candidates) {
+ if (arg.startsWith(flag))
+ return arg.mid(flag.length());
+ }
+ return Utils::nullopt;
+}
+
+inline Utils::optional<QString> extractInclude(const QString &arg)
+{
+ return extractValueIfMatches(arg, {"-I", "/I", "-isystem", "-imsvc", "/imsvc"});
+}
+inline Utils::optional<ProjectExplorer::Macro> extractMacro(const QString &arg)
+{
+ auto define = extractValueIfMatches(arg, {"-D", "/D"});
+ if (define)
+ return ProjectExplorer::Macro::fromKeyValue(define->toLatin1());
+ auto undef = extractValueIfMatches(arg, {"-U", "/U"});
+ if (undef)
+ return ProjectExplorer::Macro(undef->toLatin1(), ProjectExplorer::MacroType::Undefine);
+ return Utils::nullopt;
+}
+
+CompilerArgs splitArgs(const QStringList &args)
+{
+ CompilerArgs splited;
+ std::for_each(std::cbegin(args), std::cend(args), [&splited](const QString &arg) {
+ auto inc = extractInclude(arg);
+ if (inc) {
+ splited.includePaths << *inc;
+ } else {
+ auto macro = extractMacro(arg);
+ if (macro) {
+ splited.macros << *macro;
+ } else {
+ splited.args << arg;
+ }
+ }
+ });
+ return splited;
+}
+
+QStringList toAbsolutePath(const Utils::FilePath &refPath, QStringList &pathList)
+{
+ QStringList allAbs;
+ std::transform(std::cbegin(pathList),
+ std::cend(pathList),
+ std::back_inserter(allAbs),
+ [refPath](const QString &path) {
+ if (path.startsWith("/"))
+ return path;
+ return refPath.pathAppended(path).toString();
+ });
+ return allAbs;
+}
+
+MesonProjectParser::MesonProjectParser(const Core::Id &meson,
+ Utils::Environment env,
+ ProjectExplorer::Project *project)
+ : m_env{env}
+ , m_meson{meson}
+ , m_configuring{false}
+ , m_projectName{project->displayName()}
+{
+ connect(&m_process, &MesonProcess::finished, this, &MesonProjectParser::processFinished);
+ connect(&m_process,
+ &MesonProcess::readyReadStandardOutput,
+ &m_outputParser,
+ &MesonOutputParser::readStdo);
+
+ // TODO re-think the way all BuildSystem/ProjectParser are tied
+ // I take project info here, I also take build and src dir later from
+ // functions args.
+ auto fileFinder = new Utils::FileInProjectFinder;
+ fileFinder->setProjectDirectory(project->projectDirectory());
+ fileFinder->setProjectFiles(project->files(ProjectExplorer::Project::AllFiles));
+ m_outputParser.setFileFinder(fileFinder);
+}
+
+void MesonProjectParser::setMesonTool(const Core::Id &meson)
+{
+ m_meson = meson;
+}
+
+bool MesonProjectParser::configure(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args)
+{
+ m_introType = IntroDataType::file;
+ m_srcDir = sourcePath;
+ m_buildDir = buildPath;
+ m_outputParser.setSourceDirectory(sourcePath);
+ auto cmd = MesonTools::mesonWrapper(m_meson)->configure(sourcePath, buildPath, args);
+ // see comment near m_pendingCommands declaration
+ m_pendingCommands.enqueue(
+ {MesonTools::mesonWrapper(m_meson)->regenerate(sourcePath, buildPath), false});
+ return m_process.run(cmd, m_env, m_projectName);
+}
+
+bool MesonProjectParser::wipe(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args)
+{
+ return setup(sourcePath, buildPath, args, true);
+}
+
+bool MesonProjectParser::setup(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args,
+ bool forceWipe)
+{
+ m_introType = IntroDataType::file;
+ m_srcDir = sourcePath;
+ m_buildDir = buildPath;
+ m_outputParser.setSourceDirectory(sourcePath);
+ auto cmdArgs = args;
+ if (forceWipe || isSetup(buildPath))
+ cmdArgs << "--wipe";
+ auto cmd = MesonTools::mesonWrapper(m_meson)->setup(sourcePath, buildPath, cmdArgs);
+ return m_process.run(cmd, m_env, m_projectName);
+}
+
+bool MesonProjectParser::parse(const Utils::FilePath &sourcePath, const Utils::FilePath &buildPath)
+{
+ m_srcDir = sourcePath;
+ m_buildDir = buildPath;
+ m_outputParser.setSourceDirectory(sourcePath);
+ if (!isSetup(buildPath)) {
+ return parse(sourcePath);
+ } else {
+ m_introType = IntroDataType::file;
+ return startParser();
+ }
+}
+
+bool MesonProjectParser::parse(const Utils::FilePath &sourcePath)
+{
+ m_srcDir = sourcePath;
+ m_introType = IntroDataType::stdo;
+ m_outputParser.setSourceDirectory(sourcePath);
+ return m_process.run(MesonTools::mesonWrapper(m_meson)->introspect(sourcePath),
+ m_env,
+ m_projectName,
+ true);
+}
+
+QList<ProjectExplorer::BuildTargetInfo> MesonProjectParser::appsTargets() const
+{
+ QList<ProjectExplorer::BuildTargetInfo> apps;
+ std::for_each(std::cbegin(m_parserResult.targets),
+ std::cend(m_parserResult.targets),
+ [&apps](const Target &target) {
+ if (target.type == Target::Type::executable) {
+ ProjectExplorer::BuildTargetInfo bti;
+ bti.displayName = target.name;
+ bti.buildKey = Target::fullName(target);
+ bti.displayNameUniquifier = bti.buildKey;
+ bti.targetFilePath = Utils::FilePath::fromString(target.fileName.first());
+ bti.workingDirectory
+ = Utils::FilePath::fromString(target.fileName.first()).absolutePath();
+ bti.projectFilePath = Utils::FilePath::fromString(target.definedIn);
+ bti.usesTerminal = true;
+ apps.append(bti);
+ }
+ });
+ return apps;
+}
+bool MesonProjectParser::startParser()
+{
+ m_parserFutureResult = Utils::runAsync(
+ ProjectExplorer::ProjectExplorerPlugin::sharedThreadPool(),
+ [process = &m_process,
+ introType = m_introType,
+ buildDir = m_buildDir.toString(),
+ srcDir = m_srcDir]() {
+ if (introType == IntroDataType::file) {
+ return extractParserResults(srcDir, MesonInfoParser::parse(buildDir));
+ } else {
+ return extractParserResults(srcDir, MesonInfoParser::parse(process->stdOut()));
+ }
+ });
+
+ Utils::onFinished(m_parserFutureResult, this, &MesonProjectParser::update);
+ return true;
+}
+
+MesonProjectParser::ParserData *MesonProjectParser::extractParserResults(
+ const Utils::FilePath &srcDir, MesonInfoParser::Result &&parserResult)
+{
+ auto rootNode = ProjectTree::buildTree(srcDir,
+ parserResult.targets,
+ parserResult.buildSystemFiles);
+ return new ParserData{std::move(parserResult), std::move(rootNode)};
+}
+
+void MesonProjectParser::addMissingTargets(QStringList &targetList)
+{
+ // Not all targets are listed in introspection data
+ for (const auto &target : additionalTargets()) {
+ if (!targetList.contains(target)) {
+ targetList.append(target);
+ }
+ }
+}
+
+void MesonProjectParser::update(const QFuture<MesonProjectParser::ParserData *> &data)
+{
+ auto parserData = data.result();
+ m_parserResult = std::move(parserData->data);
+ m_rootNode = std::move(parserData->rootNode);
+ m_targetsNames.clear();
+ std::transform(std::cbegin(m_parserResult.targets),
+ std::cend(m_parserResult.targets),
+ std::back_inserter(m_targetsNames),
+ Target::fullName);
+ addMissingTargets(m_targetsNames);
+ m_targetsNames.sort();
+ delete data;
+ emit parsingCompleted(true);
+}
+
+ProjectExplorer::RawProjectPart MesonProjectParser::buildRawPart(
+ const Target &target,
+ const Target::SourceGroup &sources,
+ const ProjectExplorer::ToolChain *cxxToolChain,
+ const ProjectExplorer::ToolChain *cToolChain)
+{
+ ProjectExplorer::RawProjectPart part;
+ part.setDisplayName(target.name);
+ part.setBuildSystemTarget(Target::fullName(target));
+ part.setFiles(sources.sources + sources.generatedSources);
+ auto flags = splitArgs(sources.parameters);
+ part.setMacros(flags.macros);
+ part.setIncludePaths(toAbsolutePath(this->m_buildDir, flags.includePaths));
+ part.setProjectFileLocation(target.definedIn);
+ if (sources.language == "cpp")
+ part.setFlagsForCxx({cxxToolChain, flags.args});
+ else if (sources.language == "c")
+ part.setFlagsForC({cToolChain, flags.args});
+ part.setQtVersion(m_qtVersion);
+ return part;
+}
+
+void MesonProjectParser::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ if (exitCode == 0 && exitStatus == QProcess::NormalExit) {
+ if (m_pendingCommands.isEmpty())
+ startParser();
+ else {
+ // see comment near m_pendingCommands declaration
+ std::tuple<Command, bool> args = m_pendingCommands.dequeue();
+ m_process.run(std::get<0>(args), m_env, m_projectName, std::get<1>(args));
+ }
+ } else {
+ if (m_introType == IntroDataType::stdo) {
+ auto data = m_process.stdErr();
+ Core::MessageManager::write(QString::fromLocal8Bit(data));
+ m_outputParser.readStdo(data);
+ }
+ emit parsingCompleted(false);
+ }
+}
+
+ProjectExplorer::RawProjectParts MesonProjectParser::buildProjectParts(
+ const ProjectExplorer::ToolChain *cxxToolChain, const ProjectExplorer::ToolChain *cToolChain)
+{
+ ProjectExplorer::RawProjectParts parts;
+ for_each_source_group(m_parserResult.targets,
+ [&parts,
+ &cxxToolChain,
+ &cToolChain,
+ this](const Target &target, const Target::SourceGroup &sourceList) {
+ parts.push_back(
+ buildRawPart(target, sourceList, cxxToolChain, cToolChain));
+ });
+ return parts;
+}
+
+bool sourceGroupMatchesKit(const KitData &kit, const Target::SourceGroup &group)
+{
+ if (group.language == "c")
+ return kit.cCompilerPath == group.compiler[0];
+ if (group.language == "cpp")
+ return kit.cxxCompilerPath == group.compiler[0];
+ return true;
+}
+
+bool MesonProjectParser::matchesKit(const KitData &kit)
+{
+ bool matches = true;
+ for_each_source_group(m_parserResult.targets,
+ [&matches, &kit](const Target &, const Target::SourceGroup &sourceGroup) {
+ matches = matches && sourceGroupMatchesKit(kit, sourceGroup);
+ });
+ return matches;
+}
+
+bool MesonProjectParser::usesSameMesonVersion(const Utils::FilePath &buildPath)
+{
+ auto info = MesonInfoParser::mesonInfo(buildPath.toString());
+ auto meson = MesonTools::mesonWrapper(m_meson);
+ return info && meson && info->mesonVersion == meson->version();
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonprojectparser.h b/src/plugins/mesonprojectmanager/project/mesonprojectparser.h
new file mode 100644
index 0000000000..8db55d82b5
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonprojectparser.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "outputparsers/mesonoutputparser.h"
+#include "projecttree/mesonprojectnodes.h"
+#include "mesonprocess.h"
+#include <exewrappers/mesonwrapper.h>
+#include <kithelper/kitdata.h>
+#include <mesoninfoparser/mesoninfoparser.h>
+#include <projectexplorer/buildsystem.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/rawprojectpart.h>
+#include <utils/environment.h>
+#include <utils/fileutils.h>
+#include <QFuture>
+#include <QFutureWatcher>
+#include <QObject>
+#include <QQueue>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonProjectParser : public QObject
+{
+ Q_OBJECT
+ enum class IntroDataType { file, stdo };
+ struct ParserData
+ {
+ MesonInfoParser::Result data;
+ std::unique_ptr<MesonProjectNode> rootNode;
+ };
+
+public:
+ MesonProjectParser(const Core::Id &meson, Utils::Environment env, ProjectExplorer::Project* project);
+ void setMesonTool(const Core::Id &meson);
+ bool configure(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args);
+ bool wipe(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args);
+ bool setup(const Utils::FilePath &sourcePath,
+ const Utils::FilePath &buildPath,
+ const QStringList &args,
+ bool forceWipe = false);
+ bool parse(const Utils::FilePath &sourcePath, const Utils::FilePath &buildPath);
+ bool parse(const Utils::FilePath &sourcePath);
+
+ Q_SIGNAL void parsingCompleted(bool success);
+
+ std::unique_ptr<MesonProjectNode> takeProjectNode() { return std::move(m_rootNode); }
+
+ inline const BuildOptionsList &buildOptions() const { return m_parserResult.buildOptions; };
+ inline const TargetsList &targets() const { return m_parserResult.targets; }
+ inline const QStringList &targetsNames() const { return m_targetsNames; }
+
+ static inline QStringList additionalTargets()
+ {
+ return QStringList{Constants::Targets::all,
+ Constants::Targets::clean,
+ Constants::Targets::install,
+ Constants::Targets::benchmark,
+ Constants::Targets::scan_build};
+ }
+
+ QList<ProjectExplorer::BuildTargetInfo> appsTargets() const;
+
+ ProjectExplorer::RawProjectParts buildProjectParts(
+ const ProjectExplorer::ToolChain *cxxToolChain,
+ const ProjectExplorer::ToolChain *cToolChain);
+
+ inline void setEnvironment(const Utils::Environment &environment) { m_env = environment; }
+
+ inline void setQtVersion(Utils::QtVersion v) { m_qtVersion = v; }
+
+ bool matchesKit(const KitData &kit);
+
+ bool usesSameMesonVersion(const Utils::FilePath &buildPath);
+
+private:
+ bool startParser();
+ static ParserData *extractParserResults(const Utils::FilePath &srcDir,
+ MesonInfoParser::Result &&parserResult);
+ static void addMissingTargets(QStringList &targetList);
+ void update(const QFuture<ParserData *> &data);
+ ProjectExplorer::RawProjectPart buildRawPart(const Target &target,
+ const Target::SourceGroup &sources,
+ const ProjectExplorer::ToolChain *cxxToolChain,
+ const ProjectExplorer::ToolChain *cToolChain);
+ void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ MesonProcess m_process;
+ MesonOutputParser m_outputParser;
+ Utils::Environment m_env;
+ Core::Id m_meson;
+ Utils::FilePath m_buildDir;
+ Utils::FilePath m_srcDir;
+ QFuture<ParserData *> m_parserFutureResult;
+ bool m_configuring;
+ IntroDataType m_introType;
+ MesonInfoParser::Result m_parserResult;
+ QStringList m_targetsNames;
+ Utils::QtVersion m_qtVersion;
+ std::unique_ptr<MesonProjectNode> m_rootNode; // <- project tree root node
+ QString m_projectName;
+ // maybe moving meson to build step could make this class simpler
+ // also this should ease command dependencies
+ QQueue<std::tuple<Command, bool>> m_pendingCommands;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp
new file mode 100644
index 0000000000..2c4b1e9f6e
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonrunconfiguration.h"
+#include <mesonpluginconstants.h>
+#include <projectexplorer/buildsystem.h>
+#include <projectexplorer/desktoprunconfiguration.h>
+#include <projectexplorer/environmentaspect.h>
+#include <projectexplorer/localenvironmentaspect.h>
+#include <projectexplorer/runconfigurationaspects.h>
+#include <utils/environment.h>
+#include <utils/hostosinfo.h>
+#include <QLatin1String>
+namespace MesonProjectManager {
+namespace Internal {
+MesonRunConfiguration::MesonRunConfiguration(ProjectExplorer::Target *target, Core::Id id)
+ : ProjectExplorer::RunConfiguration{target, id}
+{
+ auto envAspect = addAspect<ProjectExplorer::LocalEnvironmentAspect>(target);
+
+ addAspect<ProjectExplorer::ExecutableAspect>();
+ addAspect<ProjectExplorer::ArgumentsAspect>();
+ addAspect<ProjectExplorer::WorkingDirectoryAspect>();
+ addAspect<ProjectExplorer::TerminalAspect>();
+
+ auto libAspect = addAspect<ProjectExplorer::UseLibraryPathsAspect>();
+ connect(libAspect,
+ &ProjectExplorer::UseLibraryPathsAspect::changed,
+ envAspect,
+ &ProjectExplorer::EnvironmentAspect::environmentChanged);
+
+ if (Utils::HostOsInfo::isMacHost()) {
+ auto dyldAspect = addAspect<ProjectExplorer::UseDyldSuffixAspect>();
+ connect(dyldAspect,
+ &ProjectExplorer::UseLibraryPathsAspect::changed,
+ envAspect,
+ &ProjectExplorer::EnvironmentAspect::environmentChanged);
+ envAspect->addModifier([dyldAspect](Utils::Environment &env) {
+ if (dyldAspect->value())
+ env.set(QLatin1String("DYLD_IMAGE_SUFFIX"), QLatin1String("_debug"));
+ });
+ }
+
+ envAspect->addModifier([this, libAspect](Utils::Environment &env) {
+ ProjectExplorer::BuildTargetInfo bti = buildTargetInfo();
+ if (bti.runEnvModifier)
+ bti.runEnvModifier(env, libAspect->value());
+ });
+
+ setUpdater([this] { updateTargetInformation(); });
+
+ connect(target,
+ &ProjectExplorer::Target::buildSystemUpdated,
+ this,
+ &ProjectExplorer::RunConfiguration::update);
+}
+
+void MesonRunConfiguration::updateTargetInformation()
+{
+ if (!activeBuildSystem())
+ return;
+
+ ProjectExplorer::BuildTargetInfo bti = buildTargetInfo();
+ auto terminalAspect = aspect<ProjectExplorer::TerminalAspect>();
+ terminalAspect->setUseTerminalHint(bti.usesTerminal);
+ aspect<ProjectExplorer::ExecutableAspect>()->setExecutable(bti.targetFilePath);
+ aspect<ProjectExplorer::WorkingDirectoryAspect>()->setDefaultWorkingDirectory(
+ bti.workingDirectory);
+ aspect<ProjectExplorer::LocalEnvironmentAspect>()->environmentChanged();
+}
+
+MesonRunConfigurationFactory::MesonRunConfigurationFactory()
+{
+ registerRunConfiguration<MesonRunConfiguration>("MesonProjectManager.MesonRunConfiguration");
+ addSupportedProjectType(Constants::Project::ID);
+ addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.h b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.h
new file mode 100644
index 0000000000..4d31bc1bf1
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/mesonrunconfiguration.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <projectexplorer/desktoprunconfiguration.h>
+#include <projectexplorer/runconfiguration.h>
+#include <projectexplorer/target.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonRunConfiguration final : public ProjectExplorer::RunConfiguration
+{
+public:
+ MesonRunConfiguration(ProjectExplorer::Target *target, Core::Id id);
+
+private:
+ void updateTargetInformation();
+};
+
+class MesonRunConfigurationFactory final : public ProjectExplorer::RunConfigurationFactory
+{
+public:
+ MesonRunConfigurationFactory();
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp b/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp
new file mode 100644
index 0000000000..3a1473d4b2
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/ninjabuildstep.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "ninjabuildstep.h"
+#include "buildoptions/mesonbuildstepconfigwidget.h"
+#include "outputparsers/mesonoutputparser.h"
+#include "mesonbuildconfiguration.h"
+#include "mesonbuildsystem.h"
+#include "mesonpluginconstants.h"
+#include <settings/general/settings.h>
+#include <settings/tools/kitaspect/ninjatoolkitaspect.h>
+#include <coreplugin/id.h>
+#include <projectexplorer/buildconfiguration.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/processparameters.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/target.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+const char TARGETS_KEY[] = "MesonProjectManager.BuildStep.BuildTargets";
+const char TOOL_ARGUMENTS_KEY[] = "MesonProjectManager.BuildStep.AdditionalArguments";
+
+NinjaBuildStep::NinjaBuildStep(ProjectExplorer::BuildStepList *bsl, Core::Id id)
+ : ProjectExplorer::AbstractProcessStep{bsl, id}
+{
+ setDefaultDisplayName(tr("Meson Build"));
+ if (m_targetName.isEmpty())
+ setBuildTarget(defaultBuildTarget());
+ setLowPriority();
+ connect(target(), &ProjectExplorer::Target::parsingFinished, this, &NinjaBuildStep::update);
+ connect(Settings::instance(),
+ &Settings::verboseNinjaChanged,
+ this,
+ &NinjaBuildStep::commandChanged);
+}
+
+ProjectExplorer::BuildStepConfigWidget *NinjaBuildStep::createConfigWidget()
+{
+ return new MesonBuildStepConfigWidget{this};
+}
+
+// --verbose is only supported since
+// https://github.com/ninja-build/ninja/commit/bf7517505ad1def03e13bec2b4131399331bc5c4
+// TODO check when to switch back to --verbose
+Utils::CommandLine NinjaBuildStep::command()
+{
+ Utils::CommandLine cmd = [this] {
+ auto tool = NinjaToolKitAspect::ninjaTool(target()->kit());
+ if (tool)
+ return Utils::CommandLine{tool->exe()};
+ return Utils::CommandLine{};
+ }();
+ if (!m_commandArgs.isEmpty())
+ cmd.addArgs(m_commandArgs, Utils::CommandLine::RawType::Raw);
+ if (Settings::verboseNinja())
+ cmd.addArg("-v");
+ cmd.addArg(m_targetName);
+ return cmd;
+}
+
+QStringList NinjaBuildStep::projectTargets()
+{
+ return static_cast<MesonBuildSystem *>(buildSystem())->targetList();
+}
+
+void NinjaBuildStep::update(bool parsingSuccessful)
+{
+ if (parsingSuccessful) {
+ if (!projectTargets().contains(m_targetName)) {
+ m_targetName = defaultBuildTarget();
+ }
+ emit targetListChanged();
+ }
+}
+
+bool NinjaBuildStep::init()
+{
+ // TODO check if the setup is ok
+ MesonBuildConfiguration *bc = static_cast<MesonBuildConfiguration *>(buildConfiguration());
+ ProjectExplorer::ProcessParameters *pp = processParameters();
+ pp->setMacroExpander(bc->macroExpander());
+ Utils::Environment env = bc->environment();
+ Utils::Environment::setupEnglishOutput(&env);
+ pp->setEnvironment(env);
+ pp->setWorkingDirectory(bc->buildDirectory());
+ pp->setCommandLine(command());
+ pp->resolveAll();
+
+ return AbstractProcessStep::init();
+}
+
+QString NinjaBuildStep::defaultBuildTarget() const
+{
+ const ProjectExplorer::BuildStepList *const bsl = stepList();
+ QTC_ASSERT(bsl, return {});
+ const Core::Id parentId = bsl->id();
+ if (parentId == ProjectExplorer::Constants::BUILDSTEPS_CLEAN)
+ return Constants::Targets::clean;
+ if (parentId == ProjectExplorer::Constants::BUILDSTEPS_DEPLOY)
+ return Constants::Targets::install;
+ return Constants::Targets::all;
+}
+
+void NinjaBuildStep::doRun()
+{
+ AbstractProcessStep::doRun();
+}
+
+void NinjaBuildStep::setupOutputFormatter(Utils::OutputFormatter *formatter)
+{
+ auto mesonOutputParser = new MesonOutputParser;
+ mesonOutputParser->setSourceDirectory(project()->projectDirectory());
+ formatter->addLineParser(mesonOutputParser);
+ m_ninjaParser = new NinjaParser;
+ m_ninjaParser->setSourceDirectory(project()->projectDirectory());
+ formatter->addLineParser(m_ninjaParser);
+ auto additionalParsers = target()->kit()->createOutputParsers();
+ std::for_each(std::cbegin(additionalParsers),
+ std::cend(additionalParsers),
+ [this](const auto parser) { parser->setRedirectionDetector(m_ninjaParser); });
+ formatter->addLineParsers(additionalParsers);
+ formatter->addSearchDir(processParameters()->effectiveWorkingDirectory());
+ AbstractProcessStep::setupOutputFormatter(formatter);
+
+ connect(m_ninjaParser, &NinjaParser::reportProgress, this, [this](int percent) {
+ emit progress(percent, QString());
+ });
+}
+
+MesonBuildStepFactory::MesonBuildStepFactory()
+{
+ registerStep<NinjaBuildStep>(Constants::MESON_BUILD_STEP_ID);
+ setSupportedProjectType(Constants::Project::ID);
+ setDisplayName(NinjaBuildStep::tr("Meson"));
+}
+
+void MesonProjectManager::Internal::NinjaBuildStep::setBuildTarget(const QString &targetName)
+{
+ m_targetName = targetName;
+}
+
+void NinjaBuildStep::setCommandArgs(const QString &args)
+{
+ m_commandArgs = args.trimmed();
+}
+
+QVariantMap NinjaBuildStep::toMap() const
+{
+ QVariantMap map(AbstractProcessStep::toMap());
+ map.insert(TARGETS_KEY, m_targetName);
+ map.insert(TOOL_ARGUMENTS_KEY, m_commandArgs);
+ return map;
+}
+
+bool NinjaBuildStep::fromMap(const QVariantMap &map)
+{
+ m_targetName = map.value(TARGETS_KEY).toString();
+ m_commandArgs = map.value(TOOL_ARGUMENTS_KEY).toString();
+ return AbstractProcessStep::fromMap(map);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/ninjabuildstep.h b/src/plugins/mesonprojectmanager/project/ninjabuildstep.h
new file mode 100644
index 0000000000..59aa78ea40
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/ninjabuildstep.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "outputparsers/ninjaparser.h"
+#include <projectexplorer/abstractprocessstep.h>
+#include <projectexplorer/buildstep.h>
+#include <utils/qtcprocess.h>
+#include <QObject>
+
+namespace MesonProjectManager {
+namespace Internal {
+class NinjaBuildStep final : public ProjectExplorer::AbstractProcessStep
+{
+ Q_OBJECT
+public:
+ NinjaBuildStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
+ ProjectExplorer::BuildStepConfigWidget *createConfigWidget() final;
+ Utils::CommandLine command();
+ QStringList projectTargets();
+ void setBuildTarget(const QString &targetName);
+ void setCommandArgs(const QString &args);
+ const QString &targetName() const { return m_targetName; }
+ Q_SIGNAL void targetListChanged();
+ Q_SIGNAL void commandChanged();
+ QVariantMap toMap() const override;
+ bool fromMap(const QVariantMap &map) override;
+
+private:
+ void update(bool parsingSuccessful);
+ bool init() override;
+ void doRun() override;
+ void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
+ QString defaultBuildTarget() const;
+ QString m_commandArgs;
+ QString m_targetName;
+ NinjaParser *m_ninjaParser;
+};
+
+class MesonBuildStepFactory final : public ProjectExplorer::BuildStepFactory
+{
+public:
+ MesonBuildStepFactory();
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.cpp b/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.cpp
new file mode 100644
index 0000000000..19b5231818
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonoutputparser.h"
+#include <projectexplorer/task.h>
+#include <projectexplorer/taskhub.h>
+namespace MesonProjectManager {
+namespace Internal {
+inline void MesonOutputParser::addTask(ProjectExplorer::Task task)
+{
+#ifndef MESONPARSER_DISABLE_TASKS_FOR_TESTS // small hack to allow unit testing without the banana/monkey/jungle
+ ProjectExplorer::TaskHub::addTask(task);
+#else
+ Q_UNUSED(task);
+#endif
+}
+
+inline void MesonOutputParser::addTask(ProjectExplorer::Task::TaskType type, const QString &line)
+{
+#ifndef MESONPARSER_DISABLE_TASKS_FOR_TESTS // small hack to allow unit testing without the banana/monkey/jungle
+ auto task = ProjectExplorer::BuildSystemTask(type, QString("Meson build:%1").arg(line));
+ addTask(task);
+#else
+ Q_UNUSED(type);
+ Q_UNUSED(line);
+#endif
+}
+
+inline Utils::OutputLineParser::LinkSpecs MesonOutputParser::addTask(
+ ProjectExplorer::Task::TaskType type,
+ const QString &line,
+ const QRegularExpressionMatch &match,
+ int fileCapIndex,
+ int lineNumberCapIndex)
+{
+ LinkSpecs linkSpecs;
+#ifndef MESONPARSER_DISABLE_TASKS_FOR_TESTS // small hack to allow unit testing without the banana/monkey/jungle
+ auto fileName = absoluteFilePath(Utils::FilePath::fromString(match.captured(fileCapIndex)));
+ auto task = ProjectExplorer::BuildSystemTask(type,
+ QString("Meson build:%1").arg(line),
+ fileName,
+ match.captured(lineNumberCapIndex).toInt());
+ addTask(task);
+ addLinkSpecForAbsoluteFilePath(linkSpecs, task.file, task.line, match, 1);
+#else
+ Q_UNUSED(type);
+ Q_UNUSED(line);
+ Q_UNUSED(match);
+ Q_UNUSED(fileCapIndex);
+ Q_UNUSED(lineNumberCapIndex);
+#endif
+ return linkSpecs;
+}
+
+void MesonOutputParser::pushLine(const QString &line)
+{
+ m_remainingLines--;
+ m_pending.append(line);
+ if (m_remainingLines == 0) {
+ addTask(ProjectExplorer::Task::TaskType::Warning, m_pending.join('\n'));
+ m_pending.clear();
+ }
+}
+
+Utils::OutputLineParser::Result MesonOutputParser::processErrors(const QString &line)
+{
+ auto optionsErrors = m_errorOptionRegex.match(line);
+ if (optionsErrors.hasMatch()) {
+ addTask(ProjectExplorer::Task::TaskType::Error, line);
+ return ProjectExplorer::OutputTaskParser::Status::Done;
+ }
+ auto locatedErrors = m_errorFileLocRegex.match(line);
+ if (locatedErrors.hasMatch()) {
+ auto linkSpecs = addTask(ProjectExplorer::Task::TaskType::Error, line, locatedErrors, 1, 2);
+ return {ProjectExplorer::OutputTaskParser::Status::Done, linkSpecs};
+ }
+ return ProjectExplorer::OutputTaskParser::Status::NotHandled;
+}
+
+Utils::OutputLineParser::Result MesonOutputParser::processWarnings(const QString &line)
+{
+ for (const auto &warning : m_multiLineWarnings) {
+ const auto match = warning.regex.match(line);
+ if (match.hasMatch()) {
+ m_remainingLines = warning.lineCnt;
+ pushLine(line);
+ return ProjectExplorer::OutputTaskParser::Status::Done;
+ }
+ }
+ return ProjectExplorer::OutputTaskParser::Status::NotHandled;
+}
+
+MesonOutputParser::MesonOutputParser()
+ : ProjectExplorer::OutputTaskParser{}
+{}
+
+Utils::OutputLineParser::Result MesonOutputParser::handleLine(const QString &line,
+ Utils::OutputFormat type)
+{
+ if (type != Utils::OutputFormat::StdOutFormat)
+ return ProjectExplorer::OutputTaskParser::Status::NotHandled;
+ if (m_remainingLines) {
+ pushLine(line);
+ return ProjectExplorer::OutputTaskParser::Status::Done;
+ }
+ auto result = processErrors(line);
+ if (result.status == ProjectExplorer::OutputTaskParser::Status::Done)
+ return result;
+ return processWarnings(line);
+}
+
+void MesonOutputParser::readStdo(const QByteArray &data)
+{
+ auto str = QString::fromLocal8Bit(data);
+ for (const auto &line : str.split('\n'))
+ handleLine(line, Utils::OutputFormat::StdOutFormat);
+}
+
+void MesonOutputParser::setSourceDirectory(const Utils::FilePath &sourceDir)
+{
+ emit addSearchDir(sourceDir);
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.h b/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.h
new file mode 100644
index 0000000000..11d6942fb2
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/outputparsers/mesonoutputparser.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "projectexplorer/ioutputparser.h"
+#include "utils/outputformatter.h"
+#include <array>
+#include <QObject>
+#include <QRegularExpression>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonOutputParser final : public ProjectExplorer::OutputTaskParser
+{
+ Q_OBJECT
+ struct WarningRegex
+ {
+ const int lineCnt;
+ const QRegularExpression regex;
+ };
+ const QRegularExpression m_errorFileLocRegex{R"((^.*meson.build):(\d+):(\d+): ERROR)"};
+ const QRegularExpression m_errorOptionRegex{R"!(ERROR: Value)!"};
+ const std::array<WarningRegex, 3> m_multiLineWarnings{
+ WarningRegex{3, QRegularExpression{R"!(WARNING: Unknown options:)!"}},
+ WarningRegex{
+ 2,
+ QRegularExpression{
+ R"!(WARNING: Project specifies a minimum meson_version|WARNING: Deprecated features used:)!"}},
+ WarningRegex{1, QRegularExpression{R"!(WARNING: )!"}}};
+ int m_remainingLines = 0;
+ QStringList m_pending;
+ void pushLine(const QString &line);
+ Result processErrors(const QString &line);
+ Result processWarnings(const QString &line);
+ void addTask(ProjectExplorer::Task::TaskType type, const QString &line);
+ void addTask(ProjectExplorer::Task task);
+ Utils::OutputLineParser::LinkSpecs addTask(ProjectExplorer::Task::TaskType type,
+ const QString &line,
+ const QRegularExpressionMatch &match,
+ int fileCapIndex,
+ int lineNumberCapIndex);
+
+public:
+ MesonOutputParser();
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void readStdo(const QByteArray &data);
+ void setSourceDirectory(const Utils::FilePath &sourceDir);
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.cpp b/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.cpp
new file mode 100644
index 0000000000..8594619d86
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "ninjaparser.h"
+#include <utils/fileutils.h>
+namespace MesonProjectManager {
+namespace Internal {
+NinjaParser::NinjaParser() {}
+
+Utils::optional<int> NinjaParser::extractProgress(const QString &line)
+{
+ auto progress = m_progressRegex.match(line);
+ if (progress.hasMatch()) {
+ auto total = progress.captured(2).toInt();
+ auto pos = progress.captured(1).toInt();
+ return pos * 100 / total;
+ }
+ return Utils::nullopt;
+}
+
+void NinjaParser::setSourceDirectory(const Utils::FilePath &sourceDir)
+{
+ emit addSearchDir(sourceDir);
+}
+
+Utils::OutputLineParser::Result NinjaParser::handleLine(const QString &line,
+ Utils::OutputFormat type)
+{
+ if (type == Utils::OutputFormat::StdOutFormat) {
+ auto progress = extractProgress(line);
+ if (progress) {
+ emit reportProgress(*progress);
+ //return ProjectExplorer::OutputTaskParser::Status::InProgress;
+ }
+ }
+ return ProjectExplorer::OutputTaskParser::Status::NotHandled;
+}
+
+bool NinjaParser::hasFatalErrors() const
+{
+ // TODO
+ return false;
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.h b/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.h
new file mode 100644
index 0000000000..209f0efc47
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/outputparsers/ninjaparser.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <projectexplorer/ioutputparser.h>
+#include <projectexplorer/task.h>
+#include <utils/optional.h>
+#include <QObject>
+#include <QRegularExpression>
+namespace MesonProjectManager {
+namespace Internal {
+class NinjaParser final : public ProjectExplorer::OutputTaskParser
+{
+ Q_OBJECT
+ QRegularExpression m_progressRegex{R"(^\[(\d+)/(\d+)\])"};
+ Utils::optional<int> extractProgress(const QString &line);
+
+public:
+ NinjaParser();
+ Result handleLine(const QString &line, Utils::OutputFormat type) override;
+ void setSourceDirectory(const Utils::FilePath &sourceDir);
+
+ bool hasDetectedRedirection() const override { return true; }
+ bool hasFatalErrors() const override;
+ Q_SIGNAL void reportProgress(int progress);
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp
new file mode 100644
index 0000000000..ec13a6518d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesonprojectnodes.h"
+#include <project/mesonbuildconfiguration.h>
+#include <project/mesonbuildsystem.h>
+#include <mesonpluginconstants.h>
+#include <projectexplorer/project.h>
+#include <projectexplorer/target.h>
+namespace MesonProjectManager {
+namespace Internal {
+
+MesonProjectNode::MesonProjectNode(const Utils::FilePath &directory)
+ : ProjectExplorer::ProjectNode{directory}
+{
+ static const auto MesonIcon = QIcon(Constants::Icons::MESON);
+ setPriority(Node::DefaultProjectPriority + 1000);
+ setIcon(MesonIcon);
+ setListInProject(false);
+}
+
+MesonFileNode::MesonFileNode(const Utils::FilePath &file)
+ : ProjectExplorer::ProjectNode{file}
+{
+ static const auto MesonFolderIcon = Core::FileIconProvider::directoryIcon(
+ Constants::Icons::MESON);
+ setIcon(MesonFolderIcon);
+ setListInProject(true);
+}
+
+MesonTargetNode::MesonTargetNode(const Utils::FilePath &directory, const QString &name)
+ : ProjectExplorer::ProjectNode{directory}
+ , m_name{name}
+{
+ setPriority(Node::DefaultProjectPriority + 900);
+ setIcon(QIcon(":/projectexplorer/images/build.png"));
+ setListInProject(false);
+ setShowWhenEmpty(true);
+ setProductType(ProjectExplorer::ProductType::Other);
+}
+
+void MesonTargetNode::build()
+{
+ ProjectExplorer::Project *p = getProject();
+ ProjectExplorer::Target *t = p ? p->activeTarget() : nullptr;
+ if (t)
+ static_cast<MesonBuildSystem *>(t->buildSystem())->mesonBuildConfiguration()->build(m_name);
+}
+
+QString MesonTargetNode::tooltip() const
+{
+ return {};
+}
+
+QString MesonTargetNode::buildKey() const
+{
+ return m_name;
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.h b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.h
new file mode 100644
index 0000000000..8ff23caf0d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/projecttree/mesonprojectnodes.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <coreplugin/fileiconprovider.h>
+#include <projectexplorer/projectnodes.h>
+#include <utils/fileutils.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonProjectNode : public ProjectExplorer::ProjectNode
+{
+public:
+ MesonProjectNode(const Utils::FilePath &directory);
+};
+
+class MesonTargetNode : public ProjectExplorer::ProjectNode
+{
+public:
+ MesonTargetNode(const Utils::FilePath &directory, const QString &name);
+ void build() override;
+ QString tooltip() const final;
+ QString buildKey() const final;
+
+private:
+ QString m_name;
+};
+
+class MesonFileNode : public ProjectExplorer::ProjectNode
+{
+public:
+ MesonFileNode(const Utils::FilePath &file);
+ bool showInSimpleTree() const final { return false; }
+ Utils::optional<Utils::FilePath> visibleAfterAddFileAction() const override
+ {
+ return filePath().pathAppended("meson.build");
+ }
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/projecttree/projecttree.cpp b/src/plugins/mesonprojectmanager/project/projecttree/projecttree.cpp
new file mode 100644
index 0000000000..4842ba4503
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/projecttree/projecttree.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "projecttree.h"
+#include <set>
+namespace MesonProjectManager {
+namespace Internal {
+ProjectTree::ProjectTree() {}
+
+void buildTargetTree(std::unique_ptr<MesonProjectNode> &root, const Target &target)
+{
+ const auto path = Utils::FilePath::fromString(target.definedIn);
+ for (const auto &group : target.sources) {
+ for (const auto &file : group.sources) {
+ root->addNestedNode(
+ std::make_unique<ProjectExplorer::FileNode>(Utils::FilePath::fromString(file),
+ ProjectExplorer::FileType::Source));
+ }
+ }
+}
+
+void addTargetNode(std::unique_ptr<MesonProjectNode> &root, const Target &target)
+{
+ root->findNode([&target, path = Utils::FilePath::fromString(target.definedIn)](
+ ProjectExplorer::Node *node) {
+ if (node->filePath() == path.absolutePath()) {
+ auto asFolder = dynamic_cast<ProjectExplorer::FolderNode *>(node);
+ if (asFolder) {
+ auto targetNode = std::make_unique<MesonTargetNode>(path.absolutePath().pathAppended(
+ target.name),
+ Target::fullName(target));
+ targetNode->setDisplayName(target.name);
+ asFolder->addNode(std::move(targetNode));
+ }
+ return true;
+ }
+ return false;
+ });
+}
+
+void addOptionsFile(std::unique_ptr<MesonProjectNode> &project)
+{
+ auto meson_options = project->filePath().pathAppended("meson_options.txt");
+ if (meson_options.exists())
+ project->addNestedNode(
+ std::make_unique<ProjectExplorer::FileNode>(meson_options,
+ ProjectExplorer::FileType::Project));
+}
+
+std::unique_ptr<MesonProjectNode> ProjectTree::buildTree(const Utils::FilePath &srcDir,
+ const TargetsList &targets,
+ const std::vector<Utils::FilePath> &bsFiles)
+{
+ using namespace ProjectExplorer;
+ std::set<Utils::FilePath> targetPaths;
+ auto root = std::make_unique<MesonProjectNode>(srcDir);
+ std::for_each(std::cbegin(targets),
+ std::cend(targets),
+ [&root, &targetPaths](const Target &target) {
+ buildTargetTree(root, target);
+ targetPaths.insert(
+ Utils::FilePath::fromString(target.definedIn).absolutePath());
+ addTargetNode(root, target);
+ });
+ for (Utils::FilePath bsFile : bsFiles) {
+ if (!bsFile.startsWith("/"))
+ bsFile = srcDir.pathAppended(bsFile.toString());
+ root->addNestedNode(
+ std::make_unique<ProjectExplorer::FileNode>(bsFile, ProjectExplorer::FileType::Project));
+ }
+ return root;
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/project/projecttree/projecttree.h b/src/plugins/mesonprojectmanager/project/projecttree/projecttree.h
new file mode 100644
index 0000000000..7df02ea55b
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/project/projecttree/projecttree.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include "mesoninfoparser/mesoninfoparser.h"
+#include "mesonprojectnodes.h"
+#include <utils/fileutils.h>
+namespace MesonProjectManager {
+namespace Internal {
+class ProjectTree
+{
+public:
+ ProjectTree();
+ static std::unique_ptr<MesonProjectNode> buildTree(const Utils::FilePath &srcDir,
+ const TargetsList &targets,
+ const std::vector<Utils::FilePath> &bsFiles);
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/resources.qrc b/src/plugins/mesonprojectmanager/resources.qrc
new file mode 100644
index 0000000000..eb7fd47f0d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/resources.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/mesonproject">
+ <file>icons/meson_logo.png</file>
+ <file>icons/meson_bw_logo.png</file>
+ <file>icons/meson_bw_logo@2x.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp b/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp
new file mode 100644
index 0000000000..0c67478031
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "generalsettingspage.h"
+#include "generalsettingswidget.h"
+#include "settings.h"
+
+#include <mesonpluginconstants.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+GeneralSettingsPage::GeneralSettingsPage()
+{
+ setId(Constants::SettingsPage::GENERAL_ID);
+ setDisplayName(tr("General"));
+ setDisplayCategory("Meson");
+ setCategory(Constants::SettingsPage::CATEGORY);
+ setCategoryIconPath(Constants::Icons::MESON_BW);
+ setWidgetCreator([]() { return new GeneralSettingsWidget; });
+ Settings::loadAll();
+}
+
+void GeneralSettingsPage::saveAll()
+{
+ Settings::saveAll();
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h b/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h
new file mode 100644
index 0000000000..8b086e70f4
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/generalsettingspage.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonTools;
+class GeneralSettingsPage final : public Core::IOptionsPage
+{
+public:
+ GeneralSettingsPage();
+ void saveAll();
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp
new file mode 100644
index 0000000000..4adfad656d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "generalsettingswidget.h"
+#include "settings.h"
+#include "ui_generalsettingswidget.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+GeneralSettingsWidget::GeneralSettingsWidget()
+ : Core::IOptionsPageWidget()
+ , ui(new Ui::GeneralSettingsWidget)
+{
+ ui->setupUi(this);
+ ui->autorunChkBox->setChecked(Settings::autorunMeson());
+ ui->verboseNinjaChkBox->setChecked(Settings::verboseNinja());
+}
+
+GeneralSettingsWidget::~GeneralSettingsWidget()
+{
+ delete ui;
+}
+
+void GeneralSettingsWidget::apply()
+{
+ Settings::setAutorunMeson(ui->autorunChkBox->isChecked());
+ Settings::setVerboseNinja(ui->verboseNinjaChkBox->isChecked());
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h
new file mode 100644
index 0000000000..cf0da678e5
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QCoreApplication>
+#include <QTabWidget>
+#include <QWidget>
+
+namespace Ui {
+class GeneralSettingsWidget;
+}
+
+namespace MesonProjectManager {
+namespace Internal {
+class GeneralSettingsWidget final : public Core::IOptionsPageWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::GeneralSettingsWidget)
+ void apply() final;
+
+public:
+ explicit GeneralSettingsWidget();
+ ~GeneralSettingsWidget();
+
+private:
+ Ui::GeneralSettingsWidget *ui;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui
new file mode 100644
index 0000000000..8f44e3df74
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/generalsettingswidget.ui
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GeneralSettingsWidget</class>
+ <widget class="QWidget" name="GeneralSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>625</width>
+ <height>349</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="autorunChkBox">
+ <property name="toolTip">
+ <string>Automatically run Meson when needed.</string>
+ </property>
+ <property name="text">
+ <string>Autorun Meson</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="verboseNinjaChkBox">
+ <property name="toolTip">
+ <string>Enables verbose mode by default when invoking Ninja.</string>
+ </property>
+ <property name="text">
+ <string>Ninja verbose mode</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/mesonprojectmanager/settings/general/settings.cpp b/src/plugins/mesonprojectmanager/settings/general/settings.cpp
new file mode 100644
index 0000000000..1193a0d8c0
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/settings.cpp
@@ -0,0 +1,33 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "settings.h"
+namespace MesonProjectManager {
+namespace Internal {
+Settings::Settings(QObject *parent)
+ : QObject(parent)
+{}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/general/settings.h b/src/plugins/mesonprojectmanager/settings/general/settings.h
new file mode 100644
index 0000000000..c9228e118d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/general/settings.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <coreplugin/icore.h>
+#include <mesonpluginconstants.h>
+#include <QObject>
+namespace MesonProjectManager {
+namespace Internal {
+template<class F>
+void with_group(QSettings *settings, const QString &name, const F &f)
+{
+ settings->beginGroup(name);
+ f();
+ settings->endGroup();
+};
+
+#define ADD_PROPERTY(name, setter, type) \
+private: \
+ type m_##name; \
+\
+public: \
+ inline static type name() { return instance()->m_##name; } \
+ inline static void setter(type value) \
+ { \
+ instance()->m_##name = value; \
+ emit instance()->name##Changed(value); \
+ } \
+ Q_SIGNAL void name##Changed(type newValue);
+
+class Settings : public QObject
+{
+ Q_OBJECT
+ explicit Settings(QObject *parent = nullptr);
+
+public:
+ inline static Settings *instance()
+ {
+ static Settings m_settings;
+ return &m_settings;
+ }
+
+ ADD_PROPERTY(autorunMeson, setAutorunMeson, bool)
+ ADD_PROPERTY(verboseNinja, setVerboseNinja, bool)
+
+ static inline void saveAll()
+ {
+ using namespace Constants;
+ auto settings = Core::ICore::settings(QSettings::Scope::UserScope);
+ with_group(settings, GeneralSettings::SECTION, [settings]() {
+ settings->setValue(GeneralSettings::AUTORUN_MESON_KEY, Settings::autorunMeson());
+ settings->setValue(GeneralSettings::VERBOSE_NINJA_KEY, Settings::verboseNinja());
+ });
+ }
+ static inline void loadAll()
+ {
+ using namespace Constants;
+ auto settings = Core::ICore::settings(QSettings::Scope::UserScope);
+ with_group(settings, GeneralSettings::SECTION, [settings]() {
+ Settings::setAutorunMeson(
+ settings->value(GeneralSettings::AUTORUN_MESON_KEY, true).toBool());
+ Settings::setVerboseNinja(
+ settings->value(GeneralSettings::VERBOSE_NINJA_KEY, true).toBool());
+ });
+ }
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.cpp b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.cpp
new file mode 100644
index 0000000000..f8861f1e88
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "mesontoolkitaspect.h"
+#include "toolkitaspectwidget.h"
+#include <utils/qtcassert.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+static const char TOOL_ID[] = "MesonProjectManager.MesonKitInformation.Meson";
+
+MesonToolKitAspect::MesonToolKitAspect()
+{
+ setObjectName(QLatin1String("MesonKitAspect"));
+ setId(TOOL_ID);
+ setDisplayName(tr("Meson Tool"));
+ setDescription(tr("The Meson tool to use when building a project with Meson.<br>"
+ "This setting is ignored when using other build systems."));
+ setPriority(9000);
+}
+
+ProjectExplorer::Tasks MesonToolKitAspect::validate(const ProjectExplorer::Kit *k) const
+{
+ ProjectExplorer::Tasks tasks;
+ const auto tool = mesonTool(k);
+ if (tool && !tool->isValid())
+ tasks << ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::Warning,
+ tr("Cannot validate this meson executable.")};
+ return tasks;
+}
+
+void MesonToolKitAspect::setup(ProjectExplorer::Kit *k)
+{
+ const auto tool = mesonTool(k);
+ if (!tool) {
+ const auto autoDetected = MesonTools::mesonWrapper();
+ if (autoDetected)
+ setMesonTool(k, autoDetected->id());
+ }
+}
+
+void MesonToolKitAspect::fix(ProjectExplorer::Kit *k)
+{
+ setup(k);
+}
+
+ProjectExplorer::KitAspect::ItemList MesonToolKitAspect::toUserOutput(
+ const ProjectExplorer::Kit *k) const
+{
+ const auto tool = mesonTool(k);
+ if (tool)
+ return {{tr("Meson"), tool->name()}};
+ return {{tr("Meson"), tr("Unconfigured")}};
+}
+
+ProjectExplorer::KitAspectWidget *MesonToolKitAspect::createConfigWidget(ProjectExplorer::Kit *k) const
+{
+ QTC_ASSERT(k, return nullptr);
+ return new ToolKitAspectWidget{k, this, ToolKitAspectWidget::ToolType::Meson};
+}
+
+void MesonToolKitAspect::setMesonTool(ProjectExplorer::Kit *kit, Core::Id id)
+{
+ QTC_ASSERT(kit && id.isValid(), return );
+ kit->setValue(TOOL_ID, id.toSetting());
+}
+
+Core::Id MesonToolKitAspect::mesonToolId(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return {});
+ return Core::Id::fromSetting(kit->value(TOOL_ID));
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.h b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.h
new file mode 100644
index 0000000000..759cdae319
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/mesontoolkitaspect.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include <exewrappers/mesontools.h>
+
+#include <coreplugin/id.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitmanager.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonToolKitAspect final : public ProjectExplorer::KitAspect
+{
+public:
+ MesonToolKitAspect();
+
+ ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const final;
+ void setup(ProjectExplorer::Kit *k) final;
+ void fix(ProjectExplorer::Kit *k) final;
+ ItemList toUserOutput(const ProjectExplorer::Kit *k) const final;
+ ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *) const final;
+
+ static void setMesonTool(ProjectExplorer::Kit *kit, Core::Id id);
+ static Core::Id mesonToolId(const ProjectExplorer::Kit *kit);
+
+ static inline decltype(auto) mesonTool(const ProjectExplorer::Kit *kit)
+ {
+ return MesonTools::mesonWrapper(MesonToolKitAspect::mesonToolId(kit));
+ }
+
+ static inline bool isValid(const ProjectExplorer::Kit *kit)
+ {
+ auto tool = mesonTool(kit);
+ return (tool && tool->isValid());
+ }
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.cpp b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.cpp
new file mode 100644
index 0000000000..aaa41f3228
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "ninjatoolkitaspect.h"
+#include "toolkitaspectwidget.h"
+#include "utils/qtcassert.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+
+static const char TOOL_ID[] = "MesonProjectManager.MesonKitInformation.Ninja";
+
+NinjaToolKitAspect::NinjaToolKitAspect()
+{
+ setObjectName(QLatin1String("NinjaKitAspect"));
+ setId(TOOL_ID);
+ setDisplayName(tr("Ninja Tool"));
+ setDescription(tr("The Ninja tool to use when building a project with Meson.<br>"
+ "This setting is ignored when using other build systems."));
+ setPriority(9000);
+}
+
+ProjectExplorer::Tasks NinjaToolKitAspect::validate(const ProjectExplorer::Kit *k) const
+{
+ ProjectExplorer::Tasks tasks;
+ const auto tool = ninjaTool(k);
+ if (tool && !tool->isValid())
+ tasks << ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::Warning,
+ tr("Cannot validate this Ninja executable.")};
+ return tasks;
+}
+
+void NinjaToolKitAspect::setup(ProjectExplorer::Kit *k)
+{
+ const auto tool = ninjaTool(k);
+ if (!tool) {
+ const auto autoDetected = MesonTools::ninjaWrapper();
+ if (autoDetected)
+ setNinjaTool(k, autoDetected->id());
+ }
+}
+
+void NinjaToolKitAspect::fix(ProjectExplorer::Kit *k)
+{
+ setup(k);
+}
+
+ProjectExplorer::KitAspect::ItemList NinjaToolKitAspect::toUserOutput(
+ const ProjectExplorer::Kit *k) const
+{
+ const auto tool = ninjaTool(k);
+ if (tool)
+ return {{tr("Ninja"), tool->name()}};
+ return {{tr("Ninja"), tr("Unconfigured")}};
+}
+
+ProjectExplorer::KitAspectWidget *NinjaToolKitAspect::createConfigWidget(ProjectExplorer::Kit *k) const
+{
+ QTC_ASSERT(k, return nullptr);
+ return new ToolKitAspectWidget{k, this, ToolKitAspectWidget::ToolType::Ninja};
+}
+
+void NinjaToolKitAspect::setNinjaTool(ProjectExplorer::Kit *kit, Core::Id id)
+{
+ QTC_ASSERT(kit && id.isValid(), return );
+ kit->setValue(TOOL_ID, id.toSetting());
+}
+
+Core::Id NinjaToolKitAspect::ninjaToolId(const ProjectExplorer::Kit *kit)
+{
+ QTC_ASSERT(kit, return {});
+ return Core::Id::fromSetting(kit->value(TOOL_ID));
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.h b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.h
new file mode 100644
index 0000000000..59e869af8c
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/ninjatoolkitaspect.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include <exewrappers/mesontools.h>
+
+#include <coreplugin/id.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitmanager.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class NinjaToolKitAspect final : public ProjectExplorer::KitAspect
+{
+public:
+ NinjaToolKitAspect();
+
+ ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const final;
+ void setup(ProjectExplorer::Kit *k) final;
+ void fix(ProjectExplorer::Kit *k) final;
+ ItemList toUserOutput(const ProjectExplorer::Kit *k) const final;
+ ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *) const final;
+
+ static void setNinjaTool(ProjectExplorer::Kit *kit, Core::Id id);
+ static Core::Id ninjaToolId(const ProjectExplorer::Kit *kit);
+
+ static inline decltype(auto) ninjaTool(const ProjectExplorer::Kit *kit)
+ {
+ return MesonTools::ninjaWrapper(NinjaToolKitAspect::ninjaToolId(kit));
+ }
+ static inline bool isValid(const ProjectExplorer::Kit *kit)
+ {
+ auto tool = ninjaTool(kit);
+ return (tool && tool->isValid());
+ }
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp
new file mode 100644
index 0000000000..84f8e8818d
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolkitaspectwidget.h"
+#include "coreplugin/icore.h"
+#include "mesonpluginconstants.h"
+#include "mesontoolkitaspect.h"
+#include "ninjatoolkitaspect.h"
+#include "utils/qtcassert.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+ToolKitAspectWidget::ToolKitAspectWidget(ProjectExplorer::Kit *kit,
+ const ProjectExplorer::KitAspect *ki,
+ ToolType type)
+ : ProjectExplorer::KitAspectWidget(kit, ki)
+ , m_toolsComboBox{new QComboBox}
+ , m_manageButton(new QPushButton(KitAspectWidget::msgManage()))
+ , m_type{type}
+{
+ m_toolsComboBox->setSizePolicy(QSizePolicy::Ignored,
+ m_toolsComboBox->sizePolicy().verticalPolicy());
+ m_toolsComboBox->setEnabled(false);
+ m_toolsComboBox->setToolTip(ki->description());
+ loadTools();
+
+ m_manageButton->setContentsMargins(0, 0, 0, 0);
+ connect(m_manageButton, &QPushButton::clicked, this, [this]() {
+ Core::ICore::showOptionsDialog(Constants::SettingsPage::TOOLS_ID, buttonWidget());
+ });
+
+ connect(MesonTools::instance(),
+ &MesonTools::toolAdded,
+ this,
+ &ToolKitAspectWidget::addTool);
+ connect(MesonTools::instance(),
+ &MesonTools::toolRemoved,
+ this,
+ &ToolKitAspectWidget::removeTool);
+ connect(m_toolsComboBox,
+ qOverload<int>(&QComboBox::currentIndexChanged),
+ this,
+ &ToolKitAspectWidget::setCurrentToolIndex);
+}
+
+ToolKitAspectWidget::~ToolKitAspectWidget()
+{
+ delete m_toolsComboBox;
+ delete m_manageButton;
+}
+
+void ToolKitAspectWidget::addTool(const MesonTools::Tool_t &tool)
+{
+ QTC_ASSERT(tool, return );
+ if (isCompatible(tool))
+ this->m_toolsComboBox->addItem(tool->name(), tool->id().toSetting());
+}
+
+void ToolKitAspectWidget::removeTool(const MesonTools::Tool_t &tool)
+{
+ QTC_ASSERT(tool, return );
+ if (!isCompatible(tool))
+ return;
+ const int index = indexOf(tool->id());
+ QTC_ASSERT(index >= 0, return );
+ if (index == m_toolsComboBox->currentIndex())
+ setToDefault();
+ m_toolsComboBox->removeItem(index);
+}
+
+void ToolKitAspectWidget::setCurrentToolIndex(int index)
+{
+ const Core::Id id = Core::Id::fromSetting(m_toolsComboBox->itemData(index));
+ if (m_type == ToolType::Meson)
+ MesonToolKitAspect::setMesonTool(m_kit, id);
+ else
+ NinjaToolKitAspect::setNinjaTool(m_kit, id);
+}
+
+int ToolKitAspectWidget::indexOf(const Core::Id &id)
+{
+ for (int i = 0; i < m_toolsComboBox->count(); ++i) {
+ if (id == Core::Id::fromSetting(m_toolsComboBox->itemData(i)))
+ return i;
+ }
+ return -1;
+}
+
+bool ToolKitAspectWidget::isCompatible(const MesonTools::Tool_t &tool)
+{
+ return (m_type == ToolType::Meson && MesonTools::isMesonWrapper(tool))
+ || (m_type == ToolType::Ninja && MesonTools::isNinjaWrapper(tool));
+}
+
+void ToolKitAspectWidget::loadTools()
+{
+ std::for_each(std::cbegin(MesonTools::tools()),
+ std::cend(MesonTools::tools()),
+ [this](const MesonTools::Tool_t &tool) { addTool(tool); });
+ refresh();
+ m_toolsComboBox->setEnabled(m_toolsComboBox->count());
+}
+
+void ToolKitAspectWidget::setToDefault()
+{
+ const MesonTools::Tool_t autoDetected = [this]() {
+ if (m_type == ToolType::Meson)
+ return std::dynamic_pointer_cast<ToolWrapper>(MesonTools::mesonWrapper());
+ return std::dynamic_pointer_cast<ToolWrapper>(MesonTools::ninjaWrapper());
+ }();
+
+ if (autoDetected) {
+ const auto index = indexOf(autoDetected->id());
+ m_toolsComboBox->setCurrentIndex(index);
+ setCurrentToolIndex(index);
+ } else {
+ m_toolsComboBox->setCurrentIndex(0);
+ setCurrentToolIndex(0);
+ }
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h
new file mode 100644
index 0000000000..b217232cf4
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/kitaspect/toolkitaspectwidget.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+
+#include "exewrappers/mesonwrapper.h"
+#include "mesontoolkitaspect.h"
+#include "ninjatoolkitaspect.h"
+#include <projectexplorer/kitmanager.h>
+
+#include <QComboBox>
+#include <QCoreApplication>
+#include <QPushButton>
+
+namespace MesonProjectManager {
+namespace Internal {
+class ToolKitAspectWidget final : public ProjectExplorer::KitAspectWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::ToolKitAspect)
+public:
+ enum class ToolType { Meson, Ninja };
+
+ ToolKitAspectWidget(ProjectExplorer::Kit *kit,
+ const ProjectExplorer::KitAspect *ki,
+ ToolType type);
+ ~ToolKitAspectWidget();
+
+private:
+ void addTool(const MesonTools::Tool_t &tool);
+ void removeTool(const MesonTools::Tool_t &tool);
+ void setCurrentToolIndex(int index);
+ int indexOf(const Core::Id &id);
+ bool isCompatible(const MesonTools::Tool_t &tool);
+ void loadTools();
+ void setToDefault();
+
+ void makeReadOnly() override { m_toolsComboBox->setEnabled(false); }
+ QWidget *mainWidget() const override { return m_toolsComboBox; }
+ QWidget *buttonWidget() const override { return m_manageButton; }
+ void refresh() override
+ {
+ const auto id = [this]() {
+ if (m_type == ToolType::Meson)
+ return MesonToolKitAspect::mesonToolId(m_kit);
+ return NinjaToolKitAspect::ninjaToolId(m_kit);
+ }();
+ if (id.isValid())
+ m_toolsComboBox->setCurrentIndex(indexOf(id));
+ else {
+ setToDefault();
+ }
+ }
+
+ QComboBox *m_toolsComboBox;
+ QPushButton *m_manageButton;
+ ToolType m_type;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.cpp
new file mode 100644
index 0000000000..f88cb2debd
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolitemsettings.h"
+#include "tooltreeitem.h"
+#include "ui_toolitemsettings.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+ToolItemSettings::ToolItemSettings(QWidget *parent)
+ : QWidget(parent)
+ , ui(new Ui::ToolItemSettings)
+{
+ ui->setupUi(this);
+ ui->mesonPathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
+ ui->mesonPathChooser->setHistoryCompleter(QLatin1String("Meson.Command.History"));
+ connect(ui->mesonPathChooser,
+ &Utils::PathChooser::rawPathChanged,
+ this,
+ &ToolItemSettings::store);
+ connect(ui->mesonNameLineEdit, &QLineEdit::textChanged, this, &ToolItemSettings::store);
+}
+
+ToolItemSettings::~ToolItemSettings()
+{
+ delete ui;
+}
+
+void ToolItemSettings::load(ToolTreeItem *item)
+{
+ if (item) {
+ m_currentId = Utils::nullopt;
+ ui->mesonNameLineEdit->setDisabled(item->isAutoDetected());
+ ui->mesonNameLineEdit->setText(item->name());
+ ui->mesonPathChooser->setDisabled(item->isAutoDetected());
+ ui->mesonPathChooser->setFileName(item->executable());
+ m_currentId = item->id();
+ } else {
+ m_currentId = Utils::nullopt;
+ }
+}
+
+void ToolItemSettings::store()
+{
+ if (m_currentId)
+ emit applyChanges(*m_currentId,
+ ui->mesonNameLineEdit->text(),
+ ui->mesonPathChooser->fileName());
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.h b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.h
new file mode 100644
index 0000000000..08f2d1f42b
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include "coreplugin/id.h"
+#include "utils/fileutils.h"
+#include "utils/optional.h"
+#include <QWidget>
+
+namespace Ui {
+class ToolItemSettings;
+}
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class ToolTreeItem;
+
+class ToolItemSettings : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ToolItemSettings(QWidget *parent = nullptr);
+ ~ToolItemSettings();
+ void load(ToolTreeItem *item);
+ void store();
+ Q_SIGNAL void applyChanges(Core::Id itemId, const QString &name, const Utils::FilePath &exe);
+
+private:
+ Ui::ToolItemSettings *ui;
+ Utils::optional<Core::Id> m_currentId{Utils::nullopt};
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.ui b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.ui
new file mode 100644
index 0000000000..60a93dca1a
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolitemsettings.ui
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ToolItemSettings</class>
+ <widget class="QWidget" name="ToolItemSettings">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>409</width>
+ <height>70</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="_nameLbl">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="_pathLbl">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Utils::PathChooser" name="mesonPathChooser" native="true"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="mesonNameLineEdit"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.cpp
new file mode 100644
index 0000000000..fc3d750a03
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolsmodel.h"
+#include "tooltreeitem.h"
+#include "utils/qtcassert.h"
+#include "utils/stringutils.h"
+#include <exewrappers/mesontools.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+ToolsModel::ToolsModel()
+{
+ setHeader({tr("Name"), tr("Location")});
+ rootItem()->appendChild(new Utils::StaticTreeItem(tr("Auto-detected")));
+ rootItem()->appendChild(new Utils::StaticTreeItem(tr("Manual")));
+ for (const auto &tool : MesonTools::tools()) {
+ addMesonTool(tool);
+ }
+}
+
+ToolTreeItem *ToolsModel::mesoneToolTreeItem(const QModelIndex &index) const
+{
+ return itemForIndexAtLevel<2>(index);
+}
+
+void ToolsModel::updateItem(const Core::Id &itemId, const QString &name, const Utils::FilePath &exe)
+{
+ auto treeItem = findItemAtLevel<2>([itemId](ToolTreeItem *n) { return n->id() == itemId; });
+ QTC_ASSERT(treeItem, return );
+ treeItem->update(name, exe);
+}
+
+void ToolsModel::addMesonTool()
+{
+ manualGroup()->appendChild(new ToolTreeItem{uniqueName(tr("New Meson or Ninja tool"))});
+}
+
+void ToolsModel::removeMesonTool(ToolTreeItem *item)
+{
+ QTC_ASSERT(item, return );
+ destroyItem(item);
+ m_itemsToRemove.enqueue(item->id());
+}
+
+ToolTreeItem *ToolsModel::cloneMesonTool(ToolTreeItem *item)
+{
+ QTC_ASSERT(item, return nullptr);
+ auto newItem = new ToolTreeItem(*item);
+ manualGroup()->appendChild(newItem);
+ return item;
+}
+
+void ToolsModel::apply()
+{
+ forItemsAtLevel<2>([this](ToolTreeItem *item) {
+ if (item->hasUnsavedChanges()) {
+ MesonTools::updateTool(item->id(), item->name(), item->executable());
+ item->setSaved();
+ emit this->dataChanged(item->index(),item->index());
+ }
+ });
+ while (!m_itemsToRemove.isEmpty()) {
+ MesonTools::removeTool(m_itemsToRemove.dequeue());
+ }
+
+}
+
+void ToolsModel::addMesonTool(const MesonTools::Tool_t &tool)
+{
+ if (tool->autoDetected())
+ autoDetectedGroup()->appendChild(new ToolTreeItem(tool));
+ else
+ manualGroup()->appendChild(new ToolTreeItem(tool));
+}
+
+QString ToolsModel::uniqueName(const QString &baseName)
+{
+ QStringList names;
+ forItemsAtLevel<2>([&names](auto *item) { names << item->name(); });
+ return Utils::makeUniquelyNumbered(baseName, names);
+}
+
+Utils::TreeItem *ToolsModel::autoDetectedGroup() const
+{
+ return rootItem()->childAt(0);
+}
+
+Utils::TreeItem *ToolsModel::manualGroup() const
+{
+ return rootItem()->childAt(1);
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.h b/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.h
new file mode 100644
index 0000000000..3707dc63c2
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolsmodel.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "toolssettingspage.h"
+#include <exewrappers/mesontools.h>
+
+#include <utils/treemodel.h>
+#include <QCoreApplication>
+#include <QQueue>
+
+namespace MesonProjectManager {
+namespace Internal {
+class ToolTreeItem;
+class ToolsModel final : public Utils::TreeModel<Utils::TreeItem, Utils::TreeItem, ToolTreeItem>
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::ToolsSettingsPage)
+public:
+ ToolsModel();
+ ToolTreeItem *mesoneToolTreeItem(const QModelIndex &index) const;
+ void updateItem(const Core::Id &itemId, const QString &name, const Utils::FilePath &exe);
+ void addMesonTool();
+ void removeMesonTool(ToolTreeItem *item);
+ ToolTreeItem *cloneMesonTool(ToolTreeItem *item);
+ void apply();
+
+private:
+ void addMesonTool(const MesonTools::Tool_t &);
+ QString uniqueName(const QString &baseName);
+ Utils::TreeItem *autoDetectedGroup() const;
+ Utils::TreeItem *manualGroup() const;
+ QQueue<Core::Id> m_itemsToRemove;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp
new file mode 100644
index 0000000000..7027517812
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolssettingsaccessor.h"
+#include <app/app_version.h>
+#include <coreplugin/icore.h>
+#include <iterator>
+#include <mesonpluginconstants.h>
+#include <utils/fileutils.h>
+#include <vector>
+#include <QCoreApplication>
+#include <QVariantMap>
+
+namespace MesonProjectManager {
+namespace Internal {
+namespace {
+inline QString entryName(int index)
+{
+ using namespace Constants;
+ return QString("%1%2").arg(ToolsSettings::ENTRY_KEY).arg(index);
+}
+} // namespace
+
+ToolsSettingsAccessor::ToolsSettingsAccessor()
+ : UpgradingSettingsAccessor("QtCreatorMesonTools",
+ QCoreApplication::translate("MesonProjectManager::MesonToolManager",
+ "Meson"),
+ Core::Constants::IDE_DISPLAY_NAME)
+{
+ setBaseFilePath(Utils::FilePath::fromString(Core::ICore::userResourcePath())
+ .pathAppended(Constants::ToolsSettings::FILENAME));
+}
+
+void ToolsSettingsAccessor::saveMesonTools(const std::vector<MesonTools::Tool_t> &tools,
+ QWidget *parent)
+{
+ using namespace Constants;
+ QVariantMap data;
+ int entry_count = 0;
+ std::for_each(std::cbegin(tools),
+ std::cend(tools),
+ [&data, &entry_count](const MesonTools::Tool_t &tool) {
+ auto asMeson = std::dynamic_pointer_cast<MesonWrapper>(tool);
+ if (asMeson)
+ data.insert(entryName(entry_count), toVariantMap<MesonWrapper>(*asMeson));
+ else {
+ auto asNinja = std::dynamic_pointer_cast<NinjaWrapper>(tool);
+ if (asNinja)
+ data.insert(entryName(entry_count),
+ toVariantMap<NinjaWrapper>(*asNinja));
+ }
+ entry_count++;
+ });
+ data.insert(ToolsSettings::ENTRY_COUNT, entry_count);
+ saveSettings(data, parent);
+}
+
+std::vector<MesonTools::Tool_t> ToolsSettingsAccessor::loadMesonTools(QWidget *parent)
+{
+ using namespace Constants;
+ auto data = restoreSettings(parent);
+ auto entry_count = data.value(ToolsSettings::ENTRY_COUNT, 0).toInt();
+ std::vector<MesonTools::Tool_t> result;
+ for (auto toolIndex = 0; toolIndex < entry_count; toolIndex++) {
+ auto name = entryName(toolIndex);
+ if (data.contains(name)) {
+ const auto map = data[name].toMap();
+ auto type = map.value(ToolsSettings::TOOL_TYPE_KEY, ToolsSettings::TOOL_TYPE_MESON);
+ if (type == ToolsSettings::TOOL_TYPE_NINJA)
+ result.emplace_back(fromVariantMap<NinjaWrapper *>(data[name].toMap()));
+ else
+ result.emplace_back(fromVariantMap<MesonWrapper *>(data[name].toMap()));
+ }
+ }
+ return result;
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.h b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.h
new file mode 100644
index 0000000000..b607666b46
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingsaccessor.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include "utils/settingsaccessor.h"
+#include <exewrappers/mesontools.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+class ToolsSettingsAccessor final : public Utils::UpgradingSettingsAccessor
+{
+public:
+ ToolsSettingsAccessor();
+ void saveMesonTools(const std::vector<MesonTools::Tool_t> &tools, QWidget *parent);
+ std::vector<MesonTools::Tool_t> loadMesonTools(QWidget *parent);
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.cpp
new file mode 100644
index 0000000000..d9c4aff271
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolssettingspage.h"
+#include "toolssettingswidget.h"
+#include <mesonpluginconstants.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+
+ToolsSettingsPage::ToolsSettingsPage()
+{
+ setId(Constants::SettingsPage::TOOLS_ID);
+ setDisplayName(tr("Tools"));
+ setCategory(Constants::SettingsPage::CATEGORY);
+ setWidgetCreator([]() { return new ToolsSettingsWidget; });
+}
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.h b/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.h
new file mode 100644
index 0000000000..66f2d3bf70
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingspage.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+namespace MesonProjectManager {
+namespace Internal {
+class MesonTools;
+class ToolsSettingsPage final : public Core::IOptionsPage
+{
+public:
+ ToolsSettingsPage();
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.cpp b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.cpp
new file mode 100644
index 0000000000..672266bad7
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "toolssettingswidget.h"
+#include "toolsmodel.h"
+#include "tooltreeitem.h"
+#include "ui_toolssettingswidget.h"
+
+namespace MesonProjectManager {
+namespace Internal {
+ToolsSettingsWidget::ToolsSettingsWidget()
+ : Core::IOptionsPageWidget()
+ , ui(new Ui::ToolsSettingsWidget)
+{
+ ui->setupUi(this);
+ ui->mesonDetails->setState(Utils::DetailsWidget::NoSummary);
+ ui->mesonDetails->setVisible(false);
+ m_itemSettings = new ToolItemSettings;
+ ui->mesonDetails->setWidget(m_itemSettings);
+
+ ui->mesonList->setModel(&m_model);
+ ui->mesonList->expandAll();
+ ui->mesonList->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ ui->mesonList->header()->setSectionResizeMode(1, QHeaderView::Stretch);
+
+ connect(ui->mesonList->selectionModel(),
+ &QItemSelectionModel::currentChanged,
+ this,
+ &ToolsSettingsWidget::currentMesonToolChanged);
+ connect(m_itemSettings, &ToolItemSettings::applyChanges, &m_model, &ToolsModel::updateItem);
+
+ connect(ui->addButton, &QPushButton::clicked, &m_model, qOverload<>(&ToolsModel::addMesonTool));
+ connect(ui->cloneButton, &QPushButton::clicked, this, &ToolsSettingsWidget::cloneMesonTool);
+ connect(ui->removeButton, &QPushButton::clicked, this, &ToolsSettingsWidget::removeMesonTool);
+}
+
+ToolsSettingsWidget::~ToolsSettingsWidget()
+{
+ delete ui;
+}
+
+void ToolsSettingsWidget::cloneMesonTool()
+{
+ if (m_currentItem) {
+ auto newItem = m_model.cloneMesonTool(m_currentItem);
+ ui->mesonList->setCurrentIndex(newItem->index());
+ }
+}
+
+void ToolsSettingsWidget::removeMesonTool()
+{
+ if (m_currentItem) {
+ m_model.removeMesonTool(m_currentItem);
+ }
+}
+
+void ToolsSettingsWidget::currentMesonToolChanged(const QModelIndex &newCurrent)
+{
+ m_currentItem = m_model.mesoneToolTreeItem(newCurrent);
+ m_itemSettings->load(m_currentItem);
+ ui->mesonDetails->setVisible(m_currentItem);
+ ui->cloneButton->setEnabled(m_currentItem);
+ ui->removeButton->setEnabled(m_currentItem && !m_currentItem->isAutoDetected());
+}
+
+void ToolsSettingsWidget::apply()
+{
+ m_model.apply();
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.h b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.h
new file mode 100644
index 0000000000..9c1bd5231f
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include "toolitemsettings.h"
+#include "toolsmodel.h"
+#include <exewrappers/mesonwrapper.h>
+
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QCoreApplication>
+#include <QTabWidget>
+#include <QWidget>
+
+
+namespace Ui {
+class ToolsSettingsWidget;
+}
+
+namespace MesonProjectManager {
+namespace Internal {
+class ToolTreeItem;
+class ToolsSettingsWidget final : public Core::IOptionsPageWidget
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::ToolsSettingsWidget)
+ void apply() final;
+
+public:
+ explicit ToolsSettingsWidget();
+ ~ToolsSettingsWidget();
+
+private:
+ void cloneMesonTool();
+ void removeMesonTool();
+ void currentMesonToolChanged(const QModelIndex &newCurrent);
+ Ui::ToolsSettingsWidget *ui;
+ ToolsModel m_model;
+ ToolItemSettings *m_itemSettings;
+ ToolTreeItem *m_currentItem = nullptr;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.ui b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.ui
new file mode 100644
index 0000000000..7cc3da0b83
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/toolssettingswidget.ui
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ToolsSettingsWidget</class>
+ <widget class="QWidget" name="MesonToolConfigWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>625</width>
+ <height>349</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTreeView" name="mesonList"/>
+ </item>
+ <item>
+ <widget class="Utils::DetailsWidget" name="mesonDetails" native="true"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QPushButton" name="addButton">
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cloneButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Clone</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="removeButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="makeDefaultButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Set as the default Meson executable to use when creating a new kit or when no value is set.</string>
+ </property>
+ <property name="text">
+ <string>Make Default</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Utils::DetailsWidget</class>
+ <extends>QWidget</extends>
+ <header location="global">utils/detailswidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.cpp b/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.cpp
new file mode 100644
index 0000000000..b7abb4dfee
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "tooltreeitem.h"
+#include <utils/utilsicons.h>
+#include <QFileInfo>
+#include <QUuid>
+
+namespace MesonProjectManager {
+namespace Internal {
+ToolTreeItem::ToolTreeItem(const QString &name)
+ : m_name{name}
+ , m_autoDetected{false}
+ , m_id(Core::Id::fromString(QUuid::createUuid().toString()))
+ , m_unsavedChanges{true}
+{
+ self_check();
+ update_tooltip();
+}
+
+ToolTreeItem::ToolTreeItem(const MesonTools::Tool_t &tool)
+ : m_name{tool->name()}
+ , m_executable{tool->exe()}
+ , m_autoDetected{tool->autoDetected()}
+ , m_id{tool->id()}
+{
+ m_tooltip = tr("Version: %1").arg(tool->version().toQString());
+ self_check();
+}
+
+ToolTreeItem::ToolTreeItem(const ToolTreeItem &other)
+ : m_name{tr("Clone of %1").arg(other.m_name)}
+ , m_executable{other.m_executable}
+ , m_autoDetected{false}
+ , m_id{Core::Id::fromString(QUuid::createUuid().toString())}
+ , m_unsavedChanges{true}
+{
+ self_check();
+ update_tooltip();
+}
+
+QVariant ToolTreeItem::data(int column, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole: {
+ switch (column) {
+ case 0: {
+ return m_name;
+ }
+ case 1: {
+ return m_executable.toUserOutput();
+ }
+ } // switch (column)
+ return QVariant();
+ }
+ case Qt::FontRole: {
+ QFont font;
+ font.setBold(m_unsavedChanges);
+ return font;
+ }
+ case Qt::ToolTipRole: {
+ if (!m_pathExists)
+ return QCoreApplication::translate("MesonProjectManager::Internal::ToolTreeItem",
+ "Meson executable path does not exist.");
+ if (!m_pathIsFile)
+ return QCoreApplication::translate("MesonProjectManager::Internal::ToolTreeItem",
+ "Meson executable path is not a file.");
+ if (!m_pathIsExecutable)
+ return QCoreApplication::translate("MesonProjectManager::Internal::ToolTreeItem",
+ "Meson executable path is not executable.");
+ return m_tooltip;
+ }
+ case Qt::DecorationRole: {
+ if (column == 0 && (!m_pathExists || !m_pathIsFile || !m_pathIsExecutable))
+ return Utils::Icons::CRITICAL.icon();
+ return {};
+ }
+ }
+ return {};
+}
+
+void ToolTreeItem::update(const QString &name, const Utils::FilePath &exe)
+{
+ m_unsavedChanges = true;
+ m_name = name;
+ if (exe != m_executable) {
+ m_executable = exe;
+ self_check();
+ update_tooltip();
+ }
+}
+
+void ToolTreeItem::self_check()
+{
+ m_pathExists = m_executable.exists();
+ m_pathIsFile = m_executable.toFileInfo().isFile();
+ m_pathIsExecutable = m_executable.toFileInfo().isExecutable();
+}
+
+void ToolTreeItem::update_tooltip(const Version &version)
+{
+ if (version.isValid)
+ m_tooltip = tr("Version: %1").arg(version.toQString());
+ else
+ m_tooltip = tr("Cannot get tool version.");
+}
+
+void ToolTreeItem::update_tooltip()
+{
+ update_tooltip(MesonWrapper::read_version(m_executable));
+}
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.h b/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.h
new file mode 100644
index 0000000000..029d00ea05
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/settings/tools/tooltreeitem.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+#include "toolssettingspage.h"
+#include <exewrappers/mesontools.h>
+#include <coreplugin/id.h>
+#include <utils/fileutils.h>
+#include <utils/optional.h>
+#include <utils/treemodel.h>
+#include <QCoreApplication>
+#include <QString>
+
+namespace MesonProjectManager {
+namespace Internal {
+class ToolTreeItem final : public Utils::TreeItem
+{
+ Q_DECLARE_TR_FUNCTIONS(MesonProjectManager::Internal::ToolsSettingsPage)
+public:
+ ToolTreeItem(const QString &name);
+ ToolTreeItem(const MesonTools::Tool_t &tool);
+ ToolTreeItem(const ToolTreeItem &other);
+ QVariant data(int column, int role) const override;
+ inline bool isAutoDetected() const noexcept { return m_autoDetected; }
+ inline QString name() const noexcept { return m_name; }
+ inline Utils::FilePath executable() const noexcept { return m_executable; }
+ inline Core::Id id() const noexcept { return m_id; }
+ inline bool hasUnsavedChanges() const noexcept { return m_unsavedChanges; }
+ inline void setSaved() { m_unsavedChanges = false; }
+ void update(const QString &name, const Utils::FilePath &exe);
+
+private:
+ void self_check();
+ void update_tooltip(const Version &version);
+ void update_tooltip();
+ QString m_name;
+ QString m_tooltip;
+ Utils::FilePath m_executable;
+ bool m_autoDetected;
+ bool m_pathExists;
+ bool m_pathIsFile;
+ bool m_pathIsExecutable;
+ Core::Id m_id;
+
+ bool m_unsavedChanges = false;
+};
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/mesonprojectmanager/tests/resources/simplecproject/main.c b/src/plugins/mesonprojectmanager/tests/resources/simplecproject/main.c
new file mode 100644
index 0000000000..e5a9ccbdf4
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/resources/simplecproject/main.c
@@ -0,0 +1,4 @@
+int main(int argc, char** argv)
+{
+ return 0;
+}
diff --git a/src/plugins/mesonprojectmanager/tests/resources/simplecproject/meson.build b/src/plugins/mesonprojectmanager/tests/resources/simplecproject/meson.build
new file mode 100644
index 0000000000..5a7009051e
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/resources/simplecproject/meson.build
@@ -0,0 +1,7 @@
+project('SimpleCProject', 'c',
+ version : '0.1',
+ default_options : ['warning_level=3'])
+
+executable('SimpleCProject',
+ 'main.c',
+ install : true)
diff --git a/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp
new file mode 100644
index 0000000000..03922a3455
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/testmesoninfoparser.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "exewrappers/mesonwrapper.h"
+#include "mesoninfoparser/mesoninfoparser.h"
+#include <iostream>
+#include <QDir>
+#include <QObject>
+#include <QString>
+#include <QTemporaryDir>
+#include <QTemporaryFile>
+#include <QtTest/QtTest>
+
+using namespace MesonProjectManager::Internal;
+
+struct projectData
+{
+ const char *name;
+ QString path;
+ QStringList targets;
+};
+
+namespace {
+static const QList<projectData> projectList{
+ {"Simple C Project", "SimpleCProject", {"SimpleCProject"}}};
+} // namespace
+
+#define WITH_CONFIGURED_PROJECT(_source_dir, _build_dir, ...) \
+ { \
+ QTemporaryDir _build_dir{"test-meson"}; \
+ const auto _meson = MesonWrapper("name", *MesonWrapper::find()); \
+ run_meson(_meson.setup(Utils::FilePath::fromString(_source_dir), \
+ Utils::FilePath::fromString(_build_dir.path()))); \
+ QVERIFY(isSetup(Utils::FilePath::fromString(_build_dir.path()))); \
+ __VA_ARGS__ \
+ }
+
+#define WITH_UNCONFIGURED_PROJECT(_source_dir, _intro_file, ...) \
+ { \
+ QTemporaryFile _intro_file; \
+ _intro_file.open(); \
+ const auto _meson = MesonWrapper("name", *MesonWrapper::find()); \
+ run_meson(_meson.introspect(Utils::FilePath::fromString(_source_dir)), &_intro_file); \
+ __VA_ARGS__ \
+ }
+
+class AMesonInfoParser : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() {}
+
+ void shouldListTargets_data()
+ {
+ QTest::addColumn<QString>("src_dir");
+ QTest::addColumn<QStringList>("expectedTargets");
+ for (const auto &project : projectList) {
+ QTest::newRow(project.name)
+ << QString("%1/%2").arg(MESON_SAMPLES_DIR).arg(project.path) << project.targets;
+ }
+ }
+
+ void shouldListTargets()
+ {
+ QFETCH(QString, src_dir);
+ QFETCH(QStringList, expectedTargets);
+ WITH_CONFIGURED_PROJECT(src_dir, build_dir, {
+ auto result = MesonInfoParser::parse(build_dir.path());
+ QStringList targetsNames;
+ std::transform(std::cbegin(result.targets),
+ std::cend(result.targets),
+ std::back_inserter(targetsNames),
+ [](const auto &target) { return target.name; });
+ QVERIFY(targetsNames == expectedTargets);
+ })
+
+ WITH_UNCONFIGURED_PROJECT(src_dir, introFile, {
+ auto result = MesonInfoParser::parse(&introFile);
+ QStringList targetsNames;
+ std::transform(std::cbegin(result.targets),
+ std::cend(result.targets),
+ std::back_inserter(targetsNames),
+ [](const auto &target) { return target.name; });
+ QVERIFY(targetsNames == expectedTargets);
+ })
+ }
+
+ void cleanupTestCase() {}
+};
+
+QTEST_MAIN(AMesonInfoParser)
+#include "testmesoninfoparser.moc"
diff --git a/src/plugins/mesonprojectmanager/tests/testmesonparser.cpp b/src/plugins/mesonprojectmanager/tests/testmesonparser.cpp
new file mode 100644
index 0000000000..6c7b3978e9
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/testmesonparser.cpp
@@ -0,0 +1,299 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include <project/outputparsers/mesonoutputparser.h>
+#include <iostream>
+#include <projectexplorer/taskhub.h>
+#include <utils/fileinprojectfinder.h>
+#include <utils/theme/theme.h>
+#include <utils/theme/theme_p.h>
+#include <QDir>
+#include <QObject>
+#include <QString>
+#include <QTemporaryDir>
+#include <QtTest/QtTest>
+
+using namespace MesonProjectManager::Internal;
+
+struct TestData
+{
+ QString stdo;
+ QStringList linesToExtract;
+};
+Q_DECLARE_METATYPE(TestData);
+
+static const TestData sample1{
+ R"(ERROR: Value "C++11" for combo option is not one of the choices. Possible choices are: "none", "c++98", "c++03", "c++11", "c++14", "c++17", "c++1z", "c++2a", "gnu++03", "gnu++11", "gnu++14", "gnu++17", "gnu++1z", "gnu++2a".
+ERROR: Value "true" for combo option is not one of the choices. Possible choices are: "shared", "static", "both".
+ERROR: Value shared is not boolean (true or false).
+)",
+ {
+ R"(ERROR: Value "C++11" for combo option is not one of the choices. Possible choices are: "none", "c++98", "c++03", "c++11", "c++14", "c++17", "c++1z", "c++2a", "gnu++03", "gnu++11", "gnu++14", "gnu++17", "gnu++1z", "gnu++2a".)",
+ R"(ERROR: Value "true" for combo option is not one of the choices. Possible choices are: "shared", "static", "both".)",
+ R"(ERROR: Value shared is not boolean (true or false).)",
+ }};
+
+static const TestData sample2{
+ R"(../core/meson.build:163:0: ERROR: could not get https://gitlab.com/mdds/mdds/-/archive/1.6.0/mdds-1.6.0.tar.gz is the internet available?)",
+ {R"(../core/meson.build:163:0: ERROR: could not get https://gitlab.com/mdds/mdds/-/archive/1.6.0/mdds-1.6.0.tar.gz is the internet available?)"}};
+
+static const TestData sample3{
+ R"!(
+The Meson build system
+Version: 0.54.0
+Source dir: /home/jeandet/Documents/prog/SciQLop
+Build dir: /home/jeandet/Documents/prog/build-SciQLop-Desktop-debug
+Build type: native build
+WARNING: Unknown options: "unknown"
+The value of new options can be set with:
+meson setup <builddir> --reconfigure -Dnew_option=new_value ...
+Project name: SciQLOP
+Project version: 1.1.0
+C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+Host machine cpu family: x86_64
+Host machine cpu: x86_64
+WARNING: rcc dependencies will not work reliably until this upstream issue is fixed: https://bugreports.qt.io/browse/QTBUG-45460
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Dependency qt5 found: YES 5.13.2 (cached)
+Found pkg-config: /usr/bin/pkg-config (1.6.3)
+Found CMake: /usr/bin/cmake (3.17.1)
+Run-time dependency cpp_utils found: NO (tried pkgconfig and cmake)
+Looking for a fallback subproject for the dependency cpp_utils
+
+|Executing subproject cpp_utils method meson
+|
+|Project name: cpp_utils
+|Project version: undefined
+|C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+|C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+|Program cppcheck found: YES (/usr/bin/cppcheck)
+|Run-time dependency catch2 found: NO (tried pkgconfig and cmake)
+|Looking for a fallback subproject for the dependency catch2
+|
+||Executing subproject catch2 method meson
+||
+||Project name: catch2
+||Project version: 2.9.0
+||C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+||C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+||Build targets in project: 1
+||Subproject catch2 finished.
+|
+|Dependency catch2 from subproject subprojects/catch2 found: YES 2.9.0
+|Build targets in project: 9
+|Subproject cpp_utils finished.
+
+Dependency cpp_utils from subproject subprojects/cpp_utils found: YES undefined
+Program moc-qt5 found: YES (/usr/bin/moc-qt5)
+Program rcc-qt5 found: YES (/usr/bin/rcc-qt5)
+Run-time dependency catalogicpp found: NO (tried pkgconfig and cmake)
+Looking for a fallback subproject for the dependency catalogicpp
+
+|Executing subproject catalogicpp method meson
+|
+|Project name: catalogicpp
+|Project version: 1.0.0
+|C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+|C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+|Dependency nlohmann_json found: YES 3.7.3 (cached)
+|Run-time dependency stduuid found: NO (tried pkgconfig and cmake)
+|Looking for a fallback subproject for the dependency stduuid
+|
+||Executing subproject stduuid method meson
+||
+||Project name: stduuid
+||Project version: 1.0.0
+||C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+||C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+||Build targets in project: 9
+||Subproject stduuid finished.
+|
+|Dependency stduuid from subproject subprojects/stduuid found: YES 1.0.0
+|Run-time dependency GTest found: NO (tried pkgconfig and system)
+|Looking for a fallback subproject for the dependency gtest
+|
+||Executing subproject gtest method meson
+||
+||Project name: gtest
+||Project version: 1.8.1
+||C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+||C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+||Dependency threads found: YES unknown (cached)
+||Dependency threads found: YES unknown (cached)
+||Dependency threads found: YES unknown (cached)
+||Dependency threads found: YES unknown (cached)
+||Build targets in project: 9
+||Subproject gtest finished.
+|
+|Dependency gtest from subproject subprojects/gtest found: YES 1.8.1
+|Build targets in project: 13
+|Subproject catalogicpp finished.
+
+Dependency catalogicpp from subproject subprojects/catalogicpp found: YES 1.0.0
+Dependency pybind11 found: YES 2.5.0 (cached)
+Run-time dependency timeseries found: NO (tried pkgconfig and cmake)
+Looking for a fallback subproject for the dependency TimeSeries
+
+|Executing subproject TimeSeries method meson
+|
+|Project name: TimeSeries
+|Project version: 0.1
+|C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+|C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+|Dependency gtest from subproject subprojects/gtest found: YES 1.8.1
+|Run-time dependency benchmark found: NO (tried pkgconfig and cmake)
+|Looking for a fallback subproject for the dependency benchmark
+|
+||Executing subproject google-benchmark method meson
+||
+||Project name: benchmark
+||Project version: 1.4.1
+||C++ compiler for the host machine: /usr/lib64/ccache/g++ (gcc 10.0.1 "g++ (GCC) 10.0.1 20200328 (Red Hat 10.0.1-0.11)")
+||C++ linker for the host machine: /usr/lib64/ccache/g++ ld.bfd 2.34-2
+||Dependency threads found: YES unknown (cached)
+||Build targets in project: 15
+||Subproject google-benchmark finished.
+|
+|Dependency benchmark from subproject subprojects/google-benchmark found: YES 1.4.1
+|Build targets in project: 22
+|Subproject TimeSeries finished.
+
+Dependency TimeSeries from subproject subprojects/TimeSeries found: YES 0.1
+Dependency cpp_utils found: YES undefined (cached)
+Detecting Qt5 tools
+ moc: YES (/usr/lib64/qt5/bin/moc, 5.13.2)
+ uic: YES (/usr/lib64/qt5/bin/uic, 5.13.2)
+ rcc: YES (/usr/lib64/qt5/bin/rcc, 5.13.2)
+ lrelease: YES (/usr/lib64/qt5/bin/lrelease, 5.13.2)
+Program python3 found: YES (/usr/bin/python3)
+Program shiboken2 found: YES (/usr/bin/shiboken2)
+Program python4Ul3 (PySide2, shiboken2, shiboken2_generator, numpy) found: YES (/usr/bin/python3) modules: PySide2, shiboken2, shiboken2_generator, numpy
+Dependency python found: YES (pkgconfig)
+WARNING: Project targeting '>=0.51.0' but tried to use feature introduced in '0.53.0': embed arg in python_installation.dependency
+Dependency python found: YES (pkgconfig)
+Program cppcheck found: YES (/usr/bin/cppcheck)
+Build targets in project: 45
+WARNING: Project specifies a minimum meson_version '>=0.51.0' but uses features which were added in newer versions:
+ * 0.53.0: {'embed arg in python_installation.dependency'}
+WARNING: Deprecated features used:
+ * 0.53.0: {'embed arg in python_installation.dependency'}
+
+SciQLOP 1.1.0
+
+ Subprojects
+ TimeSeries: YES
+ catalogicpp: YES
+ catch2: YES
+ cpp_utils: YES
+ google-benchmark: YES
+ gtest: YES
+ stduuid: YES
+
+Found ninja-1.10.0 at /usr/bin/ninja
+)!",
+ {
+ R"(WARNING: Unknown options: "unknown")",
+ R"(The value of new options can be set with:)",
+ R"(meson setup <builddir> --reconfigure -Dnew_option=new_value ...)",
+ R"(WARNING: rcc dependencies will not work reliably until this upstream issue is fixed: https://bugreports.qt.io/browse/QTBUG-45460)",
+ R"(WARNING: Project targeting '>=0.51.0' but tried to use feature introduced in '0.53.0': embed arg in python_installation.dependency)",
+ R"(WARNING: Project specifies a minimum meson_version '>=0.51.0' but uses features which were added in newer versions:)",
+ R"( * 0.53.0: {'embed arg in python_installation.dependency'})",
+ R"(WARNING: Deprecated features used:)",
+ R"( * 0.53.0: {'embed arg in python_installation.dependency'})",
+ }};
+
+static const TestData sample4{
+ R"([0/1] Regenerating build files.
+The Meson build system
+Version: 0.54.0
+Source dir: /home/jeandet/Documents/prog/SciQLop
+Build dir: /home/jeandet/Documents/prog/build-SciQLop-Desktop-debug
+Build type: native build
+
+../SciQLop/meson.build:21:0: ERROR: Expecting eof got rparen.
+)
+^
+
+A full log can be found at /home/jeandet/Documents/prog/build-SciQLop-Desktop-debug/meson-logs/meson-log.txt
+FAILED: build.ninja
+/usr/bin/meson --internal regenerate /home/jeandet/Documents/prog/SciQLop /home/jeandet/Documents/prog/build-SciQLop-Desktop-debug --backend ninja
+ninja: error: rebuilding 'build.ninja': subcommand failed
+)",
+ {R"(../SciQLop/meson.build:21:0: ERROR: Expecting eof got rparen.)"}};
+
+QStringList feedParser(MesonOutputParser &parser, const TestData &data)
+{
+ QStringList extractedLines;
+ auto lines = data.stdo.split('\n');
+ std::for_each(std::cbegin(lines), std::cend(lines), [&](const auto &line) {
+ Utils::OutputLineParser::Result result
+ = parser.handleLine(line, Utils::OutputFormat::StdOutFormat);
+ if (result.status == Utils::OutputLineParser::Status::Done)
+ extractedLines << line;
+ });
+ return extractedLines;
+}
+
+class AMesonOutputParser : public QObject
+{
+ Q_OBJECT
+
+ std::size_t task_count;
+ std::size_t error_count;
+
+private slots:
+ void initTestCase() {}
+ void extractProgress_data()
+ {
+ QTest::addColumn<TestData>("testData");
+ QTest::newRow("sample1") << sample1;
+ QTest::newRow("sample2") << sample2;
+ QTest::newRow("sample3") << sample3;
+ QTest::newRow("sample4") << sample4;
+ }
+ void extractProgress()
+ {
+ QFETCH(TestData, testData);
+ error_count = 0;
+ task_count = 0;
+ MesonOutputParser parser;
+ auto extracetdLines = feedParser(parser, testData);
+ QCOMPARE(extracetdLines, testData.linesToExtract);
+ }
+ void cleanupTestCase() {}
+};
+
+QTEST_MAIN(AMesonOutputParser)
+
+#include "testmesonparser.moc"
diff --git a/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp
new file mode 100644
index 0000000000..d3c5284ea6
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/testmesonwrapper.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "exewrappers/mesonwrapper.h"
+#include <iostream>
+#include <QDir>
+#include <QObject>
+#include <QString>
+#include <QTemporaryDir>
+#include <QtTest/QtTest>
+
+using namespace MesonProjectManager::Internal;
+
+namespace {
+static const QList<QPair<const char *, QString>> projectList{{"Simple C Project", "SimpleCProject"}};
+} // namespace
+
+class AMesonWrapper : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() {}
+
+ void shouldFindMesonFromPATH()
+ {
+ const auto path = MesonWrapper::find();
+ QVERIFY(path);
+ QVERIFY(path->exists());
+ }
+
+ void shouldReportMesonVersion()
+ {
+ const auto meson = MesonWrapper("name", *MesonWrapper::find());
+ QVERIFY(meson.isValid());
+ QVERIFY(meson.version().major == 0);
+ QVERIFY(meson.version().minor >= 50);
+ QVERIFY(meson.version().minor <= 100);
+ QVERIFY(meson.version().patch >= 0);
+ }
+
+ void shouldSetupGivenProjects_data()
+ {
+ QTest::addColumn<QString>("src_dir");
+ for (const auto &project : projectList) {
+ QTest::newRow(project.first)
+ << QString("%1/%2").arg(MESON_SAMPLES_DIR).arg(project.second);
+ }
+ }
+
+ void shouldSetupGivenProjects()
+ {
+ QFETCH(QString, src_dir);
+ QTemporaryDir build_dir{"test-meson"};
+ const auto meson = MesonWrapper("name", *MesonWrapper::find());
+ QVERIFY(run_meson(meson.setup(Utils::FilePath::fromString(src_dir),
+ Utils::FilePath::fromString(build_dir.path()))));
+ QVERIFY(
+ Utils::FilePath::fromString(build_dir.path() + "/meson-info/meson-info.json").exists());
+ QVERIFY(isSetup(Utils::FilePath::fromString(build_dir.path())));
+ }
+
+ void shouldReConfigureGivenProjects_data()
+ {
+ QTest::addColumn<QString>("src_dir");
+ for (const auto &project : projectList) {
+ QTest::newRow(project.first)
+ << QString("%1/%2").arg(MESON_SAMPLES_DIR).arg(project.second);
+ }
+ }
+
+ void shouldReConfigureGivenProjects()
+ {
+ QFETCH(QString, src_dir);
+ QTemporaryDir build_dir{"test-meson"};
+ const auto meson = MesonWrapper("name", *MesonWrapper::find());
+ QVERIFY(run_meson(meson.setup(Utils::FilePath::fromString(src_dir),
+ Utils::FilePath::fromString(build_dir.path()))));
+ QVERIFY(run_meson(meson.configure(Utils::FilePath::fromString(src_dir),
+ Utils::FilePath::fromString(build_dir.path()))));
+ }
+
+ void cleanupTestCase() {}
+};
+
+QTEST_MAIN(AMesonWrapper)
+#include "testmesonwrapper.moc"
diff --git a/src/plugins/mesonprojectmanager/tests/testninjaparser.cpp b/src/plugins/mesonprojectmanager/tests/testninjaparser.cpp
new file mode 100644
index 0000000000..0ce1530197
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/tests/testninjaparser.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include <project/outputparsers/ninjaparser.h>
+#include <iostream>
+#include <QDir>
+#include <QObject>
+#include <QString>
+#include <QTemporaryDir>
+#include <QtTest/QtTest>
+
+using namespace MesonProjectManager::Internal;
+
+struct TestData
+{
+ QString ninjaSTDO;
+ std::vector<std::size_t> steps;
+ std::size_t warnings;
+ std::size_t errors;
+};
+Q_DECLARE_METATYPE(TestData);
+
+static const TestData sample1{
+ R"([1/2] Compiling C object 'SimpleCProject@exe/main.c.o'
+../../qt-creator/src/plugins/mesonprojectmanager/tests/resources/SimpleCproject/main.c: In function ‘main’:
+../../qt-creator/src/plugins/mesonprojectmanager/tests/resources/SimpleCproject/main.c:1:14: warning: unused parameter ‘argc’ [-Wunused-parameter]
+ 1 | int main(int argc, char** argv)
+ | ~~~~^~~~
+../../qt-creator/src/plugins/mesonprojectmanager/tests/resources/SimpleCproject/main.c:1:27: warning: unused parameter ‘argv’ [-Wunused-parameter]
+ 1 | int main(int argc, char** argv)
+ | ~~~~~~~^~~~
+[2/2] Linking target SimpleCProject)",
+ {50, 100},
+ 0Ul,
+ 0Ul};
+
+static const TestData sample2{
+ R"([1/10] should skip second this one ->[30/10]
+ [2/10] <- should skip this one
+[11111] <- should skip this one
+[a/a] <- should skip this one
+[1] <- should skip this one
+[ 1 / 1 ] <- should skip this one
+[10/10 <- should skip this one
+10/10] <- should skip this one
+[-1/10] <- should skip this one
+[10/10]
+)",
+ {10, 100},
+ 0Ul,
+ 0Ul};
+
+void feedParser(NinjaParser &parser, const TestData &data)
+{
+ auto lines = data.ninjaSTDO.split('\n');
+ std::for_each(std::cbegin(lines), std::cend(lines), [&](const auto &line) {
+ parser.handleLine(line, Utils::OutputFormat::StdOutFormat);
+ });
+}
+
+class ANinjaParser : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase() {}
+ void extractProgress_data()
+ {
+ QTest::addColumn<TestData>("testData");
+ QTest::newRow("sample1") << sample1;
+ QTest::newRow("sample2") << sample2;
+ }
+ void extractProgress()
+ {
+ QFETCH(TestData, testData);
+ std::vector<std::size_t> steps;
+ NinjaParser parser;
+ connect(&parser, &NinjaParser::reportProgress, [&](int progress) {
+ steps.push_back(progress);
+ });
+ feedParser(parser, testData);
+ QVERIFY(steps == testData.steps);
+ }
+ void cleanupTestCase() {}
+};
+
+QTEST_MAIN(ANinjaParser)
+#include "testninjaparser.moc"
diff --git a/src/plugins/mesonprojectmanager/versionhelper.h b/src/plugins/mesonprojectmanager/versionhelper.h
new file mode 100644
index 0000000000..5db2e238a8
--- /dev/null
+++ b/src/plugins/mesonprojectmanager/versionhelper.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#pragma once
+#include <QRegularExpression>
+#include <QString>
+
+namespace MesonProjectManager {
+namespace Internal {
+struct Version
+{
+ int major = -1;
+ int minor = -1;
+ int patch = -1;
+ bool isValid = false;
+ Version() = default;
+ Version(const Version &) = default;
+ Version(Version &&) = default;
+ Version &operator=(const Version &) = default;
+ Version &operator=(Version &&) = default;
+
+ bool operator==(const Version &other)
+ {
+ return other.isValid && isValid && major == other.major && minor == other.minor
+ && patch == other.patch;
+ }
+
+ Version(int major, int minor, int patch)
+ : major{major}
+ , minor{minor}
+ , patch{patch}
+ , isValid{major != -1 && minor != -1 && patch != -1}
+ {}
+ QString toQString() const noexcept
+ {
+ return QString("%1.%2.%3").arg(major).arg(minor).arg(patch);
+ }
+ static inline Version fromString(const QString &str)
+ {
+ QRegularExpression regex{R"((\d+).(\d+).(\d+))"};
+ auto matched = regex.match(str);
+ if (matched.hasMatch())
+ return Version{matched.captured(1).toInt(),
+ matched.captured(2).toInt(),
+ matched.captured(3).toInt()};
+ return Version{};
+ }
+};
+
+} // namespace Internal
+} // namespace MesonProjectManager
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 3e2e78b9d1..a9da5bf019 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -26,6 +26,7 @@ SUBDIRS = \
debugger \
cpaster \
cmakeprojectmanager \
+ mesonprojectmanager \
autotoolsprojectmanager \
fakevim \
emacskeys \
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index 4a5428fa21..abae37febf 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -21,6 +21,7 @@ Project {
"classview/classview.qbs",
"clearcase/clearcase.qbs",
"cmakeprojectmanager/cmakeprojectmanager.qbs",
+ "mesonprojectmanager/mesonprojectmanager.qbs",
"compilationdatabaseprojectmanager/compilationdatabaseprojectmanager.qbs",
"coreplugin/coreplugin.qbs",
"coreplugin/images/logo/logo.qbs",
diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg
index f395ac519a..182c104e2f 100644
--- a/src/tools/icons/qtcreatoricons.svg
+++ b/src/tools/icons/qtcreatoricons.svg
@@ -3510,6 +3510,24 @@
inkscape:connector-curvature="0" />
</g>
<g
+ id="src/plugins/mesonprojectmanager/icons/meson_bw_logo"
+ transform="translate(25)">
+ <use
+ x="0"
+ y="0"
+ xlink:href="#backgroundRect_24"
+ id="use3468"
+ width="100%"
+ height="100%"
+ transform="translate(1040,64)"
+ style="display:inline" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccc"
+ d="m 1024.8541,486.4906 c -0.9743,2.43972 -1.8257,4.68139 -2.6746,7.16492 -0.2924,0.75342 -1.1797,1.3852 -1.9806,0.99464 -0.7128,-0.3945 -0.5016,-1.32039 -0.3309,-1.96401 0.6027,-2.09011 1.7301,-3.72872 2.4157,-5.78987 0.5968,-1.54777 1.0831,-3.14255 1.8098,-4.63645 0.3449,-0.81041 1.2024,-1.3909 2.1365,-1.11185 0.7741,0.25171 0.7619,1.02434 0.8311,1.69289 0.201,2.59046 0.022,5.20292 0.3793,7.78244 1.4851,-2.80096 2.5768,-5.45878 3.7721,-8.38888 0.2999,-0.80792 1.3179,-1.40764 2.1293,-0.9726 0.7535,0.57551 0.6694,1.62934 0.7257,2.48033 -0.016,2.41968 -0.059,4.27489 0.2641,6.67947 0.1261,1.11076 0.344,2.21741 0.3713,3.33589 -0.1702,0.99446 -1.7096,1.64289 -2.3612,0.72287 -0.4945,-0.76869 -0.3574,-1.71123 -0.4653,-2.57731 -0.1207,-2.00553 -0.059,-3.76869 -0.09,-5.77687 -0.8332,1.87595 -1.5739,3.79847 -2.5728,5.59662 -0.5105,0.93605 -0.9425,1.94136 -1.6745,2.73004 -0.5055,0.5036 -1.5398,0.54967 -1.8646,-0.18067 -0.2897,-0.60703 -0.2569,-1.30363 -0.3846,-1.95504 -0.2421,-1.93277 -0.3196,-3.88333 -0.4358,-5.82656 z"
+ style="fill:#000000"
+ id="path1746" />
+ </g>
+ <g
id="src/plugins/valgrind/images/kcachegrind"
transform="translate(112)">
<use
diff --git a/tests/manual/meson/mesonsampleproject/main.cpp b/tests/manual/meson/mesonsampleproject/main.cpp
new file mode 100644
index 0000000000..6dcfef8e8e
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/main.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonsampleproject.h"
+
+#include <QApplication>
+#include <QTranslator>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ QTranslator translator;
+ translator.load("mesonsampleproject_" + QLocale::system().name());
+ a.installTranslator(&translator);
+ MesonSampleProject w;
+ w.show();
+ return a.exec();
+}
diff --git a/tests/manual/meson/mesonsampleproject/meson.build b/tests/manual/meson/mesonsampleproject/meson.build
new file mode 100644
index 0000000000..901285a587
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/meson.build
@@ -0,0 +1,19 @@
+project('mesonsampleproject', 'cpp',default_options : ['cpp_std=c++11'])
+
+# Documentation: https://mesonbuild.com/Qt5-module.html
+qt5 = import('qt5')
+qt5dep = dependency('qt5', modules : ['Core', 'Widgets'])
+
+translations = qt5.compile_translations(ts_files : 'mesonsampleproject_fr_FR.ts', build_by_default : true)
+
+generated_files = qt5.preprocess(
+ moc_headers : 'mesonsampleproject.h',
+ ui_files : 'mesonsampleproject.ui',
+ dependencies: [qt5dep])
+
+executable('mesonsampleproject'
+ , 'main.cpp'
+ , 'mesonsampleproject.cpp'
+ , generated_files
+ , dependencies : [qt5dep]
+ , install : true)
diff --git a/tests/manual/meson/mesonsampleproject/mesonsampleproject.cpp b/tests/manual/meson/mesonsampleproject/mesonsampleproject.cpp
new file mode 100644
index 0000000000..9840775622
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/mesonsampleproject.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#include "mesonsampleproject.h"
+#include "ui_mesonsampleproject.h"
+
+MesonSampleProject::MesonSampleProject(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MesonSampleProject)
+{
+ ui->setupUi(this);
+}
+
+MesonSampleProject::~MesonSampleProject()
+{
+ delete ui;
+}
+
diff --git a/tests/manual/meson/mesonsampleproject/mesonsampleproject.h b/tests/manual/meson/mesonsampleproject/mesonsampleproject.h
new file mode 100644
index 0000000000..b02897e0a4
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/mesonsampleproject.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 Alexis Jeandet.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+#ifndef MESONSAMPLEPROJECT_H
+#define MESONSAMPLEPROJECT_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class MesonSampleProject; }
+QT_END_NAMESPACE
+
+class MesonSampleProject : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MesonSampleProject(QWidget *parent = nullptr);
+ ~MesonSampleProject();
+
+private:
+ Ui::MesonSampleProject *ui;
+};
+#endif // MESONSAMPLEPROJECT_H
diff --git a/tests/manual/meson/mesonsampleproject/mesonsampleproject.ui b/tests/manual/meson/mesonsampleproject/mesonsampleproject.ui
new file mode 100644
index 0000000000..51e51e1248
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/mesonsampleproject.ui
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MesonSampleProject</class>
+ <widget class="QMainWindow" name="MesonSampleProject">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>MesonSampleProject</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>This is a sample meson project</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>29</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tests/manual/meson/mesonsampleproject/mesonsampleproject_fr_FR.ts b/tests/manual/meson/mesonsampleproject/mesonsampleproject_fr_FR.ts
new file mode 100644
index 0000000000..1b4f705da2
--- /dev/null
+++ b/tests/manual/meson/mesonsampleproject/mesonsampleproject_fr_FR.ts
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="fr_FR">
+<context>
+ <name>MesonSampleProject</name>
+ <message>
+ <location filename="mesonsampleproject.ui" line="14"/>
+ <source>MesonSampleProject</source>
+ <translation>Projet de démonstration Meson</translation>
+ </message>
+ <message>
+ <location filename="mesonsampleproject.ui" line="34"/>
+ <source>This is a sample meson project</source>
+ <translation>Ceci est un projet de démonstration pour Meson</translation>
+ </message>
+</context>
+</TS>