aboutsummaryrefslogtreecommitdiff
path: root/meson
diff options
context:
space:
mode:
authorJussi Pakkanen <jpakkane@gmail.com>2016-01-16 17:21:05 +0200
committerJussi Pakkanen <jpakkane@gmail.com>2016-01-16 17:21:05 +0200
commit1510522b1b9970376a1e1cc5f39e00d8749ec19a (patch)
tree90d475d1e03df898210df467d7dedc25c1980873 /meson
parent2ee27504a83dca9982c50459e46f1b39108dc278 (diff)
downloadmeson-1510522b1b9970376a1e1cc5f39e00d8749ec19a.zip
meson-1510522b1b9970376a1e1cc5f39e00d8749ec19a.tar.gz
meson-1510522b1b9970376a1e1cc5f39e00d8749ec19a.tar.bz2
Moved mesongui into module.
Diffstat (limited to 'meson')
-rw-r--r--meson/mesonmain.ui248
-rw-r--r--meson/mesonrunner.ui52
-rw-r--r--meson/mesonstart.ui119
-rw-r--r--meson/mgui.py565
-rw-r--r--meson/mintro.py212
5 files changed, 1196 insertions, 0 deletions
diff --git a/meson/mesonmain.ui b/meson/mesonmain.ui
new file mode 100644
index 0000000..209584b
--- /dev/null
+++ b/meson/mesonmain.ui
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>740</width>
+ <height>613</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Meson</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Project</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="project_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Source directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="srcdir_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Build directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="builddir_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Build type</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="buildtype_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Backend</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="backend_label">
+ <property name="text">
+ <string>Ninja</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>2</number>
+ </property>
+ <widget class="QWidget" name="core_tab">
+ <attribute name="title">
+ <string>Core data</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_6">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="core_view"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="path_tab">
+ <attribute name="title">
+ <string>Paths</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="path_view"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="option_tab">
+ <attribute name="title">
+ <string>Options</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <layout class="QFormLayout" name="option_form"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="dependency_tab">
+ <attribute name="title">
+ <string>Dependencies</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_5">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="dep_view"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="target_tab">
+ <attribute name="title">
+ <string>Build targets</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QTreeView" name="target_view"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="6" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="save_button">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="compile_button">
+ <property name="text">
+ <string>Compile</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="test_button">
+ <property name="text">
+ <string>Run tests</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="install_button">
+ <property name="text">
+ <string>Install</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="clean_button">
+ <property name="text">
+ <string>Clean</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>740</width>
+ <height>25</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionSave"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <addaction name="menuFile"/>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ <action name="actionSave">
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ </action>
+ <action name="actionQuit">
+ <property name="text">
+ <string>&amp;Quit</string>
+ </property>
+ </action>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/meson/mesonrunner.ui b/meson/mesonrunner.ui
new file mode 100644
index 0000000..942c6bd
--- /dev/null
+++ b/meson/mesonrunner.ui
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>rundialog</class>
+ <widget class="QDialog" name="rundialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>581</width>
+ <height>368</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>External process output</string>
+ </property>
+ <property name="modal">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="timelabel">
+ <property name="text">
+ <string>Compile time: 0:0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="termbutton">
+ <property name="text">
+ <string>Terminate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QTextEdit" name="console">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/meson/mesonstart.ui b/meson/mesonstart.ui
new file mode 100644
index 0000000..c6c5f96
--- /dev/null
+++ b/meson/mesonstart.ui
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>644</width>
+ <height>192</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Meson</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Source directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="source_entry">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="source_browse_button">
+ <property name="text">
+ <string>Browse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Build directory</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="build_entry">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="build_browse_button">
+ <property name="text">
+ <string>Browse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Cross file</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="cross_entry">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="cross_browse_button">
+ <property name="text">
+ <string>Browse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="generate_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Generate</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>644</width>
+ <height>25</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/meson/mgui.py b/meson/mgui.py
new file mode 100644
index 0000000..6e57ce7
--- /dev/null
+++ b/meson/mgui.py
@@ -0,0 +1,565 @@
+#!/usr/bin/env python3
+
+# Copyright 2013-2015 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys, os, pickle, time, shutil
+from . import build, coredata, environment, mesonlib
+from PyQt5 import uic
+from PyQt5.QtWidgets import QApplication, QMainWindow, QHeaderView
+from PyQt5.QtWidgets import QComboBox, QCheckBox
+from PyQt5.QtCore import QAbstractItemModel, QModelIndex, QVariant, QTimer
+import PyQt5.QtCore
+import PyQt5.QtWidgets
+
+priv_dir = os.path.split(os.path.abspath(os.path.realpath(__file__)))[0]
+
+class PathModel(QAbstractItemModel):
+ def __init__(self, coredata):
+ super().__init__()
+ self.coredata = coredata
+ self.names = ['Prefix', 'Library dir', 'Binary dir', 'Include dir', 'Data dir',\
+ 'Man dir', 'Locale dir']
+ self.attr_name = ['prefix', 'libdir', 'bindir', 'includedir', 'datadir', \
+ 'mandir', 'localedir']
+
+ def args(self, index):
+ if index.column() == 1:
+ editable = PyQt5.QtCore.Qt.ItemIsEditable
+ else:
+ editable= 0
+ return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled | editable
+
+ def rowCount(self, index):
+ if index.isValid():
+ return 0
+ return len(self.names)
+
+ def columnCount(self, index):
+ return 2
+
+ def headerData(self, section, orientation, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ if section == 1:
+ return QVariant('Path')
+ return QVariant('Type')
+
+ def index(self, row, column, parent):
+ return self.createIndex(row, column)
+
+ def data(self, index, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ row = index.row()
+ column = index.column()
+ if column == 0:
+ return self.names[row]
+ return getattr(self.coredata, self.attr_name[row])
+
+ def parent(self, index):
+ return QModelIndex()
+
+ def setData(self, index, value, role):
+ if role != PyQt5.QtCore.Qt.EditRole:
+ return False
+ row = index.row()
+ column = index.column()
+ s = str(value)
+ setattr(self.coredata, self.attr_name[row], s)
+ self.dataChanged.emit(self.createIndex(row, column), self.createIndex(row, column))
+ return True
+
+class TargetModel(QAbstractItemModel):
+ def __init__(self, builddata):
+ super().__init__()
+ self.targets = []
+ for target in builddata.get_targets().values():
+ name = target.get_basename()
+ num_sources = len(target.get_sources()) + len(target.get_generated_sources())
+ if isinstance(target, build.Executable):
+ typename = 'executable'
+ elif isinstance(target, build.SharedLibrary):
+ typename = 'shared library'
+ elif isinstance(target, build.StaticLibrary):
+ typename = 'static library'
+ elif isinstance(target, build.CustomTarget):
+ typename = 'custom'
+ else:
+ typename = 'unknown'
+ if target.should_install():
+ installed = 'Yes'
+ else:
+ installed = 'No'
+ self.targets.append((name, typename, installed, num_sources))
+
+ def args(self, index):
+ return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled
+
+ def rowCount(self, index):
+ if index.isValid():
+ return 0
+ return len(self.targets)
+
+ def columnCount(self, index):
+ return 4
+
+ def headerData(self, section, orientation, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ if section == 3:
+ return QVariant('Source files')
+ if section == 2:
+ return QVariant('Installed')
+ if section == 1:
+ return QVariant('Type')
+ return QVariant('Name')
+
+ def data(self, index, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ row = index.row()
+ column = index.column()
+ return self.targets[row][column]
+
+ def index(self, row, column, parent):
+ return self.createIndex(row, column)
+
+ def parent(self, index):
+ return QModelIndex()
+
+class DependencyModel(QAbstractItemModel):
+ def __init__(self, coredata):
+ super().__init__()
+ self.deps = []
+ for k in coredata.deps.keys():
+ bd = coredata.deps[k]
+ name = k
+ found = bd.found()
+ if found:
+ cflags = str(bd.get_compile_args())
+ libs = str(bd.get_link_args())
+ found = 'yes'
+ else:
+ cflags = ''
+ libs = ''
+ found = 'no'
+ self.deps.append((name, found, cflags, libs))
+
+ def args(self, index):
+ return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled
+
+ def rowCount(self, index):
+ if index.isValid():
+ return 0
+ return len(self.deps)
+
+ def columnCount(self, index):
+ return 4
+
+ def headerData(self, section, orientation, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ if section == 3:
+ return QVariant('Link args')
+ if section == 2:
+ return QVariant('Compile args')
+ if section == 1:
+ return QVariant('Found')
+ return QVariant('Name')
+
+ def data(self, index, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ row = index.row()
+ column = index.column()
+ return self.deps[row][column]
+
+ def index(self, row, column, parent):
+ return self.createIndex(row, column)
+
+ def parent(self, index):
+ return QModelIndex()
+
+class CoreModel(QAbstractItemModel):
+ def __init__(self, core_data):
+ super().__init__()
+ self.elems = []
+ for langname, comp in core_data.compilers.items():
+ self.elems.append((langname + ' compiler', str(comp.get_exelist())))
+ for langname, comp in core_data.cross_compilers.items():
+ self.elems.append((langname + ' cross compiler', str(comp.get_exelist())))
+
+ def args(self, index):
+ return PyQt5.QtCore.Qt.ItemIsSelectable | PyQt5.QtCore.Qt.ItemIsEnabled
+
+ def rowCount(self, index):
+ if index.isValid():
+ return 0
+ return len(self.elems)
+
+ def columnCount(self, index):
+ return 2
+
+ def headerData(self, section, orientation, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ if section == 1:
+ return QVariant('Value')
+ return QVariant('Name')
+
+ def data(self, index, role):
+ if role != PyQt5.QtCore.Qt.DisplayRole:
+ return QVariant()
+ row = index.row()
+ column = index.column()
+ return self.elems[row][column]
+
+ def index(self, row, column, parent):
+ return self.createIndex(row, column)
+
+ def parent(self, index):
+ return QModelIndex()
+
+class OptionForm:
+ def __init__(self, coredata, form):
+ self.coredata = coredata
+ self.form = form
+ form.addRow(PyQt5.QtWidgets.QLabel("Meson options"))
+ combo = QComboBox()
+ combo.addItem('plain')
+ combo.addItem('debug')
+ combo.addItem('debugoptimized')
+ combo.addItem('release')
+ combo.setCurrentText(self.coredata.get_builtin_option('buildtype'))
+ combo.currentTextChanged.connect(self.build_type_changed)
+ self.form.addRow('Build type', combo)
+ strip = QCheckBox("")
+ strip.setChecked(self.coredata.get_builtin_option('strip'))
+ strip.stateChanged.connect(self.strip_changed)
+ self.form.addRow('Strip on install', strip)
+ coverage = QCheckBox("")
+ coverage.setChecked(self.coredata.get_builtin_option('coverage'))
+ coverage.stateChanged.connect(self.coverage_changed)
+ self.form.addRow('Enable coverage', coverage)
+ pch = QCheckBox("")
+ pch.setChecked(self.coredata.get_builtin_option('use_pch'))
+ pch.stateChanged.connect(self.pch_changed)
+ self.form.addRow('Enable pch', pch)
+ unity = QCheckBox("")
+ unity.setChecked(self.coredata.get_builtin_option('unity'))
+ unity.stateChanged.connect(self.unity_changed)
+ self.form.addRow('Unity build', unity)
+ form.addRow(PyQt5.QtWidgets.QLabel("Project options"))
+ self.set_user_options()
+
+ def set_user_options(self):
+ options = self.coredata.user_options
+ keys = list(options.keys())
+ keys.sort()
+ self.opt_keys = keys
+ self.opt_widgets = []
+ for key in keys:
+ opt = options[key]
+ if isinstance(opt, mesonlib.UserStringOption):
+ w = PyQt5.QtWidgets.QLineEdit(opt.value)
+ w.textChanged.connect(self.user_option_changed)
+ elif isinstance(opt, mesonlib.UserBooleanOption):
+ w = QCheckBox('')
+ w.setChecked(opt.value)
+ w.stateChanged.connect(self.user_option_changed)
+ elif isinstance(opt, mesonlib.UserComboOption):
+ w = QComboBox()
+ for i in opt.choices:
+ w.addItem(i)
+ w.setCurrentText(opt.value)
+ w.currentTextChanged.connect(self.user_option_changed)
+ else:
+ raise RuntimeError("Unknown option type")
+ self.opt_widgets.append(w)
+ self.form.addRow(opt.description, w)
+
+ def user_option_changed(self, dummy=None):
+ for i in range(len(self.opt_keys)):
+ key = self.opt_keys[i]
+ w = self.opt_widgets[i]
+ if isinstance(w, PyQt5.QtWidgets.QLineEdit):
+ newval = w.text()
+ elif isinstance(w, QComboBox):
+ newval = w.currentText()
+ elif isinstance(w, QCheckBox):
+ if w.checkState() == 0:
+ newval = False
+ else:
+ newval = True
+ else:
+ raise RuntimeError('Unknown widget type')
+ self.coredata.user_options[key].set_value(newval)
+
+ def build_type_changed(self, newtype):
+ self.coredata.buildtype = newtype
+
+ def strip_changed(self, newState):
+ if newState == 0:
+ ns = False
+ else:
+ ns = True
+ self.coredata.strip = ns
+
+ def coverage_changed(self, newState):
+ if newState == 0:
+ ns = False
+ else:
+ ns = True
+ self.coredata.coverage = ns
+
+ def pch_changed(self, newState):
+ if newState == 0:
+ ns = False
+ else:
+ ns = True
+ self.coredata.use_pch = ns
+
+ def unity_changed(self, newState):
+ if newState == 0:
+ ns = False
+ else:
+ ns = True
+ self.coredata.unity = ns
+
+class ProcessRunner():
+ def __init__(self, rundir, cmdlist):
+ self.cmdlist = cmdlist
+ self.ui = uic.loadUi(os.path.join(priv_dir, 'mesonrunner.ui'))
+ self.timer = QTimer(self.ui)
+ self.timer.setInterval(1000)
+ self.timer.timeout.connect(self.timeout)
+ self.process = PyQt5.QtCore.QProcess()
+ self.process.setProcessChannelMode(PyQt5.QtCore.QProcess.MergedChannels)
+ self.process.setWorkingDirectory(rundir)
+ self.process.readyRead.connect(self.read_data)
+ self.process.finished.connect(self.finished)
+ self.ui.termbutton.clicked.connect(self.terminated)
+ self.return_value = 100
+
+ def run(self):
+ self.process.start(self.cmdlist[0], self.cmdlist[1:])
+ self.timer.start()
+ self.start_time = time.time()
+ return self.ui.exec()
+
+ def read_data(self):
+ while(self.process.canReadLine()):
+ txt = bytes(self.process.readLine()).decode('utf8')
+ self.ui.console.append(txt)
+
+ def finished(self):
+ self.read_data()
+ self.ui.termbutton.setText('Done')
+ self.timer.stop()
+ self.return_value = self.process.exitCode()
+
+ def terminated(self, foo):
+ self.process.kill()
+ self.timer.stop()
+ self.ui.done(self.return_value)
+
+ def timeout(self):
+ now = time.time()
+ duration = int(now - self.start_time)
+ msg = 'Elapsed time: %d:%d' % (duration // 60, duration % 60)
+ self.ui.timelabel.setText(msg)
+
+class MesonGui():
+ def __init__(self, respawner, build_dir):
+ self.respawner = respawner
+ uifile = os.path.join(priv_dir, 'mesonmain.ui')
+ self.ui = uic.loadUi(uifile)
+ self.coredata_file = os.path.join(build_dir, 'meson-private/coredata.dat')
+ self.build_file = os.path.join(build_dir, 'meson-private/build.dat')
+ if not os.path.exists(self.coredata_file):
+ print("Argument is not build directory.")
+ sys.exit(1)
+ self.coredata = pickle.load(open(self.coredata_file, 'rb'))
+ self.build = pickle.load(open(self.build_file, 'rb'))
+ self.build_dir = self.build.environment.build_dir
+ self.src_dir = self.build.environment.source_dir
+ self.build_models()
+ self.options = OptionForm(self.coredata, self.ui.option_form)
+ self.ui.show()
+
+ def hide(self):
+ self.ui.hide()
+
+ def geometry(self):
+ return self.ui.geometry()
+
+ def move(self, x, y):
+ return self.ui.move(x, y)
+
+ def size(self):
+ return self.ui.size()
+
+ def resize(self, s):
+ return self.ui.resize(s)
+
+ def build_models(self):
+ self.path_model = PathModel(self.coredata)
+ self.target_model = TargetModel(self.build)
+ self.dep_model = DependencyModel(self.coredata)
+ self.core_model = CoreModel(self.coredata)
+ self.fill_data()
+ self.ui.core_view.setModel(self.core_model)
+ hv = QHeaderView(1)
+ hv.setModel(self.core_model)
+ self.ui.core_view.setHeader(hv)
+ self.ui.path_view.setModel(self.path_model)
+ hv = QHeaderView(1)
+ hv.setModel(self.path_model)
+ self.ui.path_view.setHeader(hv)
+ self.ui.target_view.setModel(self.target_model)
+ hv = QHeaderView(1)
+ hv.setModel(self.target_model)
+ self.ui.target_view.setHeader(hv)
+ self.ui.dep_view.setModel(self.dep_model)
+ hv = QHeaderView(1)
+ hv.setModel(self.dep_model)
+ self.ui.dep_view.setHeader(hv)
+ self.ui.compile_button.clicked.connect(self.compile)
+ self.ui.test_button.clicked.connect(self.run_tests)
+ self.ui.install_button.clicked.connect(self.install)
+ self.ui.clean_button.clicked.connect(self.clean)
+ self.ui.save_button.clicked.connect(self.save)
+
+ def fill_data(self):
+ self.ui.project_label.setText(self.build.projects[''])
+ self.ui.srcdir_label.setText(self.src_dir)
+ self.ui.builddir_label.setText(self.build_dir)
+ if self.coredata.cross_file is None:
+ btype = 'Native build'
+ else:
+ btype = 'Cross build'
+ self.ui.buildtype_label.setText(btype)
+
+ def run_process(self, cmdlist):
+ cmdlist = [shutil.which(environment.detect_ninja())] + cmdlist
+ dialog = ProcessRunner(self.build.environment.build_dir, cmdlist)
+ dialog.run()
+ # All processes (at the moment) may change cache state
+ # so reload.
+ self.respawner.respawn()
+
+ def compile(self, foo):
+ self.run_process([])
+
+ def run_tests(self, foo):
+ self.run_process(['test'])
+
+ def install(self, foo):
+ self.run_process(['install'])
+
+ def clean(self, foo):
+ self.run_process(['clean'])
+
+ def save(self, foo):
+ pickle.dump(self.coredata, open(self.coredata_file, 'wb'))
+
+class Starter():
+ def __init__(self, sdir):
+ uifile = os.path.join(priv_dir, 'mesonstart.ui')
+ self.ui = uic.loadUi(uifile)
+ self.ui.source_entry.setText(sdir)
+ self.dialog = PyQt5.QtWidgets.QFileDialog()
+ if len(sdir) == 0:
+ self.dialog.setDirectory(os.getcwd())
+ else:
+ self.dialog.setDirectory(sdir)
+ self.ui.source_browse_button.clicked.connect(self.src_browse_clicked)
+ self.ui.build_browse_button.clicked.connect(self.build_browse_clicked)
+ self.ui.cross_browse_button.clicked.connect(self.cross_browse_clicked)
+ self.ui.source_entry.textChanged.connect(self.update_button)
+ self.ui.build_entry.textChanged.connect(self.update_button)
+ self.ui.generate_button.clicked.connect(self.generate)
+ self.update_button()
+ self.ui.show()
+
+ def generate(self):
+ srcdir = self.ui.source_entry.text()
+ builddir = self.ui.build_entry.text()
+ cross = self.ui.cross_entry.text()
+ cmdlist = [os.path.join(os.path.split(__file__)[0], 'meson.py'), srcdir, builddir]
+ if cross != '':
+ cmdlist += ['--cross', cross]
+ pr = ProcessRunner(os.getcwd(), cmdlist)
+ rvalue = pr.run()
+ if rvalue == 0:
+ os.execl(__file__, 'dummy', builddir)
+
+ def update_button(self):
+ if self.ui.source_entry.text() == '' or self.ui.build_entry.text() == '':
+ self.ui.generate_button.setEnabled(False)
+ else:
+ self.ui.generate_button.setEnabled(True)
+
+ def src_browse_clicked(self):
+ self.dialog.setFileMode(2)
+ if self.dialog.exec():
+ self.ui.source_entry.setText(self.dialog.selectedFiles()[0])
+
+ def build_browse_clicked(self):
+ self.dialog.setFileMode(2)
+ if self.dialog.exec():
+ self.ui.build_entry.setText(self.dialog.selectedFiles()[0])
+
+ def cross_browse_clicked(self):
+ self.dialog.setFileMode(1)
+ if self.dialog.exec():
+ self.ui.cross_entry.setText(self.dialog.selectedFiles()[0])
+
+# Rather than rewrite all classes and arrays to be
+# updateable, just rebuild the entire GUI from
+# scratch whenever data on disk changes.
+
+class MesonGuiRespawner():
+ def __init__(self, arg):
+ self.arg = arg
+ self.gui = MesonGui(self, self.arg)
+
+ def respawn(self):
+ geo = self.gui.geometry()
+ s = self.gui.size()
+ self.gui.hide()
+ self.gui = MesonGui(self, self.arg)
+ self.gui.move(geo.x(), geo.y())
+ self.gui.resize(s)
+ # Garbage collection takes care of the old gui widget
+
+
+def run(args): # SPECIAL, Qt wants all args, including command name.
+ app = QApplication(sys.argv)
+ if len(args) == 1:
+ arg = ""
+ elif len(args) == 2:
+ arg = sys.argv[1]
+ else:
+ print(sys.argv[0], "<build or source dir>")
+ return 1
+ if os.path.exists(os.path.join(arg, 'meson-private/coredata.dat')):
+ guirespawner = MesonGuiRespawner(arg)
+ else:
+ runner = Starter(arg)
+ return app.exec_()
+
+if __name__ == '__main__':
+ sys.exit(run(sys.argv))
diff --git a/meson/mintro.py b/meson/mintro.py
new file mode 100644
index 0000000..b088117
--- /dev/null
+++ b/meson/mintro.py
@@ -0,0 +1,212 @@
+#!/usr/bin/env python3
+
+# Copyright 2014-2016 The Meson development team
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""This is a helper script for IDE developers. It allows you to
+extract information such as list of targets, files, compiler flags,
+tests and so on. All output is in JSON for simple parsing.
+
+Currently only works for the Ninja backend. Others use generated
+project files and don't need this info."""
+
+import json, pickle
+from . import coredata, build, mesonlib
+import argparse
+import sys, os
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--targets', action='store_true', dest='list_targets', default=False,
+ help='List top level targets.')
+parser.add_argument('--target-files', action='store', dest='target_files', default=None,
+ help='List source files for a given target.')
+parser.add_argument('--buildsystem-files', action='store_true', dest='buildsystem_files', default=False,
+ help='List files that make up the build system.')
+parser.add_argument('--buildoptions', action='store_true', dest='buildoptions', default=False,
+ help='List all build options.')
+parser.add_argument('--tests', action='store_true', dest='tests', default=False,
+ help='List all unit tests.')
+parser.add_argument('--benchmarks', action='store_true', dest='benchmarks', default=False,
+ help='List all benchmarks.')
+parser.add_argument('--dependencies', action='store_true', dest='dependencies', default=False,
+ help='list external dependencies.')
+parser.add_argument('args', nargs='+')
+
+def list_targets(coredata, builddata):
+ tlist = []
+ for (idname, target) in builddata.get_targets().items():
+ t = {}
+ t['name'] = target.get_basename()
+ t['id'] = idname
+ fname = target.get_filename()
+ if isinstance(fname, list):
+ fname = [os.path.join(target.subdir, x) for x in fname]
+ else:
+ fname = os.path.join(target.subdir, fname)
+ t['filename'] = fname
+ if isinstance(target, build.Executable):
+ typename = 'executable'
+ elif isinstance(target, build.SharedLibrary):
+ typename = 'shared library'
+ elif isinstance(target, build.StaticLibrary):
+ typename = 'static library'
+ elif isinstance(target, build.CustomTarget):
+ typename = 'custom'
+ elif isinstance(target, build.RunTarget):
+ typename = 'run'
+ else:
+ typename = 'unknown'
+ t['type'] = typename
+ if target.should_install():
+ t['installed'] = True
+ else:
+ t['installed'] = False
+ tlist.append(t)
+ print(json.dumps(tlist))
+
+def list_target_files(target_name, coredata, builddata):
+ try:
+ t = builddata.targets[target_name]
+ sources = t.sources + t.extra_files
+ subdir = t.subdir
+ except KeyError:
+ print("Unknown target %s." % target_name)
+ sys.exit(1)
+ sources = [os.path.join(i.subdir, i.fname) for i in sources]
+ print(json.dumps(sources))
+
+def list_buildoptions(coredata, builddata):
+ buildtype= {'choices': ['plain', 'debug', 'debugoptimized', 'release'],
+ 'type' : 'combo',
+ 'value' : coredata.buildtype,
+ 'description' : 'Build type',
+ 'name' : 'type'}
+ strip = {'value' : coredata.strip,
+ 'type' : 'boolean',
+ 'description' : 'Strip on install',
+ 'name' : 'strip'}
+ coverage = {'value': coredata.coverage,
+ 'type' : 'boolean',
+ 'description' : 'Enable coverage',
+ 'name' : 'coverage'}
+ pch = {'value' : coredata.use_pch,
+ 'type' : 'boolean',
+ 'description' : 'Use precompiled headers',
+ 'name' : 'pch'}
+ unity = {'value' : coredata.unity,
+ 'type' : 'boolean',
+ 'description' : 'Unity build',
+ 'name' : 'unity'}
+ optlist = [buildtype, strip, coverage, pch, unity]
+ add_keys(optlist, coredata.user_options)
+ add_keys(optlist, coredata.compiler_options)
+ print(json.dumps(optlist))
+
+def add_keys(optlist, options):
+ keys = list(options.keys())
+ keys.sort()
+ for key in keys:
+ opt = options[key]
+ optdict = {}
+ optdict['name'] = key
+ optdict['value'] = opt.value
+ if isinstance(opt, mesonlib.UserStringOption):
+ typestr = 'string'
+ elif isinstance(opt, mesonlib.UserBooleanOption):
+ typestr = 'boolean'
+ elif isinstance(opt, mesonlib.UserComboOption):
+ optdict['choices'] = opt.choices
+ typestr = 'combo'
+ elif isinstance(opt, mesonlib.UserStringArrayOption):
+ typestr = 'stringarray'
+ else:
+ raise RuntimeError("Unknown option type")
+ optdict['type'] = typestr
+ optdict['description'] = opt.description
+ optlist.append(optdict)
+
+def list_buildsystem_files(coredata, builddata):
+ src_dir = builddata.environment.get_source_dir()
+ # I feel dirty about this. But only slightly.
+ filelist = []
+ for root, _, files in os.walk(src_dir):
+ for f in files:
+ if f == 'meson.build' or f == 'meson_options.txt':
+ filelist.append(os.path.relpath(os.path.join(root, f), src_dir))
+ print(json.dumps(filelist))
+
+def list_deps(coredata):
+ result = {}
+ for d in coredata.deps.values():
+ if d.found():
+ args = {'compile_args': d.get_compile_args(),
+ 'link_args': d.get_link_args()}
+ result[d.name] = args
+ print(json.dumps(result))
+
+def list_tests(testdata):
+ result = []
+ for t in testdata:
+ to = {}
+ if isinstance(t.fname, str):
+ fname = [t.fname]
+ else:
+ fname = t.fname
+ to['cmd'] = fname + t.cmd_args
+ to['env'] = t.env
+ to['name'] = t.name
+ to['workdir'] = t.workdir
+ to['timeout'] = t.timeout
+ to['suite'] = t.suite
+ result.append(to)
+ print(json.dumps(result))
+
+def run(args):
+ options = parser.parse_args(args)
+ if len(options.args) > 1:
+ print('Too many arguments')
+ return 1
+ elif len(options.args) == 1:
+ bdir = options.args[0]
+ else:
+ bdir = ''
+ corefile = os.path.join(bdir, 'meson-private/coredata.dat')
+ buildfile = os.path.join(bdir, 'meson-private/build.dat')
+ testfile = os.path.join(bdir, 'meson-private/meson_test_setup.dat')
+ benchmarkfile = os.path.join(bdir, 'meson-private/meson_benchmark_setup.dat')
+ coredata = pickle.load(open(corefile, 'rb'))
+ builddata = pickle.load(open(buildfile, 'rb'))
+ testdata = pickle.load(open(testfile, 'rb'))
+ benchmarkdata = pickle.load(open(benchmarkfile, 'rb'))
+ if options.list_targets:
+ list_targets(coredata, builddata)
+ elif options.target_files is not None:
+ list_target_files(options.target_files, coredata, builddata)
+ elif options.buildsystem_files:
+ list_buildsystem_files(coredata, builddata)
+ elif options.buildoptions:
+ list_buildoptions(coredata, builddata)
+ elif options.tests:
+ list_tests(testdata)
+ elif options.benchmarks:
+ list_tests(benchmarkdata)
+ elif options.dependencies:
+ list_deps(coredata)
+ else:
+ print('No command specified')
+ return 1
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(run(sys.argv[1:]))