mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-02 07:15:27 +08:00
qt 6.5.1 original
This commit is contained in:
133
util/accessibilityinspector/accessibilityinspector.cpp
Normal file
133
util/accessibilityinspector/accessibilityinspector.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "accessibilityinspector.h"
|
||||
|
||||
#include "screenreader.h"
|
||||
#include "optionswidget.h"
|
||||
#include "accessibilityscenemanager.h"
|
||||
|
||||
#include <QtDeclarative/QtDeclarative>
|
||||
|
||||
void MouseInterceptingGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
emit mousePressed(event->scenePos().toPoint());
|
||||
QGraphicsScene::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void MouseInterceptingGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
emit mouseDobleClicked();
|
||||
QGraphicsScene::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
AccessibilitySceneManager *sceneManager = 0;
|
||||
QAccessible::UpdateHandler previousUpdateHandler = 0;
|
||||
bool updateHandlerRecursion = false;
|
||||
void accessibilityUpdateHandler(QAccessibleEvent *event)
|
||||
{
|
||||
if (updateHandlerRecursion)
|
||||
return;
|
||||
|
||||
updateHandlerRecursion = true;
|
||||
|
||||
if (sceneManager) {
|
||||
sceneManager->handleUpdate(event);
|
||||
|
||||
//qDebug() << "update";
|
||||
}
|
||||
|
||||
if (previousUpdateHandler) // call prev just to be sure.
|
||||
previousUpdateHandler(event);
|
||||
|
||||
updateHandlerRecursion = false;
|
||||
}
|
||||
|
||||
AccessibilityInspector::AccessibilityInspector(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
AccessibilityInspector::~AccessibilityInspector()
|
||||
{
|
||||
delete optionsWidget;
|
||||
delete accessibilityScene;
|
||||
delete accessibilityView;
|
||||
delete accessibilityTreeScene;
|
||||
delete accessibilityTreeView;
|
||||
delete screenReader;
|
||||
}
|
||||
|
||||
void AccessibilityInspector::inspectWindow(QWindow *window)
|
||||
{
|
||||
qDebug() << "AccessibilityInspector::inspectWindow()" << window;
|
||||
if (window->parent() || window->transientParent())
|
||||
return;
|
||||
|
||||
optionsWidget = new OptionsWidget();
|
||||
|
||||
accessibilityScene = new MouseInterceptingGraphicsScene();
|
||||
|
||||
accessibilityView = new QGraphicsView();
|
||||
accessibilityView->setScene(accessibilityScene);
|
||||
accessibilityView->resize(640, 480);
|
||||
accessibilityView->scale(1.3, 1.3);
|
||||
|
||||
accessibilityTreeScene = new QGraphicsScene();
|
||||
|
||||
accessibilityTreeView = new QGraphicsView();
|
||||
accessibilityTreeView->setScene(accessibilityTreeScene);
|
||||
accessibilityTreeView->resize(640, 480);
|
||||
|
||||
sceneManager = new AccessibilitySceneManager();
|
||||
QObject::connect(optionsWidget, SIGNAL(optionsChanged()), sceneManager, SLOT(updateAccessibilitySceneItemFlags()));
|
||||
QObject::connect(optionsWidget, SIGNAL(refreshClicked()), sceneManager, SLOT(populateAccessibilityScene()));
|
||||
QObject::connect(optionsWidget, SIGNAL(refreshClicked()), sceneManager, SLOT(populateAccessibilityTreeScene()));
|
||||
QObject::connect(optionsWidget, SIGNAL(scaleChanged(int)), sceneManager, SLOT(changeScale(int)));
|
||||
|
||||
sceneManager->setOptionsWidget(optionsWidget);
|
||||
sceneManager->setRootWindow(window);
|
||||
sceneManager->setScene(accessibilityScene);
|
||||
sceneManager->setView(accessibilityView);
|
||||
sceneManager->setTreeScene(accessibilityTreeScene);
|
||||
sceneManager->setTreeView(accessibilityTreeView);
|
||||
|
||||
screenReader = new ScreenReader;
|
||||
QObject::connect(accessibilityScene, SIGNAL(mousePressed(QPoint)), screenReader, SLOT(touchPoint(QPoint)));
|
||||
QObject::connect(accessibilityScene, SIGNAL(mouseDobleClicked()), screenReader, SLOT(activate()));
|
||||
QObject::connect(screenReader, SIGNAL(selected(QObject*)), sceneManager, SLOT(setSelected(QObject*)));
|
||||
screenReader->setRootObject(window);
|
||||
screenReader->setOptionsWidget(optionsWidget);
|
||||
|
||||
previousUpdateHandler = QAccessible::installUpdateHandler(accessibilityUpdateHandler);
|
||||
|
||||
QTimer::singleShot(100, sceneManager, SLOT(populateAccessibilityScene()));
|
||||
QTimer::singleShot(100, sceneManager, SLOT(populateAccessibilityTreeScene()));
|
||||
|
||||
QSettings settings;
|
||||
accessibilityView->restoreGeometry(settings.value("accessiblityGeometry").toByteArray());
|
||||
accessibilityView->setObjectName(QLatin1String("accessibilityInspectorView"));
|
||||
accessibilityView->show();
|
||||
|
||||
|
||||
accessibilityTreeView->restoreGeometry(settings.value("treeGeometry").toByteArray());
|
||||
accessibilityTreeView->setObjectName(QLatin1String("accessibilityInspectorTreeView"));
|
||||
accessibilityTreeView->show();
|
||||
optionsWidget->restoreGeometry(settings.value("optionsGeometry").toByteArray());
|
||||
optionsWidget->setObjectName(QLatin1String("accessibilityInspectorOptions"));
|
||||
optionsWidget->show();
|
||||
}
|
||||
|
||||
void AccessibilityInspector::saveWindowGeometry()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue("accessiblityGeometry", accessibilityView->saveGeometry());
|
||||
settings.setValue("treeGeometry", accessibilityTreeView->saveGeometry());
|
||||
settings.setValue("optionsGeometry", optionsWidget->saveGeometry());
|
||||
}
|
||||
|
||||
QString translateRole(QAccessible::Role role)
|
||||
{
|
||||
return qAccessibleRoleString(role);
|
||||
}
|
||||
|
49
util/accessibilityinspector/accessibilityinspector.h
Normal file
49
util/accessibilityinspector/accessibilityinspector.h
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef ACCESSIBILITYINSPECTOR_H
|
||||
#define ACCESSIBILITYINSPECTOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qgraphicsscene.h>
|
||||
#include <QAccessible>
|
||||
|
||||
QString translateRole(QAccessible::Role role);
|
||||
|
||||
class OptionsWidget;
|
||||
class MouseInterceptingGraphicsScene;
|
||||
class QGraphicsView;
|
||||
class QGraphicsScene;
|
||||
class AccessibilitySceneManager;
|
||||
class ScreenReader;
|
||||
class AccessibilityInspector : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AccessibilityInspector(QObject *parent = nullptr);
|
||||
~AccessibilityInspector();
|
||||
void inspectWindow(QWindow *window);
|
||||
void saveWindowGeometry();
|
||||
signals:
|
||||
|
||||
private:
|
||||
OptionsWidget *optionsWidget;
|
||||
MouseInterceptingGraphicsScene *accessibilityScene;
|
||||
QGraphicsView *accessibilityView;
|
||||
QGraphicsScene *accessibilityTreeScene;
|
||||
QGraphicsView *accessibilityTreeView;
|
||||
ScreenReader *screenReader;
|
||||
};
|
||||
|
||||
class MouseInterceptingGraphicsScene : public QGraphicsScene
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
|
||||
signals:
|
||||
void mousePressed(const QPoint point);
|
||||
void mouseDobleClicked();
|
||||
};
|
||||
|
||||
#endif // ACCESSIBILITYINSPECTOR_H
|
19
util/accessibilityinspector/accessibilityinspector.pri
Normal file
19
util/accessibilityinspector/accessibilityinspector.pri
Normal file
@ -0,0 +1,19 @@
|
||||
QT += declarative
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
# DEFINES += ACCESSIBILITYINSPECTOR_NO_UITOOLS
|
||||
# QT += uitools
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/screenreader.h \
|
||||
$$PWD/optionswidget.h \
|
||||
$$PWD/accessibilityscenemanager.h \
|
||||
$$PWD/accessibilityinspector.h
|
||||
SOURCES += \
|
||||
$$PWD/optionswidget.cpp \
|
||||
$$PWD/accessibilityscenemanager.cpp \
|
||||
$$PWD/screenreader.cpp \
|
||||
$$PWD/accessibilityinspector.cpp
|
||||
|
||||
|
||||
|
5
util/accessibilityinspector/accessibilityinspector.pro
Normal file
5
util/accessibilityinspector/accessibilityinspector.pro
Normal file
@ -0,0 +1,5 @@
|
||||
include (accessibilityinspector.pri)
|
||||
|
||||
SOURCES += main.cpp \
|
||||
|
||||
CONFIG += console
|
444
util/accessibilityinspector/accessibilityscenemanager.cpp
Normal file
444
util/accessibilityinspector/accessibilityscenemanager.cpp
Normal file
@ -0,0 +1,444 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "accessibilityscenemanager.h"
|
||||
|
||||
AccessibilitySceneManager::AccessibilitySceneManager()
|
||||
{
|
||||
m_window = 0;
|
||||
m_view = 0;
|
||||
m_scene = 0;
|
||||
m_rootItem = 0;
|
||||
m_optionsWidget = 0;
|
||||
m_selectedObject = 0;
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::populateAccessibilityScene()
|
||||
{
|
||||
m_scene->clear();
|
||||
m_graphicsItems.clear();
|
||||
|
||||
QAccessibleInterface * rootInterface = m_window->accessibleRoot();
|
||||
if (!rootInterface)
|
||||
return;
|
||||
|
||||
populateAccessibilityScene(rootInterface, m_scene);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::updateAccessibilitySceneItemFlags()
|
||||
{
|
||||
qDebug() << "update";
|
||||
foreach (QObject *object, m_graphicsItems.keys()) {
|
||||
if (!object)
|
||||
continue;
|
||||
QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
|
||||
if (!interface)
|
||||
continue;
|
||||
updateItemFlags(m_graphicsItems.value(object), interface);
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::populateAccessibilityTreeScene()
|
||||
{
|
||||
m_treeScene->clear();
|
||||
QAccessibleInterface * rootInterface = m_window->accessibleRoot();
|
||||
if (!rootInterface) {
|
||||
qWarning("QWindow::accessibleRoot returned 0");
|
||||
return;
|
||||
}
|
||||
|
||||
populateAccessibilityTreeScene(rootInterface);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::handleUpdate(QAccessibleEvent *event)
|
||||
{
|
||||
QObject *object = event->object();
|
||||
QAccessible::Event type = event->type();
|
||||
|
||||
QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
|
||||
if (!interface)
|
||||
return;
|
||||
|
||||
QString name = interface->text(QAccessible::Name);
|
||||
|
||||
if (type == QAccessible::ObjectCreated) {
|
||||
// qDebug() << "ObjectCreated" << object << name;
|
||||
populateAccessibilityScene(interface, m_scene);
|
||||
}
|
||||
|
||||
QGraphicsRectItem *item = m_graphicsItems.value(object);
|
||||
|
||||
if (!item) {
|
||||
// qDebug() << "populateAccessibilityScene failed for" << object;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == QAccessible::LocationChanged) {
|
||||
|
||||
//if (name.startsWith("List"))
|
||||
qDebug() << "locationChange" << object << name << interface->rect();
|
||||
|
||||
updateItem(item, interface);
|
||||
for (int i = 0; i < interface->childCount(); ++i) {
|
||||
QAccessibleInterface *child = interface->child(i);
|
||||
if (child) {
|
||||
updateItem(m_graphicsItems.value(child->object()), child);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (type == QAccessible::ObjectDestroyed) {
|
||||
// qDebug() << "ObjectDestroyed" << object << name;
|
||||
delete m_graphicsItems.value(object);
|
||||
m_graphicsItems.remove(object);
|
||||
m_animatedObjects.remove(object);
|
||||
if (object == m_selectedObject) {
|
||||
m_selectedObject = 0;
|
||||
}
|
||||
} else if (type == QAccessible::ObjectHide) {
|
||||
// qDebug() << "ObjectCreated Hide" << object;
|
||||
updateItemFlags(item, interface);
|
||||
} else if (type == QAccessible::ObjectShow) {
|
||||
// qDebug() << "ObjectCreated Show" << object;
|
||||
updateItemFlags(item, interface);
|
||||
} else if (type == QAccessible::ScrollingStart) {
|
||||
qDebug() << "ObjectCreated ScrollingStart" << object;
|
||||
for (int i = 0; i < interface->childCount(); ++i) {
|
||||
QAccessibleInterface *child = interface->child(i);
|
||||
if (child) {
|
||||
m_animatedObjects.insert(child->object());
|
||||
}
|
||||
}
|
||||
} else if (type == QAccessible::ScrollingEnd) {
|
||||
// qDebug() << "ObjectCreated ScrollingEnd" << object;
|
||||
foreach (QObject *object, m_animatedObjects) {
|
||||
updateItem(m_graphicsItems.value(object), interface);
|
||||
}
|
||||
m_animatedObjects.clear();
|
||||
|
||||
} else {
|
||||
// qDebug() << "other update" << object;
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::setSelected(QObject *object)
|
||||
{
|
||||
m_scene->update(); // scedule update
|
||||
|
||||
// clear existing selection
|
||||
if (m_selectedObject) {
|
||||
QObject *previousSelectedObject = m_selectedObject;
|
||||
m_selectedObject = 0;
|
||||
updateItem(previousSelectedObject);
|
||||
}
|
||||
|
||||
m_selectedObject = object;
|
||||
updateItem(object);
|
||||
|
||||
populateAccessibilityTreeScene();
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::changeScale(int)
|
||||
{
|
||||
// No QGraphicsView::setScale :(
|
||||
|
||||
//m_view->scale(scale / 10.0, scale / 10.0);
|
||||
//if (m_rootItem)
|
||||
// m_view->ensureVisible(m_rootItem);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::updateItems(QObject *root)
|
||||
{
|
||||
QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(root);
|
||||
if (!interface)
|
||||
return;
|
||||
updateItem(m_graphicsItems.value(root), interface);
|
||||
|
||||
for (int i = 0; i < interface->childCount(); ++i) {
|
||||
QAccessibleInterface *child = interface->child(i);
|
||||
updateItems(child->object());
|
||||
}
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::updateItem(QObject *object)
|
||||
{
|
||||
if (!object)
|
||||
return;
|
||||
|
||||
QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(object);
|
||||
if (!interface)
|
||||
return;
|
||||
|
||||
updateItem(m_graphicsItems.value(object), interface);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::updateItem(QGraphicsRectItem *item, QAccessibleInterface *interface)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QRect rect = interface->rect();
|
||||
item->setPos(rect.topLeft());
|
||||
item->setRect(QRect(QPoint(0,0), rect.size()));
|
||||
|
||||
updateItemFlags(item, interface);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::updateItemFlags(QGraphicsRectItem *item, QAccessibleInterface *interface)
|
||||
{
|
||||
// qDebug() << "udpateItemFlags" << interface << interface->object();
|
||||
|
||||
bool shouldShow = true;
|
||||
|
||||
if (m_optionsWidget->hideInvisibleItems()) {
|
||||
if (isHidden(interface)) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_optionsWidget->hideOffscreenItems()) {
|
||||
if (interface->state().offscreen) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_optionsWidget->hidePaneItems()) {
|
||||
if (interface->role() & QAccessible::Pane) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_optionsWidget->hideNullObjectItems()) {
|
||||
if (interface->object() == 0) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_optionsWidget->hideNullRectItems()) {
|
||||
if (interface->rect().isNull()) {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
item->setVisible(shouldShow);
|
||||
|
||||
if (interface->object() && interface->object() == m_selectedObject)
|
||||
item->setBrush(QColor(Qt::yellow));
|
||||
else
|
||||
item->setBrush(QColor(Qt::white));
|
||||
|
||||
m_view->update();
|
||||
}
|
||||
|
||||
QGraphicsRectItem * AccessibilitySceneManager::processInterface(QAccessibleInterface * interface, QGraphicsScene *scene)
|
||||
{
|
||||
// Process this interface
|
||||
|
||||
QGraphicsRectItem * item = new QGraphicsRectItem();
|
||||
scene->addItem(item);
|
||||
if (!m_rootItem)
|
||||
m_rootItem = item;
|
||||
|
||||
QString name = interface->text(QAccessible::Name);
|
||||
QString description; // = interface->text(QAccessibleInterface::Description, child);
|
||||
QString role = translateRole(interface->role());
|
||||
int childCount = interface->childCount();
|
||||
|
||||
/* qDebug() << "name:" << name << "local pos" <<
|
||||
interface->rect(0) << "description" << description << "childCount" << childCount;
|
||||
*/
|
||||
|
||||
updateItem(item, interface);
|
||||
|
||||
QGraphicsSimpleTextItem * textItem = new QGraphicsSimpleTextItem();
|
||||
textItem->setParentItem(item);
|
||||
textItem->setPos(QPoint(5, 5));
|
||||
|
||||
QString text;
|
||||
text.append("Name: " + name + " ");
|
||||
if (!description.isEmpty())
|
||||
text.append("Description: " + description + " ");
|
||||
text.append("Role: " + role + " ");
|
||||
if (childCount > 0)
|
||||
text.append("ChildCount: " + QString::number(childCount) + " ");
|
||||
textItem->setText(text);
|
||||
|
||||
QFont font;
|
||||
font.setPointSize(10);
|
||||
// font.setPointSize(14);
|
||||
textItem->setFont(font);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::populateAccessibilityScene(QAccessibleInterface * interface, QGraphicsScene *scene)
|
||||
{
|
||||
if (!interface)
|
||||
return;
|
||||
|
||||
QGraphicsRectItem *item = processInterface(interface, scene);
|
||||
|
||||
QObject *object = interface->object();
|
||||
if (object) {
|
||||
m_graphicsItems.insert(object, item);
|
||||
}
|
||||
|
||||
for (int i = 0; i < interface->childCount(); ++i) {
|
||||
QAccessibleInterface *child = interface->child(i);
|
||||
updateItems(child->object());
|
||||
populateAccessibilityScene(child, scene);
|
||||
}
|
||||
}
|
||||
|
||||
AccessibilitySceneManager::TreeItem AccessibilitySceneManager::computeLevels(QAccessibleInterface * interface, int level)
|
||||
{
|
||||
if (interface == 0)
|
||||
return TreeItem();
|
||||
|
||||
TreeItem currentLevel;
|
||||
|
||||
int usedChildren = 0;
|
||||
for (int i = 0; i < interface->childCount(); ++i) {
|
||||
QAccessibleInterface *child = interface->child(i);
|
||||
if (child != 0) {
|
||||
++usedChildren;
|
||||
TreeItem childLevel = computeLevels(child, level + 1);
|
||||
currentLevel.children.append(childLevel);
|
||||
currentLevel.width += childLevel.width + m_treeItemHorizontalPadding;
|
||||
}
|
||||
}
|
||||
|
||||
// leaf node case
|
||||
if (usedChildren == 0) {
|
||||
currentLevel.width = m_treeItemWidth + m_treeItemHorizontalPadding;
|
||||
}
|
||||
|
||||
// capture information:
|
||||
currentLevel.name = interface->text(QAccessible::Name);
|
||||
currentLevel.description += interface->text(QAccessible::DebugDescription);
|
||||
currentLevel.role = translateRole(interface->role());
|
||||
currentLevel.rect = interface->rect();
|
||||
currentLevel.state = interface->state();
|
||||
currentLevel.object = interface->object();
|
||||
|
||||
return currentLevel;
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::populateAccessibilityTreeScene(QAccessibleInterface * interface)
|
||||
{
|
||||
if (!interface)
|
||||
return;
|
||||
|
||||
// set some layout metrics:
|
||||
m_treeItemWidth = 90;
|
||||
m_treeItemHorizontalPadding = 10;
|
||||
m_treeItemHeight = 60;
|
||||
m_treeItemVerticalPadding = 30;
|
||||
|
||||
// We want to draw the accessibility hiearchy as a vertical
|
||||
// tree, growing from the root node at the top.
|
||||
|
||||
// First, figure out the number of levels and the width of each level:
|
||||
m_rootTreeItem = computeLevels(interface, 0);
|
||||
|
||||
// create graphics items for each tree item
|
||||
addGraphicsItems(m_rootTreeItem, 0, 0);
|
||||
}
|
||||
|
||||
void AccessibilitySceneManager::addGraphicsItems(AccessibilitySceneManager::TreeItem item, int row, int xPos)
|
||||
{
|
||||
//qDebug() << "add graphics item" << row << item.name << item.role << xPos << item.width << item.children.count();
|
||||
|
||||
int yPos = row * (m_treeItemHeight + m_treeItemVerticalPadding);
|
||||
|
||||
// Process this interface
|
||||
QGraphicsRectItem * graphicsItem = new QGraphicsRectItem();
|
||||
graphicsItem->setPos(xPos, yPos);
|
||||
graphicsItem->setRect(0, 0, m_treeItemWidth, m_treeItemHeight);
|
||||
graphicsItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
|
||||
|
||||
if (item.object && item.object == m_selectedObject)
|
||||
graphicsItem->setBrush(QColor(Qt::yellow));
|
||||
else
|
||||
graphicsItem->setBrush(QColor(Qt::white));
|
||||
|
||||
if (item.state.offscreen) {
|
||||
QPen linePen;
|
||||
linePen.setStyle(Qt::DashLine);
|
||||
graphicsItem->setPen(linePen);
|
||||
}
|
||||
|
||||
m_treeScene->addItem(graphicsItem);
|
||||
|
||||
QGraphicsTextItem * textItem = new QGraphicsTextItem();
|
||||
textItem->setParentItem(graphicsItem);
|
||||
textItem->setPos(QPoint(0, 0));
|
||||
|
||||
QFont font;
|
||||
font.setPointSize(8);
|
||||
textItem->setFont(font);
|
||||
|
||||
QString text;
|
||||
text += item.name + "\n";
|
||||
text += item.role + "\n";
|
||||
text += item.description.split(QLatin1Char(' '), Qt::SkipEmptyParts).join("\n") + "\n";
|
||||
text += "P:" + QString::number(item.rect.x()) + " " + QString::number(item.rect.y()) + " ";
|
||||
text += "S:" + QString::number(item.rect.width()) + " " + QString::number(item.rect.height()) + "\n";
|
||||
|
||||
textItem->setPlainText(text);
|
||||
|
||||
// recurse to children
|
||||
int childIndex = 0;
|
||||
int childCount = item.children.count();
|
||||
int segmentSize = item.width / qMax(1, childCount);
|
||||
int segmentCenterOffset = segmentSize / 2;
|
||||
int segmentsStart = xPos - (item.width / 2);
|
||||
foreach (TreeItem child, item.children) {
|
||||
// spread the children out, covering the width, centered on xPos
|
||||
int segmentPosition = segmentsStart + (segmentSize * childIndex) + segmentCenterOffset;
|
||||
addGraphicsItems(child, row + 1, segmentPosition);
|
||||
++childIndex;
|
||||
}
|
||||
|
||||
// add lines from parents to kids
|
||||
int boxBottom = yPos + m_treeItemHeight;
|
||||
int boxMiddleX = xPos + m_treeItemWidth / 2;
|
||||
int yBottomMiddle = boxBottom + m_treeItemVerticalPadding / 2;
|
||||
int boxTop = yPos;
|
||||
int yTopMiddle = boxTop - m_treeItemVerticalPadding / 2;
|
||||
|
||||
if (row > 0) {
|
||||
QGraphicsLineItem *childVerticalStem = new QGraphicsLineItem();
|
||||
childVerticalStem->setLine(boxMiddleX, yTopMiddle, boxMiddleX, boxTop);
|
||||
m_treeScene->addItem(childVerticalStem);
|
||||
}
|
||||
|
||||
if (childCount > 0) {
|
||||
QGraphicsLineItem *parentVerticalStem = new QGraphicsLineItem();
|
||||
parentVerticalStem->setLine(boxMiddleX, boxBottom, boxMiddleX, yBottomMiddle);
|
||||
m_treeScene->addItem(parentVerticalStem);
|
||||
}
|
||||
|
||||
if (childCount > 1) {
|
||||
QGraphicsLineItem *horizontalStem = new QGraphicsLineItem();
|
||||
// match the end points with the horizontal lines
|
||||
int lineStartX = segmentsStart + segmentCenterOffset + m_treeItemWidth / 2;
|
||||
int lineStopX = segmentsStart + segmentSize * (childCount -1) + segmentCenterOffset + m_treeItemWidth / 2;
|
||||
horizontalStem->setLine(lineStartX, yBottomMiddle, lineStopX , yBottomMiddle);
|
||||
m_treeScene->addItem(horizontalStem);
|
||||
}
|
||||
}
|
||||
|
||||
bool AccessibilitySceneManager::isHidden(QAccessibleInterface *interface)
|
||||
{
|
||||
QAccessibleInterface *current = interface;
|
||||
while (current) {
|
||||
|
||||
if (current->state().invisible) {
|
||||
return true;
|
||||
}
|
||||
|
||||
current = current->parent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
79
util/accessibilityinspector/accessibilityscenemanager.h
Normal file
79
util/accessibilityinspector/accessibilityscenemanager.h
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef ACCESSIBILITYSCENEMANAGER_H
|
||||
#define ACCESSIBILITYSCENEMANAGER_H
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include "optionswidget.h"
|
||||
|
||||
QString translateRole(QAccessible::Role role);
|
||||
class AccessibilitySceneManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AccessibilitySceneManager();
|
||||
void setRootWindow(QWindow * window) { m_window = window; }
|
||||
void setView(QGraphicsView *view) { m_view = view; }
|
||||
void setScene(QGraphicsScene *scene) { m_scene = scene; }
|
||||
void setTreeView(QGraphicsView *treeView) { m_treeView = treeView; }
|
||||
void setTreeScene(QGraphicsScene *treeScene) { m_treeScene = treeScene; }
|
||||
|
||||
void setOptionsWidget(OptionsWidget *optionsWidget) { m_optionsWidget = optionsWidget; }
|
||||
public slots:
|
||||
void populateAccessibilityScene();
|
||||
void updateAccessibilitySceneItemFlags();
|
||||
void populateAccessibilityTreeScene();
|
||||
void handleUpdate(QAccessibleEvent *event);
|
||||
void setSelected(QObject *object);
|
||||
|
||||
void changeScale(int scale);
|
||||
private:
|
||||
void updateItems(QObject *root);
|
||||
void updateItem(QObject *object);
|
||||
void updateItem(QGraphicsRectItem *item, QAccessibleInterface *interface);
|
||||
void updateItemFlags(QGraphicsRectItem *item, QAccessibleInterface *interface);
|
||||
|
||||
void populateAccessibilityScene(QAccessibleInterface * interface, QGraphicsScene *scene);
|
||||
QGraphicsRectItem * processInterface(QAccessibleInterface * interface, QGraphicsScene *scene);
|
||||
|
||||
struct TreeItem;
|
||||
TreeItem computeLevels(QAccessibleInterface * interface, int level);
|
||||
void populateAccessibilityTreeScene(QAccessibleInterface * interface);
|
||||
void addGraphicsItems(TreeItem item, int row, int xPos);
|
||||
|
||||
bool isHidden(QAccessibleInterface *interface);
|
||||
|
||||
QWindow *m_window;
|
||||
QGraphicsView *m_view;
|
||||
QGraphicsScene *m_scene;
|
||||
QGraphicsView *m_treeView;
|
||||
QGraphicsScene *m_treeScene;
|
||||
QGraphicsItem *m_rootItem;
|
||||
OptionsWidget *m_optionsWidget;
|
||||
QObject *m_selectedObject;
|
||||
|
||||
QHash<QObject *, QGraphicsRectItem*> m_graphicsItems;
|
||||
QSet<QObject *> m_animatedObjects;
|
||||
|
||||
struct TreeItem {
|
||||
QList<TreeItem> children;
|
||||
int width;
|
||||
QString name;
|
||||
QString role;
|
||||
QString description;
|
||||
QRect rect;
|
||||
QAccessible::State state;
|
||||
QObject *object;
|
||||
TreeItem() : width(0) {}
|
||||
};
|
||||
|
||||
TreeItem m_rootTreeItem;
|
||||
int m_treeItemWidth;
|
||||
int m_treeItemHorizontalPadding;
|
||||
int m_treeItemHeight;
|
||||
int m_treeItemVerticalPadding;
|
||||
};
|
||||
|
||||
#endif // ACCESSIBILITYSCENEMANAGER_H
|
81
util/accessibilityinspector/main.cpp
Normal file
81
util/accessibilityinspector/main.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtDeclarative/QtDeclarative>
|
||||
#include <QtUiTools/QtUiTools>
|
||||
|
||||
#include "accessibilityinspector.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
if (app.arguments().count() < 2) {
|
||||
qDebug() << "Usage: accessebilityInspector [ ui-file | qml-file ] [Option]";
|
||||
qDebug() << "Option:";
|
||||
#ifdef QT_ACCESSIBILITY_INSPECTOR_SCENE_GRAPH
|
||||
qDebug() << "-qtquick1: Use QDeclarativeView instead of QSGView for rendering QML files";
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString fileName = app.arguments().at(1);
|
||||
QString mode;
|
||||
if (app.arguments().count() > 2) {
|
||||
mode = app.arguments().at(2);
|
||||
}
|
||||
|
||||
QWidget *window;
|
||||
|
||||
if (fileName.endsWith(".ui")) {
|
||||
QUiLoader loader;
|
||||
QFile file(fileName);
|
||||
file.open(QFile::ReadOnly);
|
||||
window = loader.load(&file, 0);
|
||||
} else if (fileName.endsWith(".qml")){
|
||||
QUrl fileUrl;
|
||||
if (fileName.startsWith(":")) { // detect resources.
|
||||
QString name = fileName;
|
||||
name.remove(0, 2); // reomve ":/"
|
||||
fileUrl.setUrl(QLatin1String("qrc:/") + name);
|
||||
} else {
|
||||
fileUrl = QUrl::fromLocalFile(fileName);
|
||||
}
|
||||
|
||||
#ifdef QT_ACCESSIBILITY_INSPECTOR_SCENE_GRAPH
|
||||
if (mode == QLatin1String("-qtquick1"))
|
||||
#endif
|
||||
{
|
||||
QDeclarativeView * declarativeView = new QDeclarativeView();
|
||||
declarativeView->setSource(fileUrl);
|
||||
window = declarativeView;
|
||||
}
|
||||
#ifdef QT_ACCESSIBILITY_INSPECTOR_SCENE_GRAPH
|
||||
else {
|
||||
QSGView * sceneGraphView = new QSGView();
|
||||
sceneGraphView->setSource(fileUrl);
|
||||
window = sceneGraphView;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
qDebug() << "Error: don't know what to do with" << fileName;
|
||||
}
|
||||
|
||||
AccessibilityInspector *accessibilityInspector = new AccessibilityInspector();
|
||||
|
||||
accessibilityInspector->inspectWindow(window);
|
||||
|
||||
window->move(50, 50);
|
||||
window->show();
|
||||
|
||||
int ret = app.exec();
|
||||
|
||||
accessibilityInspector->saveWindowGeometry();
|
||||
delete accessibilityInspector;
|
||||
|
||||
return ret;
|
||||
|
||||
|
||||
}
|
||||
|
5
util/accessibilityinspector/optionswidget.cpp
Normal file
5
util/accessibilityinspector/optionswidget.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "optionswidget.h"
|
||||
|
95
util/accessibilityinspector/optionswidget.h
Normal file
95
util/accessibilityinspector/optionswidget.h
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef OPTIONSWIDGET_H
|
||||
#define OPTIONSWIDGET_H
|
||||
|
||||
#include <QtGui>
|
||||
#include <QtWidgets>
|
||||
|
||||
class OptionsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OptionsWidget()
|
||||
:QWidget()
|
||||
{
|
||||
QVBoxLayout *m_layout = new QVBoxLayout;
|
||||
|
||||
m_refresh = new QPushButton(this);
|
||||
m_refresh->setText(QLatin1String("Refresh"));
|
||||
m_layout->addWidget(m_refresh);
|
||||
connect(m_refresh, SIGNAL(clicked()), SIGNAL(refreshClicked()));
|
||||
|
||||
m_hideInvisibleItems = new QCheckBox(this);
|
||||
m_layout->addWidget(m_hideInvisibleItems);
|
||||
m_hideInvisibleItems->setText("Hide Invisible Items");
|
||||
m_hideInvisibleItems->setChecked(true);
|
||||
connect(m_hideInvisibleItems, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
m_hideOffscreenItems = new QCheckBox(this);
|
||||
m_layout->addWidget(m_hideOffscreenItems);
|
||||
m_hideOffscreenItems->setText("Hide Offscreen Items");
|
||||
m_hideOffscreenItems->setChecked(true);
|
||||
connect(m_hideOffscreenItems, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
m_hidePaneItems = new QCheckBox(this);
|
||||
m_layout->addWidget(m_hidePaneItems);
|
||||
m_hidePaneItems->setText("Hide Items with the Pane role");
|
||||
m_hidePaneItems->setChecked(true);
|
||||
connect(m_hidePaneItems, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
m_hideNullObjectItems = new QCheckBox(this);
|
||||
m_layout->addWidget(m_hideNullObjectItems);
|
||||
m_hideNullObjectItems->setText("Hide Items with a null QObject pointer");
|
||||
m_hideNullObjectItems->setChecked(true);
|
||||
connect(m_hideNullObjectItems, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
m_hideNullRectItems = new QCheckBox(this);
|
||||
m_layout->addWidget(m_hideNullRectItems);
|
||||
m_hideNullRectItems->setText("Hide Items with a null rect");
|
||||
m_hideNullRectItems->setChecked(true);
|
||||
connect(m_hideNullRectItems, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
m_enableTextToSpeach = new QCheckBox(this);
|
||||
m_layout->addWidget(m_enableTextToSpeach);
|
||||
m_enableTextToSpeach->setText("Enable Text To Speech");
|
||||
m_enableTextToSpeach->setChecked(false);
|
||||
connect(m_enableTextToSpeach, SIGNAL(toggled(bool)), SIGNAL(optionsChanged()));
|
||||
|
||||
|
||||
m_scale = new QSlider(Qt::Horizontal);
|
||||
// m_layout->addWidget(m_scale);
|
||||
m_scale->setRange(5, 30);
|
||||
m_scale->setValue(1);
|
||||
connect(m_scale, SIGNAL(valueChanged(int)), SIGNAL(scaleChanged(int)));
|
||||
|
||||
this->setLayout(m_layout);
|
||||
}
|
||||
|
||||
bool hideInvisibleItems() { return m_hideInvisibleItems->isChecked(); }
|
||||
bool hideOffscreenItems() { return m_hideOffscreenItems->isChecked(); }
|
||||
bool hidePaneItems() { return m_hidePaneItems->isChecked(); }
|
||||
bool hideNullObjectItems() { return m_hideNullObjectItems->isChecked(); }
|
||||
bool hideNullRectItems() { return m_hideNullRectItems->isChecked(); }
|
||||
bool enableTextToSpeach() { return m_enableTextToSpeach->isChecked(); }
|
||||
signals:
|
||||
void optionsChanged();
|
||||
void refreshClicked();
|
||||
void scaleChanged(int);
|
||||
|
||||
private:
|
||||
QVBoxLayout *m_layout;
|
||||
|
||||
QPushButton *m_refresh;
|
||||
QCheckBox *m_hideInvisibleItems;
|
||||
QCheckBox *m_hideOffscreenItems;
|
||||
QCheckBox *m_hidePaneItems;
|
||||
QCheckBox *m_hideNullObjectItems;
|
||||
QCheckBox *m_hideNullRectItems;
|
||||
QCheckBox *m_enableTextToSpeach;
|
||||
QSlider *m_scale;
|
||||
};
|
||||
|
||||
|
||||
#endif // OPTIONSWIDGET_H
|
99
util/accessibilityinspector/screenreader.cpp
Normal file
99
util/accessibilityinspector/screenreader.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "screenreader.h"
|
||||
#include "optionswidget.h"
|
||||
#include "accessibilityscenemanager.h"
|
||||
#include <QtGui>
|
||||
|
||||
ScreenReader::ScreenReader(QObject *parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
m_selectedInterface = 0;
|
||||
m_rootInterface = 0;
|
||||
bool activateCalled = false;
|
||||
}
|
||||
|
||||
ScreenReader::~ScreenReader()
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenReader::setRootObject(QObject *rootObject)
|
||||
{
|
||||
m_rootInterface = QAccessible::queryAccessibleInterface(rootObject);
|
||||
}
|
||||
|
||||
void ScreenReader::setOptionsWidget(OptionsWidget *optionsWidget)
|
||||
{
|
||||
m_optionsWidget = optionsWidget;
|
||||
}
|
||||
|
||||
void ScreenReader::touchPoint(const QPoint &point)
|
||||
{
|
||||
qDebug() << "touch" << point;
|
||||
// Wait and see if this touch is the start of a double-tap
|
||||
// (activate will then be called and cancel the touch processing)
|
||||
m_activateCalled = false;
|
||||
m_currentTouchPoint = point;
|
||||
QTimer::singleShot(200, this, SLOT(processTouchPoint()));
|
||||
}
|
||||
|
||||
void ScreenReader::processTouchPoint()
|
||||
{
|
||||
if (m_activateCalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rootInterface == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QAccessibleInterface * currentInterface = m_rootInterface;
|
||||
|
||||
int hit = -2;
|
||||
int guardCounter = 0;
|
||||
const int guardMax = 40;
|
||||
while (currentInterface != 0) {
|
||||
++guardCounter;
|
||||
if (guardCounter > guardMax) {
|
||||
qDebug() << "touchPoint exit recursion overflow";
|
||||
return; // outside
|
||||
}
|
||||
|
||||
QAccessibleInterface * hit = currentInterface->childAt(m_currentTouchPoint.x(), m_currentTouchPoint.y());
|
||||
if (!hit)
|
||||
break;
|
||||
currentInterface = hit;
|
||||
}
|
||||
|
||||
m_selectedInterface = currentInterface;
|
||||
if (m_selectedInterface->object())
|
||||
emit selected(m_selectedInterface->object());
|
||||
if (m_optionsWidget->enableTextToSpeach())
|
||||
speak(m_selectedInterface->text(QAccessible::Name)
|
||||
/*+ "," + translateRole(m_selectedInterface->role(0)) */);
|
||||
|
||||
// qDebug() << "touchPoint exit found" << m_selectedInterface->text(QAccessible::Name, 0) << m_selectedInterface->object() << m_selectedInterface->rect(0);
|
||||
}
|
||||
|
||||
void ScreenReader::activate()
|
||||
{
|
||||
qDebug() << "ScreenReader::activate";
|
||||
m_activateCalled = true;
|
||||
if (m_selectedInterface) {
|
||||
m_selectedInterface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenReader::speak(const QString &text, const QString &/*voice*/)
|
||||
{
|
||||
QFile f("festivalspeachhack");
|
||||
f.open(QIODevice::WriteOnly);
|
||||
f.write(text.toLocal8Bit());
|
||||
f.close();
|
||||
|
||||
QProcess *process = new QProcess;
|
||||
process->start("/usr/bin/festival", QStringList() << "--tts" << "festivalspeachhack");
|
||||
}
|
||||
|
||||
|
46
util/accessibilityinspector/screenreader.h
Normal file
46
util/accessibilityinspector/screenreader.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#ifndef SCREENREADER_H
|
||||
#define SCREENREADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QAccessible>
|
||||
#include <QAccessibleBridge>
|
||||
|
||||
/*
|
||||
A Simple screen reader for touch-based user interfaces.
|
||||
|
||||
Requires a text-to-speach backend. Currently implemented
|
||||
using festival on unix.
|
||||
*/
|
||||
class OptionsWidget;
|
||||
class ScreenReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ScreenReader(QObject *parent = nullptr);
|
||||
~ScreenReader();
|
||||
|
||||
void setRootObject(QObject *rootObject);
|
||||
void setOptionsWidget(OptionsWidget *optionsWidget);
|
||||
public slots:
|
||||
void touchPoint(const QPoint &point);
|
||||
void activate();
|
||||
protected slots:
|
||||
void processTouchPoint();
|
||||
signals:
|
||||
void selected(QObject *object);
|
||||
|
||||
protected:
|
||||
void speak(const QString &text, const QString &voice = QString());
|
||||
private:
|
||||
QAccessibleInterface *m_selectedInterface;
|
||||
QAccessibleInterface *m_rootInterface;
|
||||
OptionsWidget *m_optionsWidget;
|
||||
QPoint m_currentTouchPoint;
|
||||
bool m_activateCalled;
|
||||
};
|
||||
|
||||
#endif // SCREENREADER_H
|
1
util/aglfn/README
Normal file
1
util/aglfn/README
Normal file
@ -0,0 +1 @@
|
||||
Aglfn is used to generate the Adobe Glyph List For New Fonts data in src/gui/text.
|
3
util/aglfn/aglfn.pro
Normal file
3
util/aglfn/aglfn.pro
Normal file
@ -0,0 +1,3 @@
|
||||
SOURCES += main.cpp
|
||||
QT = core
|
||||
CONFIG += console
|
697
util/aglfn/data/aglfn.txt
Normal file
697
util/aglfn/data/aglfn.txt
Normal file
@ -0,0 +1,697 @@
|
||||
# -----------------------------------------------------------
|
||||
# Copyright 2003, 2005-2008, 2010 Adobe Systems Incorporated.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or
|
||||
# without modification, are permitted provided that the
|
||||
# following conditions are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials
|
||||
# provided with the distribution.
|
||||
#
|
||||
# Neither the name of Adobe Systems Incorporated nor the names
|
||||
# of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific prior
|
||||
# written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# -----------------------------------------------------------
|
||||
# Name: Adobe Glyph List For New Fonts
|
||||
# Table version: 1.7
|
||||
# Date: November 6, 2008
|
||||
# URL: http://sourceforge.net/adobe/aglfn/
|
||||
#
|
||||
# Description:
|
||||
#
|
||||
# AGLFN (Adobe Glyph List For New Fonts) provides a list of base glyph
|
||||
# names that are recommended for new fonts, which are compatible with
|
||||
# the AGL (Adobe Glyph List) Specification, and which should be used
|
||||
# as described in Section 6 of that document. AGLFN comprises the set
|
||||
# of glyph names from AGL that map via the AGL Specification rules to
|
||||
# the semantically correct UV (Unicode Value). For example, "Asmall"
|
||||
# is omitted because AGL maps this glyph name to the PUA (Private Use
|
||||
# Area) value U+F761, rather than to the UV that maps from the glyph
|
||||
# name "A." Also omitted is "ffi," because AGL maps this to the
|
||||
# Alphabetic Presentation Forms value U+FB03, rather than decomposing
|
||||
# it into the following sequence of three UVs: U+0066, U+0066, and
|
||||
# U+0069. The name "arrowvertex" has been omitted because this glyph
|
||||
# now has a real UV, and AGL is now incorrect in mapping it to the PUA
|
||||
# value U+F8E6. If you do not find an appropriate name for your glyph
|
||||
# in this list, then please refer to Section 6 of the AGL
|
||||
# Specification.
|
||||
#
|
||||
# Format: three semicolon-delimited fields:
|
||||
# (1) Standard UV or CUS UV--four uppercase hexadecimal digits
|
||||
# (2) Glyph name--upper/lowercase letters and digits
|
||||
# (3) Character names: Unicode character names for standard UVs, and
|
||||
# descriptive names for CUS UVs--uppercase letters, hyphen, and
|
||||
# space
|
||||
#
|
||||
# The records are sorted by glyph name in increasing ASCII order,
|
||||
# entries with the same glyph name are sorted in decreasing priority
|
||||
# order, the UVs and Unicode character names are provided for
|
||||
# convenience, lines starting with "#" are comments, and blank lines
|
||||
# should be ignored.
|
||||
#
|
||||
# Revision History:
|
||||
#
|
||||
# 1.7 [6 November 2008]
|
||||
# - Reverted to the original 1.4 and earlier mappings for Delta,
|
||||
# Omega, and mu.
|
||||
# - Removed mappings for "afii" names. These should now be assigned
|
||||
# "uni" names.
|
||||
# - Removed mappings for "commaaccent" names. These should now be
|
||||
# assigned "uni" names.
|
||||
#
|
||||
# 1.6 [30 January 2006]
|
||||
# - Completed work intended in 1.5.
|
||||
#
|
||||
# 1.5 [23 November 2005]
|
||||
# - Removed duplicated block at end of file.
|
||||
# - Changed mappings:
|
||||
# 2206;Delta;INCREMENT changed to 0394;Delta;GREEK CAPITAL LETTER DELTA
|
||||
# 2126;Omega;OHM SIGN changed to 03A9;Omega;GREEK CAPITAL LETTER OMEGA
|
||||
# 03BC;mu;MICRO SIGN changed to 03BC;mu;GREEK SMALL LETTER MU
|
||||
# - Corrected statement above about why "ffi" is omitted.
|
||||
#
|
||||
# 1.4 [24 September 2003]
|
||||
# - Changed version to 1.4, to avoid confusion with the AGL 1.3.
|
||||
# - Fixed spelling errors in the header.
|
||||
# - Fully removed "arrowvertex," as it is mapped only to a PUA Unicode
|
||||
# value in some fonts.
|
||||
#
|
||||
# 1.1 [17 April 2003]
|
||||
# - Renamed [Tt]cedilla back to [Tt]commaaccent.
|
||||
#
|
||||
# 1.0 [31 January 2003]
|
||||
# - Original version.
|
||||
# - Derived from the AGLv1.2 by:
|
||||
# removing the PUA area codes;
|
||||
# removing duplicate Unicode mappings; and
|
||||
# renaming "tcommaaccent" to "tcedilla" and "Tcommaaccent" to "Tcedilla"
|
||||
#
|
||||
0041;A;LATIN CAPITAL LETTER A
|
||||
00C6;AE;LATIN CAPITAL LETTER AE
|
||||
01FC;AEacute;LATIN CAPITAL LETTER AE WITH ACUTE
|
||||
00C1;Aacute;LATIN CAPITAL LETTER A WITH ACUTE
|
||||
0102;Abreve;LATIN CAPITAL LETTER A WITH BREVE
|
||||
00C2;Acircumflex;LATIN CAPITAL LETTER A WITH CIRCUMFLEX
|
||||
00C4;Adieresis;LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
00C0;Agrave;LATIN CAPITAL LETTER A WITH GRAVE
|
||||
0391;Alpha;GREEK CAPITAL LETTER ALPHA
|
||||
0386;Alphatonos;GREEK CAPITAL LETTER ALPHA WITH TONOS
|
||||
0100;Amacron;LATIN CAPITAL LETTER A WITH MACRON
|
||||
0104;Aogonek;LATIN CAPITAL LETTER A WITH OGONEK
|
||||
00C5;Aring;LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
01FA;Aringacute;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
|
||||
00C3;Atilde;LATIN CAPITAL LETTER A WITH TILDE
|
||||
0042;B;LATIN CAPITAL LETTER B
|
||||
0392;Beta;GREEK CAPITAL LETTER BETA
|
||||
0043;C;LATIN CAPITAL LETTER C
|
||||
0106;Cacute;LATIN CAPITAL LETTER C WITH ACUTE
|
||||
010C;Ccaron;LATIN CAPITAL LETTER C WITH CARON
|
||||
00C7;Ccedilla;LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
0108;Ccircumflex;LATIN CAPITAL LETTER C WITH CIRCUMFLEX
|
||||
010A;Cdotaccent;LATIN CAPITAL LETTER C WITH DOT ABOVE
|
||||
03A7;Chi;GREEK CAPITAL LETTER CHI
|
||||
0044;D;LATIN CAPITAL LETTER D
|
||||
010E;Dcaron;LATIN CAPITAL LETTER D WITH CARON
|
||||
0110;Dcroat;LATIN CAPITAL LETTER D WITH STROKE
|
||||
2206;Delta;INCREMENT
|
||||
0045;E;LATIN CAPITAL LETTER E
|
||||
00C9;Eacute;LATIN CAPITAL LETTER E WITH ACUTE
|
||||
0114;Ebreve;LATIN CAPITAL LETTER E WITH BREVE
|
||||
011A;Ecaron;LATIN CAPITAL LETTER E WITH CARON
|
||||
00CA;Ecircumflex;LATIN CAPITAL LETTER E WITH CIRCUMFLEX
|
||||
00CB;Edieresis;LATIN CAPITAL LETTER E WITH DIAERESIS
|
||||
0116;Edotaccent;LATIN CAPITAL LETTER E WITH DOT ABOVE
|
||||
00C8;Egrave;LATIN CAPITAL LETTER E WITH GRAVE
|
||||
0112;Emacron;LATIN CAPITAL LETTER E WITH MACRON
|
||||
014A;Eng;LATIN CAPITAL LETTER ENG
|
||||
0118;Eogonek;LATIN CAPITAL LETTER E WITH OGONEK
|
||||
0395;Epsilon;GREEK CAPITAL LETTER EPSILON
|
||||
0388;Epsilontonos;GREEK CAPITAL LETTER EPSILON WITH TONOS
|
||||
0397;Eta;GREEK CAPITAL LETTER ETA
|
||||
0389;Etatonos;GREEK CAPITAL LETTER ETA WITH TONOS
|
||||
00D0;Eth;LATIN CAPITAL LETTER ETH
|
||||
20AC;Euro;EURO SIGN
|
||||
0046;F;LATIN CAPITAL LETTER F
|
||||
0047;G;LATIN CAPITAL LETTER G
|
||||
0393;Gamma;GREEK CAPITAL LETTER GAMMA
|
||||
011E;Gbreve;LATIN CAPITAL LETTER G WITH BREVE
|
||||
01E6;Gcaron;LATIN CAPITAL LETTER G WITH CARON
|
||||
011C;Gcircumflex;LATIN CAPITAL LETTER G WITH CIRCUMFLEX
|
||||
0120;Gdotaccent;LATIN CAPITAL LETTER G WITH DOT ABOVE
|
||||
0048;H;LATIN CAPITAL LETTER H
|
||||
25CF;H18533;BLACK CIRCLE
|
||||
25AA;H18543;BLACK SMALL SQUARE
|
||||
25AB;H18551;WHITE SMALL SQUARE
|
||||
25A1;H22073;WHITE SQUARE
|
||||
0126;Hbar;LATIN CAPITAL LETTER H WITH STROKE
|
||||
0124;Hcircumflex;LATIN CAPITAL LETTER H WITH CIRCUMFLEX
|
||||
0049;I;LATIN CAPITAL LETTER I
|
||||
0132;IJ;LATIN CAPITAL LIGATURE IJ
|
||||
00CD;Iacute;LATIN CAPITAL LETTER I WITH ACUTE
|
||||
012C;Ibreve;LATIN CAPITAL LETTER I WITH BREVE
|
||||
00CE;Icircumflex;LATIN CAPITAL LETTER I WITH CIRCUMFLEX
|
||||
00CF;Idieresis;LATIN CAPITAL LETTER I WITH DIAERESIS
|
||||
0130;Idotaccent;LATIN CAPITAL LETTER I WITH DOT ABOVE
|
||||
2111;Ifraktur;BLACK-LETTER CAPITAL I
|
||||
00CC;Igrave;LATIN CAPITAL LETTER I WITH GRAVE
|
||||
012A;Imacron;LATIN CAPITAL LETTER I WITH MACRON
|
||||
012E;Iogonek;LATIN CAPITAL LETTER I WITH OGONEK
|
||||
0399;Iota;GREEK CAPITAL LETTER IOTA
|
||||
03AA;Iotadieresis;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
|
||||
038A;Iotatonos;GREEK CAPITAL LETTER IOTA WITH TONOS
|
||||
0128;Itilde;LATIN CAPITAL LETTER I WITH TILDE
|
||||
004A;J;LATIN CAPITAL LETTER J
|
||||
0134;Jcircumflex;LATIN CAPITAL LETTER J WITH CIRCUMFLEX
|
||||
004B;K;LATIN CAPITAL LETTER K
|
||||
039A;Kappa;GREEK CAPITAL LETTER KAPPA
|
||||
004C;L;LATIN CAPITAL LETTER L
|
||||
0139;Lacute;LATIN CAPITAL LETTER L WITH ACUTE
|
||||
039B;Lambda;GREEK CAPITAL LETTER LAMDA
|
||||
013D;Lcaron;LATIN CAPITAL LETTER L WITH CARON
|
||||
013F;Ldot;LATIN CAPITAL LETTER L WITH MIDDLE DOT
|
||||
0141;Lslash;LATIN CAPITAL LETTER L WITH STROKE
|
||||
004D;M;LATIN CAPITAL LETTER M
|
||||
039C;Mu;GREEK CAPITAL LETTER MU
|
||||
004E;N;LATIN CAPITAL LETTER N
|
||||
0143;Nacute;LATIN CAPITAL LETTER N WITH ACUTE
|
||||
0147;Ncaron;LATIN CAPITAL LETTER N WITH CARON
|
||||
00D1;Ntilde;LATIN CAPITAL LETTER N WITH TILDE
|
||||
039D;Nu;GREEK CAPITAL LETTER NU
|
||||
004F;O;LATIN CAPITAL LETTER O
|
||||
0152;OE;LATIN CAPITAL LIGATURE OE
|
||||
00D3;Oacute;LATIN CAPITAL LETTER O WITH ACUTE
|
||||
014E;Obreve;LATIN CAPITAL LETTER O WITH BREVE
|
||||
00D4;Ocircumflex;LATIN CAPITAL LETTER O WITH CIRCUMFLEX
|
||||
00D6;Odieresis;LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
00D2;Ograve;LATIN CAPITAL LETTER O WITH GRAVE
|
||||
01A0;Ohorn;LATIN CAPITAL LETTER O WITH HORN
|
||||
0150;Ohungarumlaut;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
|
||||
014C;Omacron;LATIN CAPITAL LETTER O WITH MACRON
|
||||
2126;Omega;OHM SIGN
|
||||
038F;Omegatonos;GREEK CAPITAL LETTER OMEGA WITH TONOS
|
||||
039F;Omicron;GREEK CAPITAL LETTER OMICRON
|
||||
038C;Omicrontonos;GREEK CAPITAL LETTER OMICRON WITH TONOS
|
||||
00D8;Oslash;LATIN CAPITAL LETTER O WITH STROKE
|
||||
01FE;Oslashacute;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
|
||||
00D5;Otilde;LATIN CAPITAL LETTER O WITH TILDE
|
||||
0050;P;LATIN CAPITAL LETTER P
|
||||
03A6;Phi;GREEK CAPITAL LETTER PHI
|
||||
03A0;Pi;GREEK CAPITAL LETTER PI
|
||||
03A8;Psi;GREEK CAPITAL LETTER PSI
|
||||
0051;Q;LATIN CAPITAL LETTER Q
|
||||
0052;R;LATIN CAPITAL LETTER R
|
||||
0154;Racute;LATIN CAPITAL LETTER R WITH ACUTE
|
||||
0158;Rcaron;LATIN CAPITAL LETTER R WITH CARON
|
||||
211C;Rfraktur;BLACK-LETTER CAPITAL R
|
||||
03A1;Rho;GREEK CAPITAL LETTER RHO
|
||||
0053;S;LATIN CAPITAL LETTER S
|
||||
250C;SF010000;BOX DRAWINGS LIGHT DOWN AND RIGHT
|
||||
2514;SF020000;BOX DRAWINGS LIGHT UP AND RIGHT
|
||||
2510;SF030000;BOX DRAWINGS LIGHT DOWN AND LEFT
|
||||
2518;SF040000;BOX DRAWINGS LIGHT UP AND LEFT
|
||||
253C;SF050000;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
|
||||
252C;SF060000;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
|
||||
2534;SF070000;BOX DRAWINGS LIGHT UP AND HORIZONTAL
|
||||
251C;SF080000;BOX DRAWINGS LIGHT VERTICAL AND RIGHT
|
||||
2524;SF090000;BOX DRAWINGS LIGHT VERTICAL AND LEFT
|
||||
2500;SF100000;BOX DRAWINGS LIGHT HORIZONTAL
|
||||
2502;SF110000;BOX DRAWINGS LIGHT VERTICAL
|
||||
2561;SF190000;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
|
||||
2562;SF200000;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
|
||||
2556;SF210000;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
|
||||
2555;SF220000;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
|
||||
2563;SF230000;BOX DRAWINGS DOUBLE VERTICAL AND LEFT
|
||||
2551;SF240000;BOX DRAWINGS DOUBLE VERTICAL
|
||||
2557;SF250000;BOX DRAWINGS DOUBLE DOWN AND LEFT
|
||||
255D;SF260000;BOX DRAWINGS DOUBLE UP AND LEFT
|
||||
255C;SF270000;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
|
||||
255B;SF280000;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
|
||||
255E;SF360000;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
|
||||
255F;SF370000;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
|
||||
255A;SF380000;BOX DRAWINGS DOUBLE UP AND RIGHT
|
||||
2554;SF390000;BOX DRAWINGS DOUBLE DOWN AND RIGHT
|
||||
2569;SF400000;BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
2566;SF410000;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
|
||||
2560;SF420000;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
|
||||
2550;SF430000;BOX DRAWINGS DOUBLE HORIZONTAL
|
||||
256C;SF440000;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
|
||||
2567;SF450000;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
|
||||
2568;SF460000;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
|
||||
2564;SF470000;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
|
||||
2565;SF480000;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
|
||||
2559;SF490000;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
|
||||
2558;SF500000;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
|
||||
2552;SF510000;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
|
||||
2553;SF520000;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
|
||||
256B;SF530000;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
|
||||
256A;SF540000;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
|
||||
015A;Sacute;LATIN CAPITAL LETTER S WITH ACUTE
|
||||
0160;Scaron;LATIN CAPITAL LETTER S WITH CARON
|
||||
015E;Scedilla;LATIN CAPITAL LETTER S WITH CEDILLA
|
||||
015C;Scircumflex;LATIN CAPITAL LETTER S WITH CIRCUMFLEX
|
||||
03A3;Sigma;GREEK CAPITAL LETTER SIGMA
|
||||
0054;T;LATIN CAPITAL LETTER T
|
||||
03A4;Tau;GREEK CAPITAL LETTER TAU
|
||||
0166;Tbar;LATIN CAPITAL LETTER T WITH STROKE
|
||||
0164;Tcaron;LATIN CAPITAL LETTER T WITH CARON
|
||||
0398;Theta;GREEK CAPITAL LETTER THETA
|
||||
00DE;Thorn;LATIN CAPITAL LETTER THORN
|
||||
0055;U;LATIN CAPITAL LETTER U
|
||||
00DA;Uacute;LATIN CAPITAL LETTER U WITH ACUTE
|
||||
016C;Ubreve;LATIN CAPITAL LETTER U WITH BREVE
|
||||
00DB;Ucircumflex;LATIN CAPITAL LETTER U WITH CIRCUMFLEX
|
||||
00DC;Udieresis;LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
00D9;Ugrave;LATIN CAPITAL LETTER U WITH GRAVE
|
||||
01AF;Uhorn;LATIN CAPITAL LETTER U WITH HORN
|
||||
0170;Uhungarumlaut;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
|
||||
016A;Umacron;LATIN CAPITAL LETTER U WITH MACRON
|
||||
0172;Uogonek;LATIN CAPITAL LETTER U WITH OGONEK
|
||||
03A5;Upsilon;GREEK CAPITAL LETTER UPSILON
|
||||
03D2;Upsilon1;GREEK UPSILON WITH HOOK SYMBOL
|
||||
03AB;Upsilondieresis;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
|
||||
038E;Upsilontonos;GREEK CAPITAL LETTER UPSILON WITH TONOS
|
||||
016E;Uring;LATIN CAPITAL LETTER U WITH RING ABOVE
|
||||
0168;Utilde;LATIN CAPITAL LETTER U WITH TILDE
|
||||
0056;V;LATIN CAPITAL LETTER V
|
||||
0057;W;LATIN CAPITAL LETTER W
|
||||
1E82;Wacute;LATIN CAPITAL LETTER W WITH ACUTE
|
||||
0174;Wcircumflex;LATIN CAPITAL LETTER W WITH CIRCUMFLEX
|
||||
1E84;Wdieresis;LATIN CAPITAL LETTER W WITH DIAERESIS
|
||||
1E80;Wgrave;LATIN CAPITAL LETTER W WITH GRAVE
|
||||
0058;X;LATIN CAPITAL LETTER X
|
||||
039E;Xi;GREEK CAPITAL LETTER XI
|
||||
0059;Y;LATIN CAPITAL LETTER Y
|
||||
00DD;Yacute;LATIN CAPITAL LETTER Y WITH ACUTE
|
||||
0176;Ycircumflex;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
|
||||
0178;Ydieresis;LATIN CAPITAL LETTER Y WITH DIAERESIS
|
||||
1EF2;Ygrave;LATIN CAPITAL LETTER Y WITH GRAVE
|
||||
005A;Z;LATIN CAPITAL LETTER Z
|
||||
0179;Zacute;LATIN CAPITAL LETTER Z WITH ACUTE
|
||||
017D;Zcaron;LATIN CAPITAL LETTER Z WITH CARON
|
||||
017B;Zdotaccent;LATIN CAPITAL LETTER Z WITH DOT ABOVE
|
||||
0396;Zeta;GREEK CAPITAL LETTER ZETA
|
||||
0061;a;LATIN SMALL LETTER A
|
||||
00E1;aacute;LATIN SMALL LETTER A WITH ACUTE
|
||||
0103;abreve;LATIN SMALL LETTER A WITH BREVE
|
||||
00E2;acircumflex;LATIN SMALL LETTER A WITH CIRCUMFLEX
|
||||
00B4;acute;ACUTE ACCENT
|
||||
0301;acutecomb;COMBINING ACUTE ACCENT
|
||||
00E4;adieresis;LATIN SMALL LETTER A WITH DIAERESIS
|
||||
00E6;ae;LATIN SMALL LETTER AE
|
||||
01FD;aeacute;LATIN SMALL LETTER AE WITH ACUTE
|
||||
00E0;agrave;LATIN SMALL LETTER A WITH GRAVE
|
||||
2135;aleph;ALEF SYMBOL
|
||||
03B1;alpha;GREEK SMALL LETTER ALPHA
|
||||
03AC;alphatonos;GREEK SMALL LETTER ALPHA WITH TONOS
|
||||
0101;amacron;LATIN SMALL LETTER A WITH MACRON
|
||||
0026;ampersand;AMPERSAND
|
||||
2220;angle;ANGLE
|
||||
2329;angleleft;LEFT-POINTING ANGLE BRACKET
|
||||
232A;angleright;RIGHT-POINTING ANGLE BRACKET
|
||||
0387;anoteleia;GREEK ANO TELEIA
|
||||
0105;aogonek;LATIN SMALL LETTER A WITH OGONEK
|
||||
2248;approxequal;ALMOST EQUAL TO
|
||||
00E5;aring;LATIN SMALL LETTER A WITH RING ABOVE
|
||||
01FB;aringacute;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
|
||||
2194;arrowboth;LEFT RIGHT ARROW
|
||||
21D4;arrowdblboth;LEFT RIGHT DOUBLE ARROW
|
||||
21D3;arrowdbldown;DOWNWARDS DOUBLE ARROW
|
||||
21D0;arrowdblleft;LEFTWARDS DOUBLE ARROW
|
||||
21D2;arrowdblright;RIGHTWARDS DOUBLE ARROW
|
||||
21D1;arrowdblup;UPWARDS DOUBLE ARROW
|
||||
2193;arrowdown;DOWNWARDS ARROW
|
||||
2190;arrowleft;LEFTWARDS ARROW
|
||||
2192;arrowright;RIGHTWARDS ARROW
|
||||
2191;arrowup;UPWARDS ARROW
|
||||
2195;arrowupdn;UP DOWN ARROW
|
||||
21A8;arrowupdnbse;UP DOWN ARROW WITH BASE
|
||||
005E;asciicircum;CIRCUMFLEX ACCENT
|
||||
007E;asciitilde;TILDE
|
||||
002A;asterisk;ASTERISK
|
||||
2217;asteriskmath;ASTERISK OPERATOR
|
||||
0040;at;COMMERCIAL AT
|
||||
00E3;atilde;LATIN SMALL LETTER A WITH TILDE
|
||||
0062;b;LATIN SMALL LETTER B
|
||||
005C;backslash;REVERSE SOLIDUS
|
||||
007C;bar;VERTICAL LINE
|
||||
03B2;beta;GREEK SMALL LETTER BETA
|
||||
2588;block;FULL BLOCK
|
||||
007B;braceleft;LEFT CURLY BRACKET
|
||||
007D;braceright;RIGHT CURLY BRACKET
|
||||
005B;bracketleft;LEFT SQUARE BRACKET
|
||||
005D;bracketright;RIGHT SQUARE BRACKET
|
||||
02D8;breve;BREVE
|
||||
00A6;brokenbar;BROKEN BAR
|
||||
2022;bullet;BULLET
|
||||
0063;c;LATIN SMALL LETTER C
|
||||
0107;cacute;LATIN SMALL LETTER C WITH ACUTE
|
||||
02C7;caron;CARON
|
||||
21B5;carriagereturn;DOWNWARDS ARROW WITH CORNER LEFTWARDS
|
||||
010D;ccaron;LATIN SMALL LETTER C WITH CARON
|
||||
00E7;ccedilla;LATIN SMALL LETTER C WITH CEDILLA
|
||||
0109;ccircumflex;LATIN SMALL LETTER C WITH CIRCUMFLEX
|
||||
010B;cdotaccent;LATIN SMALL LETTER C WITH DOT ABOVE
|
||||
00B8;cedilla;CEDILLA
|
||||
00A2;cent;CENT SIGN
|
||||
03C7;chi;GREEK SMALL LETTER CHI
|
||||
25CB;circle;WHITE CIRCLE
|
||||
2297;circlemultiply;CIRCLED TIMES
|
||||
2295;circleplus;CIRCLED PLUS
|
||||
02C6;circumflex;MODIFIER LETTER CIRCUMFLEX ACCENT
|
||||
2663;club;BLACK CLUB SUIT
|
||||
003A;colon;COLON
|
||||
20A1;colonmonetary;COLON SIGN
|
||||
002C;comma;COMMA
|
||||
2245;congruent;APPROXIMATELY EQUAL TO
|
||||
00A9;copyright;COPYRIGHT SIGN
|
||||
00A4;currency;CURRENCY SIGN
|
||||
0064;d;LATIN SMALL LETTER D
|
||||
2020;dagger;DAGGER
|
||||
2021;daggerdbl;DOUBLE DAGGER
|
||||
010F;dcaron;LATIN SMALL LETTER D WITH CARON
|
||||
0111;dcroat;LATIN SMALL LETTER D WITH STROKE
|
||||
00B0;degree;DEGREE SIGN
|
||||
03B4;delta;GREEK SMALL LETTER DELTA
|
||||
2666;diamond;BLACK DIAMOND SUIT
|
||||
00A8;dieresis;DIAERESIS
|
||||
0385;dieresistonos;GREEK DIALYTIKA TONOS
|
||||
00F7;divide;DIVISION SIGN
|
||||
2593;dkshade;DARK SHADE
|
||||
2584;dnblock;LOWER HALF BLOCK
|
||||
0024;dollar;DOLLAR SIGN
|
||||
20AB;dong;DONG SIGN
|
||||
02D9;dotaccent;DOT ABOVE
|
||||
0323;dotbelowcomb;COMBINING DOT BELOW
|
||||
0131;dotlessi;LATIN SMALL LETTER DOTLESS I
|
||||
22C5;dotmath;DOT OPERATOR
|
||||
0065;e;LATIN SMALL LETTER E
|
||||
00E9;eacute;LATIN SMALL LETTER E WITH ACUTE
|
||||
0115;ebreve;LATIN SMALL LETTER E WITH BREVE
|
||||
011B;ecaron;LATIN SMALL LETTER E WITH CARON
|
||||
00EA;ecircumflex;LATIN SMALL LETTER E WITH CIRCUMFLEX
|
||||
00EB;edieresis;LATIN SMALL LETTER E WITH DIAERESIS
|
||||
0117;edotaccent;LATIN SMALL LETTER E WITH DOT ABOVE
|
||||
00E8;egrave;LATIN SMALL LETTER E WITH GRAVE
|
||||
0038;eight;DIGIT EIGHT
|
||||
2208;element;ELEMENT OF
|
||||
2026;ellipsis;HORIZONTAL ELLIPSIS
|
||||
0113;emacron;LATIN SMALL LETTER E WITH MACRON
|
||||
2014;emdash;EM DASH
|
||||
2205;emptyset;EMPTY SET
|
||||
2013;endash;EN DASH
|
||||
014B;eng;LATIN SMALL LETTER ENG
|
||||
0119;eogonek;LATIN SMALL LETTER E WITH OGONEK
|
||||
03B5;epsilon;GREEK SMALL LETTER EPSILON
|
||||
03AD;epsilontonos;GREEK SMALL LETTER EPSILON WITH TONOS
|
||||
003D;equal;EQUALS SIGN
|
||||
2261;equivalence;IDENTICAL TO
|
||||
212E;estimated;ESTIMATED SYMBOL
|
||||
03B7;eta;GREEK SMALL LETTER ETA
|
||||
03AE;etatonos;GREEK SMALL LETTER ETA WITH TONOS
|
||||
00F0;eth;LATIN SMALL LETTER ETH
|
||||
0021;exclam;EXCLAMATION MARK
|
||||
203C;exclamdbl;DOUBLE EXCLAMATION MARK
|
||||
00A1;exclamdown;INVERTED EXCLAMATION MARK
|
||||
2203;existential;THERE EXISTS
|
||||
0066;f;LATIN SMALL LETTER F
|
||||
2640;female;FEMALE SIGN
|
||||
2012;figuredash;FIGURE DASH
|
||||
25A0;filledbox;BLACK SQUARE
|
||||
25AC;filledrect;BLACK RECTANGLE
|
||||
0035;five;DIGIT FIVE
|
||||
215D;fiveeighths;VULGAR FRACTION FIVE EIGHTHS
|
||||
0192;florin;LATIN SMALL LETTER F WITH HOOK
|
||||
0034;four;DIGIT FOUR
|
||||
2044;fraction;FRACTION SLASH
|
||||
20A3;franc;FRENCH FRANC SIGN
|
||||
0067;g;LATIN SMALL LETTER G
|
||||
03B3;gamma;GREEK SMALL LETTER GAMMA
|
||||
011F;gbreve;LATIN SMALL LETTER G WITH BREVE
|
||||
01E7;gcaron;LATIN SMALL LETTER G WITH CARON
|
||||
011D;gcircumflex;LATIN SMALL LETTER G WITH CIRCUMFLEX
|
||||
0121;gdotaccent;LATIN SMALL LETTER G WITH DOT ABOVE
|
||||
00DF;germandbls;LATIN SMALL LETTER SHARP S
|
||||
2207;gradient;NABLA
|
||||
0060;grave;GRAVE ACCENT
|
||||
0300;gravecomb;COMBINING GRAVE ACCENT
|
||||
003E;greater;GREATER-THAN SIGN
|
||||
2265;greaterequal;GREATER-THAN OR EQUAL TO
|
||||
00AB;guillemotleft;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
00BB;guillemotright;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
|
||||
2039;guilsinglleft;SINGLE LEFT-POINTING ANGLE QUOTATION MARK
|
||||
203A;guilsinglright;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
|
||||
0068;h;LATIN SMALL LETTER H
|
||||
0127;hbar;LATIN SMALL LETTER H WITH STROKE
|
||||
0125;hcircumflex;LATIN SMALL LETTER H WITH CIRCUMFLEX
|
||||
2665;heart;BLACK HEART SUIT
|
||||
0309;hookabovecomb;COMBINING HOOK ABOVE
|
||||
2302;house;HOUSE
|
||||
02DD;hungarumlaut;DOUBLE ACUTE ACCENT
|
||||
002D;hyphen;HYPHEN-MINUS
|
||||
0069;i;LATIN SMALL LETTER I
|
||||
00ED;iacute;LATIN SMALL LETTER I WITH ACUTE
|
||||
012D;ibreve;LATIN SMALL LETTER I WITH BREVE
|
||||
00EE;icircumflex;LATIN SMALL LETTER I WITH CIRCUMFLEX
|
||||
00EF;idieresis;LATIN SMALL LETTER I WITH DIAERESIS
|
||||
00EC;igrave;LATIN SMALL LETTER I WITH GRAVE
|
||||
0133;ij;LATIN SMALL LIGATURE IJ
|
||||
012B;imacron;LATIN SMALL LETTER I WITH MACRON
|
||||
221E;infinity;INFINITY
|
||||
222B;integral;INTEGRAL
|
||||
2321;integralbt;BOTTOM HALF INTEGRAL
|
||||
2320;integraltp;TOP HALF INTEGRAL
|
||||
2229;intersection;INTERSECTION
|
||||
25D8;invbullet;INVERSE BULLET
|
||||
25D9;invcircle;INVERSE WHITE CIRCLE
|
||||
263B;invsmileface;BLACK SMILING FACE
|
||||
012F;iogonek;LATIN SMALL LETTER I WITH OGONEK
|
||||
03B9;iota;GREEK SMALL LETTER IOTA
|
||||
03CA;iotadieresis;GREEK SMALL LETTER IOTA WITH DIALYTIKA
|
||||
0390;iotadieresistonos;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
|
||||
03AF;iotatonos;GREEK SMALL LETTER IOTA WITH TONOS
|
||||
0129;itilde;LATIN SMALL LETTER I WITH TILDE
|
||||
006A;j;LATIN SMALL LETTER J
|
||||
0135;jcircumflex;LATIN SMALL LETTER J WITH CIRCUMFLEX
|
||||
006B;k;LATIN SMALL LETTER K
|
||||
03BA;kappa;GREEK SMALL LETTER KAPPA
|
||||
0138;kgreenlandic;LATIN SMALL LETTER KRA
|
||||
006C;l;LATIN SMALL LETTER L
|
||||
013A;lacute;LATIN SMALL LETTER L WITH ACUTE
|
||||
03BB;lambda;GREEK SMALL LETTER LAMDA
|
||||
013E;lcaron;LATIN SMALL LETTER L WITH CARON
|
||||
0140;ldot;LATIN SMALL LETTER L WITH MIDDLE DOT
|
||||
003C;less;LESS-THAN SIGN
|
||||
2264;lessequal;LESS-THAN OR EQUAL TO
|
||||
258C;lfblock;LEFT HALF BLOCK
|
||||
20A4;lira;LIRA SIGN
|
||||
2227;logicaland;LOGICAL AND
|
||||
00AC;logicalnot;NOT SIGN
|
||||
2228;logicalor;LOGICAL OR
|
||||
017F;longs;LATIN SMALL LETTER LONG S
|
||||
25CA;lozenge;LOZENGE
|
||||
0142;lslash;LATIN SMALL LETTER L WITH STROKE
|
||||
2591;ltshade;LIGHT SHADE
|
||||
006D;m;LATIN SMALL LETTER M
|
||||
00AF;macron;MACRON
|
||||
2642;male;MALE SIGN
|
||||
2212;minus;MINUS SIGN
|
||||
2032;minute;PRIME
|
||||
00B5;mu;MICRO SIGN
|
||||
00D7;multiply;MULTIPLICATION SIGN
|
||||
266A;musicalnote;EIGHTH NOTE
|
||||
266B;musicalnotedbl;BEAMED EIGHTH NOTES
|
||||
006E;n;LATIN SMALL LETTER N
|
||||
0144;nacute;LATIN SMALL LETTER N WITH ACUTE
|
||||
0149;napostrophe;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
|
||||
0148;ncaron;LATIN SMALL LETTER N WITH CARON
|
||||
0039;nine;DIGIT NINE
|
||||
2209;notelement;NOT AN ELEMENT OF
|
||||
2260;notequal;NOT EQUAL TO
|
||||
2284;notsubset;NOT A SUBSET OF
|
||||
00F1;ntilde;LATIN SMALL LETTER N WITH TILDE
|
||||
03BD;nu;GREEK SMALL LETTER NU
|
||||
0023;numbersign;NUMBER SIGN
|
||||
006F;o;LATIN SMALL LETTER O
|
||||
00F3;oacute;LATIN SMALL LETTER O WITH ACUTE
|
||||
014F;obreve;LATIN SMALL LETTER O WITH BREVE
|
||||
00F4;ocircumflex;LATIN SMALL LETTER O WITH CIRCUMFLEX
|
||||
00F6;odieresis;LATIN SMALL LETTER O WITH DIAERESIS
|
||||
0153;oe;LATIN SMALL LIGATURE OE
|
||||
02DB;ogonek;OGONEK
|
||||
00F2;ograve;LATIN SMALL LETTER O WITH GRAVE
|
||||
01A1;ohorn;LATIN SMALL LETTER O WITH HORN
|
||||
0151;ohungarumlaut;LATIN SMALL LETTER O WITH DOUBLE ACUTE
|
||||
014D;omacron;LATIN SMALL LETTER O WITH MACRON
|
||||
03C9;omega;GREEK SMALL LETTER OMEGA
|
||||
03D6;omega1;GREEK PI SYMBOL
|
||||
03CE;omegatonos;GREEK SMALL LETTER OMEGA WITH TONOS
|
||||
03BF;omicron;GREEK SMALL LETTER OMICRON
|
||||
03CC;omicrontonos;GREEK SMALL LETTER OMICRON WITH TONOS
|
||||
0031;one;DIGIT ONE
|
||||
2024;onedotenleader;ONE DOT LEADER
|
||||
215B;oneeighth;VULGAR FRACTION ONE EIGHTH
|
||||
00BD;onehalf;VULGAR FRACTION ONE HALF
|
||||
00BC;onequarter;VULGAR FRACTION ONE QUARTER
|
||||
2153;onethird;VULGAR FRACTION ONE THIRD
|
||||
25E6;openbullet;WHITE BULLET
|
||||
00AA;ordfeminine;FEMININE ORDINAL INDICATOR
|
||||
00BA;ordmasculine;MASCULINE ORDINAL INDICATOR
|
||||
221F;orthogonal;RIGHT ANGLE
|
||||
00F8;oslash;LATIN SMALL LETTER O WITH STROKE
|
||||
01FF;oslashacute;LATIN SMALL LETTER O WITH STROKE AND ACUTE
|
||||
00F5;otilde;LATIN SMALL LETTER O WITH TILDE
|
||||
0070;p;LATIN SMALL LETTER P
|
||||
00B6;paragraph;PILCROW SIGN
|
||||
0028;parenleft;LEFT PARENTHESIS
|
||||
0029;parenright;RIGHT PARENTHESIS
|
||||
2202;partialdiff;PARTIAL DIFFERENTIAL
|
||||
0025;percent;PERCENT SIGN
|
||||
002E;period;FULL STOP
|
||||
00B7;periodcentered;MIDDLE DOT
|
||||
22A5;perpendicular;UP TACK
|
||||
2030;perthousand;PER MILLE SIGN
|
||||
20A7;peseta;PESETA SIGN
|
||||
03C6;phi;GREEK SMALL LETTER PHI
|
||||
03D5;phi1;GREEK PHI SYMBOL
|
||||
03C0;pi;GREEK SMALL LETTER PI
|
||||
002B;plus;PLUS SIGN
|
||||
00B1;plusminus;PLUS-MINUS SIGN
|
||||
211E;prescription;PRESCRIPTION TAKE
|
||||
220F;product;N-ARY PRODUCT
|
||||
2282;propersubset;SUBSET OF
|
||||
2283;propersuperset;SUPERSET OF
|
||||
221D;proportional;PROPORTIONAL TO
|
||||
03C8;psi;GREEK SMALL LETTER PSI
|
||||
0071;q;LATIN SMALL LETTER Q
|
||||
003F;question;QUESTION MARK
|
||||
00BF;questiondown;INVERTED QUESTION MARK
|
||||
0022;quotedbl;QUOTATION MARK
|
||||
201E;quotedblbase;DOUBLE LOW-9 QUOTATION MARK
|
||||
201C;quotedblleft;LEFT DOUBLE QUOTATION MARK
|
||||
201D;quotedblright;RIGHT DOUBLE QUOTATION MARK
|
||||
2018;quoteleft;LEFT SINGLE QUOTATION MARK
|
||||
201B;quotereversed;SINGLE HIGH-REVERSED-9 QUOTATION MARK
|
||||
2019;quoteright;RIGHT SINGLE QUOTATION MARK
|
||||
201A;quotesinglbase;SINGLE LOW-9 QUOTATION MARK
|
||||
0027;quotesingle;APOSTROPHE
|
||||
0072;r;LATIN SMALL LETTER R
|
||||
0155;racute;LATIN SMALL LETTER R WITH ACUTE
|
||||
221A;radical;SQUARE ROOT
|
||||
0159;rcaron;LATIN SMALL LETTER R WITH CARON
|
||||
2286;reflexsubset;SUBSET OF OR EQUAL TO
|
||||
2287;reflexsuperset;SUPERSET OF OR EQUAL TO
|
||||
00AE;registered;REGISTERED SIGN
|
||||
2310;revlogicalnot;REVERSED NOT SIGN
|
||||
03C1;rho;GREEK SMALL LETTER RHO
|
||||
02DA;ring;RING ABOVE
|
||||
2590;rtblock;RIGHT HALF BLOCK
|
||||
0073;s;LATIN SMALL LETTER S
|
||||
015B;sacute;LATIN SMALL LETTER S WITH ACUTE
|
||||
0161;scaron;LATIN SMALL LETTER S WITH CARON
|
||||
015F;scedilla;LATIN SMALL LETTER S WITH CEDILLA
|
||||
015D;scircumflex;LATIN SMALL LETTER S WITH CIRCUMFLEX
|
||||
2033;second;DOUBLE PRIME
|
||||
00A7;section;SECTION SIGN
|
||||
003B;semicolon;SEMICOLON
|
||||
0037;seven;DIGIT SEVEN
|
||||
215E;seveneighths;VULGAR FRACTION SEVEN EIGHTHS
|
||||
2592;shade;MEDIUM SHADE
|
||||
03C3;sigma;GREEK SMALL LETTER SIGMA
|
||||
03C2;sigma1;GREEK SMALL LETTER FINAL SIGMA
|
||||
223C;similar;TILDE OPERATOR
|
||||
0036;six;DIGIT SIX
|
||||
002F;slash;SOLIDUS
|
||||
263A;smileface;WHITE SMILING FACE
|
||||
0020;space;SPACE
|
||||
2660;spade;BLACK SPADE SUIT
|
||||
00A3;sterling;POUND SIGN
|
||||
220B;suchthat;CONTAINS AS MEMBER
|
||||
2211;summation;N-ARY SUMMATION
|
||||
263C;sun;WHITE SUN WITH RAYS
|
||||
0074;t;LATIN SMALL LETTER T
|
||||
03C4;tau;GREEK SMALL LETTER TAU
|
||||
0167;tbar;LATIN SMALL LETTER T WITH STROKE
|
||||
0165;tcaron;LATIN SMALL LETTER T WITH CARON
|
||||
2234;therefore;THEREFORE
|
||||
03B8;theta;GREEK SMALL LETTER THETA
|
||||
03D1;theta1;GREEK THETA SYMBOL
|
||||
00FE;thorn;LATIN SMALL LETTER THORN
|
||||
0033;three;DIGIT THREE
|
||||
215C;threeeighths;VULGAR FRACTION THREE EIGHTHS
|
||||
00BE;threequarters;VULGAR FRACTION THREE QUARTERS
|
||||
02DC;tilde;SMALL TILDE
|
||||
0303;tildecomb;COMBINING TILDE
|
||||
0384;tonos;GREEK TONOS
|
||||
2122;trademark;TRADE MARK SIGN
|
||||
25BC;triagdn;BLACK DOWN-POINTING TRIANGLE
|
||||
25C4;triaglf;BLACK LEFT-POINTING POINTER
|
||||
25BA;triagrt;BLACK RIGHT-POINTING POINTER
|
||||
25B2;triagup;BLACK UP-POINTING TRIANGLE
|
||||
0032;two;DIGIT TWO
|
||||
2025;twodotenleader;TWO DOT LEADER
|
||||
2154;twothirds;VULGAR FRACTION TWO THIRDS
|
||||
0075;u;LATIN SMALL LETTER U
|
||||
00FA;uacute;LATIN SMALL LETTER U WITH ACUTE
|
||||
016D;ubreve;LATIN SMALL LETTER U WITH BREVE
|
||||
00FB;ucircumflex;LATIN SMALL LETTER U WITH CIRCUMFLEX
|
||||
00FC;udieresis;LATIN SMALL LETTER U WITH DIAERESIS
|
||||
00F9;ugrave;LATIN SMALL LETTER U WITH GRAVE
|
||||
01B0;uhorn;LATIN SMALL LETTER U WITH HORN
|
||||
0171;uhungarumlaut;LATIN SMALL LETTER U WITH DOUBLE ACUTE
|
||||
016B;umacron;LATIN SMALL LETTER U WITH MACRON
|
||||
005F;underscore;LOW LINE
|
||||
2017;underscoredbl;DOUBLE LOW LINE
|
||||
222A;union;UNION
|
||||
2200;universal;FOR ALL
|
||||
0173;uogonek;LATIN SMALL LETTER U WITH OGONEK
|
||||
2580;upblock;UPPER HALF BLOCK
|
||||
03C5;upsilon;GREEK SMALL LETTER UPSILON
|
||||
03CB;upsilondieresis;GREEK SMALL LETTER UPSILON WITH DIALYTIKA
|
||||
03B0;upsilondieresistonos;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
|
||||
03CD;upsilontonos;GREEK SMALL LETTER UPSILON WITH TONOS
|
||||
016F;uring;LATIN SMALL LETTER U WITH RING ABOVE
|
||||
0169;utilde;LATIN SMALL LETTER U WITH TILDE
|
||||
0076;v;LATIN SMALL LETTER V
|
||||
0077;w;LATIN SMALL LETTER W
|
||||
1E83;wacute;LATIN SMALL LETTER W WITH ACUTE
|
||||
0175;wcircumflex;LATIN SMALL LETTER W WITH CIRCUMFLEX
|
||||
1E85;wdieresis;LATIN SMALL LETTER W WITH DIAERESIS
|
||||
2118;weierstrass;SCRIPT CAPITAL P
|
||||
1E81;wgrave;LATIN SMALL LETTER W WITH GRAVE
|
||||
0078;x;LATIN SMALL LETTER X
|
||||
03BE;xi;GREEK SMALL LETTER XI
|
||||
0079;y;LATIN SMALL LETTER Y
|
||||
00FD;yacute;LATIN SMALL LETTER Y WITH ACUTE
|
||||
0177;ycircumflex;LATIN SMALL LETTER Y WITH CIRCUMFLEX
|
||||
00FF;ydieresis;LATIN SMALL LETTER Y WITH DIAERESIS
|
||||
00A5;yen;YEN SIGN
|
||||
1EF3;ygrave;LATIN SMALL LETTER Y WITH GRAVE
|
||||
007A;z;LATIN SMALL LETTER Z
|
||||
017A;zacute;LATIN SMALL LETTER Z WITH ACUTE
|
||||
017E;zcaron;LATIN SMALL LETTER Z WITH CARON
|
||||
017C;zdotaccent;LATIN SMALL LETTER Z WITH DOT ABOVE
|
||||
0030;zero;DIGIT ZERO
|
||||
03B6;zeta;GREEK SMALL LETTER ZETA
|
||||
#END
|
141
util/aglfn/main.cpp
Normal file
141
util/aglfn/main.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <qbytearray.h>
|
||||
#include <qlist.h>
|
||||
#include <qmap.h>
|
||||
#include <qfile.h>
|
||||
|
||||
static QByteArray fileVersion;
|
||||
|
||||
static QList<QByteArray> glyphNames;
|
||||
static QList<ushort> glyphNameOffsets;
|
||||
static QMap<ushort, ushort> uni_to_agl_map; // sort by code point for bsearch
|
||||
|
||||
static void readGlyphList()
|
||||
{
|
||||
qDebug("Reading aglfn.txt:");
|
||||
QFile f("data/aglfn.txt");
|
||||
if (!f.exists())
|
||||
qFatal("Couldn't find aglfn.txt");
|
||||
|
||||
f.open(QFile::ReadOnly);
|
||||
|
||||
glyphNames.append(".notdef");
|
||||
glyphNameOffsets.append(0);
|
||||
uni_to_agl_map.insert(0, 0);
|
||||
while (!f.atEnd()) {
|
||||
QByteArray line;
|
||||
line.resize(1024);
|
||||
int len = f.readLine(line.data(), 1024);
|
||||
line.resize(len-1);
|
||||
|
||||
int comment = line.indexOf('#');
|
||||
if (comment != -1) {
|
||||
if (fileVersion.isEmpty()) {
|
||||
int commentTableVersion = line.indexOf("Table version:", comment);
|
||||
if (commentTableVersion != -1)
|
||||
fileVersion = line.mid(commentTableVersion + 15).trimmed();
|
||||
}
|
||||
line = line.left(comment);
|
||||
}
|
||||
line = line.trimmed();
|
||||
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
QList<QByteArray> l = line.split(';');
|
||||
Q_ASSERT(l.size() == 3);
|
||||
|
||||
bool ok;
|
||||
ushort codepoint = l[0].toUShort(&ok, 16);
|
||||
Q_ASSERT(ok);
|
||||
QByteArray glyphName = l[1].trimmed();
|
||||
|
||||
int glyphIndex = glyphNames.indexOf(glyphName);
|
||||
if (glyphIndex == -1) {
|
||||
glyphIndex = glyphNames.size();
|
||||
glyphNameOffsets.append(glyphNameOffsets.last() + glyphNames.last().size() + 1);
|
||||
glyphNames.append(glyphName);
|
||||
}
|
||||
uni_to_agl_map.insert(codepoint, glyphIndex);
|
||||
}
|
||||
|
||||
qDebug(" %d unique glyph names found", glyphNames.size());
|
||||
}
|
||||
|
||||
static QByteArray createGlyphList()
|
||||
{
|
||||
qDebug("createGlyphList:");
|
||||
|
||||
QByteArray out;
|
||||
|
||||
out += "static const char glyph_names[] =\n\"";
|
||||
int linelen = 2;
|
||||
for (int i = 0; i < glyphNames.size(); ++i) {
|
||||
if (linelen + glyphNames.at(i).size() + 2 >= 80) {
|
||||
linelen = 2;
|
||||
out += "\"\n\"";
|
||||
}
|
||||
linelen += glyphNames.at(i).size() + 2;
|
||||
out += glyphNames.at(i) + "\\0";
|
||||
}
|
||||
if (out.endsWith("\""))
|
||||
out.chop(2);
|
||||
out += "\"\n;\n\n";
|
||||
|
||||
out += "struct AGLEntry {\n"
|
||||
" unsigned short uc;\n"
|
||||
" unsigned short index;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"inline bool operator<(unsigned short uc, AGLEntry entry)\n"
|
||||
"{ return uc < entry.uc; }\n"
|
||||
"inline bool operator<(AGLEntry entry, unsigned short uc)\n"
|
||||
"{ return entry.uc < uc; }\n"
|
||||
"\n"
|
||||
"static const AGLEntry unicode_to_agl_map[] = {";
|
||||
|
||||
int i = 0;
|
||||
QMap<ushort, ushort>::const_iterator it = uni_to_agl_map.constBegin();
|
||||
while (it != uni_to_agl_map.constEnd()) {
|
||||
if (i++ % 4 == 0)
|
||||
out += "\n ";
|
||||
out += " { 0x" + QByteArray::number(it.key(), 16).rightJustified(4, '0') + ", ";
|
||||
out += QByteArray::number(glyphNameOffsets.at(it.value())).leftJustified(4, ' ') + " },";
|
||||
++it;
|
||||
}
|
||||
out.chop(1);
|
||||
out += "\n};\n\n";
|
||||
|
||||
out += "enum { unicode_to_agl_map_size = sizeof(unicode_to_agl_map) / sizeof(unicode_to_agl_map[0]) };\n\n";
|
||||
|
||||
qDebug(" Glyph names list uses : %d bytes", glyphNameOffsets.last() + glyphNames.last().size() + 1);
|
||||
qDebug(" Unicode to Glyph names map uses : %d bytes", uni_to_agl_map.size()*4);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
{
|
||||
readGlyphList();
|
||||
|
||||
QByteArray header =
|
||||
"// Copyright (C) 2016 The Qt Company Ltd.\n"
|
||||
"// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only\n"
|
||||
"\n";
|
||||
|
||||
QByteArray note =
|
||||
"/* This file is autogenerated from the Adobe Glyph List database" +
|
||||
(!fileVersion.isEmpty() ? " v" + fileVersion : "") + ". Do not edit */\n\n";
|
||||
|
||||
QFile f("../../src/gui/text/qfontsubset_agl.cpp");
|
||||
f.open(QFile::WriteOnly|QFile::Truncate);
|
||||
f.write(header);
|
||||
f.write(note);
|
||||
f.write("namespace {\n\n");
|
||||
f.write(createGlyphList());
|
||||
f.write("}\n");
|
||||
f.close();
|
||||
}
|
106
util/android/android_emulator_launcher.sh
Normal file
106
util/android/android_emulator_launcher.sh
Normal file
@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
# Copyright (C) 2021 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
# This util launches the Android emulator and ensures it doesn't stuck/freeze
|
||||
# by detecting that and restarting it
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
EMULATOR_MAX_RETRIES=5
|
||||
EMULATOR_EXEC="$ANDROID_SDK_ROOT/emulator/emulator"
|
||||
ADB_EXEC="$ANDROID_SDK_ROOT/platform-tools/adb"
|
||||
if [ -z "${ANDROID_EMULATOR}" ]
|
||||
then
|
||||
EMULATOR_NAME="@emulator_x86_api_23"
|
||||
else
|
||||
EMULATOR_NAME="$ANDROID_EMULATOR"
|
||||
fi
|
||||
|
||||
|
||||
function check_for_android_device
|
||||
{
|
||||
$ADB_EXEC devices \
|
||||
| awk 'NR==2{print $2}' | grep -qE '^(online|device)$'
|
||||
}
|
||||
|
||||
# WARNING: On the very first boot of the emulator it happens that the device
|
||||
# "finishes" booting and getprop shows bootanim=stopped and
|
||||
# boot_completed=1. But sometimes not all packages have been installed (`pm
|
||||
# list packages` shows only 16 packages installed), and after around half a
|
||||
# minute the boot animation starts spinning (bootanim=running) again despite
|
||||
# boot_completed=1 all the time. After some minutes the boot animation stops
|
||||
# again and the list of packages contains 80 packages. Only then the device is
|
||||
# fully booted, and only then is dev.bootcomplete=1.
|
||||
#
|
||||
# To reproduce the emulator booting as the first time, you have to delete the
|
||||
# cached images found inside $HOME/.android especially the
|
||||
# "userdata-qemu.img.qcow2" file.
|
||||
function check_if_fully_booted
|
||||
{
|
||||
# The "getprop" command separates lines with \r\n so we trim them
|
||||
bootanim=` $ADB_EXEC shell getprop init.svc.bootanim | tr -d '\r\n'`
|
||||
boot_completed=`$ADB_EXEC shell getprop sys.boot_completed | tr -d '\r\n'`
|
||||
bootcomplete=` $ADB_EXEC shell getprop dev.bootcomplete | tr -d '\r\n'`
|
||||
echo "bootanim=$bootanim boot_completed=$boot_completed bootcomplete=$bootcomplete"
|
||||
[ "$bootanim" = stopped ] && [ "$boot_completed" = 1 ] && [ "$bootcomplete" = 1 ]
|
||||
}
|
||||
|
||||
|
||||
|
||||
for counter in `seq ${EMULATOR_MAX_RETRIES}`
|
||||
do
|
||||
$ADB_EXEC start-server
|
||||
|
||||
if check_for_android_device
|
||||
then
|
||||
echo "Emulator is already running but it shouldn't be. Aborting\!"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
echo "Starting emulator, try ${counter}/${EMULATOR_MAX_RETRIES}"
|
||||
$EMULATOR_EXEC $EMULATOR_NAME \
|
||||
-gpu swiftshader_indirect -no-audio -partition-size 4096 \
|
||||
-cores 4 -memory 16000 -no-snapshot-load -no-snapshot-save \
|
||||
</dev/null >$HOME/emulator.log 2>&1 &
|
||||
emulator_pid=$!
|
||||
disown $emulator_pid
|
||||
|
||||
echo "Waiting for emulated device to appear..."
|
||||
$ADB_EXEC wait-for-device
|
||||
|
||||
echo "Waiting a few minutes for the emulator to fully boot..."
|
||||
emulator_status=down
|
||||
for i in `seq 300`
|
||||
do
|
||||
sleep 1
|
||||
|
||||
if check_for_android_device && check_if_fully_booted
|
||||
then
|
||||
emulator_status=up
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If emulator status is still offline after timeout period,
|
||||
# we can assume it's stuck, and we must restart it
|
||||
if [ $emulator_status = up ]
|
||||
then
|
||||
echo "Emulator started successfully"
|
||||
break
|
||||
else
|
||||
if [ $counter -lt $EMULATOR_MAX_RETRIES ]
|
||||
then
|
||||
echo "Emulator failed to start, forcefully killing current instance and re-starting emulator"
|
||||
kill $emulator_pid || true
|
||||
sleep 5
|
||||
elif [ $counter -eq $EMULATOR_MAX_RETRIES ]
|
||||
then
|
||||
echo "Emulator failed to start, reached maximum number of retries. Aborting\!"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
exit 0
|
20
util/cmake/Makefile
Normal file
20
util/cmake/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
test: flake8 mypy pytest black_format_check
|
||||
|
||||
coverage:
|
||||
pytest --cov .
|
||||
|
||||
format:
|
||||
black *.py --line-length 100
|
||||
|
||||
black_format_check:
|
||||
black *.py --line-length 100 --check
|
||||
|
||||
flake8:
|
||||
flake8 *.py --ignore=E501,E266,E203,W503,F541
|
||||
|
||||
pytest:
|
||||
pytest
|
||||
|
||||
mypy:
|
||||
mypy --pretty *.py
|
18
util/cmake/Pipfile
Normal file
18
util/cmake/Pipfile
Normal file
@ -0,0 +1,18 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pyparsing = "*"
|
||||
sympy = "*"
|
||||
mypy = "*"
|
||||
pytest = "*"
|
||||
pytest-cov = "*"
|
||||
flake8 = "*"
|
||||
portalocker = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
57
util/cmake/README.md
Normal file
57
util/cmake/README.md
Normal file
@ -0,0 +1,57 @@
|
||||
# CMake Utils
|
||||
|
||||
This directory holds scripts to help the porting process from `qmake` to `cmake` for Qt6.
|
||||
|
||||
If you're looking to port your own Qt-based project from `qmake` to `cmake`, please use
|
||||
[qmake2cmake](https://wiki.qt.io/Qmake2cmake).
|
||||
|
||||
# Requirements
|
||||
|
||||
* [Python 3.7](https://www.python.org/downloads/),
|
||||
* `pipenv` or `pip` to manage the modules.
|
||||
|
||||
## Python modules
|
||||
|
||||
Since Python has many ways of handling projects, you have a couple of options to
|
||||
install the dependencies of the scripts:
|
||||
|
||||
### Using `pipenv`
|
||||
|
||||
The dependencies are specified on the `Pipfile`, so you just need to run
|
||||
`pipenv install` and that will automatically create a virtual environment
|
||||
that you can activate with a `pipenv shell`.
|
||||
|
||||
### Using `pip`
|
||||
|
||||
It's highly recommended to use a [virtualenvironment](https://virtualenv.pypa.io/en/latest/)
|
||||
to avoid conflict with other packages that are already installed: `pip install virtualenv`.
|
||||
|
||||
* Create an environment: `virtualenv env`,
|
||||
* Activate the environment: `source env/bin/activate`
|
||||
(on Windows: `source env\Scripts\activate.bat`)
|
||||
* Install the requirements: `pip install -r requirements.txt`
|
||||
|
||||
If the `pip install` command above doesn't work, try:
|
||||
|
||||
```
|
||||
python3.7 -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
# Contributing to the scripts
|
||||
|
||||
You can verify if the styling of a script is compliant with PEP8, with a couple of exceptions:
|
||||
|
||||
Install [flake8](http://flake8.pycqa.org/en/latest/) (`pip install flake8`) and run it
|
||||
on all python source files:
|
||||
|
||||
```
|
||||
make flake8
|
||||
```
|
||||
|
||||
You can also modify the file with an automatic formatter,
|
||||
like [black](https://black.readthedocs.io/en/stable/) (`pip install black`),
|
||||
and execute it:
|
||||
|
||||
```
|
||||
make format
|
||||
```
|
116
util/cmake/cmakeconversionrate.py
Normal file
116
util/cmake/cmakeconversionrate.py
Normal file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import typing
|
||||
|
||||
|
||||
def _parse_commandline():
|
||||
parser = ArgumentParser(description="Calculate the conversion rate to cmake.")
|
||||
parser.add_argument("--debug", dest="debug", action="store_true", help="Turn on debug output")
|
||||
parser.add_argument(
|
||||
"source_directory",
|
||||
metavar="<Source Directory>",
|
||||
type=str,
|
||||
help="The Qt module source directory",
|
||||
)
|
||||
parser.add_argument(
|
||||
"binary_directory",
|
||||
metavar="<CMake build directory>",
|
||||
type=str,
|
||||
help="The CMake build directory (might be empty)",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def calculate_baseline(source_directory: str, *, debug: bool = False) -> int:
|
||||
if debug:
|
||||
print(f'Scanning "{source_directory}" for qmake-based tests.')
|
||||
result = subprocess.run(
|
||||
'/usr/bin/git grep -E "^\\s*CONFIG\\s*\\+?=.*\\btestcase\\b" | sort -u | wc -l',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
cwd=source_directory,
|
||||
)
|
||||
return int(result.stdout)
|
||||
|
||||
|
||||
def build(source_directory: str, binary_directory: str, *, debug=False) -> None:
|
||||
abs_source = os.path.abspath(source_directory)
|
||||
if not os.path.isdir(binary_directory):
|
||||
os.makedirs(binary_directory)
|
||||
if not os.path.exists(os.path.join(binary_directory, "CMakeCache.txt")):
|
||||
|
||||
if debug:
|
||||
print(f'Running cmake in "{binary_directory}"')
|
||||
result = subprocess.run(["/usr/bin/cmake", "-GNinja", abs_source], cwd=binary_directory)
|
||||
if debug:
|
||||
print(f"CMake return code: {result.returncode}.")
|
||||
|
||||
assert result.returncode == 0
|
||||
|
||||
if debug:
|
||||
print(f'Running ninja in "{binary_directory}".')
|
||||
result = subprocess.run("/usr/bin/ninja", cwd=binary_directory)
|
||||
if debug:
|
||||
print(f"Ninja return code: {result.returncode}.")
|
||||
|
||||
assert result.returncode == 0
|
||||
|
||||
|
||||
def test(binary_directory: str, *, debug=False) -> typing.Tuple[int, int]:
|
||||
if debug:
|
||||
print(f'Running ctest in "{binary_directory}".')
|
||||
result = subprocess.run(
|
||||
'/usr/bin/ctest -j 250 | grep "tests passed, "',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
cwd=binary_directory,
|
||||
)
|
||||
summary = result.stdout.decode("utf-8").replace("\n", "")
|
||||
if debug:
|
||||
print(f"Test summary: {summary} ({result.returncode}).")
|
||||
|
||||
matches = re.fullmatch(r"\d+% tests passed, (\d+) tests failed out of (\d+)", summary)
|
||||
if matches:
|
||||
if debug:
|
||||
print(f"Matches: failed {matches.group(1)}, total {matches.group(2)}.")
|
||||
return (int(matches.group(2)), int(matches.group(2)) - int(matches.group(1)))
|
||||
|
||||
return (0, 0)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = _parse_commandline()
|
||||
|
||||
base_line = calculate_baseline(args.source_directory, debug=args.debug)
|
||||
if base_line <= 0:
|
||||
print(f"Could not find the qmake baseline in {args.source_directory}.")
|
||||
return 1
|
||||
|
||||
if args.debug:
|
||||
print(f"qmake baseline: {base_line} test binaries.")
|
||||
|
||||
cmake_total = 0
|
||||
cmake_success = 0
|
||||
try:
|
||||
build(args.source_directory, args.binary_directory, debug=args.debug)
|
||||
(cmake_total, cmake_success) = test(args.binary_directory, debug=args.debug)
|
||||
finally:
|
||||
if cmake_total == 0:
|
||||
print("\n\n\nCould not calculate the cmake state.")
|
||||
return 2
|
||||
else:
|
||||
print(f"\n\n\nCMake test conversion rate: {cmake_total/base_line:.2f}.")
|
||||
print(f"CMake test success rate : {cmake_success/base_line:.2f}.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
211
util/cmake/condition_simplifier.py
Normal file
211
util/cmake/condition_simplifier.py
Normal file
@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2021 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
import re
|
||||
from sympy import simplify_logic, And, Or, Not, SympifyError # type: ignore
|
||||
from condition_simplifier_cache import simplify_condition_memoize
|
||||
|
||||
|
||||
def _iterate_expr_tree(expr, op, matches):
|
||||
assert expr.func == op
|
||||
keepers = ()
|
||||
for arg in expr.args:
|
||||
if arg in matches:
|
||||
matches = tuple(x for x in matches if x != arg)
|
||||
elif arg == op:
|
||||
(matches, extra_keepers) = _iterate_expr_tree(arg, op, matches)
|
||||
keepers = (*keepers, *extra_keepers)
|
||||
else:
|
||||
keepers = (*keepers, arg)
|
||||
return matches, keepers
|
||||
|
||||
|
||||
def _simplify_expressions(expr, op, matches, replacement):
|
||||
for arg in expr.args:
|
||||
expr = expr.subs(arg, _simplify_expressions(arg, op, matches, replacement))
|
||||
|
||||
if expr.func == op:
|
||||
(to_match, keepers) = tuple(_iterate_expr_tree(expr, op, matches))
|
||||
if len(to_match) == 0:
|
||||
# build expression with keepers and replacement:
|
||||
if keepers:
|
||||
start = replacement
|
||||
current_expr = None
|
||||
last_expr = keepers[-1]
|
||||
for repl_arg in keepers[:-1]:
|
||||
current_expr = op(start, repl_arg)
|
||||
start = current_expr
|
||||
top_expr = op(start, last_expr)
|
||||
else:
|
||||
top_expr = replacement
|
||||
|
||||
expr = expr.subs(expr, top_expr)
|
||||
|
||||
return expr
|
||||
|
||||
|
||||
def _simplify_flavors_in_condition(base: str, flavors, expr):
|
||||
"""Simplify conditions based on the knowledge of which flavors
|
||||
belong to which OS."""
|
||||
base_expr = simplify_logic(base)
|
||||
false_expr = simplify_logic("false")
|
||||
for flavor in flavors:
|
||||
flavor_expr = simplify_logic(flavor)
|
||||
expr = _simplify_expressions(expr, And, (base_expr, flavor_expr), flavor_expr)
|
||||
expr = _simplify_expressions(expr, Or, (base_expr, flavor_expr), base_expr)
|
||||
expr = _simplify_expressions(expr, And, (Not(base_expr), flavor_expr), false_expr)
|
||||
return expr
|
||||
|
||||
|
||||
def _simplify_os_families(expr, family_members, other_family_members):
|
||||
for family in family_members:
|
||||
for other in other_family_members:
|
||||
if other in family_members:
|
||||
continue # skip those in the sub-family
|
||||
|
||||
f_expr = simplify_logic(family)
|
||||
o_expr = simplify_logic(other)
|
||||
|
||||
expr = _simplify_expressions(expr, And, (f_expr, Not(o_expr)), f_expr)
|
||||
expr = _simplify_expressions(expr, And, (Not(f_expr), o_expr), o_expr)
|
||||
expr = _simplify_expressions(expr, And, (f_expr, o_expr), simplify_logic("false"))
|
||||
return expr
|
||||
|
||||
|
||||
def _recursive_simplify(expr):
|
||||
"""Simplify the expression as much as possible based on
|
||||
domain knowledge."""
|
||||
input_expr = expr
|
||||
|
||||
# Simplify even further, based on domain knowledge:
|
||||
# windowses = ('WIN32', 'WINRT')
|
||||
apples = ("MACOS", "UIKIT", "IOS", "TVOS", "WATCHOS")
|
||||
bsds = ("FREEBSD", "OPENBSD", "NETBSD")
|
||||
androids = ("ANDROID",)
|
||||
unixes = (
|
||||
"APPLE",
|
||||
*apples,
|
||||
"BSD",
|
||||
*bsds,
|
||||
"LINUX",
|
||||
*androids,
|
||||
"HAIKU",
|
||||
"INTEGRITY",
|
||||
"VXWORKS",
|
||||
"QNX",
|
||||
"WASM",
|
||||
)
|
||||
|
||||
unix_expr = simplify_logic("UNIX")
|
||||
win_expr = simplify_logic("WIN32")
|
||||
false_expr = simplify_logic("false")
|
||||
true_expr = simplify_logic("true")
|
||||
|
||||
expr = expr.subs(Not(unix_expr), win_expr) # NOT UNIX -> WIN32
|
||||
expr = expr.subs(Not(win_expr), unix_expr) # NOT WIN32 -> UNIX
|
||||
|
||||
# UNIX [OR foo ]OR WIN32 -> ON [OR foo]
|
||||
expr = _simplify_expressions(expr, Or, (unix_expr, win_expr), true_expr)
|
||||
# UNIX [AND foo ]AND WIN32 -> OFF [AND foo]
|
||||
expr = _simplify_expressions(expr, And, (unix_expr, win_expr), false_expr)
|
||||
|
||||
expr = _simplify_flavors_in_condition("WIN32", ("WINRT",), expr)
|
||||
expr = _simplify_flavors_in_condition("APPLE", apples, expr)
|
||||
expr = _simplify_flavors_in_condition("BSD", bsds, expr)
|
||||
expr = _simplify_flavors_in_condition("UNIX", unixes, expr)
|
||||
|
||||
# Simplify families of OSes against other families:
|
||||
expr = _simplify_os_families(expr, ("WIN32", "WINRT"), unixes)
|
||||
expr = _simplify_os_families(expr, androids, unixes)
|
||||
expr = _simplify_os_families(expr, ("BSD", *bsds), unixes)
|
||||
|
||||
for family in ("HAIKU", "QNX", "INTEGRITY", "LINUX", "VXWORKS"):
|
||||
expr = _simplify_os_families(expr, (family,), unixes)
|
||||
|
||||
# Now simplify further:
|
||||
expr = simplify_logic(expr)
|
||||
|
||||
while expr != input_expr:
|
||||
input_expr = expr
|
||||
expr = _recursive_simplify(expr)
|
||||
|
||||
return expr
|
||||
|
||||
|
||||
@simplify_condition_memoize
|
||||
def simplify_condition(condition: str) -> str:
|
||||
input_condition = condition.strip()
|
||||
|
||||
# Map to sympy syntax:
|
||||
condition = " " + input_condition + " "
|
||||
condition = condition.replace("(", " ( ")
|
||||
condition = condition.replace(")", " ) ")
|
||||
|
||||
tmp = ""
|
||||
while tmp != condition:
|
||||
tmp = condition
|
||||
|
||||
condition = condition.replace(" NOT ", " ~ ")
|
||||
condition = condition.replace(" AND ", " & ")
|
||||
condition = condition.replace(" OR ", " | ")
|
||||
condition = condition.replace(" ON ", " true ")
|
||||
condition = condition.replace(" OFF ", " false ")
|
||||
# Replace dashes with a token
|
||||
condition = condition.replace("-", "_dash_")
|
||||
|
||||
# SymPy chokes on expressions that contain two tokens one next to
|
||||
# the other delimited by a space, which are not an operation.
|
||||
# So a CMake condition like "TARGET Foo::Bar" fails the whole
|
||||
# expression simplifying process.
|
||||
# Turn these conditions into a single token so that SymPy can parse
|
||||
# the expression, and thus simplify it.
|
||||
# Do this by replacing and keeping a map of conditions to single
|
||||
# token symbols.
|
||||
# Support both target names without double colons, and with double
|
||||
# colons.
|
||||
pattern = re.compile(r"(TARGET [a-zA-Z]+(?:::[a-zA-Z]+)?)")
|
||||
target_symbol_mapping = {}
|
||||
all_target_conditions = re.findall(pattern, condition)
|
||||
for target_condition in all_target_conditions:
|
||||
# Replace spaces and colons with underscores.
|
||||
target_condition_symbol_name = re.sub("[ :]", "_", target_condition)
|
||||
target_symbol_mapping[target_condition_symbol_name] = target_condition
|
||||
condition = re.sub(target_condition, target_condition_symbol_name, condition)
|
||||
|
||||
# Do similar token mapping for comparison operators.
|
||||
pattern = re.compile(r"([a-zA-Z_0-9]+ (?:STRLESS|STREQUAL|STRGREATER) [a-zA-Z_0-9]+)")
|
||||
comparison_symbol_mapping = {}
|
||||
all_comparisons = re.findall(pattern, condition)
|
||||
for comparison in all_comparisons:
|
||||
# Replace spaces and colons with underscores.
|
||||
comparison_symbol_name = re.sub("[ ]", "_", comparison)
|
||||
comparison_symbol_mapping[comparison_symbol_name] = comparison
|
||||
condition = re.sub(comparison, comparison_symbol_name, condition)
|
||||
|
||||
try:
|
||||
# Generate and simplify condition using sympy:
|
||||
condition_expr = simplify_logic(condition)
|
||||
condition = str(_recursive_simplify(condition_expr))
|
||||
|
||||
# Restore the target conditions.
|
||||
for symbol_name in target_symbol_mapping:
|
||||
condition = re.sub(symbol_name, target_symbol_mapping[symbol_name], condition)
|
||||
|
||||
# Restore comparisons.
|
||||
for comparison in comparison_symbol_mapping:
|
||||
condition = re.sub(comparison, comparison_symbol_mapping[comparison], condition)
|
||||
|
||||
# Map back to CMake syntax:
|
||||
condition = condition.replace("~", "NOT ")
|
||||
condition = condition.replace("&", "AND")
|
||||
condition = condition.replace("|", "OR")
|
||||
condition = condition.replace("True", "ON")
|
||||
condition = condition.replace("False", "OFF")
|
||||
condition = condition.replace("_dash_", "-")
|
||||
except (SympifyError, TypeError, AttributeError):
|
||||
# sympy did not like our input, so leave this condition alone:
|
||||
condition = input_condition
|
||||
|
||||
return condition or "ON"
|
154
util/cmake/condition_simplifier_cache.py
Normal file
154
util/cmake/condition_simplifier_cache.py
Normal file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
import atexit
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
from typing import Any, Callable, Dict
|
||||
|
||||
condition_simplifier_cache_enabled = True
|
||||
|
||||
|
||||
def set_condition_simplified_cache_enabled(value: bool):
|
||||
global condition_simplifier_cache_enabled
|
||||
condition_simplifier_cache_enabled = value
|
||||
|
||||
|
||||
def get_current_file_path() -> str:
|
||||
try:
|
||||
this_file = __file__
|
||||
except NameError:
|
||||
this_file = sys.argv[0]
|
||||
this_file = os.path.abspath(this_file)
|
||||
return this_file
|
||||
|
||||
|
||||
def get_cache_location() -> str:
|
||||
this_file = get_current_file_path()
|
||||
dir_path = os.path.dirname(this_file)
|
||||
cache_path = os.path.join(dir_path, ".pro2cmake_cache", "cache.json")
|
||||
return cache_path
|
||||
|
||||
|
||||
def get_file_checksum(file_path: str) -> str:
|
||||
try:
|
||||
with open(file_path, "r") as content_file:
|
||||
content = content_file.read()
|
||||
except IOError:
|
||||
content = str(time.time())
|
||||
checksum = hashlib.md5(content.encode("utf-8")).hexdigest()
|
||||
return checksum
|
||||
|
||||
|
||||
def get_condition_simplifier_checksum() -> str:
|
||||
current_file_path = get_current_file_path()
|
||||
dir_name = os.path.dirname(current_file_path)
|
||||
condition_simplifier_path = os.path.join(dir_name, "condition_simplifier.py")
|
||||
return get_file_checksum(condition_simplifier_path)
|
||||
|
||||
|
||||
def init_cache_dict():
|
||||
return {
|
||||
"checksum": get_condition_simplifier_checksum(),
|
||||
"schema_version": "1",
|
||||
"cache": {"conditions": {}},
|
||||
}
|
||||
|
||||
|
||||
def merge_dicts_recursive(a: Dict[str, Any], other: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Merges values of "other" into "a", mutates a."""
|
||||
for key in other:
|
||||
if key in a:
|
||||
if isinstance(a[key], dict) and isinstance(other[key], dict):
|
||||
merge_dicts_recursive(a[key], other[key])
|
||||
elif a[key] == other[key]:
|
||||
pass
|
||||
else:
|
||||
a[key] = other[key]
|
||||
return a
|
||||
|
||||
|
||||
def open_file_safe(file_path: str, mode: str = "r+"):
|
||||
# Use portalocker package for file locking if available,
|
||||
# otherwise print a message to install the package.
|
||||
try:
|
||||
import portalocker # type: ignore
|
||||
|
||||
return portalocker.Lock(file_path, mode=mode, flags=portalocker.LOCK_EX)
|
||||
except ImportError:
|
||||
print(
|
||||
"The conversion script is missing a required package: portalocker. Please run "
|
||||
"python -m pip install -r requirements.txt to install the missing dependency."
|
||||
)
|
||||
exit(1)
|
||||
|
||||
|
||||
def simplify_condition_memoize(f: Callable[[str], str]):
|
||||
cache_path = get_cache_location()
|
||||
cache_file_content: Dict[str, Any] = {}
|
||||
|
||||
if os.path.exists(cache_path):
|
||||
try:
|
||||
with open_file_safe(cache_path, mode="r") as cache_file:
|
||||
cache_file_content = json.load(cache_file)
|
||||
except (IOError, ValueError):
|
||||
print(f"Invalid pro2cmake cache file found at: {cache_path}. Removing it.")
|
||||
os.remove(cache_path)
|
||||
|
||||
if not cache_file_content:
|
||||
cache_file_content = init_cache_dict()
|
||||
|
||||
current_checksum = get_condition_simplifier_checksum()
|
||||
if cache_file_content["checksum"] != current_checksum:
|
||||
cache_file_content = init_cache_dict()
|
||||
|
||||
def update_cache_file():
|
||||
if not os.path.exists(cache_path):
|
||||
os.makedirs(os.path.dirname(cache_path), exist_ok=True)
|
||||
# Create the file if it doesn't exist, but don't override
|
||||
# it.
|
||||
with open(cache_path, "a"):
|
||||
pass
|
||||
|
||||
updated_cache = cache_file_content
|
||||
|
||||
with open_file_safe(cache_path, "r+") as cache_file_write_handle:
|
||||
# Read any existing cache content, and truncate the file.
|
||||
cache_file_existing_content = cache_file_write_handle.read()
|
||||
cache_file_write_handle.seek(0)
|
||||
cache_file_write_handle.truncate()
|
||||
|
||||
# Merge the new cache into the old cache if it exists.
|
||||
if cache_file_existing_content:
|
||||
possible_cache = json.loads(cache_file_existing_content)
|
||||
if (
|
||||
"checksum" in possible_cache
|
||||
and "schema_version" in possible_cache
|
||||
and possible_cache["checksum"] == cache_file_content["checksum"]
|
||||
and possible_cache["schema_version"] == cache_file_content["schema_version"]
|
||||
):
|
||||
updated_cache = merge_dicts_recursive(dict(possible_cache), updated_cache)
|
||||
|
||||
json.dump(updated_cache, cache_file_write_handle, indent=4)
|
||||
|
||||
# Flush any buffered writes.
|
||||
cache_file_write_handle.flush()
|
||||
os.fsync(cache_file_write_handle.fileno())
|
||||
|
||||
atexit.register(update_cache_file)
|
||||
|
||||
def helper(condition: str) -> str:
|
||||
if (
|
||||
condition not in cache_file_content["cache"]["conditions"]
|
||||
or not condition_simplifier_cache_enabled
|
||||
):
|
||||
cache_file_content["cache"]["conditions"][condition] = f(condition)
|
||||
return cache_file_content["cache"]["conditions"][condition]
|
||||
|
||||
return helper
|
1559
util/cmake/configurejson2cmake.py
Normal file
1559
util/cmake/configurejson2cmake.py
Normal file
File diff suppressed because it is too large
Load Diff
13
util/cmake/generate_module_map.sh
Normal file
13
util/cmake/generate_module_map.sh
Normal file
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/bash
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
pro_files=$(find . -name \*.pro)
|
||||
|
||||
for f in ${pro_files}; do
|
||||
if grep "^load(qt_module)" "${f}" > /dev/null ; then
|
||||
target=$(grep "TARGET" "${f}" | cut -d'=' -f2 | sed -e "s/\s*//g")
|
||||
module=$(basename ${f})
|
||||
echo "'${module%.pro}': '${target}',"
|
||||
fi
|
||||
done
|
869
util/cmake/helper.py
Normal file
869
util/cmake/helper.py
Normal file
@ -0,0 +1,869 @@
|
||||
# Copyright (C) 2021 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import re
|
||||
import typing
|
||||
|
||||
|
||||
class LibraryMapping:
|
||||
def __init__(
|
||||
self,
|
||||
soName: str,
|
||||
packageName: typing.Optional[str],
|
||||
targetName: typing.Optional[str],
|
||||
*,
|
||||
resultVariable: typing.Optional[str] = None,
|
||||
extra: typing.List[str] = [],
|
||||
components: typing.Optional[typing.List[str]] = None,
|
||||
appendFoundSuffix: bool = True,
|
||||
emit_if: str = "",
|
||||
is_bundled_with_qt: bool = False,
|
||||
test_library_overwrite: str = "",
|
||||
run_library_test: bool = False,
|
||||
no_link_so_name: str = "",
|
||||
) -> None:
|
||||
self.soName = soName
|
||||
self.packageName = packageName
|
||||
self.resultVariable = resultVariable
|
||||
self.appendFoundSuffix = appendFoundSuffix
|
||||
# Allows passing addiitonal arguments to the generated find_package call.
|
||||
self.extra = extra
|
||||
self.components = components
|
||||
self.targetName = targetName
|
||||
|
||||
# True if qt bundles the library sources as part of Qt.
|
||||
self.is_bundled_with_qt = is_bundled_with_qt
|
||||
|
||||
# if emit_if is non-empty, the generated find_package call
|
||||
# for a library will be surrounded by this condition.
|
||||
self.emit_if = emit_if
|
||||
|
||||
# Allow overwriting library name when used with tests. E.g.: _nolink
|
||||
# targets do not exist when used during compile tests
|
||||
self.test_library_overwrite = test_library_overwrite
|
||||
|
||||
# Run the library compile test of configure.json
|
||||
self.run_library_test = run_library_test
|
||||
|
||||
# The custom nolink library mapping associated with this one.
|
||||
self.no_link_so_name = no_link_so_name
|
||||
|
||||
def is_qt(self) -> bool:
|
||||
return self.packageName == "Qt" or self.packageName == "Qt5" or self.packageName == "Qt6"
|
||||
|
||||
|
||||
_qt_library_map = [
|
||||
# Qt:
|
||||
LibraryMapping("androidextras", "Qt6", "Qt::AndroidExtras", components=["AndroidExtras"]),
|
||||
LibraryMapping("3danimation", "Qt6", "Qt::3DAnimation", components=["3DAnimation"]),
|
||||
LibraryMapping("3dcore", "Qt6", "Qt::3DCore", components=["3DCore"]),
|
||||
LibraryMapping("3dcoretest", "Qt6", "Qt::3DCoreTest", components=["3DCoreTest"]),
|
||||
LibraryMapping("3dextras", "Qt6", "Qt::3DExtras", components=["3DExtras"]),
|
||||
LibraryMapping("3dinput", "Qt6", "Qt::3DInput", components=["3DInput"]),
|
||||
LibraryMapping("3dlogic", "Qt6", "Qt::3DLogic", components=["3DLogic"]),
|
||||
LibraryMapping("3dquick", "Qt6", "Qt::3DQuick", components=["3DQuick"]),
|
||||
LibraryMapping("3dquickextras", "Qt6", "Qt::3DQuickExtras", components=["3DQuickExtras"]),
|
||||
LibraryMapping("3dquickinput", "Qt6", "Qt::3DQuickInput", components=["3DQuickInput"]),
|
||||
LibraryMapping("3dquickrender", "Qt6", "Qt::3DQuickRender", components=["3DQuickRender"]),
|
||||
LibraryMapping("3drender", "Qt6", "Qt::3DRender", components=["3DRender"]),
|
||||
LibraryMapping(
|
||||
"application-lib", "Qt6", "Qt::AppManApplication", components=["AppManApplication"]
|
||||
),
|
||||
LibraryMapping("axbase", "Qt6", "Qt::AxBasePrivate", components=["AxBasePrivate"]),
|
||||
LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", components=["AxContainer"]),
|
||||
LibraryMapping("axserver", "Qt6", "Qt::AxServer", components=["AxServer"]),
|
||||
LibraryMapping("bluetooth", "Qt6", "Qt::Bluetooth", components=["Bluetooth"]),
|
||||
LibraryMapping("bootstrap", "Qt6", "Qt::Bootstrap", components=["Bootstrap"]),
|
||||
# bootstrap-dbus: Not needed in Qt6!
|
||||
LibraryMapping("client", "Qt6", "Qt::WaylandClient", components=["WaylandClient"]),
|
||||
LibraryMapping("coap", "Qt6", "Qt::Coap", components=["Coap"]),
|
||||
LibraryMapping("common-lib", "Qt6", "Qt::AppManCommon", components=["AppManCommon"]),
|
||||
LibraryMapping("compositor", "Qt6", "Qt::WaylandCompositor", components=["WaylandCompositor"]),
|
||||
LibraryMapping("concurrent", "Qt6", "Qt::Concurrent", components=["Concurrent"]),
|
||||
LibraryMapping("container", "Qt6", "Qt::AxContainer", components=["AxContainer"]),
|
||||
LibraryMapping("control", "Qt6", "Qt::AxServer", components=["AxServer"]),
|
||||
LibraryMapping("core_headers", "Qt6", "Qt::WebEngineCore", components=["WebEngineCore"]),
|
||||
LibraryMapping("core", "Qt6", "Qt::Core", components=["Core"]),
|
||||
LibraryMapping("crypto-lib", "Qt6", "Qt::AppManCrypto", components=["AppManCrypto"]),
|
||||
LibraryMapping("dbus", "Qt6", "Qt::DBus", components=["DBus"]),
|
||||
LibraryMapping("designer", "Qt6", "Qt::Designer", components=["Designer"]),
|
||||
LibraryMapping(
|
||||
"designercomponents",
|
||||
"Qt6",
|
||||
"Qt::DesignerComponentsPrivate",
|
||||
components=["DesignerComponentsPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"devicediscovery",
|
||||
"Qt6",
|
||||
"Qt::DeviceDiscoverySupportPrivate",
|
||||
components=["DeviceDiscoverySupportPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"devicediscovery_support",
|
||||
"Qt6",
|
||||
"Qt::DeviceDiscoverySupportPrivate",
|
||||
components=["DeviceDiscoverySupportPrivate"],
|
||||
),
|
||||
LibraryMapping("edid", "Qt6", "Qt::EdidSupport", components=["EdidSupport"]),
|
||||
LibraryMapping("edid_support", "Qt6", "Qt::EdidSupport", components=["EdidSupport"]),
|
||||
LibraryMapping("eglconvenience", "Qt6", "Qt::EglSupport", components=["EglSupport"]),
|
||||
LibraryMapping(
|
||||
"eglfsdeviceintegration",
|
||||
"Qt6",
|
||||
"Qt::EglFSDeviceIntegrationPrivate",
|
||||
components=["EglFSDeviceIntegrationPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"eglfs_kms_support",
|
||||
"Qt6",
|
||||
"Qt::EglFsKmsSupportPrivate",
|
||||
components=["EglFsKmsSupportPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"eglfs_kms_gbm_support",
|
||||
"Qt6",
|
||||
"Qt::EglFsKmsGbmSupportPrivate",
|
||||
components=["EglFsKmsGbmSupportPrivate"],
|
||||
),
|
||||
LibraryMapping("egl_support", "Qt6", "Qt::EglSupport", components=["EglSupport"]),
|
||||
# enginio: Not needed in Qt6!
|
||||
LibraryMapping(
|
||||
"eventdispatchers",
|
||||
"Qt6",
|
||||
"Qt::EventDispatcherSupport",
|
||||
components=["EventDispatcherSupport"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"eventdispatcher_support",
|
||||
"Qt6",
|
||||
"Qt::EventDispatcherSupport",
|
||||
components=["EventDispatcherSupport"],
|
||||
),
|
||||
LibraryMapping("fbconvenience", "Qt6", "Qt::FbSupportPrivate", components=["FbSupportPrivate"]),
|
||||
LibraryMapping("fb_support", "Qt6", "Qt::FbSupportPrivate", components=["FbSupportPrivate"]),
|
||||
LibraryMapping(
|
||||
"fontdatabase_support",
|
||||
"Qt6",
|
||||
"Qt::FontDatabaseSupport",
|
||||
components=["FontDatabaseSupport"],
|
||||
),
|
||||
LibraryMapping("gamepad", "Qt6", "Qt::Gamepad", components=["Gamepad"]),
|
||||
LibraryMapping("geniviextras", "Qt6", "Qt::GeniviExtras", components=["GeniviExtras"]),
|
||||
LibraryMapping("global", "Qt6", "Qt::Core", components=["Core"]), # manually added special case
|
||||
LibraryMapping("glx_support", "Qt6", "Qt::GlxSupport", components=["GlxSupport"]),
|
||||
LibraryMapping("gsttools", "Qt6", "Qt::MultimediaGstTools", components=["MultimediaGstTools"]),
|
||||
LibraryMapping("gui", "Qt6", "Qt::Gui", components=["Gui"]),
|
||||
LibraryMapping("help", "Qt6", "Qt::Help", components=["Help"]),
|
||||
LibraryMapping(
|
||||
"hunspellinputmethod",
|
||||
"Qt6",
|
||||
"Qt::HunspellInputMethodPrivate",
|
||||
components=["HunspellInputMethodPrivate"],
|
||||
),
|
||||
LibraryMapping("input", "Qt6", "Qt::InputSupportPrivate", components=["InputSupportPrivate"]),
|
||||
LibraryMapping(
|
||||
"input_support",
|
||||
"Qt6",
|
||||
"Qt::InputSupportPrivate",
|
||||
components=["InputSupportPrivate"],
|
||||
),
|
||||
LibraryMapping("installer-lib", "Qt6", "Qt::AppManInstaller", components=["AppManInstaller"]),
|
||||
LibraryMapping("ivi", "Qt6", "Qt::Ivi", components=["Ivi"]),
|
||||
LibraryMapping("ivicore", "Qt6", "Qt::IviCore", components=["IviCore"]),
|
||||
LibraryMapping("ivimedia", "Qt6", "Qt::IviMedia", components=["IviMedia"]),
|
||||
LibraryMapping("knx", "Qt6", "Qt::Knx", components=["Knx"]),
|
||||
LibraryMapping(
|
||||
"kmsconvenience", "Qt6", "Qt::KmsSupportPrivate", components=["KmsSupportPrivate"]
|
||||
),
|
||||
LibraryMapping("kms_support", "Qt6", "Qt::KmsSupportPrivate", components=["KmsSupportPrivate"]),
|
||||
LibraryMapping("launcher-lib", "Qt6", "Qt::AppManLauncher", components=["AppManLauncher"]),
|
||||
LibraryMapping("lib", "Qt6", "Qt::Designer", components=["Designer"]),
|
||||
LibraryMapping(
|
||||
"linuxaccessibility_support",
|
||||
"Qt6",
|
||||
"Qt::LinuxAccessibilitySupport",
|
||||
components=["LinuxAccessibilitySupport"],
|
||||
),
|
||||
LibraryMapping("location", "Qt6", "Qt::Location", components=["Location"]),
|
||||
LibraryMapping("macextras", "Qt6", "Qt::MacExtras", components=["MacExtras"]),
|
||||
LibraryMapping("main-lib", "Qt6", "Qt::AppManMain", components=["AppManMain"]),
|
||||
LibraryMapping("manager-lib", "Qt6", "Qt::AppManManager", components=["AppManManager"]),
|
||||
LibraryMapping("monitor-lib", "Qt6", "Qt::AppManMonitor", components=["AppManMonitor"]),
|
||||
LibraryMapping("mqtt", "Qt6", "Qt::Mqtt", components=["Mqtt"]),
|
||||
LibraryMapping("multimedia", "Qt6", "Qt::Multimedia", components=["Multimedia"]),
|
||||
LibraryMapping(
|
||||
"multimediawidgets",
|
||||
"Qt6",
|
||||
"Qt::MultimediaWidgets",
|
||||
components=["MultimediaWidgets"],
|
||||
),
|
||||
LibraryMapping("network", "Qt6", "Qt::Network", components=["Network"]),
|
||||
LibraryMapping("networkauth", "Qt6", "Qt::NetworkAuth", components=["NetworkAuth"]),
|
||||
LibraryMapping("nfc", "Qt6", "Qt::Nfc", components=["Nfc"]),
|
||||
LibraryMapping("oauth", "Qt6", "Qt::NetworkAuth", components=["NetworkAuth"]),
|
||||
LibraryMapping("opcua", "Qt6", "Qt::OpcUa", components=["OpcUa"]),
|
||||
LibraryMapping("opcua_private", "Qt6", "Qt::OpcUaPrivate", components=["OpcUaPrivate"]),
|
||||
LibraryMapping("opengl", "Qt6", "Qt::OpenGL", components=["OpenGL"]),
|
||||
LibraryMapping("openglwidgets", "Qt6", "Qt::OpenGLWidgets", components=["OpenGLWidgets"]),
|
||||
LibraryMapping("package-lib", "Qt6", "Qt::AppManPackage", components=["AppManPackage"]),
|
||||
LibraryMapping(
|
||||
"packetprotocol",
|
||||
"Qt6",
|
||||
"Qt::PacketProtocolPrivate",
|
||||
components=["PacketProtocolPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"particles",
|
||||
"Qt6",
|
||||
"Qt::QuickParticlesPrivate",
|
||||
components=["QuickParticlesPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"plugin-interfaces",
|
||||
"Qt6",
|
||||
"Qt::AppManPluginInterfaces",
|
||||
components=["AppManPluginInterfaces"],
|
||||
),
|
||||
LibraryMapping("positioning", "Qt6", "Qt::Positioning", components=["Positioning"]),
|
||||
LibraryMapping(
|
||||
"positioningquick", "Qt6", "Qt::PositioningQuick", components=["PositioningQuick"]
|
||||
),
|
||||
LibraryMapping("printsupport", "Qt6", "Qt::PrintSupport", components=["PrintSupport"]),
|
||||
LibraryMapping("purchasing", "Qt6", "Qt::Purchasing", components=["Purchasing"]),
|
||||
LibraryMapping("qmldebug", "Qt6", "Qt::QmlDebugPrivate", components=["QmlDebugPrivate"]),
|
||||
LibraryMapping(
|
||||
"qmldevtools", "Qt6", "Qt::QmlDevToolsPrivate", components=["QmlDevToolsPrivate"]
|
||||
),
|
||||
LibraryMapping(
|
||||
"qmlcompiler", "Qt6", "Qt::QmlCompilerPrivate", components=["QmlCompilerPrivate"]
|
||||
),
|
||||
LibraryMapping("qml", "Qt6", "Qt::Qml", components=["Qml"]),
|
||||
LibraryMapping("qmldom", "Qt6", "Qt::QmlDomPrivate", components=["QmlDomPrivate"]),
|
||||
LibraryMapping("qmlmodels", "Qt6", "Qt::QmlModels", components=["QmlModels"]),
|
||||
LibraryMapping("qmltest", "Qt6", "Qt::QuickTest", components=["QuickTest"]),
|
||||
LibraryMapping(
|
||||
"qtmultimediaquicktools",
|
||||
"Qt6",
|
||||
"Qt::MultimediaQuickPrivate",
|
||||
components=["MultimediaQuickPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"quick3dassetimport",
|
||||
"Qt6",
|
||||
"Qt::Quick3DAssetImport",
|
||||
components=["Quick3DAssetImport"],
|
||||
),
|
||||
LibraryMapping("core5compat", "Qt6", "Qt::Core5Compat", components=["Core5Compat"]),
|
||||
LibraryMapping("quick3d", "Qt6", "Qt::Quick3D", components=["Quick3D"]),
|
||||
LibraryMapping("quick3drender", "Qt6", "Qt::Quick3DRender", components=["Quick3DRender"]),
|
||||
LibraryMapping(
|
||||
"quick3druntimerender",
|
||||
"Qt6",
|
||||
"Qt::Quick3DRuntimeRender",
|
||||
components=["Quick3DRuntimeRender"],
|
||||
),
|
||||
LibraryMapping("quick3dutils", "Qt6", "Qt::Quick3DUtils", components=["Quick3DUtils"]),
|
||||
LibraryMapping("quickcontrols2", "Qt6", "Qt::QuickControls2", components=["QuickControls2"]),
|
||||
LibraryMapping(
|
||||
"quickcontrols2impl",
|
||||
"Qt6",
|
||||
"Qt::QuickControls2Impl",
|
||||
components=["QuickControls2Impl"],
|
||||
),
|
||||
LibraryMapping("quick", "Qt6", "Qt::Quick", components=["Quick"]),
|
||||
LibraryMapping(
|
||||
"quickshapes", "Qt6", "Qt::QuickShapesPrivate", components=["QuickShapesPrivate"]
|
||||
),
|
||||
LibraryMapping("quicktemplates2", "Qt6", "Qt::QuickTemplates2", components=["QuickTemplates2"]),
|
||||
LibraryMapping("quickwidgets", "Qt6", "Qt::QuickWidgets", components=["QuickWidgets"]),
|
||||
LibraryMapping("remoteobjects", "Qt6", "Qt::RemoteObjects", components=["RemoteObjects"]),
|
||||
LibraryMapping("script", "Qt6", "Qt::Script", components=["Script"]),
|
||||
LibraryMapping("scripttools", "Qt6", "Qt::ScriptTools", components=["ScriptTools"]),
|
||||
LibraryMapping("scxml", "Qt6", "Qt::Scxml", components=["Scxml"]),
|
||||
LibraryMapping("sensors", "Qt6", "Qt::Sensors", components=["Sensors"]),
|
||||
LibraryMapping("serialport", "Qt6", "Qt::SerialPort", components=["SerialPort"]),
|
||||
LibraryMapping("serialbus", "Qt6", "Qt::SerialBus", components=["SerialBus"]),
|
||||
LibraryMapping("services", "Qt6", "Qt::ServiceSupport", components=["ServiceSupport"]),
|
||||
LibraryMapping("service_support", "Qt6", "Qt::ServiceSupport", components=["ServiceSupport"]),
|
||||
LibraryMapping("shadertools", "Qt6", "Qt::ShaderTools", components=["ShaderTools"]),
|
||||
LibraryMapping("statemachine", "Qt6", "Qt::StateMachine", components=["StateMachine"]),
|
||||
LibraryMapping("sql", "Qt6", "Qt::Sql", components=["Sql"]),
|
||||
LibraryMapping("svg", "Qt6", "Qt::Svg", components=["Svg"]),
|
||||
LibraryMapping("svgwidgets", "Qt6", "Qt::SvgWidgets", components=["SvgWidgets"]),
|
||||
LibraryMapping("charts", "Qt6", "Qt::Charts", components=["Charts"]),
|
||||
LibraryMapping("testlib", "Qt6", "Qt::Test", components=["Test"]),
|
||||
LibraryMapping("texttospeech", "Qt6", "Qt::TextToSpeech", components=["TextToSpeech"]),
|
||||
LibraryMapping("theme_support", "Qt6", "Qt::ThemeSupport", components=["ThemeSupport"]),
|
||||
LibraryMapping("tts", "Qt6", "Qt::TextToSpeech", components=["TextToSpeech"]),
|
||||
LibraryMapping("uiplugin", "Qt6", "Qt::UiPlugin", components=["UiPlugin"]),
|
||||
LibraryMapping("uitools", "Qt6", "Qt::UiTools", components=["UiTools"]),
|
||||
LibraryMapping("virtualkeyboard", "Qt6", "Qt::VirtualKeyboard", components=["VirtualKeyboard"]),
|
||||
LibraryMapping("waylandclient", "Qt6", "Qt::WaylandClient", components=["WaylandClient"]),
|
||||
LibraryMapping(
|
||||
"waylandcompositor",
|
||||
"Qt6",
|
||||
"Qt::WaylandCompositor",
|
||||
components=["WaylandCompositor"],
|
||||
),
|
||||
LibraryMapping("webchannel", "Qt6", "Qt::WebChannel", components=["WebChannel"]),
|
||||
LibraryMapping("webengine", "Qt6", "Qt::WebEngine", components=["WebEngine"]),
|
||||
LibraryMapping(
|
||||
"webenginewidgets", "Qt6", "Qt::WebEngineWidgets", components=["WebEngineWidgets"]
|
||||
),
|
||||
LibraryMapping("websockets", "Qt6", "Qt::WebSockets", components=["WebSockets"]),
|
||||
LibraryMapping("webview", "Qt6", "Qt::WebView", components=["WebView"]),
|
||||
LibraryMapping("widgets", "Qt6", "Qt::Widgets", components=["Widgets"]),
|
||||
LibraryMapping("window-lib", "Qt6", "Qt::AppManWindow", components=["AppManWindow"]),
|
||||
LibraryMapping("winextras", "Qt6", "Qt::WinExtras", components=["WinExtras"]),
|
||||
LibraryMapping("x11extras", "Qt6", "Qt::X11Extras", components=["X11Extras"]),
|
||||
LibraryMapping("xcb_qpa_lib", "Qt6", "Qt::XcbQpaPrivate", components=["XcbQpaPrivate"]),
|
||||
LibraryMapping(
|
||||
"xkbcommon_support", "Qt6", "Qt::XkbCommonSupport", components=["XkbCommonSupport"]
|
||||
),
|
||||
LibraryMapping("xmlpatterns", "Qt6", "Qt::XmlPatterns", components=["XmlPatterns"]),
|
||||
LibraryMapping("xml", "Qt6", "Qt::Xml", components=["Xml"]),
|
||||
LibraryMapping("qmlworkerscript", "Qt6", "Qt::QmlWorkerScript", components=["QmlWorkerScript"]),
|
||||
LibraryMapping(
|
||||
"quickparticles",
|
||||
"Qt6",
|
||||
"Qt::QuickParticlesPrivate",
|
||||
components=["QuickParticlesPrivate"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"linuxofono_support",
|
||||
"Qt6",
|
||||
"Qt::LinuxOfonoSupport",
|
||||
components=["LinuxOfonoSupport"],
|
||||
),
|
||||
LibraryMapping(
|
||||
"linuxofono_support_private",
|
||||
"Qt6",
|
||||
"Qt::LinuxOfonoSupportPrivate",
|
||||
components=["LinuxOfonoSupportPrivate"],
|
||||
),
|
||||
LibraryMapping("tools", "Qt6", "Qt::Tools", components=["Tools"]),
|
||||
LibraryMapping("axcontainer", "Qt6", "Qt::AxContainer", components=["AxContainer"]),
|
||||
LibraryMapping("webkitwidgets", "Qt6", "Qt::WebKitWidgets", components=["WebKitWidgets"]),
|
||||
LibraryMapping("zlib", "Qt6", "Qt::Zlib", components=["Zlib"]),
|
||||
LibraryMapping("httpserver", "Qt6", "Qt::HttpServer", components=["HttpServer"]),
|
||||
LibraryMapping("sslserver", "Qt6", "Qt::SslServer", components=["HttpServer"]),
|
||||
]
|
||||
|
||||
# Note that the library map is adjusted dynamically further down.
|
||||
_library_map = [
|
||||
# 3rd party:
|
||||
LibraryMapping("atspi", "ATSPI2", "PkgConfig::ATSPI2"),
|
||||
LibraryMapping(
|
||||
"backtrace", "WrapBacktrace", "WrapBacktrace::WrapBacktrace", emit_if="config.unix"
|
||||
),
|
||||
LibraryMapping("bluez", "BlueZ", "PkgConfig::BlueZ"),
|
||||
LibraryMapping("brotli", "WrapBrotli", "WrapBrotli::WrapBrotliDec"),
|
||||
LibraryMapping("corewlan", None, None),
|
||||
LibraryMapping("cups", "Cups", "Cups::Cups"),
|
||||
LibraryMapping("directfb", "DirectFB", "PkgConfig::DirectFB"),
|
||||
LibraryMapping("db2", "DB2", "DB2::DB2"),
|
||||
LibraryMapping("dbus", "WrapDBus1", "dbus-1", resultVariable="DBus1", extra=["1.2"]),
|
||||
LibraryMapping(
|
||||
"doubleconversion", "WrapSystemDoubleConversion",
|
||||
"WrapSystemDoubleConversion::WrapSystemDoubleConversion"
|
||||
),
|
||||
LibraryMapping("dlt", "DLT", "DLT::DLT"),
|
||||
LibraryMapping("drm", "Libdrm", "Libdrm::Libdrm"),
|
||||
LibraryMapping("egl", "EGL", "EGL::EGL"),
|
||||
LibraryMapping("flite", "Flite", "Flite::Flite"),
|
||||
LibraryMapping("flite_alsa", "ALSA", "ALSA::ALSA"),
|
||||
LibraryMapping(
|
||||
"fontconfig", "Fontconfig", "Fontconfig::Fontconfig", resultVariable="FONTCONFIG"
|
||||
),
|
||||
LibraryMapping(
|
||||
"freetype",
|
||||
"WrapFreetype",
|
||||
"WrapFreetype::WrapFreetype",
|
||||
extra=["2.2.0", "REQUIRED"],
|
||||
is_bundled_with_qt=True,
|
||||
),
|
||||
LibraryMapping("gbm", "gbm", "gbm::gbm"),
|
||||
LibraryMapping("glib", "GLIB2", "GLIB2::GLIB2"),
|
||||
LibraryMapping("iconv", "WrapIconv", "WrapIconv::WrapIconv"),
|
||||
LibraryMapping("gtk3", "GTK3", "PkgConfig::GTK3", extra=["3.6"]),
|
||||
LibraryMapping("gssapi", "GSSAPI", "GSSAPI::GSSAPI"),
|
||||
LibraryMapping(
|
||||
"harfbuzz",
|
||||
"WrapHarfbuzz",
|
||||
"WrapHarfbuzz::WrapHarfbuzz",
|
||||
is_bundled_with_qt=True,
|
||||
extra=["2.6.0"],
|
||||
),
|
||||
LibraryMapping("host_dbus", None, None),
|
||||
LibraryMapping("icu", "ICU", "ICU::i18n ICU::uc ICU::data", components=["i18n", "uc", "data"]),
|
||||
LibraryMapping("journald", "Libsystemd", "PkgConfig::Libsystemd"),
|
||||
LibraryMapping("jpeg", "JPEG", "JPEG::JPEG"), # see also libjpeg
|
||||
LibraryMapping("libatomic", "WrapAtomic", "WrapAtomic::WrapAtomic"),
|
||||
LibraryMapping("libb2", "Libb2", "Libb2::Libb2"),
|
||||
LibraryMapping("libclang", "WrapLibClang", "WrapLibClang::WrapLibClang"),
|
||||
LibraryMapping("libdl", None, "${CMAKE_DL_LIBS}"),
|
||||
LibraryMapping("libinput", "Libinput", "Libinput::Libinput"),
|
||||
LibraryMapping("libjpeg", "JPEG", "JPEG::JPEG"), # see also jpeg
|
||||
LibraryMapping("libpng", "WrapPNG", "WrapPNG::WrapPNG", is_bundled_with_qt=True),
|
||||
LibraryMapping("libproxy", "Libproxy", "PkgConfig::Libproxy"),
|
||||
LibraryMapping("librt", "WrapRt", "WrapRt::WrapRt"),
|
||||
LibraryMapping("libudev", "Libudev", "PkgConfig::Libudev"),
|
||||
LibraryMapping("lttng-ust", "LTTngUST", "LTTng::UST", resultVariable="LTTNGUST"),
|
||||
LibraryMapping("libmd4c", "WrapMd4c", "WrapMd4c::WrapMd4c", is_bundled_with_qt=True),
|
||||
LibraryMapping("mtdev", "Mtdev", "PkgConfig::Mtdev"),
|
||||
LibraryMapping("mysql", "MySQL", "MySQL::MySQL"),
|
||||
LibraryMapping("odbc", "ODBC", "ODBC::ODBC"),
|
||||
LibraryMapping("opengl_es2", "GLESv2", "GLESv2::GLESv2"),
|
||||
LibraryMapping("opengl", "WrapOpenGL", "WrapOpenGL::WrapOpenGL", resultVariable="WrapOpenGL"),
|
||||
LibraryMapping(
|
||||
"openssl_headers",
|
||||
"WrapOpenSSLHeaders",
|
||||
"WrapOpenSSLHeaders::WrapOpenSSLHeaders",
|
||||
resultVariable="TEST_openssl_headers",
|
||||
appendFoundSuffix=False,
|
||||
test_library_overwrite="WrapOpenSSLHeaders::WrapOpenSSLHeaders",
|
||||
run_library_test=True,
|
||||
),
|
||||
LibraryMapping(
|
||||
"openssl",
|
||||
"WrapOpenSSL",
|
||||
"WrapOpenSSL::WrapOpenSSL",
|
||||
resultVariable="TEST_openssl",
|
||||
appendFoundSuffix=False,
|
||||
run_library_test=True,
|
||||
no_link_so_name="openssl_headers",
|
||||
),
|
||||
LibraryMapping("oci", "Oracle", "Oracle::OCI"),
|
||||
LibraryMapping(
|
||||
"pcre2",
|
||||
"WrapPCRE2",
|
||||
"WrapPCRE2::WrapPCRE2",
|
||||
extra=["10.20", "REQUIRED"],
|
||||
is_bundled_with_qt=True,
|
||||
),
|
||||
LibraryMapping("pps", "PPS", "PPS::PPS"),
|
||||
LibraryMapping("psql", "PostgreSQL", "PostgreSQL::PostgreSQL"),
|
||||
LibraryMapping("slog2", "Slog2", "Slog2::Slog2"),
|
||||
LibraryMapping("speechd", "SpeechDispatcher", "SpeechDispatcher::SpeechDispatcher"),
|
||||
LibraryMapping("sqlite2", None, None), # No more sqlite2 support in Qt6!
|
||||
LibraryMapping("sqlite3", "SQLite3", "SQLite::SQLite3"),
|
||||
LibraryMapping("sqlite", "SQLite3", "SQLite::SQLite3"),
|
||||
LibraryMapping(
|
||||
"taglib", "WrapTagLib", "WrapTagLib::WrapTagLib", is_bundled_with_qt=True
|
||||
), # used in qtivi
|
||||
LibraryMapping("tslib", "Tslib", "PkgConfig::Tslib"),
|
||||
LibraryMapping("udev", "Libudev", "PkgConfig::Libudev"),
|
||||
LibraryMapping("udev", "Libudev", "PkgConfig::Libudev"), # see also libudev!
|
||||
LibraryMapping("vulkan", "WrapVulkanHeaders", "WrapVulkanHeaders::WrapVulkanHeaders"),
|
||||
LibraryMapping("wayland_server", "Wayland", "Wayland::Server"), # used in qtbase/src/gui
|
||||
LibraryMapping("wayland-server", "Wayland", "Wayland::Server"), # used in qtwayland
|
||||
LibraryMapping("wayland-client", "Wayland", "Wayland::Client"),
|
||||
LibraryMapping("wayland-cursor", "Wayland", "Wayland::Cursor"),
|
||||
LibraryMapping("wayland-egl", "Wayland", "Wayland::Egl"),
|
||||
LibraryMapping(
|
||||
"wayland-kms", "Waylandkms", "PkgConfig::Waylandkms"
|
||||
), # TODO: check if this actually works
|
||||
LibraryMapping("x11", "X11", "X11::X11"),
|
||||
LibraryMapping("x11sm", "X11", "${X11_SM_LIB} ${X11_ICE_LIB}", resultVariable="X11_SM"),
|
||||
LibraryMapping(
|
||||
"xcb",
|
||||
"XCB",
|
||||
"XCB::XCB",
|
||||
extra=["1.11"],
|
||||
resultVariable="TARGET XCB::XCB",
|
||||
appendFoundSuffix=False,
|
||||
),
|
||||
LibraryMapping("xcb_glx", "XCB", "XCB::GLX", components=["GLX"], resultVariable="XCB_GLX"),
|
||||
LibraryMapping(
|
||||
"xcb_cursor",
|
||||
"XCB",
|
||||
"XCB::CURSOR",
|
||||
extra=["0.1.1", "COMPONENTS", "CURSOR"],
|
||||
resultVariable="XCB_CURSOR",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_icccm",
|
||||
"XCB",
|
||||
"XCB::ICCCM",
|
||||
extra=["0.3.9"],
|
||||
components=["ICCCM"],
|
||||
resultVariable="XCB_ICCCM",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_image",
|
||||
"XCB",
|
||||
"XCB::IMAGE",
|
||||
extra=["0.3.9"],
|
||||
components=["IMAGE"],
|
||||
resultVariable="XCB_IMAGE",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_keysyms",
|
||||
"XCB",
|
||||
"XCB::KEYSYMS",
|
||||
extra=["0.3.9"],
|
||||
components=["KEYSYMS"],
|
||||
resultVariable="XCB_KEYSYMS",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_randr", "XCB", "XCB::RANDR", components=["RANDR"], resultVariable="XCB_RANDR"
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_render",
|
||||
"XCB",
|
||||
"XCB::RENDER",
|
||||
components=["RENDER"],
|
||||
resultVariable="XCB_RENDER",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_renderutil",
|
||||
"XCB",
|
||||
"XCB::RENDERUTIL",
|
||||
extra=["0.3.9"],
|
||||
components=["RENDERUTIL"],
|
||||
resultVariable="XCB_RENDERUTIL",
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_shape", "XCB", "XCB::SHAPE", components=["SHAPE"], resultVariable="XCB_SHAPE"
|
||||
),
|
||||
LibraryMapping("xcb_shm", "XCB", "XCB::SHM", components=["SHM"], resultVariable="XCB_SHM"),
|
||||
LibraryMapping("xcb_sync", "XCB", "XCB::SYNC", components=["SYNC"], resultVariable="XCB_SYNC"),
|
||||
LibraryMapping(
|
||||
"xcb_xfixes",
|
||||
"XCB",
|
||||
"XCB::XFIXES",
|
||||
components=["XFIXES"],
|
||||
resultVariable="TARGET XCB::XFIXES",
|
||||
appendFoundSuffix=False,
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb-xfixes",
|
||||
"XCB",
|
||||
"XCB::XFIXES",
|
||||
components=["XFIXES"],
|
||||
resultVariable="TARGET XCB::XFIXES",
|
||||
appendFoundSuffix=False,
|
||||
),
|
||||
LibraryMapping(
|
||||
"xcb_xinput",
|
||||
"XCB",
|
||||
"XCB::XINPUT",
|
||||
extra=["1.12"],
|
||||
components=["XINPUT"],
|
||||
resultVariable="XCB_XINPUT",
|
||||
),
|
||||
LibraryMapping("xcb_xkb", "XCB", "XCB::XKB", components=["XKB"], resultVariable="XCB_XKB"),
|
||||
LibraryMapping("xcb_xlib", "X11_XCB", "X11::XCB"),
|
||||
LibraryMapping("xcomposite", "XComposite", "PkgConfig::XComposite"),
|
||||
LibraryMapping("xkbcommon_evdev", "XKB", "XKB::XKB", extra=["0.5.0"]), # see also xkbcommon
|
||||
LibraryMapping("xkbcommon_x11", "XKB_COMMON_X11", "PkgConfig::XKB_COMMON_X11", extra=["0.5.0"]),
|
||||
LibraryMapping("xkbcommon", "XKB", "XKB::XKB", extra=["0.5.0"]),
|
||||
LibraryMapping("xlib", "X11", "X11::X11"),
|
||||
LibraryMapping("xrender", "XRender", "PkgConfig::XRender", extra=["0.6"]),
|
||||
LibraryMapping("zlib", "WrapZLIB", "WrapZLIB::WrapZLIB", extra=["1.0.8"]),
|
||||
LibraryMapping("zstd", "WrapZSTD", "WrapZSTD::WrapZSTD", extra=["1.3"]),
|
||||
LibraryMapping("tiff", "TIFF", "TIFF::TIFF"),
|
||||
LibraryMapping("webp", "WrapWebP", "WrapWebP::WrapWebP"),
|
||||
LibraryMapping("jasper", "WrapJasper", "WrapJasper::WrapJasper"),
|
||||
LibraryMapping("mng", "Libmng", "Libmng::Libmng"),
|
||||
LibraryMapping("sdl2", "WrapSDL2", "WrapSDL2::WrapSDL2"),
|
||||
LibraryMapping("hunspell", "Hunspell", "Hunspell::Hunspell"),
|
||||
LibraryMapping(
|
||||
"qt3d-assimp",
|
||||
"WrapQt3DAssimp",
|
||||
"WrapQt3DAssimp::WrapQt3DAssimp",
|
||||
extra=["5"],
|
||||
run_library_test=True,
|
||||
resultVariable="TEST_assimp",
|
||||
appendFoundSuffix=False,
|
||||
),
|
||||
LibraryMapping(
|
||||
"quick3d_assimp",
|
||||
"WrapQuick3DAssimp",
|
||||
"WrapQuick3DAssimp::WrapQuick3DAssimp",
|
||||
extra=["5"],
|
||||
run_library_test=True,
|
||||
resultVariable="TEST_quick3d_assimp",
|
||||
appendFoundSuffix=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def _adjust_library_map():
|
||||
# Assign a Linux condition on all wayland related packages.
|
||||
# Assign platforms that have X11 condition on all X11 related packages.
|
||||
# We don't want to get pages of package not found messages on
|
||||
# Windows and macOS, and this also improves configure time on
|
||||
# those platforms.
|
||||
linux_package_prefixes = ["wayland"]
|
||||
x11_package_prefixes = ["xcb", "x11", "xkb", "xrender", "xlib"]
|
||||
for i, _ in enumerate(_library_map):
|
||||
if any([_library_map[i].soName.startswith(p) for p in linux_package_prefixes]):
|
||||
_library_map[i].emit_if = "config.linux"
|
||||
if any([_library_map[i].soName.startswith(p) for p in x11_package_prefixes]):
|
||||
_library_map[i].emit_if = "X11_SUPPORTED"
|
||||
|
||||
|
||||
_adjust_library_map()
|
||||
|
||||
|
||||
def find_3rd_party_library_mapping(soName: str) -> typing.Optional[LibraryMapping]:
|
||||
for i in _library_map:
|
||||
if i.soName == soName:
|
||||
return i
|
||||
return None
|
||||
|
||||
|
||||
def find_qt_library_mapping(soName: str) -> typing.Optional[LibraryMapping]:
|
||||
for i in _qt_library_map:
|
||||
if i.soName == soName:
|
||||
return i
|
||||
return None
|
||||
|
||||
|
||||
def find_library_info_for_target(targetName: str) -> typing.Optional[LibraryMapping]:
|
||||
qt_target = targetName
|
||||
if targetName.endswith("Private"):
|
||||
qt_target = qt_target[:-7]
|
||||
|
||||
for i in _qt_library_map:
|
||||
if i.targetName == qt_target:
|
||||
return i
|
||||
|
||||
for i in _library_map:
|
||||
if i.targetName == targetName:
|
||||
return i
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# For a given qmake library (e.g. 'openssl_headers'), check whether this is a fake library used
|
||||
# for the /nolink annotation, and return the actual annotated qmake library ('openssl/nolink').
|
||||
def find_annotated_qmake_lib_name(lib: str) -> str:
|
||||
for entry in _library_map:
|
||||
if entry.no_link_so_name == lib:
|
||||
return entry.soName + "/nolink"
|
||||
return lib
|
||||
|
||||
|
||||
def featureName(name: str) -> str:
|
||||
replacement_char = "_"
|
||||
if name.startswith("c++"):
|
||||
replacement_char = "x"
|
||||
return re.sub(r"[^a-zA-Z0-9_]", replacement_char, name)
|
||||
|
||||
|
||||
def map_qt_library(lib: str) -> str:
|
||||
private = False
|
||||
if lib.endswith("-private"):
|
||||
private = True
|
||||
lib = lib[:-8]
|
||||
mapped = find_qt_library_mapping(lib)
|
||||
qt_name = lib
|
||||
if mapped:
|
||||
assert mapped.targetName # Qt libs must have a target name set
|
||||
qt_name = mapped.targetName
|
||||
if private:
|
||||
qt_name += "Private"
|
||||
return qt_name
|
||||
|
||||
|
||||
platform_mapping = {
|
||||
"win32": "WIN32",
|
||||
"win": "WIN32",
|
||||
"unix": "UNIX",
|
||||
"darwin": "APPLE",
|
||||
"linux": "LINUX",
|
||||
"integrity": "INTEGRITY",
|
||||
"qnx": "QNX",
|
||||
"vxworks": "VXWORKS",
|
||||
"hpux": "HPUX",
|
||||
"nacl": "NACL",
|
||||
"android": "ANDROID",
|
||||
"uikit": "UIKIT",
|
||||
"tvos": "TVOS",
|
||||
"watchos": "WATCHOS",
|
||||
"winrt": "WINRT",
|
||||
"wasm": "WASM",
|
||||
"emscripten": "EMSCRIPTEN",
|
||||
"msvc": "MSVC",
|
||||
"clang": "CLANG",
|
||||
"gcc": "GCC",
|
||||
"icc": "ICC",
|
||||
"intel_icc": "ICC",
|
||||
"osx": "MACOS",
|
||||
"ios": "IOS",
|
||||
"freebsd": "FREEBSD",
|
||||
"openbsd": "OPENBSD",
|
||||
"mingw": "MINGW",
|
||||
"netbsd": "NETBSD",
|
||||
"haiku": "HAIKU",
|
||||
"mac": "APPLE",
|
||||
"macx": "MACOS",
|
||||
"macos": "MACOS",
|
||||
"macx-icc": "(MACOS AND ICC)",
|
||||
}
|
||||
|
||||
|
||||
def map_platform(platform: str) -> str:
|
||||
"""Return the qmake platform as cmake platform or the unchanged string."""
|
||||
return platform_mapping.get(platform, platform)
|
||||
|
||||
|
||||
def is_known_3rd_party_library(lib: str) -> bool:
|
||||
handling_no_link = False
|
||||
if lib.endswith("/nolink") or lib.endswith("_nolink"):
|
||||
lib = lib[:-7]
|
||||
handling_no_link = True
|
||||
mapping = find_3rd_party_library_mapping(lib)
|
||||
if handling_no_link and mapping and mapping.no_link_so_name:
|
||||
no_link_mapping = find_3rd_party_library_mapping(mapping.no_link_so_name)
|
||||
if no_link_mapping:
|
||||
mapping = no_link_mapping
|
||||
|
||||
return mapping is not None
|
||||
|
||||
|
||||
def map_3rd_party_library(lib: str) -> str:
|
||||
handling_no_link = False
|
||||
libpostfix = ""
|
||||
if lib.endswith("/nolink"):
|
||||
lib = lib[:-7]
|
||||
libpostfix = "_nolink"
|
||||
handling_no_link = True
|
||||
|
||||
mapping = find_3rd_party_library_mapping(lib)
|
||||
|
||||
if handling_no_link and mapping and mapping.no_link_so_name:
|
||||
no_link_mapping = find_3rd_party_library_mapping(mapping.no_link_so_name)
|
||||
if no_link_mapping:
|
||||
mapping = no_link_mapping
|
||||
libpostfix = ""
|
||||
|
||||
if not mapping or not mapping.targetName:
|
||||
return lib
|
||||
|
||||
return mapping.targetName + libpostfix
|
||||
|
||||
|
||||
compile_test_dependent_library_mapping = {
|
||||
"dtls": {"openssl": "openssl_headers"},
|
||||
"ocsp": {"openssl": "openssl_headers"},
|
||||
}
|
||||
|
||||
|
||||
def get_compile_test_dependent_library_mapping(compile_test_name: str, dependency_name: str):
|
||||
if compile_test_name in compile_test_dependent_library_mapping:
|
||||
mapping = compile_test_dependent_library_mapping[compile_test_name]
|
||||
if dependency_name in mapping:
|
||||
return mapping[dependency_name]
|
||||
|
||||
return dependency_name
|
||||
|
||||
|
||||
def generate_find_package_info(
|
||||
lib: LibraryMapping,
|
||||
use_qt_find_package: bool = True,
|
||||
*,
|
||||
indent: int = 0,
|
||||
emit_if: str = "",
|
||||
use_system_package_name: bool = False,
|
||||
remove_REQUIRED_from_extra: bool = True,
|
||||
components_required: bool = True,
|
||||
module: str = "",
|
||||
) -> str:
|
||||
isRequired = False
|
||||
|
||||
extra = lib.extra.copy()
|
||||
if lib.components:
|
||||
extra.append("COMPONENTS" if components_required else "OPTIONAL_COMPONENTS")
|
||||
extra += lib.components
|
||||
|
||||
if "REQUIRED" in extra and use_qt_find_package:
|
||||
isRequired = True
|
||||
if remove_REQUIRED_from_extra:
|
||||
extra.remove("REQUIRED")
|
||||
|
||||
cmake_target_name = lib.targetName
|
||||
assert cmake_target_name
|
||||
|
||||
# _nolink or not does not matter at this point:
|
||||
if cmake_target_name.endswith("_nolink") or cmake_target_name.endswith("/nolink"):
|
||||
cmake_target_name = cmake_target_name[:-7]
|
||||
|
||||
initial_package_name: str = lib.packageName if lib.packageName else ""
|
||||
package_name: str = initial_package_name
|
||||
if use_system_package_name:
|
||||
replace_args = ["Wrap", "WrapSystem"]
|
||||
package_name = package_name.replace(*replace_args) # type: ignore
|
||||
cmake_target_name = cmake_target_name.replace(*replace_args) # type: ignore
|
||||
|
||||
if use_qt_find_package:
|
||||
if cmake_target_name:
|
||||
extra += ["PROVIDED_TARGETS", cmake_target_name]
|
||||
if module:
|
||||
extra += ["MODULE_NAME", module]
|
||||
extra += ["QMAKE_LIB", find_annotated_qmake_lib_name(lib.soName)]
|
||||
|
||||
result = ""
|
||||
one_ind = " "
|
||||
ind = one_ind * indent
|
||||
|
||||
if use_qt_find_package:
|
||||
if extra:
|
||||
result = f"{ind}qt_find_package({package_name} {' '.join(extra)})\n"
|
||||
else:
|
||||
result = f"{ind}qt_find_package({package_name})\n"
|
||||
|
||||
if isRequired:
|
||||
result += (
|
||||
f"{ind}set_package_properties({initial_package_name} PROPERTIES TYPE REQUIRED)\n"
|
||||
)
|
||||
else:
|
||||
if extra:
|
||||
result = f"{ind}find_package({package_name} {' '.join(extra)})\n"
|
||||
else:
|
||||
result = f"{ind}find_package({package_name})\n"
|
||||
|
||||
# If a package should be found only in certain conditions, wrap
|
||||
# the find_package call within that condition.
|
||||
if emit_if:
|
||||
result = f"if(({emit_if}) OR QT_FIND_ALL_PACKAGES_ALWAYS)\n{one_ind}{result}endif()\n"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _set_up_py_parsing_nicer_debug_output(pp):
|
||||
indent = -1
|
||||
|
||||
def increase_indent(fn):
|
||||
def wrapper_function(*args):
|
||||
nonlocal indent
|
||||
indent += 1
|
||||
print("> " * indent, end="")
|
||||
return fn(*args)
|
||||
|
||||
return wrapper_function
|
||||
|
||||
def decrease_indent(fn):
|
||||
def wrapper_function(*args):
|
||||
nonlocal indent
|
||||
print("> " * indent, end="")
|
||||
indent -= 1
|
||||
return fn(*args)
|
||||
|
||||
return wrapper_function
|
||||
|
||||
if hasattr(pp, "_defaultStartDebugAction"):
|
||||
pp._defaultStartDebugAction = increase_indent(pp._defaultStartDebugAction)
|
||||
pp._defaultSuccessDebugAction = decrease_indent(pp._defaultSuccessDebugAction)
|
||||
pp._defaultExceptionDebugAction = decrease_indent(pp._defaultExceptionDebugAction)
|
||||
elif hasattr(pp.core, "_default_start_debug_action"):
|
||||
pp.core._default_start_debug_action = increase_indent(pp.core._default_start_debug_action)
|
||||
pp.core._default_success_debug_action = decrease_indent(
|
||||
pp.core._default_success_debug_action
|
||||
)
|
||||
pp.core._default_exception_debug_action = decrease_indent(
|
||||
pp.core._default_exception_debug_action
|
||||
)
|
76
util/cmake/json_parser.py
Normal file
76
util/cmake/json_parser.py
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import pyparsing as pp # type: ignore
|
||||
import json
|
||||
import re
|
||||
from helper import _set_up_py_parsing_nicer_debug_output
|
||||
|
||||
_set_up_py_parsing_nicer_debug_output(pp)
|
||||
|
||||
|
||||
class QMakeSpecificJSONParser:
|
||||
def __init__(self, *, debug: bool = False) -> None:
|
||||
self.debug = debug
|
||||
self.grammar = self.create_py_parsing_grammar()
|
||||
|
||||
def create_py_parsing_grammar(self):
|
||||
# Keep around all whitespace.
|
||||
pp.ParserElement.setDefaultWhitespaceChars("")
|
||||
|
||||
def add_element(name: str, value: pp.ParserElement):
|
||||
nonlocal self
|
||||
if self.debug:
|
||||
value.setName(name)
|
||||
value.setDebug()
|
||||
return value
|
||||
|
||||
# Our grammar is pretty simple. We want to remove all newlines
|
||||
# inside quoted strings, to make the quoted strings JSON
|
||||
# compliant. So our grammar should skip to the first quote while
|
||||
# keeping everything before it as-is, process the quoted string
|
||||
# skip to the next quote, and repeat that until the end of the
|
||||
# file.
|
||||
|
||||
EOF = add_element("EOF", pp.StringEnd())
|
||||
SkipToQuote = add_element("SkipToQuote", pp.SkipTo('"'))
|
||||
SkipToEOF = add_element("SkipToEOF", pp.SkipTo(EOF))
|
||||
|
||||
def remove_newlines_and_whitespace_in_quoted_string(tokens):
|
||||
first_string = tokens[0]
|
||||
replaced_string = re.sub(r"\n[ ]*", " ", first_string)
|
||||
return replaced_string
|
||||
|
||||
QuotedString = add_element(
|
||||
"QuotedString", pp.QuotedString(quoteChar='"', multiline=True, unquoteResults=False)
|
||||
)
|
||||
QuotedString.setParseAction(remove_newlines_and_whitespace_in_quoted_string)
|
||||
|
||||
QuotedTerm = add_element("QuotedTerm", pp.Optional(SkipToQuote) + QuotedString)
|
||||
Grammar = add_element("Grammar", pp.OneOrMore(QuotedTerm) + SkipToEOF)
|
||||
|
||||
return Grammar
|
||||
|
||||
def parse_file_using_py_parsing(self, file: str):
|
||||
print(f'Pre processing "{file}" using py parsing to remove incorrect newlines.')
|
||||
try:
|
||||
with open(file, "r") as file_fd:
|
||||
contents = file_fd.read()
|
||||
|
||||
parser_result = self.grammar.parseString(contents, parseAll=True)
|
||||
token_list = parser_result.asList()
|
||||
joined_string = "".join(token_list)
|
||||
|
||||
return joined_string
|
||||
except pp.ParseException as pe:
|
||||
print(pe.line)
|
||||
print(" " * (pe.col - 1) + "^")
|
||||
print(pe)
|
||||
raise pe
|
||||
|
||||
def parse(self, file: str):
|
||||
pre_processed_string = self.parse_file_using_py_parsing(file)
|
||||
print(f'Parsing "{file}" using json.loads().')
|
||||
json_parsed = json.loads(pre_processed_string)
|
||||
return json_parsed
|
5102
util/cmake/pro2cmake.py
Normal file
5102
util/cmake/pro2cmake.py
Normal file
File diff suppressed because it is too large
Load Diff
210
util/cmake/pro_conversion_rate.py
Normal file
210
util/cmake/pro_conversion_rate.py
Normal file
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
"""
|
||||
This utility script shows statistics about
|
||||
converted .pro -> CMakeLists.txt files.
|
||||
|
||||
To execute: python3 pro_conversion_rate.py <src dir>
|
||||
where <src dir> can be any qt source directory. For better statistics,
|
||||
specify a module root source dir (like ./qtbase or ./qtsvg).
|
||||
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import os
|
||||
import typing
|
||||
from typing import Dict, Union
|
||||
from timeit import default_timer
|
||||
|
||||
|
||||
def _parse_commandline():
|
||||
parser = ArgumentParser(description="Find pro files for which there are no CMakeLists.txt.")
|
||||
parser.add_argument(
|
||||
"source_directory", metavar="<src dir>", type=str, help="The source directory"
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
class Blacklist:
|
||||
"""Class to check if a certain dir_name / dir_path is blacklisted"""
|
||||
|
||||
def __init__(self, names: typing.List[str], path_parts: typing.List[str]):
|
||||
self.names = names
|
||||
self.path_parts = path_parts
|
||||
|
||||
# The lookup algorithm
|
||||
self.lookup = self.is_blacklisted_part
|
||||
self.tree = None
|
||||
|
||||
try:
|
||||
# If package is available, use Aho-Corasick algorithm,
|
||||
from ahocorapy.keywordtree import KeywordTree # type: ignore
|
||||
|
||||
self.tree = KeywordTree(case_insensitive=True)
|
||||
|
||||
for p in self.path_parts:
|
||||
self.tree.add(p)
|
||||
self.tree.finalize()
|
||||
|
||||
self.lookup = self.is_blacklisted_part_aho
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def is_blacklisted(self, dir_name: str, dir_path: str) -> bool:
|
||||
# First check if exact dir name is blacklisted.
|
||||
if dir_name in self.names:
|
||||
return True
|
||||
|
||||
# Check if a path part is blacklisted (e.g. util/cmake)
|
||||
return self.lookup(dir_path)
|
||||
|
||||
def is_blacklisted_part(self, dir_path: str) -> bool:
|
||||
if any(part in dir_path for part in self.path_parts):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_blacklisted_part_aho(self, dir_path: str) -> bool:
|
||||
return self.tree.search(dir_path) is not None # type: ignore
|
||||
|
||||
|
||||
def recursive_scan(path: str, extension: str, result_paths: typing.List[str], blacklist: Blacklist):
|
||||
"""Find files ending with a certain extension, filtering out blacklisted entries"""
|
||||
try:
|
||||
for entry in os.scandir(path):
|
||||
if entry.is_file() and entry.path.endswith(extension):
|
||||
result_paths.append(entry.path)
|
||||
elif entry.is_dir():
|
||||
if blacklist.is_blacklisted(entry.name, entry.path):
|
||||
continue
|
||||
recursive_scan(entry.path, extension, result_paths, blacklist)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def check_for_cmake_project(pro_path: str) -> bool:
|
||||
pro_dir_name = os.path.dirname(pro_path)
|
||||
cmake_project_path = os.path.join(pro_dir_name, "CMakeLists.txt")
|
||||
return os.path.exists(cmake_project_path)
|
||||
|
||||
|
||||
def compute_stats(
|
||||
src_path: str,
|
||||
pros_with_missing_project: typing.List[str],
|
||||
total_pros: int,
|
||||
existing_pros: int,
|
||||
missing_pros: int,
|
||||
) -> dict:
|
||||
stats: Dict[str, Dict[str, Union[str, int, float]]] = {}
|
||||
stats["total projects"] = {"label": "Total pro files found", "value": total_pros}
|
||||
stats["existing projects"] = {
|
||||
"label": "Existing CMakeLists.txt files found",
|
||||
"value": existing_pros,
|
||||
}
|
||||
stats["missing projects"] = {
|
||||
"label": "Missing CMakeLists.txt files found",
|
||||
"value": missing_pros,
|
||||
}
|
||||
stats["missing examples"] = {"label": "Missing examples", "value": 0}
|
||||
stats["missing tests"] = {"label": "Missing tests", "value": 0}
|
||||
stats["missing src"] = {"label": "Missing src/**/**", "value": 0}
|
||||
stats["missing plugins"] = {"label": "Missing plugins", "value": 0}
|
||||
|
||||
for p in pros_with_missing_project:
|
||||
rel_path = os.path.relpath(p, src_path)
|
||||
if rel_path.startswith("examples"):
|
||||
assert isinstance(stats["missing examples"]["value"], int)
|
||||
stats["missing examples"]["value"] += 1
|
||||
elif rel_path.startswith("tests"):
|
||||
assert isinstance(stats["missing tests"]["value"], int)
|
||||
stats["missing tests"]["value"] += 1
|
||||
elif rel_path.startswith(os.path.join("src", "plugins")):
|
||||
assert isinstance(stats["missing plugins"]["value"], int)
|
||||
stats["missing plugins"]["value"] += 1
|
||||
elif rel_path.startswith("src"):
|
||||
assert isinstance(stats["missing src"]["value"], int)
|
||||
stats["missing src"]["value"] += 1
|
||||
|
||||
for stat in stats:
|
||||
if int(stats[stat]["value"]) > 0:
|
||||
stats[stat]["percentage"] = round(float(stats[stat]["value"]) * 100 / total_pros, 2)
|
||||
return stats
|
||||
|
||||
|
||||
def print_stats(
|
||||
src_path: str,
|
||||
pros_with_missing_project: typing.List[str],
|
||||
stats: dict,
|
||||
scan_time: float,
|
||||
script_time: float,
|
||||
):
|
||||
|
||||
if stats["total projects"]["value"] == 0:
|
||||
print("No .pro files found. Did you specify a correct source path?")
|
||||
return
|
||||
|
||||
if stats["total projects"]["value"] == stats["existing projects"]["value"]:
|
||||
print("All projects were converted.")
|
||||
else:
|
||||
print("Missing CMakeLists.txt files for the following projects: \n")
|
||||
|
||||
for p in pros_with_missing_project:
|
||||
rel_path = os.path.relpath(p, src_path)
|
||||
print(rel_path)
|
||||
|
||||
print("\nStatistics: \n")
|
||||
|
||||
for stat in stats:
|
||||
if stats[stat]["value"] > 0:
|
||||
print(
|
||||
f"{stats[stat]['label']:<40}: {stats[stat]['value']} ({stats[stat]['percentage']}%)"
|
||||
)
|
||||
|
||||
print(f"\n{'Scan time':<40}: {scan_time:.10f} seconds")
|
||||
print(f"{'Total script time':<40}: {script_time:.10f} seconds")
|
||||
|
||||
|
||||
def main():
|
||||
args = _parse_commandline()
|
||||
src_path = os.path.abspath(args.source_directory)
|
||||
pro_paths = []
|
||||
|
||||
extension = ".pro"
|
||||
|
||||
blacklist_names = ["config.tests", "doc", "3rdparty", "angle"]
|
||||
blacklist_path_parts = [os.path.join("util", "cmake")]
|
||||
|
||||
script_start_time = default_timer()
|
||||
blacklist = Blacklist(blacklist_names, blacklist_path_parts)
|
||||
|
||||
scan_time_start = default_timer()
|
||||
recursive_scan(src_path, extension, pro_paths, blacklist)
|
||||
scan_time_end = default_timer()
|
||||
scan_time = scan_time_end - scan_time_start
|
||||
|
||||
total_pros = len(pro_paths)
|
||||
|
||||
pros_with_missing_project = []
|
||||
for pro_path in pro_paths:
|
||||
if not check_for_cmake_project(pro_path):
|
||||
pros_with_missing_project.append(pro_path)
|
||||
|
||||
missing_pros = len(pros_with_missing_project)
|
||||
existing_pros = total_pros - missing_pros
|
||||
|
||||
stats = compute_stats(
|
||||
src_path, pros_with_missing_project, total_pros, existing_pros, missing_pros
|
||||
)
|
||||
script_end_time = default_timer()
|
||||
script_time = script_end_time - script_start_time
|
||||
|
||||
print_stats(src_path, pros_with_missing_project, stats, scan_time, script_time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
422
util/cmake/qmake_parser.py
Normal file
422
util/cmake/qmake_parser.py
Normal file
@ -0,0 +1,422 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
from itertools import chain
|
||||
from typing import Tuple
|
||||
|
||||
import pyparsing as pp # type: ignore
|
||||
|
||||
from helper import _set_up_py_parsing_nicer_debug_output
|
||||
|
||||
_set_up_py_parsing_nicer_debug_output(pp)
|
||||
|
||||
|
||||
def fixup_linecontinuation(contents: str) -> str:
|
||||
# Remove all line continuations, aka a backslash followed by
|
||||
# a newline character with an arbitrary amount of whitespace
|
||||
# between the backslash and the newline.
|
||||
# This greatly simplifies the qmake parsing grammar.
|
||||
contents = re.sub(r"([^\t ])\\[ \t]*\n", "\\1 ", contents)
|
||||
contents = re.sub(r"\\[ \t]*\n", "", contents)
|
||||
return contents
|
||||
|
||||
|
||||
def fixup_comments(contents: str) -> str:
|
||||
# Get rid of completely commented out lines.
|
||||
# So any line which starts with a '#' char and ends with a new line
|
||||
# will be replaced by a single new line.
|
||||
# The # may be preceded by any number of spaces or tabs.
|
||||
#
|
||||
# This is needed because qmake syntax is weird. In a multi line
|
||||
# assignment (separated by backslashes and newlines aka
|
||||
# # \\\n ), if any of the lines are completely commented out, in
|
||||
# principle the assignment should fail.
|
||||
#
|
||||
# It should fail because you would have a new line separating
|
||||
# the previous value from the next value, and the next value would
|
||||
# not be interpreted as a value, but as a new token / operation.
|
||||
# qmake is lenient though, and accepts that, so we need to take
|
||||
# care of it as well, as if the commented line didn't exist in the
|
||||
# first place.
|
||||
|
||||
contents = re.sub(r"(^|\n)[ \t]*#[^\n]*?\n", "\n", contents, re.DOTALL)
|
||||
return contents
|
||||
|
||||
|
||||
def flatten_list(input_list):
|
||||
"""Flattens an irregular nested list into a simple list."""
|
||||
for el in input_list:
|
||||
if isinstance(el, collections.abc.Iterable) and not isinstance(el, (str, bytes)):
|
||||
yield from flatten_list(el)
|
||||
else:
|
||||
yield el
|
||||
|
||||
|
||||
def handle_function_value(group: pp.ParseResults):
|
||||
function_name = group[0]
|
||||
function_args = group[1]
|
||||
if function_name == "qtLibraryTarget":
|
||||
if len(function_args) > 1:
|
||||
raise RuntimeError(
|
||||
"Don't know what to with more than one function argument "
|
||||
"for $$qtLibraryTarget()."
|
||||
)
|
||||
return str(function_args[0])
|
||||
|
||||
if function_name == "quote":
|
||||
# Do nothing, just return a string result
|
||||
return str(group)
|
||||
|
||||
if function_name == "files":
|
||||
return str(function_args[0])
|
||||
|
||||
if function_name == "basename":
|
||||
if len(function_args) != 1:
|
||||
print(f"XXXX basename with more than one argument")
|
||||
if function_args[0] == "_PRO_FILE_PWD_":
|
||||
return os.path.basename(os.getcwd())
|
||||
print(f"XXXX basename with value other than _PRO_FILE_PWD_")
|
||||
return os.path.basename(str(function_args[0]))
|
||||
|
||||
if isinstance(function_args, pp.ParseResults):
|
||||
function_args = list(flatten_list(function_args.asList()))
|
||||
|
||||
# For other functions, return the whole expression as a string.
|
||||
return f"$${function_name}({' '.join(function_args)})"
|
||||
|
||||
|
||||
class QmakeParser:
|
||||
def __init__(self, *, debug: bool = False) -> None:
|
||||
self.debug = debug
|
||||
self._Grammar = self._generate_grammar()
|
||||
|
||||
def _generate_grammar(self):
|
||||
# Define grammar:
|
||||
pp.ParserElement.setDefaultWhitespaceChars(" \t")
|
||||
|
||||
def add_element(name: str, value: pp.ParserElement):
|
||||
nonlocal self
|
||||
if self.debug:
|
||||
value.setName(name)
|
||||
value.setDebug()
|
||||
return value
|
||||
|
||||
EOL = add_element("EOL", pp.Suppress(pp.LineEnd()))
|
||||
Else = add_element("Else", pp.Keyword("else"))
|
||||
Identifier = add_element(
|
||||
"Identifier", pp.Word(f"{pp.alphas}_", bodyChars=pp.alphanums + "_-./")
|
||||
)
|
||||
BracedValue = add_element(
|
||||
"BracedValue",
|
||||
pp.nestedExpr(
|
||||
ignoreExpr=pp.quotedString
|
||||
| pp.QuotedString(
|
||||
quoteChar="$(", endQuoteChar=")", escQuote="\\", unquoteResults=False
|
||||
)
|
||||
).setParseAction(lambda s, l, t: ["(", *t[0], ")"]),
|
||||
)
|
||||
|
||||
Substitution = add_element(
|
||||
"Substitution",
|
||||
pp.Combine(
|
||||
pp.Literal("$")
|
||||
+ (
|
||||
(
|
||||
(pp.Literal("$") + Identifier + pp.Optional(pp.nestedExpr()))
|
||||
| (pp.Literal("(") + Identifier + pp.Literal(")"))
|
||||
| (pp.Literal("{") + Identifier + pp.Literal("}"))
|
||||
| (
|
||||
pp.Literal("$")
|
||||
+ pp.Literal("{")
|
||||
+ Identifier
|
||||
+ pp.Optional(pp.nestedExpr())
|
||||
+ pp.Literal("}")
|
||||
)
|
||||
| (pp.Literal("$") + pp.Literal("[") + Identifier + pp.Literal("]"))
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
LiteralValuePart = add_element(
|
||||
"LiteralValuePart", pp.Word(pp.printables, excludeChars="$#{}()")
|
||||
)
|
||||
SubstitutionValue = add_element(
|
||||
"SubstitutionValue",
|
||||
pp.Combine(pp.OneOrMore(Substitution | LiteralValuePart | pp.Literal("$"))),
|
||||
)
|
||||
FunctionValue = add_element(
|
||||
"FunctionValue",
|
||||
pp.Group(
|
||||
pp.Suppress(pp.Literal("$") + pp.Literal("$"))
|
||||
+ Identifier
|
||||
+ pp.nestedExpr() # .setParseAction(lambda s, l, t: ['(', *t[0], ')'])
|
||||
).setParseAction(lambda s, l, t: handle_function_value(*t)),
|
||||
)
|
||||
Value = add_element(
|
||||
"Value",
|
||||
pp.NotAny(Else | pp.Literal("}") | EOL)
|
||||
+ (
|
||||
pp.QuotedString(quoteChar='"', escChar="\\")
|
||||
| FunctionValue
|
||||
| SubstitutionValue
|
||||
| BracedValue
|
||||
),
|
||||
)
|
||||
|
||||
Values = add_element("Values", pp.ZeroOrMore(Value)("value"))
|
||||
|
||||
Op = add_element(
|
||||
"OP",
|
||||
pp.Literal("=")
|
||||
| pp.Literal("-=")
|
||||
| pp.Literal("+=")
|
||||
| pp.Literal("*=")
|
||||
| pp.Literal("~="),
|
||||
)
|
||||
|
||||
Key = add_element("Key", Identifier)
|
||||
|
||||
Operation = add_element(
|
||||
"Operation", Key("key") + pp.locatedExpr(Op)("operation") + Values("value")
|
||||
)
|
||||
CallArgs = add_element("CallArgs", pp.nestedExpr())
|
||||
|
||||
def parse_call_args(results):
|
||||
out = ""
|
||||
for item in chain(*results):
|
||||
if isinstance(item, str):
|
||||
out += item
|
||||
else:
|
||||
out += "(" + parse_call_args(item) + ")"
|
||||
return out
|
||||
|
||||
CallArgs.setParseAction(parse_call_args)
|
||||
|
||||
Load = add_element("Load", pp.Keyword("load") + CallArgs("loaded"))
|
||||
Include = add_element(
|
||||
"Include", pp.Keyword("include") + pp.locatedExpr(CallArgs)("included")
|
||||
)
|
||||
Option = add_element("Option", pp.Keyword("option") + CallArgs("option"))
|
||||
RequiresCondition = add_element("RequiresCondition", pp.originalTextFor(pp.nestedExpr()))
|
||||
|
||||
def parse_requires_condition(s, l_unused, t):
|
||||
# The following expression unwraps the condition via the additional info
|
||||
# set by originalTextFor.
|
||||
condition_without_parentheses = s[t._original_start + 1 : t._original_end - 1]
|
||||
|
||||
# And this replaces the colons with '&&' similar how it's done for 'Condition'.
|
||||
condition_without_parentheses = (
|
||||
condition_without_parentheses.strip().replace(":", " && ").strip(" && ")
|
||||
)
|
||||
return condition_without_parentheses
|
||||
|
||||
RequiresCondition.setParseAction(parse_requires_condition)
|
||||
Requires = add_element(
|
||||
"Requires", pp.Keyword("requires") + RequiresCondition("project_required_condition")
|
||||
)
|
||||
|
||||
FunctionArgumentsAsString = add_element(
|
||||
"FunctionArgumentsAsString", pp.originalTextFor(pp.nestedExpr())
|
||||
)
|
||||
QtNoMakeTools = add_element(
|
||||
"QtNoMakeTools",
|
||||
pp.Keyword("qtNomakeTools") + FunctionArgumentsAsString("qt_no_make_tools_arguments"),
|
||||
)
|
||||
|
||||
# ignore the whole thing...
|
||||
DefineTestDefinition = add_element(
|
||||
"DefineTestDefinition",
|
||||
pp.Suppress(
|
||||
pp.Keyword("defineTest")
|
||||
+ CallArgs
|
||||
+ pp.nestedExpr(opener="{", closer="}", ignoreExpr=pp.LineEnd())
|
||||
),
|
||||
)
|
||||
|
||||
# ignore the whole thing...
|
||||
ForLoop = add_element(
|
||||
"ForLoop",
|
||||
pp.Suppress(
|
||||
pp.Keyword("for")
|
||||
+ CallArgs
|
||||
+ pp.nestedExpr(opener="{", closer="}", ignoreExpr=pp.LineEnd())
|
||||
),
|
||||
)
|
||||
|
||||
# ignore the whole thing...
|
||||
ForLoopSingleLine = add_element(
|
||||
"ForLoopSingleLine",
|
||||
pp.Suppress(pp.Keyword("for") + CallArgs + pp.Literal(":") + pp.SkipTo(EOL)),
|
||||
)
|
||||
|
||||
# ignore the whole thing...
|
||||
FunctionCall = add_element("FunctionCall", pp.Suppress(Identifier + pp.nestedExpr()))
|
||||
|
||||
Scope = add_element("Scope", pp.Forward())
|
||||
|
||||
Statement = add_element(
|
||||
"Statement",
|
||||
pp.Group(
|
||||
Load
|
||||
| Include
|
||||
| Option
|
||||
| Requires
|
||||
| QtNoMakeTools
|
||||
| ForLoop
|
||||
| ForLoopSingleLine
|
||||
| DefineTestDefinition
|
||||
| FunctionCall
|
||||
| Operation
|
||||
),
|
||||
)
|
||||
StatementLine = add_element("StatementLine", Statement + (EOL | pp.FollowedBy("}")))
|
||||
StatementGroup = add_element(
|
||||
"StatementGroup", pp.ZeroOrMore(StatementLine | Scope | pp.Suppress(EOL))
|
||||
)
|
||||
|
||||
Block = add_element(
|
||||
"Block",
|
||||
pp.Suppress("{")
|
||||
+ pp.Optional(EOL)
|
||||
+ StatementGroup
|
||||
+ pp.Optional(EOL)
|
||||
+ pp.Suppress("}")
|
||||
+ pp.Optional(EOL),
|
||||
)
|
||||
|
||||
ConditionEnd = add_element(
|
||||
"ConditionEnd",
|
||||
pp.FollowedBy(
|
||||
(pp.Optional(pp.White()) + (pp.Literal(":") | pp.Literal("{") | pp.Literal("|")))
|
||||
),
|
||||
)
|
||||
|
||||
ConditionPart1 = add_element(
|
||||
"ConditionPart1", (pp.Optional("!") + Identifier + pp.Optional(BracedValue))
|
||||
)
|
||||
ConditionPart2 = add_element("ConditionPart2", pp.CharsNotIn("#{}|:=\\\n"))
|
||||
ConditionPart = add_element(
|
||||
"ConditionPart", (ConditionPart1 ^ ConditionPart2) + ConditionEnd
|
||||
)
|
||||
|
||||
ConditionOp = add_element("ConditionOp", pp.Literal("|") ^ pp.Literal(":"))
|
||||
ConditionWhiteSpace = add_element(
|
||||
"ConditionWhiteSpace", pp.Suppress(pp.Optional(pp.White(" ")))
|
||||
)
|
||||
|
||||
# Unfortunately qmake condition operators have no precedence,
|
||||
# and are simply evaluated left to right. To emulate that, wrap
|
||||
# each condition sub-expression in parentheses.
|
||||
# So c1|c2:c3 is evaluated by qmake as (c1|c2):c3.
|
||||
# The following variable keeps count on how many parentheses
|
||||
# should be added to the beginning of the condition. Each
|
||||
# condition sub-expression always gets an ")", and in the
|
||||
# end the whole condition gets many "(". Note that instead
|
||||
# inserting the actual parentheses, we insert special markers
|
||||
# which get replaced in the end.
|
||||
condition_parts_count = 0
|
||||
# Whitespace in the markers is important. Assumes the markers
|
||||
# never appear in .pro files.
|
||||
l_paren_marker = "_(_ "
|
||||
r_paren_marker = " _)_"
|
||||
|
||||
def handle_condition_part(condition_part_parse_result: pp.ParseResults) -> str:
|
||||
condition_part_list = [*condition_part_parse_result]
|
||||
nonlocal condition_parts_count
|
||||
condition_parts_count += 1
|
||||
condition_part_joined = "".join(condition_part_list)
|
||||
# Add ending parenthesis marker. The counterpart is added
|
||||
# in handle_condition.
|
||||
return f"{condition_part_joined}{r_paren_marker}"
|
||||
|
||||
ConditionPart.setParseAction(handle_condition_part)
|
||||
ConditionRepeated = add_element(
|
||||
"ConditionRepeated", pp.ZeroOrMore(ConditionOp + ConditionWhiteSpace + ConditionPart)
|
||||
)
|
||||
|
||||
def handle_condition(condition_parse_results: pp.ParseResults) -> str:
|
||||
nonlocal condition_parts_count
|
||||
prepended_parentheses = l_paren_marker * condition_parts_count
|
||||
result = prepended_parentheses + " ".join(condition_parse_results).strip().replace(
|
||||
":", " && "
|
||||
).strip(" && ")
|
||||
# If there are only 2 condition sub-expressions, there is no
|
||||
# need for parentheses.
|
||||
if condition_parts_count < 3:
|
||||
result = result.replace(l_paren_marker, "")
|
||||
result = result.replace(r_paren_marker, "")
|
||||
result = result.strip(" ")
|
||||
else:
|
||||
result = result.replace(l_paren_marker, "( ")
|
||||
result = result.replace(r_paren_marker, " )")
|
||||
# Strip parentheses and spaces around the final
|
||||
# condition.
|
||||
result = result[1:-1]
|
||||
result = result.strip(" ")
|
||||
# Reset the parenthesis count for the next condition.
|
||||
condition_parts_count = 0
|
||||
return result
|
||||
|
||||
Condition = add_element("Condition", pp.Combine(ConditionPart + ConditionRepeated))
|
||||
Condition.setParseAction(handle_condition)
|
||||
|
||||
# Weird thing like write_file(a)|error() where error() is the alternative condition
|
||||
# which happens to be a function call. In this case there is no scope, but our code expects
|
||||
# a scope with a list of statements, so create a fake empty statement.
|
||||
ConditionEndingInFunctionCall = add_element(
|
||||
"ConditionEndingInFunctionCall",
|
||||
pp.Suppress(ConditionOp)
|
||||
+ FunctionCall
|
||||
+ pp.Empty().setParseAction(lambda x: [[]]).setResultsName("statements"),
|
||||
)
|
||||
|
||||
SingleLineScope = add_element(
|
||||
"SingleLineScope",
|
||||
pp.Suppress(pp.Literal(":")) + pp.Group(Block | (Statement + EOL))("statements"),
|
||||
)
|
||||
MultiLineScope = add_element("MultiLineScope", Block("statements"))
|
||||
|
||||
SingleLineElse = add_element(
|
||||
"SingleLineElse",
|
||||
pp.Suppress(pp.Literal(":")) + (Scope | Block | (Statement + pp.Optional(EOL))),
|
||||
)
|
||||
MultiLineElse = add_element("MultiLineElse", Block)
|
||||
ElseBranch = add_element("ElseBranch", pp.Suppress(Else) + (SingleLineElse | MultiLineElse))
|
||||
|
||||
# Scope is already add_element'ed in the forward declaration above.
|
||||
Scope <<= pp.Group(
|
||||
Condition("condition")
|
||||
+ (SingleLineScope | MultiLineScope | ConditionEndingInFunctionCall)
|
||||
+ pp.Optional(ElseBranch)("else_statements")
|
||||
)
|
||||
|
||||
Grammar = StatementGroup("statements")
|
||||
Grammar.ignore(pp.pythonStyleComment())
|
||||
|
||||
return Grammar
|
||||
|
||||
def parseFile(self, file: str) -> Tuple[pp.ParseResults, str]:
|
||||
print(f'Parsing "{file}"...')
|
||||
try:
|
||||
with open(file, "r") as file_fd:
|
||||
contents = file_fd.read()
|
||||
|
||||
# old_contents = contents
|
||||
contents = fixup_comments(contents)
|
||||
contents = fixup_linecontinuation(contents)
|
||||
result = self._Grammar.parseString(contents, parseAll=True)
|
||||
except pp.ParseException as pe:
|
||||
print(pe.line)
|
||||
print(f"{' ' * (pe.col-1)}^")
|
||||
print(pe)
|
||||
raise pe
|
||||
return result, contents
|
||||
|
||||
|
||||
def parseProFile(file: str, *, debug=False) -> Tuple[pp.ParseResults, str]:
|
||||
parser = QmakeParser(debug=debug)
|
||||
return parser.parseFile(file)
|
8
util/cmake/requirements.txt
Normal file
8
util/cmake/requirements.txt
Normal file
@ -0,0 +1,8 @@
|
||||
pytest; python_version >= '3.7'
|
||||
pytest-cov; python_version >= '3.7'
|
||||
mypy; python_version >= '3.7'
|
||||
pyparsing; python_version >= '3.7'
|
||||
sympy; python_version >= '3.7'
|
||||
portalocker; python_version >= '3.7'
|
||||
black; python_version >= '3.7'
|
||||
|
221
util/cmake/run_pro2cmake.py
Normal file
221
util/cmake/run_pro2cmake.py
Normal file
@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import glob
|
||||
import os
|
||||
import subprocess
|
||||
import concurrent.futures
|
||||
import sys
|
||||
import typing
|
||||
import argparse
|
||||
from argparse import ArgumentParser
|
||||
|
||||
|
||||
def parse_command_line() -> argparse.Namespace:
|
||||
parser = ArgumentParser(
|
||||
description="Run pro2cmake on all .pro files recursively in given path. "
|
||||
"You can pass additional arguments to the pro2cmake calls by appending "
|
||||
"-- --foo --bar"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-existing",
|
||||
dest="only_existing",
|
||||
action="store_true",
|
||||
help="Run pro2cmake only on .pro files that already have a CMakeLists.txt.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-missing",
|
||||
dest="only_missing",
|
||||
action="store_true",
|
||||
help="Run pro2cmake only on .pro files that do not have a CMakeLists.txt.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-qtbase-main-modules",
|
||||
dest="only_qtbase_main_modules",
|
||||
action="store_true",
|
||||
help="Run pro2cmake only on the main modules in qtbase.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--skip-subdirs-projects",
|
||||
dest="skip_subdirs_projects",
|
||||
action="store_true",
|
||||
help="Don't run pro2cmake on TEMPLATE=subdirs projects.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--is-example",
|
||||
dest="is_example",
|
||||
action="store_true",
|
||||
help="Run pro2cmake with --is-example flag.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--count", dest="count", help="How many projects should be converted.", type=int
|
||||
)
|
||||
parser.add_argument(
|
||||
"--offset",
|
||||
dest="offset",
|
||||
help="From the list of found projects, from which project should conversion begin.",
|
||||
type=int,
|
||||
)
|
||||
parser.add_argument(
|
||||
"path", metavar="<path>", type=str, help="The path where to look for .pro files."
|
||||
)
|
||||
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
# Error out when the unknown arguments do not start with a "--",
|
||||
# which implies passing through arguments to pro2cmake.
|
||||
if len(unknown) > 0 and unknown[0] != "--":
|
||||
parser.error("unrecognized arguments: {}".format(" ".join(unknown)))
|
||||
else:
|
||||
args.pro2cmake_args = unknown[1:]
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def find_all_pro_files(base_path: str, args: argparse.Namespace):
|
||||
def sorter(pro_file: str) -> str:
|
||||
"""Sorter that tries to prioritize main pro files in a directory."""
|
||||
pro_file_without_suffix = pro_file.rsplit("/", 1)[-1][:-4]
|
||||
dir_name = os.path.dirname(pro_file)
|
||||
if dir_name == ".":
|
||||
dir_name = os.path.basename(os.getcwd())
|
||||
if dir_name.endswith(pro_file_without_suffix):
|
||||
return dir_name
|
||||
return dir_name + "/__" + pro_file
|
||||
|
||||
all_files = []
|
||||
previous_dir_name: typing.Optional[str] = None
|
||||
|
||||
print("Finding .pro files.")
|
||||
glob_result = glob.glob(os.path.join(base_path, "**/*.pro"), recursive=True)
|
||||
|
||||
def cmake_lists_exists_filter(path):
|
||||
path_dir_name = os.path.dirname(path)
|
||||
if os.path.exists(os.path.join(path_dir_name, "CMakeLists.txt")):
|
||||
return True
|
||||
return False
|
||||
|
||||
def cmake_lists_missing_filter(path):
|
||||
return not cmake_lists_exists_filter(path)
|
||||
|
||||
def qtbase_main_modules_filter(path):
|
||||
main_modules = [
|
||||
"corelib",
|
||||
"network",
|
||||
"gui",
|
||||
"widgets",
|
||||
"testlib",
|
||||
"printsupport",
|
||||
"opengl",
|
||||
"sql",
|
||||
"dbus",
|
||||
"concurrent",
|
||||
"xml",
|
||||
]
|
||||
path_suffixes = [f"src/{m}/{m}.pro" for m in main_modules]
|
||||
|
||||
for path_suffix in path_suffixes:
|
||||
if path.endswith(path_suffix):
|
||||
return True
|
||||
return False
|
||||
|
||||
filter_result = glob_result
|
||||
filter_func = None
|
||||
if args.only_existing:
|
||||
filter_func = cmake_lists_exists_filter
|
||||
elif args.only_missing:
|
||||
filter_func = cmake_lists_missing_filter
|
||||
elif args.only_qtbase_main_modules:
|
||||
filter_func = qtbase_main_modules_filter
|
||||
|
||||
if filter_func:
|
||||
print("Filtering.")
|
||||
filter_result = [p for p in filter_result if filter_func(p)]
|
||||
|
||||
for pro_file in sorted(filter_result, key=sorter):
|
||||
dir_name = os.path.dirname(pro_file)
|
||||
if dir_name == previous_dir_name:
|
||||
print("Skipping:", pro_file)
|
||||
else:
|
||||
all_files.append(pro_file)
|
||||
previous_dir_name = dir_name
|
||||
return all_files
|
||||
|
||||
|
||||
def run(all_files: typing.List[str], pro2cmake: str, args: argparse.Namespace) -> typing.List[str]:
|
||||
failed_files = []
|
||||
files_count = len(all_files)
|
||||
workers = os.cpu_count() or 1
|
||||
|
||||
if args.only_qtbase_main_modules:
|
||||
# qtbase main modules take longer than usual to process.
|
||||
workers = 2
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=workers, initargs=(10,)) as pool:
|
||||
print("Firing up thread pool executor.")
|
||||
|
||||
def _process_a_file(data: typing.Tuple[str, int, int]) -> typing.Tuple[int, str, str]:
|
||||
filename, index, total = data
|
||||
pro2cmake_args = []
|
||||
if sys.platform == "win32":
|
||||
pro2cmake_args.append(sys.executable)
|
||||
pro2cmake_args.append(pro2cmake)
|
||||
if args.is_example:
|
||||
pro2cmake_args.append("--is-example")
|
||||
if args.skip_subdirs_projects:
|
||||
pro2cmake_args.append("--skip-subdirs-project")
|
||||
pro2cmake_args.append(os.path.basename(filename))
|
||||
|
||||
if args.pro2cmake_args:
|
||||
pro2cmake_args += args.pro2cmake_args
|
||||
|
||||
result = subprocess.run(
|
||||
pro2cmake_args,
|
||||
cwd=os.path.dirname(filename),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
stdout = f"Converted[{index}/{total}]: {filename}\n"
|
||||
return result.returncode, filename, stdout + result.stdout.decode()
|
||||
|
||||
for return_code, filename, stdout in pool.map(
|
||||
_process_a_file,
|
||||
zip(all_files, range(1, files_count + 1), (files_count for _ in all_files)),
|
||||
):
|
||||
if return_code:
|
||||
failed_files.append(filename)
|
||||
print(stdout)
|
||||
|
||||
return failed_files
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_command_line()
|
||||
|
||||
script_path = os.path.dirname(os.path.abspath(__file__))
|
||||
pro2cmake = os.path.join(script_path, "pro2cmake.py")
|
||||
base_path = args.path
|
||||
|
||||
all_files = find_all_pro_files(base_path, args)
|
||||
if args.offset:
|
||||
all_files = all_files[args.offset :]
|
||||
if args.count:
|
||||
all_files = all_files[: args.count]
|
||||
files_count = len(all_files)
|
||||
|
||||
failed_files = run(all_files, pro2cmake, args)
|
||||
if len(all_files) == 0:
|
||||
print("No files found.")
|
||||
|
||||
if failed_files:
|
||||
print(
|
||||
f"The following files were not successfully "
|
||||
f"converted ({len(failed_files)} of {files_count}):"
|
||||
)
|
||||
for f in failed_files:
|
||||
print(f' "{f}"')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
397
util/cmake/special_case_helper.py
Normal file
397
util/cmake/special_case_helper.py
Normal file
@ -0,0 +1,397 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2019 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
"""
|
||||
This is a helper script that takes care of reapplying special case
|
||||
modifications when regenerating a CMakeLists.txt file using
|
||||
pro2cmake.py or configure.cmake with configurejson2cmake.py.
|
||||
|
||||
It has two modes of operation:
|
||||
1) Dumb "special case" block removal and re-application.
|
||||
2) Smart "special case" diff application, using a previously generated
|
||||
"clean" CMakeLists.txt/configure.cmake as a source. "clean" in this
|
||||
case means a generated file which has no "special case" modifications.
|
||||
|
||||
Both modes use a temporary git repository to compute and reapply
|
||||
"special case" diffs.
|
||||
|
||||
For the first mode to work, the developer has to mark changes
|
||||
with "# special case" markers on every line they want to keep. Or
|
||||
enclose blocks of code they want to keep between "# special case begin"
|
||||
and "# special case end" markers.
|
||||
|
||||
For example:
|
||||
|
||||
SOURCES
|
||||
foo.cpp
|
||||
bar.cpp # special case
|
||||
|
||||
SOURCES
|
||||
foo1.cpp
|
||||
foo2.cpp
|
||||
# special case begin
|
||||
foo3.cpp
|
||||
foo4.cpp
|
||||
# special case end
|
||||
|
||||
The second mode, as mentioned, requires a previous "clean"
|
||||
CMakeLists.txt/configure.cmake file.
|
||||
|
||||
The script can then compute the exact diff between
|
||||
a "clean" and "modified" (with special cases) file, and reapply that
|
||||
diff to a newly generated "CMakeLists.txt"/"configure.cmake" file.
|
||||
|
||||
This implies that we always have to keep a "clean" file alongside the
|
||||
"modified" project file for each project (corelib, gui, etc.) So we
|
||||
have to commit both files to the repository.
|
||||
|
||||
If there is no such "clean" file, we can use the first operation mode
|
||||
to generate one. After that, we only have to use the second operation
|
||||
mode for the project file in question.
|
||||
|
||||
When the script is used, the developer only has to take care of fixing
|
||||
the newly generated "modified" file. The "clean" file is automatically
|
||||
handled and git add'ed by the script, and will be committed together
|
||||
with the "modified" file.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import subprocess
|
||||
import filecmp
|
||||
import time
|
||||
import typing
|
||||
import stat
|
||||
|
||||
from shutil import copyfile
|
||||
from shutil import rmtree
|
||||
from textwrap import dedent
|
||||
|
||||
|
||||
def remove_special_cases(original: str) -> str:
|
||||
# Remove content between the following markers
|
||||
# '# special case begin' and '# special case end'.
|
||||
# This also remove the markers.
|
||||
replaced = re.sub(
|
||||
r"\n[^#\n]*?#[^\n]*?special case begin.*?#[^\n]*special case end[^\n]*?\n",
|
||||
"\n",
|
||||
original,
|
||||
0,
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
# Remove individual lines that have the "# special case" marker.
|
||||
replaced = re.sub(r"\n.*#.*special case[^\n]*\n", "\n", replaced)
|
||||
return replaced
|
||||
|
||||
|
||||
def read_content_from_file(file_path: str) -> str:
|
||||
with open(file_path, "r") as file_fd:
|
||||
content = file_fd.read()
|
||||
return content
|
||||
|
||||
|
||||
def write_content_to_file(file_path: str, content: str) -> None:
|
||||
with open(file_path, "w") as file_fd:
|
||||
file_fd.write(content)
|
||||
|
||||
|
||||
def resolve_simple_git_conflicts(file_path: str, debug=False) -> None:
|
||||
content = read_content_from_file(file_path)
|
||||
# If the conflict represents the addition of a new content hunk,
|
||||
# keep the content and remove the conflict markers.
|
||||
if debug:
|
||||
print("Resolving simple conflicts automatically.")
|
||||
replaced = re.sub(r"\n<<<<<<< HEAD\n=======(.+?)>>>>>>> master\n", r"\1", content, 0, re.DOTALL)
|
||||
write_content_to_file(file_path, replaced)
|
||||
|
||||
|
||||
def copyfile_log(src: str, dst: str, debug=False):
|
||||
if debug:
|
||||
print(f"Copying {src} to {dst}.")
|
||||
copyfile(src, dst)
|
||||
|
||||
|
||||
def check_if_git_in_path() -> bool:
|
||||
is_win = os.name == "nt"
|
||||
for path in os.environ["PATH"].split(os.pathsep):
|
||||
git_path = os.path.join(path, "git")
|
||||
if is_win:
|
||||
git_path += ".exe"
|
||||
if os.path.isfile(git_path) and os.access(git_path, os.X_OK):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def run_process_quiet(args_string: str, debug=False) -> bool:
|
||||
if debug:
|
||||
print(f'Running command: "{args_string}"')
|
||||
args_list = args_string.split()
|
||||
try:
|
||||
subprocess.run(args_list, check=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
# git merge with conflicts returns with exit code 1, but that's not
|
||||
# an error for us.
|
||||
if "git merge" not in args_string:
|
||||
if debug:
|
||||
print(
|
||||
dedent(
|
||||
f"""\
|
||||
Error while running: "{args_string}"
|
||||
{e.stdout}"""
|
||||
)
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def does_file_have_conflict_markers(file_path: str, debug=False) -> bool:
|
||||
if debug:
|
||||
print(f"Checking if {file_path} has no leftover conflict markers.")
|
||||
content_actual = read_content_from_file(file_path)
|
||||
if "<<<<<<< HEAD" in content_actual:
|
||||
print(f"Conflict markers found in {file_path}. " "Please remove or solve them first.")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def create_file_with_no_special_cases(
|
||||
original_file_path: str, no_special_cases_file_path: str, debug=False
|
||||
):
|
||||
"""
|
||||
Reads content of original CMakeLists.txt/configure.cmake, removes all content
|
||||
between "# special case" markers or lines, saves the result into a
|
||||
new file.
|
||||
"""
|
||||
content_actual = read_content_from_file(original_file_path)
|
||||
if debug:
|
||||
print(f"Removing special case blocks from {original_file_path}.")
|
||||
content_no_special_cases = remove_special_cases(content_actual)
|
||||
|
||||
if debug:
|
||||
print(
|
||||
f"Saving original contents of {original_file_path} "
|
||||
f"with removed special case blocks to {no_special_cases_file_path}"
|
||||
)
|
||||
write_content_to_file(no_special_cases_file_path, content_no_special_cases)
|
||||
|
||||
|
||||
def rm_tree_on_error_handler(func: typing.Callable[..., None], path: str, exception_info: tuple):
|
||||
# If the path is read only, try to make it writable, and try
|
||||
# to remove the path again.
|
||||
if not os.access(path, os.W_OK):
|
||||
os.chmod(path, stat.S_IWRITE)
|
||||
func(path)
|
||||
else:
|
||||
print(f"Error while trying to remove path: {path}. Exception: {exception_info}")
|
||||
|
||||
|
||||
class SpecialCaseHandler(object):
|
||||
def __init__(
|
||||
self,
|
||||
original_file_path: str,
|
||||
generated_file_path: str,
|
||||
base_dir: str,
|
||||
keep_temporary_files=False,
|
||||
debug=False,
|
||||
) -> None:
|
||||
self.base_dir = base_dir
|
||||
self.original_file_path = original_file_path
|
||||
self.generated_file_path = generated_file_path
|
||||
self.keep_temporary_files = keep_temporary_files
|
||||
self.use_heuristic = False
|
||||
self.debug = debug
|
||||
|
||||
@property
|
||||
def prev_file_path(self) -> str:
|
||||
filename = ".prev_" + os.path.basename(self.original_file_path)
|
||||
return os.path.join(self.base_dir, filename)
|
||||
|
||||
@property
|
||||
def post_merge_file_path(self) -> str:
|
||||
original_file_name = os.path.basename(self.original_file_path)
|
||||
(original_file_basename, original_file_ext) = os.path.splitext(original_file_name)
|
||||
filename = original_file_basename + "-post-merge" + original_file_ext
|
||||
return os.path.join(self.base_dir, filename)
|
||||
|
||||
@property
|
||||
def no_special_file_path(self) -> str:
|
||||
original_file_name = os.path.basename(self.original_file_path)
|
||||
(original_file_basename, original_file_ext) = os.path.splitext(original_file_name)
|
||||
filename = original_file_basename + ".no-special" + original_file_ext
|
||||
return os.path.join(self.base_dir, filename)
|
||||
|
||||
def apply_git_merge_magic(self, no_special_cases_file_path: str) -> None:
|
||||
# Create new folder for temporary repo, and ch dir into it.
|
||||
repo = os.path.join(self.base_dir, "tmp_repo")
|
||||
repo_absolute_path = os.path.abspath(repo)
|
||||
txt = os.path.basename(self.original_file_path)
|
||||
|
||||
try:
|
||||
os.mkdir(repo)
|
||||
current_dir = os.getcwd()
|
||||
os.chdir(repo)
|
||||
except Exception as e:
|
||||
print(f"Failed to create temporary directory for temporary git repo. Exception: {e}")
|
||||
raise e
|
||||
|
||||
generated_file_path = os.path.join("..", self.generated_file_path)
|
||||
original_file_path = os.path.join("..", self.original_file_path)
|
||||
no_special_cases_file_path = os.path.join("..", no_special_cases_file_path)
|
||||
post_merge_file_path = os.path.join("..", self.post_merge_file_path)
|
||||
|
||||
try:
|
||||
# Create new repo with the "clean" CMakeLists.txt/configure.cmake file.
|
||||
run_process_quiet("git init .", debug=self.debug)
|
||||
run_process_quiet("git config user.name fake", debug=self.debug)
|
||||
run_process_quiet("git config user.email fake@fake", debug=self.debug)
|
||||
copyfile_log(no_special_cases_file_path, txt, debug=self.debug)
|
||||
run_process_quiet(f"git add {txt}", debug=self.debug)
|
||||
run_process_quiet("git commit -m no_special", debug=self.debug)
|
||||
run_process_quiet("git checkout -b no_special", debug=self.debug)
|
||||
|
||||
# Copy the original "modified" file (with the special cases)
|
||||
# and make a new commit.
|
||||
run_process_quiet("git checkout -b original", debug=self.debug)
|
||||
copyfile_log(original_file_path, txt, debug=self.debug)
|
||||
run_process_quiet(f"git add {txt}", debug=self.debug)
|
||||
run_process_quiet("git commit -m original", debug=self.debug)
|
||||
|
||||
# Checkout the commit with "clean" file again, and create a
|
||||
# new branch.
|
||||
run_process_quiet("git checkout no_special", debug=self.debug)
|
||||
run_process_quiet("git checkout -b newly_generated", debug=self.debug)
|
||||
|
||||
# Copy the new "modified" file and make a commit.
|
||||
copyfile_log(generated_file_path, txt, debug=self.debug)
|
||||
run_process_quiet(f"git add {txt}", debug=self.debug)
|
||||
run_process_quiet("git commit -m newly_generated", debug=self.debug)
|
||||
|
||||
# Merge the "old" branch with modifications into the "new"
|
||||
# branch with the newly generated file.
|
||||
run_process_quiet("git merge original", debug=self.debug)
|
||||
|
||||
# Resolve some simple conflicts (just remove the markers)
|
||||
# for cases that don't need intervention.
|
||||
resolve_simple_git_conflicts(txt, debug=self.debug)
|
||||
|
||||
# Copy the resulting file from the merge.
|
||||
copyfile_log(txt, post_merge_file_path)
|
||||
except Exception as e:
|
||||
print(f"Git merge conflict resolution process failed. Exception: {e}")
|
||||
raise e
|
||||
finally:
|
||||
os.chdir(current_dir)
|
||||
|
||||
# Remove the temporary repo.
|
||||
try:
|
||||
if not self.keep_temporary_files:
|
||||
rmtree(repo_absolute_path, onerror=rm_tree_on_error_handler)
|
||||
except Exception as e:
|
||||
print(f"Error removing temporary repo. Exception: {e}")
|
||||
|
||||
def save_next_clean_file(self):
|
||||
files_are_equivalent = filecmp.cmp(self.generated_file_path, self.post_merge_file_path)
|
||||
|
||||
if not files_are_equivalent:
|
||||
# Before overriding the generated file with the post
|
||||
# merge result, save the new "clean" file for future
|
||||
# regenerations.
|
||||
copyfile_log(self.generated_file_path, self.prev_file_path, debug=self.debug)
|
||||
|
||||
# Attempt to git add until we succeed. It can fail when
|
||||
# run_pro2cmake executes pro2cmake in multiple threads, and git
|
||||
# has acquired the index lock.
|
||||
success = False
|
||||
failed_once = False
|
||||
i = 0
|
||||
while not success and i < 20:
|
||||
success = run_process_quiet(f"git add {self.prev_file_path}", debug=self.debug)
|
||||
if not success:
|
||||
failed_once = True
|
||||
i += 1
|
||||
time.sleep(0.1)
|
||||
|
||||
if failed_once and not success:
|
||||
if self.debug:
|
||||
print("Retrying git add, the index.lock was probably acquired.")
|
||||
if failed_once and success:
|
||||
if self.debug:
|
||||
print("git add succeeded.")
|
||||
elif failed_once and not success:
|
||||
print(f"git add failed. Make sure to git add {self.prev_file_path} yourself.")
|
||||
|
||||
def handle_special_cases_helper(self) -> bool:
|
||||
"""
|
||||
Uses git to reapply special case modifications to the "new"
|
||||
generated CMakeLists.gen.txt/configure.cmake.gen file.
|
||||
|
||||
If use_heuristic is True, a new file is created from the
|
||||
original file, with special cases removed.
|
||||
|
||||
If use_heuristic is False, an existing "clean" file with no
|
||||
special cases is used from a previous conversion. The "clean"
|
||||
file is expected to be in the same folder as the original one.
|
||||
"""
|
||||
try:
|
||||
if does_file_have_conflict_markers(self.original_file_path):
|
||||
return False
|
||||
|
||||
if self.use_heuristic:
|
||||
create_file_with_no_special_cases(
|
||||
self.original_file_path, self.no_special_file_path
|
||||
)
|
||||
no_special_cases_file_path = self.no_special_file_path
|
||||
else:
|
||||
no_special_cases_file_path = self.prev_file_path
|
||||
|
||||
if self.debug:
|
||||
print(
|
||||
f"Using git to reapply special case modifications to newly "
|
||||
f"generated {self.generated_file_path} file"
|
||||
)
|
||||
|
||||
self.apply_git_merge_magic(no_special_cases_file_path)
|
||||
self.save_next_clean_file()
|
||||
|
||||
copyfile_log(self.post_merge_file_path, self.generated_file_path)
|
||||
if not self.keep_temporary_files:
|
||||
os.remove(self.post_merge_file_path)
|
||||
if self.debug:
|
||||
print(
|
||||
"Special case reapplication using git is complete. "
|
||||
"Make sure to fix remaining conflict markers."
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error occurred while trying to reapply special case modifications: {e}")
|
||||
return False
|
||||
finally:
|
||||
if not self.keep_temporary_files and self.use_heuristic:
|
||||
os.remove(self.no_special_file_path)
|
||||
|
||||
return True
|
||||
|
||||
def handle_special_cases(self) -> bool:
|
||||
original_file_exists = os.path.isfile(self.original_file_path)
|
||||
prev_file_exists = os.path.isfile(self.prev_file_path)
|
||||
self.use_heuristic = not prev_file_exists
|
||||
|
||||
git_available = check_if_git_in_path()
|
||||
keep_special_cases = original_file_exists and git_available
|
||||
|
||||
if not git_available:
|
||||
print(
|
||||
"You need to have git in PATH in order to reapply the special "
|
||||
"case modifications."
|
||||
)
|
||||
|
||||
copy_generated_file = True
|
||||
|
||||
if keep_special_cases:
|
||||
copy_generated_file = self.handle_special_cases_helper()
|
||||
|
||||
return copy_generated_file
|
0
util/cmake/tests/__init__.py
Normal file
0
util/cmake/tests/__init__.py
Normal file
6
util/cmake/tests/data/comment_scope.pro
Normal file
6
util/cmake/tests/data/comment_scope.pro
Normal file
@ -0,0 +1,6 @@
|
||||
# QtCore can't be compiled with -Wl,-no-undefined because it uses the "environ"
|
||||
# variable and on FreeBSD and OpenBSD, this variable is in the final executable itself.
|
||||
# OpenBSD 6.0 will include environ in libc.
|
||||
freebsd|openbsd: QMAKE_LFLAGS_NOUNDEF =
|
||||
|
||||
include(animation/animation.pri)
|
2
util/cmake/tests/data/complex_assign.pro
Normal file
2
util/cmake/tests/data/complex_assign.pro
Normal file
@ -0,0 +1,2 @@
|
||||
qmake-clean.commands += (cd qmake && $(MAKE) clean ":-(==)-:" '(Foo)' )
|
||||
|
4
util/cmake/tests/data/complex_condition.pro
Normal file
4
util/cmake/tests/data/complex_condition.pro
Normal file
@ -0,0 +1,4 @@
|
||||
!system("dbus-send --session --type=signal / local.AutotestCheck.Hello >$$QMAKE_SYSTEM_NULL_DEVICE 2>&1") {
|
||||
SOURCES = dbus.cpp
|
||||
}
|
||||
|
22
util/cmake/tests/data/complex_values.pro
Normal file
22
util/cmake/tests/data/complex_values.pro
Normal file
@ -0,0 +1,22 @@
|
||||
linux:!static {
|
||||
precompile_header {
|
||||
# we'll get an error if we just use SOURCES +=
|
||||
no_pch_assembler.commands = $$QMAKE_CC -c $(CFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
|
||||
no_pch_assembler.dependency_type = TYPE_C
|
||||
no_pch_assembler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
|
||||
no_pch_assembler.input = NO_PCH_ASM
|
||||
no_pch_assembler.name = compiling[no_pch] ${QMAKE_FILE_IN}
|
||||
silent: no_pch_assembler.commands = @echo compiling[no_pch] ${QMAKE_FILE_IN} && $$no_pch_assembler.commands
|
||||
CMAKE_ANGLE_GLES2_IMPLIB_RELEASE = libGLESv2.$${QMAKE_EXTENSION_STATICLIB}
|
||||
HOST_BINS = $$[QT_HOST_BINS]
|
||||
CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/
|
||||
TR_EXCLUDE += ../3rdparty/*
|
||||
|
||||
QMAKE_EXTRA_COMPILERS += no_pch_assembler
|
||||
NO_PCH_ASM += global/minimum-linux.S
|
||||
} else {
|
||||
SOURCES += global/minimum-linux.S
|
||||
}
|
||||
HEADERS += global/minimum-linux_p.h
|
||||
}
|
||||
|
11
util/cmake/tests/data/condition_operator_precedence.pro
Normal file
11
util/cmake/tests/data/condition_operator_precedence.pro
Normal file
@ -0,0 +1,11 @@
|
||||
a1|a2 {
|
||||
DEFINES += d
|
||||
}
|
||||
|
||||
b1|b2:b3 {
|
||||
DEFINES += d
|
||||
}
|
||||
|
||||
c1|c2:c3|c4 {
|
||||
DEFINES += d
|
||||
}
|
2
util/cmake/tests/data/condition_without_scope.pro
Normal file
2
util/cmake/tests/data/condition_without_scope.pro
Normal file
@ -0,0 +1,2 @@
|
||||
write_file("a", contents)|error()
|
||||
|
4
util/cmake/tests/data/contains_scope.pro
Normal file
4
util/cmake/tests/data/contains_scope.pro
Normal file
@ -0,0 +1,4 @@
|
||||
contains(DEFINES,QT_EVAL):include(eval.pri)
|
||||
|
||||
HOST_BINS = $$[QT_HOST_BINS]
|
||||
|
4
util/cmake/tests/data/conversion/optional_qt_modules.pro
Normal file
4
util/cmake/tests/data/conversion/optional_qt_modules.pro
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = myapp
|
||||
QT = core network widgets
|
||||
win32: QT += opengl
|
||||
SOURCES = main.cpp
|
8
util/cmake/tests/data/conversion/qt_version_check.pro
Normal file
8
util/cmake/tests/data/conversion/qt_version_check.pro
Normal file
@ -0,0 +1,8 @@
|
||||
QT += core gui
|
||||
SOURCES += main.cpp
|
||||
greaterThan(QT_MAJOR_VERSION, 5):lessThan(QT_MINOR_VERSION, 1):equals(QT_PATCH_VERSION, 0) {
|
||||
DEFINES += SUPER_FRESH_MAJOR_QT_RELEASE
|
||||
}
|
||||
greaterThan(QT_VERSION, 6.6.5):lessThan(QT_VERSION, 6.6.7):equals(QT_VERSION, 6.6.6): {
|
||||
DEFINES += QT_VERSION_OF_THE_BEAST
|
||||
}
|
3
util/cmake/tests/data/conversion/required_qt_modules.pro
Normal file
3
util/cmake/tests/data/conversion/required_qt_modules.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = myapp
|
||||
QT = core network widgets
|
||||
SOURCES = main.cpp
|
6
util/cmake/tests/data/definetest.pro
Normal file
6
util/cmake/tests/data/definetest.pro
Normal file
@ -0,0 +1,6 @@
|
||||
defineTest(pathIsAbsolute) {
|
||||
p = $$clean_path($$1)
|
||||
!isEmpty(p):isEqual(p, $$absolute_path($$p)): return(true)
|
||||
return(false)
|
||||
}
|
||||
|
6
util/cmake/tests/data/else.pro
Normal file
6
util/cmake/tests/data/else.pro
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
linux {
|
||||
SOURCES += a.cpp
|
||||
} else {
|
||||
SOURCES += b.cpp
|
||||
}
|
4
util/cmake/tests/data/else2.pro
Normal file
4
util/cmake/tests/data/else2.pro
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
osx: A = 1
|
||||
else: win32: B = 2
|
||||
else: C = 3
|
7
util/cmake/tests/data/else3.pro
Normal file
7
util/cmake/tests/data/else3.pro
Normal file
@ -0,0 +1,7 @@
|
||||
qtConfig(timezone) {
|
||||
A = 1
|
||||
} else:win32 {
|
||||
B = 2
|
||||
} else {
|
||||
C = 3
|
||||
}
|
6
util/cmake/tests/data/else4.pro
Normal file
6
util/cmake/tests/data/else4.pro
Normal file
@ -0,0 +1,6 @@
|
||||
qtConfig(timezone) {
|
||||
A = 1
|
||||
} else:win32: B = 2
|
||||
else {
|
||||
C = 3
|
||||
}
|
10
util/cmake/tests/data/else5.pro
Normal file
10
util/cmake/tests/data/else5.pro
Normal file
@ -0,0 +1,10 @@
|
||||
# comments
|
||||
qtConfig(timezone) { # bar
|
||||
A = 1
|
||||
} else:win32 {
|
||||
B = 2 # foo
|
||||
} else { C = 3
|
||||
# baz
|
||||
# foobar
|
||||
}
|
||||
# endcomment
|
11
util/cmake/tests/data/else6.pro
Normal file
11
util/cmake/tests/data/else6.pro
Normal file
@ -0,0 +1,11 @@
|
||||
qtConfig(timezone) \
|
||||
{
|
||||
A = \
|
||||
1
|
||||
} \
|
||||
else:win32: \
|
||||
B = 2
|
||||
else: \
|
||||
C \
|
||||
= 3
|
||||
|
2
util/cmake/tests/data/else7.pro
Normal file
2
util/cmake/tests/data/else7.pro
Normal file
@ -0,0 +1,2 @@
|
||||
msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x65000000
|
||||
|
5
util/cmake/tests/data/else8.pro
Normal file
5
util/cmake/tests/data/else8.pro
Normal file
@ -0,0 +1,5 @@
|
||||
qtConfig(timezone) { A = 1 } else:win32: {\
|
||||
B = 2 \
|
||||
} else: \
|
||||
C \
|
||||
= 3 \
|
2
util/cmake/tests/data/escaped_value.pro
Normal file
2
util/cmake/tests/data/escaped_value.pro
Normal file
@ -0,0 +1,2 @@
|
||||
MODULE_AUX_INCLUDES = \
|
||||
\$\$QT_MODULE_INCLUDE_BASE/QtANGLE
|
11
util/cmake/tests/data/for.pro
Normal file
11
util/cmake/tests/data/for.pro
Normal file
@ -0,0 +1,11 @@
|
||||
SOURCES = main.cpp
|
||||
for (config, SIMD) {
|
||||
uc = $$upper($$config)
|
||||
DEFINES += QT_COMPILER_SUPPORTS_$${uc}
|
||||
|
||||
add_cflags {
|
||||
cflags = QMAKE_CFLAGS_$${uc}
|
||||
!defined($$cflags, var): error("This compiler does not support $${uc}")
|
||||
QMAKE_CXXFLAGS += $$eval($$cflags)
|
||||
}
|
||||
}
|
4
util/cmake/tests/data/function_if.pro
Normal file
4
util/cmake/tests/data/function_if.pro
Normal file
@ -0,0 +1,4 @@
|
||||
pathIsAbsolute($$CMAKE_HOST_DATA_DIR) {
|
||||
CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/
|
||||
}
|
||||
|
3
util/cmake/tests/data/include.pro
Normal file
3
util/cmake/tests/data/include.pro
Normal file
@ -0,0 +1,3 @@
|
||||
A = 42
|
||||
include(foo) # load foo
|
||||
B=23
|
10
util/cmake/tests/data/lc.pro
Normal file
10
util/cmake/tests/data/lc.pro
Normal file
@ -0,0 +1,10 @@
|
||||
TEMPLATE=subdirs
|
||||
SUBDIRS=\
|
||||
qmacstyle \
|
||||
qstyle \
|
||||
qstyleoption \
|
||||
qstylesheetstyle \
|
||||
|
||||
!qtConfig(private_tests): SUBDIRS -= \
|
||||
qstylesheetstyle \
|
||||
|
22
util/cmake/tests/data/lc_with_comment.pro
Normal file
22
util/cmake/tests/data/lc_with_comment.pro
Normal file
@ -0,0 +1,22 @@
|
||||
SUBDIRS = \
|
||||
# dds \
|
||||
tga \
|
||||
wbmp
|
||||
|
||||
MYVAR = foo # comment
|
||||
MYVAR = foo2# comment
|
||||
MYVAR = foo3# comment #
|
||||
|
||||
MYVAR = foo4# comment #
|
||||
|
||||
##
|
||||
#
|
||||
#
|
||||
##
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
# #
|
||||
|
||||
MYVAR = foo5# comment # #
|
3
util/cmake/tests/data/load.pro
Normal file
3
util/cmake/tests/data/load.pro
Normal file
@ -0,0 +1,3 @@
|
||||
A = 42
|
||||
load(foo)# load foo
|
||||
B=23
|
3
util/cmake/tests/data/multi_condition_divided_by_lc.pro
Normal file
3
util/cmake/tests/data/multi_condition_divided_by_lc.pro
Normal file
@ -0,0 +1,3 @@
|
||||
equals(a): \
|
||||
greaterThan(a):flags += 1
|
||||
|
4
util/cmake/tests/data/multiline_assign.pro
Normal file
4
util/cmake/tests/data/multiline_assign.pro
Normal file
@ -0,0 +1,4 @@
|
||||
A = 42 \
|
||||
43 \
|
||||
44
|
||||
B=23
|
2
util/cmake/tests/data/nested_function_calls.pro
Normal file
2
util/cmake/tests/data/nested_function_calls.pro
Normal file
@ -0,0 +1,2 @@
|
||||
requires(qtConfig(dlopen))
|
||||
|
5
util/cmake/tests/data/quoted.pro
Normal file
5
util/cmake/tests/data/quoted.pro
Normal file
@ -0,0 +1,5 @@
|
||||
if(linux*|hurd*):!cross_compile:!static:!*-armcc* {
|
||||
prog=$$quote(if (/program interpreter: (.*)]/) { print $1; })
|
||||
DEFINES += ELF_INTERPRETER=\\\"$$system(LC_ALL=C readelf -l /bin/ls | perl -n -e \'$$prog\')\\\"
|
||||
}
|
||||
|
4
util/cmake/tests/data/single_line_for.pro
Normal file
4
util/cmake/tests/data/single_line_for.pro
Normal file
@ -0,0 +1,4 @@
|
||||
for(d, sd): \
|
||||
exists($$d/$${d}.pro): \
|
||||
SUBDIRS += $$d
|
||||
|
3
util/cmake/tests/data/sql.pro
Normal file
3
util/cmake/tests/data/sql.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
kernel \
|
17
util/cmake/tests/data/standardpaths.pro
Normal file
17
util/cmake/tests/data/standardpaths.pro
Normal file
@ -0,0 +1,17 @@
|
||||
win32 {
|
||||
!winrt {
|
||||
SOURCES +=io/qstandardpaths_win.cpp
|
||||
} else {
|
||||
SOURCES +=io/qstandardpaths_winrt.cpp
|
||||
}
|
||||
} else:unix {
|
||||
mac {
|
||||
OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
|
||||
} else:android {
|
||||
SOURCES += io/qstandardpaths_android.cpp
|
||||
} else:haiku {
|
||||
SOURCES += io/qstandardpaths_haiku.cpp
|
||||
} else {
|
||||
SOURCES += io/qstandardpaths_unix.cpp
|
||||
}
|
||||
}
|
2
util/cmake/tests/data/unset.pro
Normal file
2
util/cmake/tests/data/unset.pro
Normal file
@ -0,0 +1,2 @@
|
||||
unset(f16c_cxx)
|
||||
|
2
util/cmake/tests/data/value_function.pro
Normal file
2
util/cmake/tests/data/value_function.pro
Normal file
@ -0,0 +1,2 @@
|
||||
TARGET = Dummy
|
||||
TARGET = $$qtLibraryTarget($$TARGET)
|
66
util/cmake/tests/test_conversion.py
Normal file
66
util/cmake/tests/test_conversion.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from pro2cmake import Scope, SetOperation, merge_scopes, recursive_evaluate_scope
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import pytest
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import typing
|
||||
|
||||
debug_mode = bool(os.environ.get("DEBUG_PRO2CMAKE_TEST_CONVERSION"))
|
||||
test_script_dir = pathlib.Path(__file__).parent.resolve()
|
||||
pro2cmake_dir = test_script_dir.parent.resolve()
|
||||
pro2cmake_py = pro2cmake_dir.joinpath("pro2cmake.py")
|
||||
test_data_dir = test_script_dir.joinpath("data", "conversion")
|
||||
|
||||
|
||||
def convert(base_name: str):
|
||||
pro_file_name = str(base_name) + ".pro"
|
||||
pro_file_path = test_data_dir.joinpath(pro_file_name)
|
||||
assert(pro_file_path.exists())
|
||||
with TemporaryDirectory(prefix="testqmake2cmake") as tmp_dir_str:
|
||||
tmp_dir = pathlib.Path(tmp_dir_str)
|
||||
output_file_path = tmp_dir.joinpath("CMakeLists.txt")
|
||||
exit_code = subprocess.call([pro2cmake_py, "--is-example", "-o", output_file_path, pro_file_path])
|
||||
assert(exit_code == 0)
|
||||
if debug_mode:
|
||||
shutil.copyfile(output_file_path, tempfile.gettempdir() + "/pro2cmake/CMakeLists.txt")
|
||||
f = open(output_file_path, "r")
|
||||
assert(f)
|
||||
content = f.read()
|
||||
assert(content)
|
||||
return content
|
||||
|
||||
|
||||
def test_qt_modules():
|
||||
output = convert("required_qt_modules")
|
||||
find_package_lines = []
|
||||
for line in output.split("\n"):
|
||||
if "find_package(" in line:
|
||||
find_package_lines.append(line.strip())
|
||||
assert(["find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)",
|
||||
"find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network Widgets)"] == find_package_lines)
|
||||
|
||||
output = convert("optional_qt_modules")
|
||||
find_package_lines = []
|
||||
for line in output.split("\n"):
|
||||
if "find_package(" in line:
|
||||
find_package_lines.append(line.strip())
|
||||
assert(["find_package(QT NAMES Qt5 Qt6 REQUIRED COMPONENTS Core)",
|
||||
"find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network Widgets)",
|
||||
"find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS OpenGL)"] == find_package_lines)
|
||||
|
||||
def test_qt_version_check():
|
||||
output = convert("qt_version_check")
|
||||
interesting_lines = []
|
||||
for line in output.split("\n"):
|
||||
if line.startswith("if(") and "QT_VERSION" in line:
|
||||
interesting_lines.append(line.strip())
|
||||
assert(["if(( ( (QT_VERSION_MAJOR GREATER 5) ) AND (QT_VERSION_MINOR LESS 1) ) AND (QT_VERSION_PATCH EQUAL 0))", "if(( ( (QT_VERSION VERSION_GREATER 6.6.5) ) AND (QT_VERSION VERSION_LESS 6.6.7) ) AND (QT_VERSION VERSION_EQUAL 6.6.6))"] == interesting_lines)
|
19
util/cmake/tests/test_lc_fixup.py
Normal file
19
util/cmake/tests/test_lc_fixup.py
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from qmake_parser import fixup_linecontinuation
|
||||
|
||||
|
||||
def test_no_change():
|
||||
input = "test \\\nline2\n line3"
|
||||
output = "test line2\n line3"
|
||||
result = fixup_linecontinuation(input)
|
||||
assert output == result
|
||||
|
||||
|
||||
def test_fix():
|
||||
input = "test \\\t\nline2\\\n line3\\ \nline4 \\ \t\nline5\\\n\n\n"
|
||||
output = "test line2 line3 line4 line5 \n\n"
|
||||
result = fixup_linecontinuation(input)
|
||||
assert output == result
|
160
util/cmake/tests/test_logic_mapping.py
Normal file
160
util/cmake/tests/test_logic_mapping.py
Normal file
@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from condition_simplifier import simplify_condition
|
||||
|
||||
|
||||
def validate_simplify(input: str, expected: str) -> None:
|
||||
output = simplify_condition(input)
|
||||
assert output == expected
|
||||
|
||||
|
||||
def validate_simplify_unchanged(input: str) -> None:
|
||||
validate_simplify(input, input)
|
||||
|
||||
|
||||
def test_simplify_on():
|
||||
validate_simplify_unchanged('ON')
|
||||
|
||||
|
||||
def test_simplify_off():
|
||||
validate_simplify_unchanged('OFF')
|
||||
|
||||
|
||||
def test_simplify_not_on():
|
||||
validate_simplify('NOT ON', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_not_off():
|
||||
validate_simplify('NOT OFF', 'ON')
|
||||
|
||||
|
||||
def test_simplify_isEmpty():
|
||||
validate_simplify_unchanged('isEmpty(foo)')
|
||||
|
||||
|
||||
def test_simplify_not_isEmpty():
|
||||
validate_simplify_unchanged('NOT isEmpty(foo)')
|
||||
|
||||
|
||||
def test_simplify_simple_and():
|
||||
validate_simplify_unchanged('QT_FEATURE_bar AND QT_FEATURE_foo')
|
||||
|
||||
|
||||
def test_simplify_simple_or():
|
||||
validate_simplify_unchanged('QT_FEATURE_bar OR QT_FEATURE_foo')
|
||||
|
||||
|
||||
def test_simplify_simple_not():
|
||||
validate_simplify_unchanged('NOT QT_FEATURE_foo')
|
||||
|
||||
|
||||
def test_simplify_simple_and_reorder():
|
||||
validate_simplify('QT_FEATURE_foo AND QT_FEATURE_bar', 'QT_FEATURE_bar AND QT_FEATURE_foo')
|
||||
|
||||
|
||||
def test_simplify_simple_or_reorder():
|
||||
validate_simplify('QT_FEATURE_foo OR QT_FEATURE_bar', 'QT_FEATURE_bar OR QT_FEATURE_foo')
|
||||
|
||||
|
||||
def test_simplify_unix_or_win32():
|
||||
validate_simplify('WIN32 OR UNIX', 'ON')
|
||||
|
||||
|
||||
def test_simplify_unix_or_win32_or_foobar_or_barfoo():
|
||||
validate_simplify('WIN32 OR UNIX OR foobar OR barfoo', 'ON')
|
||||
|
||||
|
||||
def test_simplify_not_not_bar():
|
||||
validate_simplify(' NOT NOT bar ', 'bar')
|
||||
|
||||
|
||||
def test_simplify_not_unix():
|
||||
validate_simplify('NOT UNIX', 'WIN32')
|
||||
|
||||
|
||||
def test_simplify_not_win32():
|
||||
validate_simplify('NOT WIN32', 'UNIX')
|
||||
|
||||
|
||||
def test_simplify_unix_and_win32():
|
||||
validate_simplify('WIN32 AND UNIX', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_unix_or_win32():
|
||||
validate_simplify('WIN32 OR UNIX', 'ON')
|
||||
|
||||
|
||||
def test_simplify_unix_and_win32_or_foobar_or_barfoo():
|
||||
validate_simplify('WIN32 AND foobar AND UNIX AND barfoo', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_watchos_and_win32():
|
||||
validate_simplify('WATCHOS AND WIN32', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_win32_and_watchos():
|
||||
validate_simplify('WIN32 AND WATCHOS', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_apple_and_appleosx():
|
||||
validate_simplify('APPLE AND MACOS', 'MACOS')
|
||||
|
||||
|
||||
def test_simplify_apple_or_appleosx():
|
||||
validate_simplify('APPLE OR MACOS', 'APPLE')
|
||||
|
||||
|
||||
def test_simplify_apple_or_appleosx_level1():
|
||||
validate_simplify('foobar AND (APPLE OR MACOS )', 'APPLE AND foobar')
|
||||
|
||||
|
||||
def test_simplify_apple_or_appleosx_level1_double():
|
||||
validate_simplify('foobar AND (APPLE OR MACOS )', 'APPLE AND foobar')
|
||||
|
||||
|
||||
def test_simplify_apple_or_appleosx_level1_double_with_extra_spaces():
|
||||
validate_simplify('foobar AND (APPLE OR MACOS ) '
|
||||
'AND ( MACOS OR APPLE )', 'APPLE AND foobar')
|
||||
|
||||
|
||||
def test_simplify_apple_or_appleosx_level2():
|
||||
validate_simplify('foobar AND ( ( APPLE OR WATCHOS ) '
|
||||
'OR MACOS ) AND ( MACOS OR APPLE ) '
|
||||
'AND ( (WIN32 OR WINRT) OR UNIX) ', 'APPLE AND foobar')
|
||||
|
||||
|
||||
def test_simplify_not_apple_and_appleosx():
|
||||
validate_simplify('NOT APPLE AND MACOS', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_unix_and_bar_or_win32():
|
||||
validate_simplify('WIN32 AND bar AND UNIX', 'OFF')
|
||||
|
||||
|
||||
def test_simplify_unix_or_bar_or_win32():
|
||||
validate_simplify('WIN32 OR bar OR UNIX', 'ON')
|
||||
|
||||
|
||||
def test_simplify_complex_true():
|
||||
validate_simplify('WIN32 OR ( APPLE OR UNIX)', 'ON')
|
||||
|
||||
|
||||
def test_simplify_apple_unix_freebsd():
|
||||
validate_simplify('( APPLE OR ( UNIX OR FREEBSD ))', 'UNIX')
|
||||
|
||||
|
||||
def test_simplify_apple_unix_freebsd_foobar():
|
||||
validate_simplify('( APPLE OR ( UNIX OR FREEBSD ) OR foobar)',
|
||||
'UNIX OR foobar')
|
||||
|
||||
|
||||
def test_simplify_complex_false():
|
||||
validate_simplify('WIN32 AND foobar AND ( '
|
||||
'APPLE OR ( UNIX OR FREEBSD ))',
|
||||
'OFF')
|
||||
|
||||
|
||||
def test_simplify_android_not_apple():
|
||||
validate_simplify('ANDROID AND NOT MACOS', 'ANDROID')
|
32
util/cmake/tests/test_operations.py
Normal file
32
util/cmake/tests/test_operations.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from pro2cmake import AddOperation, SetOperation, UniqueAddOperation, RemoveOperation
|
||||
|
||||
def test_add_operation():
|
||||
op = AddOperation(['bar', 'buz'])
|
||||
|
||||
result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x)
|
||||
assert ['foo', 'bar', 'bar', 'buz'] == result
|
||||
|
||||
|
||||
def test_uniqueadd_operation():
|
||||
op = UniqueAddOperation(['bar', 'buz'])
|
||||
|
||||
result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x)
|
||||
assert ['foo', 'bar', 'buz'] == result
|
||||
|
||||
|
||||
def test_set_operation():
|
||||
op = SetOperation(['bar', 'buz'])
|
||||
|
||||
result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x)
|
||||
assert ['bar', 'buz'] == result
|
||||
|
||||
|
||||
def test_remove_operation():
|
||||
op = RemoveOperation(['bar', 'buz'])
|
||||
|
||||
result = op.process(['foo', 'bar'], ['foo', 'bar'], lambda x: x)
|
||||
assert ['foo', '-buz'] == result
|
343
util/cmake/tests/test_parsing.py
Normal file
343
util/cmake/tests/test_parsing.py
Normal file
@ -0,0 +1,343 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2018 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import os
|
||||
from pro2cmake import map_condition
|
||||
from qmake_parser import QmakeParser
|
||||
from condition_simplifier import simplify_condition
|
||||
|
||||
|
||||
_tests_path = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def validate_op(key, op, value, to_validate):
|
||||
assert key == to_validate['key']
|
||||
assert op == to_validate['operation']['value']
|
||||
assert value == to_validate.get('value', None)
|
||||
|
||||
|
||||
def validate_single_op(key, op, value, to_validate):
|
||||
assert len(to_validate) == 1
|
||||
validate_op(key, op, value, to_validate[0])
|
||||
|
||||
|
||||
def evaluate_condition(to_validate):
|
||||
assert 'condition' in to_validate
|
||||
assert 'statements' in to_validate
|
||||
|
||||
return (to_validate['condition'],
|
||||
to_validate['statements'],
|
||||
to_validate.get('else_statements', {}))
|
||||
|
||||
|
||||
def validate_default_else_test(file_name):
|
||||
result = parse_file(file_name)
|
||||
assert len(result) == 1
|
||||
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
assert cond == 'qtConfig(timezone)'
|
||||
validate_single_op('A', '=', ['1'], if_branch)
|
||||
|
||||
assert len(else_branch) == 1
|
||||
(cond2, if2_branch, else2_branch) = evaluate_condition(else_branch[0])
|
||||
assert cond2 == 'win32'
|
||||
validate_single_op('B', '=', ['2'], if2_branch)
|
||||
validate_single_op('C', '=', ['3'], else2_branch)
|
||||
|
||||
|
||||
def parse_file(file):
|
||||
p = QmakeParser(debug=True)
|
||||
result, _ = p.parseFile(file)
|
||||
|
||||
print('\n\n#### Parser result:')
|
||||
print(result)
|
||||
print('\n#### End of parser result.\n')
|
||||
|
||||
print('\n\n####Parser result dictionary:')
|
||||
print(result.asDict())
|
||||
print('\n#### End of parser result dictionary.\n')
|
||||
|
||||
result_dictionary = result.asDict()
|
||||
|
||||
assert len(result_dictionary) == 1
|
||||
|
||||
return result_dictionary['statements']
|
||||
|
||||
|
||||
def test_else():
|
||||
result = parse_file(_tests_path + '/data/else.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
|
||||
assert cond == 'linux'
|
||||
validate_single_op('SOURCES', '+=', ['a.cpp'], if_branch)
|
||||
validate_single_op('SOURCES', '+=', ['b.cpp'], else_branch)
|
||||
|
||||
|
||||
def test_else2():
|
||||
result = parse_file(_tests_path + '/data/else2.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
assert cond == 'osx'
|
||||
validate_single_op('A', '=', ['1'], if_branch)
|
||||
|
||||
assert len(else_branch) == 1
|
||||
(cond2, if2_branch, else2_branch) = evaluate_condition(else_branch[0])
|
||||
assert cond2 == 'win32'
|
||||
validate_single_op('B', '=', ['2'], if2_branch)
|
||||
|
||||
validate_single_op('C', '=', ['3'], else2_branch)
|
||||
|
||||
|
||||
def test_else3():
|
||||
validate_default_else_test(_tests_path + '/data/else3.pro')
|
||||
|
||||
|
||||
def test_else4():
|
||||
validate_default_else_test(_tests_path + '/data/else4.pro')
|
||||
|
||||
|
||||
def test_else5():
|
||||
validate_default_else_test(_tests_path + '/data/else5.pro')
|
||||
|
||||
|
||||
def test_else6():
|
||||
validate_default_else_test(_tests_path + '/data/else6.pro')
|
||||
|
||||
|
||||
def test_else7():
|
||||
result = parse_file(_tests_path + '/data/else7.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_else8():
|
||||
validate_default_else_test(_tests_path + '/data/else8.pro')
|
||||
|
||||
|
||||
def test_multiline_assign():
|
||||
result = parse_file(_tests_path + '/data/multiline_assign.pro')
|
||||
assert len(result) == 2
|
||||
validate_op('A', '=', ['42', '43', '44'], result[0])
|
||||
validate_op('B', '=', ['23'], result[1])
|
||||
|
||||
|
||||
def test_include():
|
||||
result = parse_file(_tests_path + '/data/include.pro')
|
||||
assert len(result) == 3
|
||||
validate_op('A', '=', ['42'], result[0])
|
||||
include = result[1]
|
||||
assert len(include) == 1
|
||||
assert 'included' in include
|
||||
assert include['included'].get('value', '') == 'foo'
|
||||
validate_op('B', '=', ['23'], result[2])
|
||||
|
||||
|
||||
def test_load():
|
||||
result = parse_file(_tests_path + '/data/load.pro')
|
||||
assert len(result) == 3
|
||||
validate_op('A', '=', ['42'], result[0])
|
||||
load = result[1]
|
||||
assert len(load) == 1
|
||||
assert load.get('loaded', '') == 'foo'
|
||||
validate_op('B', '=', ['23'], result[2])
|
||||
|
||||
|
||||
def test_definetest():
|
||||
result = parse_file(_tests_path + '/data/definetest.pro')
|
||||
assert len(result) == 1
|
||||
assert result[0] == []
|
||||
|
||||
|
||||
def test_for():
|
||||
result = parse_file(_tests_path + '/data/for.pro')
|
||||
assert len(result) == 2
|
||||
validate_op('SOURCES', '=', ['main.cpp'], result[0])
|
||||
assert result[1] == []
|
||||
|
||||
|
||||
def test_single_line_for():
|
||||
result = parse_file(_tests_path + '/data/single_line_for.pro')
|
||||
assert len(result) == 1
|
||||
assert result[0] == []
|
||||
|
||||
|
||||
def test_unset():
|
||||
result = parse_file(_tests_path + '/data/unset.pro')
|
||||
assert len(result) == 1
|
||||
assert result[0] == []
|
||||
|
||||
|
||||
def test_quoted():
|
||||
result = parse_file(_tests_path + '/data/quoted.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_complex_values():
|
||||
result = parse_file(_tests_path + '/data/complex_values.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_function_if():
|
||||
result = parse_file(_tests_path + '/data/function_if.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_realworld_standardpaths():
|
||||
result = parse_file(_tests_path + '/data/standardpaths.pro')
|
||||
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
assert cond == 'win32'
|
||||
assert len(if_branch) == 1
|
||||
assert len(else_branch) == 1
|
||||
|
||||
# win32:
|
||||
(cond1, if_branch1, else_branch1) = evaluate_condition(if_branch[0])
|
||||
assert cond1 == '!winrt'
|
||||
assert len(if_branch1) == 1
|
||||
validate_op('SOURCES', '+=', ['io/qstandardpaths_win.cpp'], if_branch1[0])
|
||||
assert len(else_branch1) == 1
|
||||
validate_op('SOURCES', '+=', ['io/qstandardpaths_winrt.cpp'], else_branch1[0])
|
||||
|
||||
# unix:
|
||||
(cond2, if_branch2, else_branch2) = evaluate_condition(else_branch[0])
|
||||
assert cond2 == 'unix'
|
||||
assert len(if_branch2) == 1
|
||||
assert len(else_branch2) == 0
|
||||
|
||||
# mac / else:
|
||||
(cond3, if_branch3, else_branch3) = evaluate_condition(if_branch2[0])
|
||||
assert cond3 == 'mac'
|
||||
assert len(if_branch3) == 1
|
||||
validate_op('OBJECTIVE_SOURCES', '+=', ['io/qstandardpaths_mac.mm'], if_branch3[0])
|
||||
assert len(else_branch3) == 1
|
||||
|
||||
# android / else:
|
||||
(cond4, if_branch4, else_branch4) = evaluate_condition(else_branch3[0])
|
||||
assert cond4 == 'android'
|
||||
assert len(if_branch4) == 1
|
||||
validate_op('SOURCES', '+=', ['io/qstandardpaths_android.cpp'], if_branch4[0])
|
||||
assert len(else_branch4) == 1
|
||||
|
||||
# haiku / else:
|
||||
(cond5, if_branch5, else_branch5) = evaluate_condition(else_branch4[0])
|
||||
assert cond5 == 'haiku'
|
||||
assert len(if_branch5) == 1
|
||||
validate_op('SOURCES', '+=', ['io/qstandardpaths_haiku.cpp'], if_branch5[0])
|
||||
assert len(else_branch5) == 1
|
||||
validate_op('SOURCES', '+=', ['io/qstandardpaths_unix.cpp'], else_branch5[0])
|
||||
|
||||
|
||||
def test_realworld_comment_scope():
|
||||
result = parse_file(_tests_path + '/data/comment_scope.pro')
|
||||
assert len(result) == 2
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
assert cond == 'freebsd|openbsd'
|
||||
assert len(if_branch) == 1
|
||||
validate_op('QMAKE_LFLAGS_NOUNDEF', '=', [], if_branch[0])
|
||||
|
||||
assert 'included' in result[1]
|
||||
assert result[1]['included'].get('value', '') == 'animation/animation.pri'
|
||||
|
||||
|
||||
def test_realworld_contains_scope():
|
||||
result = parse_file(_tests_path + '/data/contains_scope.pro')
|
||||
assert len(result) == 2
|
||||
|
||||
|
||||
def test_realworld_complex_assign():
|
||||
result = parse_file(_tests_path + '/data/complex_assign.pro')
|
||||
assert len(result) == 1
|
||||
validate_op('qmake-clean.commands', '+=', '( cd qmake && $(MAKE) clean ":-(==)-:" \'(Foo)\' )'.split(),
|
||||
result[0])
|
||||
|
||||
|
||||
def test_realworld_complex_condition():
|
||||
result = parse_file(_tests_path + '/data/complex_condition.pro')
|
||||
assert len(result) == 1
|
||||
(cond, if_branch, else_branch) = evaluate_condition(result[0])
|
||||
assert cond == '!system("dbus-send --session --type=signal / ' \
|
||||
'local.AutotestCheck.Hello >$$QMAKE_SYSTEM_NULL_DEVICE ' \
|
||||
'2>&1")'
|
||||
assert len(if_branch) == 1
|
||||
validate_op('SOURCES', '=', ['dbus.cpp'], if_branch[0])
|
||||
|
||||
assert len(else_branch) == 0
|
||||
|
||||
|
||||
def test_realworld_sql():
|
||||
result = parse_file(_tests_path + '/data/sql.pro')
|
||||
assert len(result) == 2
|
||||
validate_op('TEMPLATE', '=', ['subdirs'], result[0])
|
||||
validate_op('SUBDIRS', '=', ['kernel'], result[1])
|
||||
|
||||
|
||||
def test_realworld_qtconfig():
|
||||
result = parse_file(_tests_path + '/data/escaped_value.pro')
|
||||
assert len(result) == 1
|
||||
validate_op('MODULE_AUX_INCLUDES', '=', ['\\$\\$QT_MODULE_INCLUDE_BASE/QtANGLE'], result[0])
|
||||
|
||||
|
||||
def test_realworld_lc():
|
||||
result = parse_file(_tests_path + '/data/lc.pro')
|
||||
assert len(result) == 3
|
||||
|
||||
|
||||
def test_realworld_lc_with_comment_in_between():
|
||||
result = parse_file(_tests_path + '/data/lc_with_comment.pro')
|
||||
|
||||
my_var = result[1]['value'][0]
|
||||
assert my_var == 'foo'
|
||||
|
||||
my_var = result[2]['value'][0]
|
||||
assert my_var == 'foo2'
|
||||
|
||||
my_var = result[3]['value'][0]
|
||||
assert my_var == 'foo3'
|
||||
|
||||
my_var = result[4]['value'][0]
|
||||
assert my_var == 'foo4'
|
||||
|
||||
my_var = result[5]['value'][0]
|
||||
assert my_var == 'foo5'
|
||||
|
||||
sub_dirs = result[0]['value']
|
||||
assert sub_dirs[0] == 'tga'
|
||||
assert sub_dirs[1] == 'wbmp'
|
||||
assert len(result) == 6
|
||||
|
||||
|
||||
def test_condition_without_scope():
|
||||
result = parse_file(_tests_path + '/data/condition_without_scope.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_multi_condition_divided_by_lc():
|
||||
result = parse_file(_tests_path + '/data/multi_condition_divided_by_lc.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
def test_nested_function_calls():
|
||||
result = parse_file(_tests_path + '/data/nested_function_calls.pro')
|
||||
assert len(result) == 1
|
||||
|
||||
def test_value_function():
|
||||
result = parse_file(_tests_path + '/data/value_function.pro')
|
||||
target = result[0]['value'][0]
|
||||
assert target == 'Dummy'
|
||||
value = result[1]['value']
|
||||
assert value[0] == '$$TARGET'
|
||||
|
||||
|
||||
def test_condition_operator_precedence():
|
||||
result = parse_file(_tests_path + '/data/condition_operator_precedence.pro')
|
||||
|
||||
def validate_simplify(input_str: str, expected: str) -> None:
|
||||
output = simplify_condition(map_condition(input_str))
|
||||
assert output == expected
|
||||
|
||||
validate_simplify(result[0]["condition"], "a1 OR a2")
|
||||
validate_simplify(result[1]["condition"], "b3 AND (b1 OR b2)")
|
||||
validate_simplify(result[2]["condition"], "c4 OR (c1 AND c3) OR (c2 AND c3)")
|
318
util/cmake/tests/test_scope_handling.py
Normal file
318
util/cmake/tests/test_scope_handling.py
Normal file
@ -0,0 +1,318 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2021 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
from pro2cmake import Scope, SetOperation, merge_scopes, recursive_evaluate_scope
|
||||
|
||||
import pytest
|
||||
import typing
|
||||
|
||||
ScopeList = typing.List[Scope]
|
||||
|
||||
def _map_to_operation(**kwargs):
|
||||
result = {} # type: typing.Mapping[str, typing.List[SetOperation]]
|
||||
for (key, value) in kwargs.items():
|
||||
result[key] = [SetOperation([value])]
|
||||
return result
|
||||
|
||||
|
||||
def _new_scope(*, parent_scope=None, condition='', **kwargs) -> Scope:
|
||||
return Scope(parent_scope=parent_scope,
|
||||
qmake_file='file1', condition=condition, operations=_map_to_operation(**kwargs))
|
||||
|
||||
|
||||
def _evaluate_scopes(scopes: ScopeList) -> ScopeList:
|
||||
for s in scopes:
|
||||
if not s.parent:
|
||||
recursive_evaluate_scope(s)
|
||||
return scopes
|
||||
|
||||
|
||||
def _validate(input_scopes: ScopeList, output_scopes: ScopeList):
|
||||
merged_scopes = merge_scopes(input_scopes)
|
||||
assert merged_scopes == output_scopes
|
||||
|
||||
|
||||
def test_evaluate_one_scope():
|
||||
scope = _new_scope(condition='QT_FEATURE_foo', test1='bar')
|
||||
|
||||
input_scope = scope
|
||||
recursive_evaluate_scope(scope)
|
||||
assert scope == input_scope
|
||||
|
||||
|
||||
def test_evaluate_child_scope():
|
||||
scope = _new_scope(condition='QT_FEATURE_foo', test1='bar')
|
||||
_new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar')
|
||||
|
||||
input_scope = scope
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
assert scope.total_condition == 'QT_FEATURE_foo'
|
||||
assert len(scope.children) == 1
|
||||
assert scope.get_string('test1') == 'bar'
|
||||
assert scope.get_string('test2', 'not found') == 'not found'
|
||||
|
||||
child = scope.children[0]
|
||||
assert child.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo'
|
||||
assert child.get_string('test1', 'not found') == 'not found'
|
||||
assert child.get_string('test2') == 'bar'
|
||||
|
||||
|
||||
def test_evaluate_two_child_scopes():
|
||||
scope = _new_scope(condition='QT_FEATURE_foo', test1='bar')
|
||||
_new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar')
|
||||
_new_scope(parent_scope=scope, condition='QT_FEATURE_buz', test3='buz')
|
||||
|
||||
input_scope = scope
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
assert scope.total_condition == 'QT_FEATURE_foo'
|
||||
assert len(scope.children) == 2
|
||||
assert scope.get_string('test1') == 'bar'
|
||||
assert scope.get_string('test2', 'not found') == 'not found'
|
||||
assert scope.get_string('test3', 'not found') == 'not found'
|
||||
|
||||
child1 = scope.children[0]
|
||||
assert child1.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo'
|
||||
assert child1.get_string('test1', 'not found') == 'not found'
|
||||
assert child1.get_string('test2') == 'bar'
|
||||
assert child1.get_string('test3', 'not found') == 'not found'
|
||||
|
||||
child2 = scope.children[1]
|
||||
assert child2.total_condition == 'QT_FEATURE_buz AND QT_FEATURE_foo'
|
||||
assert child2.get_string('test1', 'not found') == 'not found'
|
||||
assert child2.get_string('test2') == ''
|
||||
assert child2.get_string('test3', 'not found') == 'buz'
|
||||
|
||||
|
||||
def test_evaluate_else_child_scopes():
|
||||
scope = _new_scope(condition='QT_FEATURE_foo', test1='bar')
|
||||
_new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar')
|
||||
_new_scope(parent_scope=scope, condition='else', test3='buz')
|
||||
|
||||
input_scope = scope
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
assert scope.total_condition == 'QT_FEATURE_foo'
|
||||
assert len(scope.children) == 2
|
||||
assert scope.get_string('test1') == 'bar'
|
||||
assert scope.get_string('test2', 'not found') == 'not found'
|
||||
assert scope.get_string('test3', 'not found') == 'not found'
|
||||
|
||||
child1 = scope.children[0]
|
||||
assert child1.total_condition == 'QT_FEATURE_bar AND QT_FEATURE_foo'
|
||||
assert child1.get_string('test1', 'not found') == 'not found'
|
||||
assert child1.get_string('test2') == 'bar'
|
||||
assert child1.get_string('test3', 'not found') == 'not found'
|
||||
|
||||
child2 = scope.children[1]
|
||||
assert child2.total_condition == 'QT_FEATURE_foo AND NOT QT_FEATURE_bar'
|
||||
assert child2.get_string('test1', 'not found') == 'not found'
|
||||
assert child2.get_string('test2') == ''
|
||||
assert child2.get_string('test3', 'not found') == 'buz'
|
||||
|
||||
|
||||
def test_evaluate_invalid_else_child_scopes():
|
||||
scope = _new_scope(condition='QT_FEATURE_foo', test1='bar')
|
||||
_new_scope(parent_scope=scope, condition='else', test3='buz')
|
||||
_new_scope(parent_scope=scope, condition='QT_FEATURE_bar', test2='bar')
|
||||
|
||||
input_scope = scope
|
||||
with pytest.raises(AssertionError):
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
|
||||
def test_merge_empty_scope_list():
|
||||
_validate([], [])
|
||||
|
||||
|
||||
def test_merge_one_scope():
|
||||
scopes = [_new_scope(test='foo')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
|
||||
_validate(scopes, scopes)
|
||||
|
||||
|
||||
def test_merge_one_on_scope():
|
||||
scopes = [_new_scope(condition='ON', test='foo')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
|
||||
_validate(scopes, scopes)
|
||||
|
||||
|
||||
def test_merge_one_off_scope():
|
||||
scopes = [_new_scope(condition='OFF', test='foo')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
|
||||
_validate(scopes, [])
|
||||
|
||||
|
||||
def test_merge_one_conditioned_scope():
|
||||
scopes = [_new_scope(condition='QT_FEATURE_foo', test='foo')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
|
||||
_validate(scopes, scopes)
|
||||
|
||||
|
||||
def test_merge_two_scopes_with_same_condition():
|
||||
scopes = [_new_scope(condition='QT_FEATURE_bar', test='foo'),
|
||||
_new_scope(condition='QT_FEATURE_bar', test2='bar')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
recursive_evaluate_scope(scopes[1])
|
||||
|
||||
result = merge_scopes(scopes)
|
||||
|
||||
assert len(result) == 1
|
||||
r0 = result[0]
|
||||
assert r0.total_condition == 'QT_FEATURE_bar'
|
||||
assert r0.get_string('test') == 'foo'
|
||||
assert r0.get_string('test2') == 'bar'
|
||||
|
||||
|
||||
def test_merge_three_scopes_two_with_same_condition():
|
||||
scopes = [_new_scope(condition='QT_FEATURE_bar', test='foo'),
|
||||
_new_scope(condition='QT_FEATURE_baz', test1='buz'),
|
||||
_new_scope(condition='QT_FEATURE_bar', test2='bar')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
recursive_evaluate_scope(scopes[1])
|
||||
recursive_evaluate_scope(scopes[2])
|
||||
|
||||
result = merge_scopes(scopes)
|
||||
|
||||
assert len(result) == 2
|
||||
r0 = result[0]
|
||||
assert r0.total_condition == 'QT_FEATURE_bar'
|
||||
assert r0.get_string('test') == 'foo'
|
||||
assert r0.get_string('test2') == 'bar'
|
||||
|
||||
assert result[1] == scopes[1]
|
||||
|
||||
|
||||
def test_merge_two_unrelated_on_off_scopes():
|
||||
scopes = [_new_scope(condition='ON', test='foo'),
|
||||
_new_scope(condition='OFF', test2='bar')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
recursive_evaluate_scope(scopes[1])
|
||||
|
||||
_validate(scopes, [scopes[0]])
|
||||
|
||||
|
||||
def test_merge_two_unrelated_on_off_scopes():
|
||||
scopes = [_new_scope(condition='OFF', test='foo'),
|
||||
_new_scope(condition='ON', test2='bar')]
|
||||
|
||||
recursive_evaluate_scope(scopes[0])
|
||||
recursive_evaluate_scope(scopes[1])
|
||||
|
||||
_validate(scopes, [scopes[1]])
|
||||
|
||||
|
||||
def test_merge_parent_child_scopes_with_different_conditions():
|
||||
scope = _new_scope(condition='FOO', test1='parent')
|
||||
scopes = [scope, _new_scope(parent_scope=scope, condition='bar', test2='child')]
|
||||
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
_validate(scopes, scopes)
|
||||
|
||||
|
||||
def test_merge_parent_child_scopes_with_same_conditions():
|
||||
scope = _new_scope(condition='FOO AND bar', test1='parent')
|
||||
scopes = [scope, _new_scope(parent_scope=scope, condition='FOO AND bar', test2='child')]
|
||||
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
result = merge_scopes(scopes)
|
||||
|
||||
assert len(result) == 1
|
||||
r0 = result[0]
|
||||
assert r0.parent == None
|
||||
assert r0.total_condition == 'FOO AND bar'
|
||||
assert r0.get_string('test1') == 'parent'
|
||||
assert r0.get_string('test2') == 'child'
|
||||
|
||||
|
||||
def test_merge_parent_child_scopes_with_on_child_condition():
|
||||
scope = _new_scope(condition='FOO AND bar', test1='parent')
|
||||
scopes = [scope, _new_scope(parent_scope=scope, condition='ON', test2='child')]
|
||||
|
||||
recursive_evaluate_scope(scope)
|
||||
|
||||
result = merge_scopes(scopes)
|
||||
|
||||
assert len(result) == 1
|
||||
r0 = result[0]
|
||||
assert r0.parent == None
|
||||
assert r0.total_condition == 'FOO AND bar'
|
||||
assert r0.get_string('test1') == 'parent'
|
||||
assert r0.get_string('test2') == 'child'
|
||||
|
||||
|
||||
# Real world examples:
|
||||
|
||||
# qstandardpaths selection:
|
||||
|
||||
def test_qstandardpaths_scopes():
|
||||
# top level:
|
||||
scope1 = _new_scope(condition='ON', scope_id=1)
|
||||
|
||||
# win32 {
|
||||
scope2 = _new_scope(parent_scope=scope1, condition='WIN32')
|
||||
# !winrt {
|
||||
# SOURCES += io/qstandardpaths_win.cpp
|
||||
scope3 = _new_scope(parent_scope=scope2, condition='NOT WINRT',
|
||||
SOURCES='qsp_win.cpp')
|
||||
# } else {
|
||||
# SOURCES += io/qstandardpaths_winrt.cpp
|
||||
scope4 = _new_scope(parent_scope=scope2, condition='else',
|
||||
SOURCES='qsp_winrt.cpp')
|
||||
# }
|
||||
# else: unix {
|
||||
scope5 = _new_scope(parent_scope=scope1, condition='else')
|
||||
scope6 = _new_scope(parent_scope=scope5, condition='UNIX')
|
||||
# mac {
|
||||
# OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm
|
||||
scope7 = _new_scope(parent_scope=scope6, condition='MACOS', SOURCES='qsp_mac.mm')
|
||||
# } else:android {
|
||||
# SOURCES += io/qstandardpaths_android.cpp
|
||||
scope8 = _new_scope(parent_scope=scope6, condition='else')
|
||||
scope9 = _new_scope(parent_scope=scope8, condition='ANDROID AND NOT UNKNOWN_PLATFORM', SOURCES='qsp_android.cpp')
|
||||
# } else:haiku {
|
||||
# SOURCES += io/qstandardpaths_haiku.cpp
|
||||
scope10 = _new_scope(parent_scope=scope8, condition='else')
|
||||
scope11 = _new_scope(parent_scope=scope10, condition='HAIKU', SOURCES='qsp_haiku.cpp')
|
||||
# } else {
|
||||
# SOURCES +=io/qstandardpaths_unix.cpp
|
||||
scope12 = _new_scope(parent_scope=scope10, condition='else', SOURCES='qsp_unix.cpp')
|
||||
# }
|
||||
# }
|
||||
|
||||
recursive_evaluate_scope(scope1)
|
||||
|
||||
assert scope1.total_condition == 'ON'
|
||||
assert scope2.total_condition == 'WIN32'
|
||||
assert scope3.total_condition == 'WIN32 AND NOT WINRT'
|
||||
assert scope4.total_condition == 'WINRT'
|
||||
assert scope5.total_condition == 'UNIX'
|
||||
assert scope6.total_condition == 'UNIX'
|
||||
assert scope7.total_condition == 'MACOS'
|
||||
assert scope8.total_condition == 'UNIX AND NOT MACOS'
|
||||
assert scope9.total_condition == 'ANDROID AND NOT UNKNOWN_PLATFORM'
|
||||
assert scope10.total_condition == 'UNIX AND NOT MACOS AND (UNKNOWN_PLATFORM OR NOT ANDROID)'
|
||||
assert scope11.total_condition == 'HAIKU AND (UNKNOWN_PLATFORM OR NOT ANDROID)'
|
||||
assert scope12.total_condition == 'UNIX AND NOT HAIKU AND NOT MACOS AND (UNKNOWN_PLATFORM OR NOT ANDROID)'
|
||||
|
||||
def test_recursive_expansion():
|
||||
scope = _new_scope(A='Foo',B='$$A/Bar')
|
||||
assert scope.get_string('A') == 'Foo'
|
||||
assert scope.get_string('B') == '$$A/Bar'
|
||||
assert scope._expand_value('$$B/Source.cpp') == ['Foo/Bar/Source.cpp']
|
||||
assert scope._expand_value('$$B') == ['Foo/Bar']
|
79
util/edid/qedidvendortable.py
Normal file
79
util/edid/qedidvendortable.py
Normal file
@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
import urllib.request
|
||||
|
||||
# The original source for this data used to be
|
||||
# 'https://git.fedorahosted.org/cgit/hwdata.git/plain/pnp.ids'
|
||||
# which is discontinued. For now there seems to be a fork at:
|
||||
url = 'https://github.com/vcrhonek/hwdata/raw/master/pnp.ids'
|
||||
|
||||
copyright = """
|
||||
// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
"""
|
||||
|
||||
notice = """/*
|
||||
* This lookup table was generated from {}
|
||||
*
|
||||
* Do not change this file directly, instead edit the
|
||||
* qtbase/util/edid/qedidvendortable.py script and regenerate this file.
|
||||
*/""".format(url)
|
||||
|
||||
header = """
|
||||
#ifndef QEDIDVENDORTABLE_P_H
|
||||
#define QEDIDVENDORTABLE_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct VendorTable {
|
||||
const char id[4];
|
||||
const char name[%d];
|
||||
};
|
||||
|
||||
static const VendorTable q_edidVendorTable[] = {"""
|
||||
|
||||
footer = """};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QEDIDVENDORTABLE_P_H"""
|
||||
|
||||
vendors = {}
|
||||
|
||||
max_vendor_length = 0
|
||||
|
||||
response = urllib.request.urlopen(url)
|
||||
data = response.read().decode('utf-8')
|
||||
for line in data.split('\n'):
|
||||
l = line.split()
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
elif len(l) == 0:
|
||||
continue
|
||||
else:
|
||||
pnp_id = l[0].upper()
|
||||
vendors[pnp_id] = ' '.join(l[1:])
|
||||
if len(vendors[pnp_id]) > max_vendor_length:
|
||||
max_vendor_length = len(vendors[pnp_id])
|
||||
|
||||
print(copyright)
|
||||
print(notice)
|
||||
print(header % (max_vendor_length + 1))
|
||||
for pnp_id in sorted(vendors.keys()):
|
||||
print(' { "%s", "%s" },' % (pnp_id, vendors[pnp_id]))
|
||||
print(footer)
|
147
util/glgen/README.txt
Normal file
147
util/glgen/README.txt
Normal file
@ -0,0 +1,147 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
This is the glgen application used to generate OpenGL related classes from the
|
||||
official Khronos OpenGL specification and typemap files.
|
||||
|
||||
To run this application download the gl.spec and gl.tm files from:
|
||||
|
||||
http://www.opengl.org/registry/api/gl.spec
|
||||
http://www.opengl.org/registry/api/gl.tm
|
||||
|
||||
and place them into the application directory. These files are not stored in
|
||||
the Qt Project's git repo or downloaded automatically to
|
||||
|
||||
a) avoid copyright issues
|
||||
b) make sure the version of OpenGL used is controlled by a human
|
||||
|
||||
The glgen application parses these files and generates:
|
||||
|
||||
1) A set of public classes, one for each combination of OpenGL version and profile.
|
||||
2) A set of backend helper classes that contain the actual function pointers
|
||||
3) A factory class for the classes in 1)
|
||||
4) A set of classes, one for each OpenGL extension which introduces new entry points
|
||||
|
||||
We will now describe each of these categories.
|
||||
|
||||
|
||||
OpenGL Version and Profile Classes
|
||||
==================================
|
||||
|
||||
The base class of this set is QAbstractOpenGLFunctions. From this we inherit one class
|
||||
for each OpenGL version and if supported, profile.
|
||||
|
||||
The Core profile contains only the non-deprecated functionality. The Compatibility profile
|
||||
also includes all functionality that was removed in OpenGL 3.1. Therefore, for OpenGL
|
||||
3.2 onwards we have two classes for each version.
|
||||
|
||||
All of these classes are named with the following convention:
|
||||
|
||||
QOpenGLFunctions_<MAJOR>_<MINOR>[_PROFILE]
|
||||
|
||||
For example QOpenGLFunctions_2_1, QOpenGLFunctions_4_3_Core
|
||||
|
||||
The source and header files for these classes take the form
|
||||
|
||||
qopenglfunction_<MAJOR>_<MINOR>[_PROFILE].cpp
|
||||
qopenglfunction_<MAJOR>_<MINOR>[_PROFILE].h
|
||||
|
||||
and should be moved to
|
||||
|
||||
$QTBASE/src/gui/opengl/
|
||||
|
||||
and forms part of the public QtGui library API.
|
||||
|
||||
|
||||
Backend Helper Classes
|
||||
======================
|
||||
|
||||
Every OpenGL function is categorised by which version it was introduced with and
|
||||
whether it is part of the Core Profile and is deemed part of the core specification
|
||||
or whther it is only part of the Compatibility profile and has been marked as
|
||||
deprecated.
|
||||
|
||||
Glgen creates a backend helper class containing function pointers to match each
|
||||
possible case. E.g. QOpenGLFunctions_1_5_CoreBackend contains functions introduced
|
||||
in OpenGL 1.5 which are still core (not deprecated).
|
||||
|
||||
The public frontend classes described above contain pointers to the set of backend
|
||||
objects necessary to implement the functions for their version and profile.
|
||||
|
||||
Creating new instances of these backend objects for each public version functions
|
||||
object would be wasteful in terms of memory (repeated function pointers) and CPU
|
||||
time (no need to keep re-solving the same functions).
|
||||
|
||||
We cannot share the backend objects globally as OpenGL entry point addresses are
|
||||
specific to the OpenGL context. They cannot even be reliably shared between a
|
||||
context group. This is not surprising if you consider the case of contexts in a share
|
||||
group where the contexts have different versions or even profiles. We therefore share
|
||||
the backend instances at the QOpenGLContext level using a simple reference counting
|
||||
scheme.
|
||||
|
||||
When the frontend version functions objects are intialized they check to see if
|
||||
the associated context already has suitable backend objects available. If so they use
|
||||
them, otherwise they will create backend objects and associate them with the context.
|
||||
|
||||
The backend classes are in
|
||||
|
||||
qopenglversionfunctions.h
|
||||
qopenglversionfunctions.cpp
|
||||
|
||||
and should also be moved to
|
||||
|
||||
$QTBASE/src/gui/opengl/
|
||||
|
||||
|
||||
OpenGL Version and Profile Factory
|
||||
==================================
|
||||
|
||||
Instances of the OpenGL version and profile classes described above can be obtained
|
||||
from QOpenGLContext by means of the versionFunctions() member. The OpenGLContext
|
||||
retains ownership of the QOpenGLFunctions_* object. If a suitable object does not
|
||||
already exist it is created by the factory class generated by glgen.
|
||||
|
||||
It is possible to request version functions objects for any version/profile
|
||||
combination from a context. However not all requests can be serviced. For example
|
||||
consider the case of an OpenGL 3.3 Core profile context. In this case:
|
||||
|
||||
* Requesting a 3.3 core profile functions object would succeed.
|
||||
* Requesting a 3.3 compatibility profile functions object would fail. We would fail
|
||||
to resolve the deprecated functions.
|
||||
* Requesting a 4.3 core profile functions object would fail. We would fail to resolve
|
||||
the new core functions introduced in versions 4.0-4.3.
|
||||
* Requesting a 3.1 functions object would succeed. There is nothing in 3.1 that is not
|
||||
also in 3.3 core.
|
||||
|
||||
If a request is not able to be serviced the factory, and hence QOpenGLContext::versionFunctions()
|
||||
will return a null pointer that can be checked for.
|
||||
|
||||
The source and header file for this class should be moved to
|
||||
|
||||
$QTBASE/src/gui/opengl/
|
||||
|
||||
and forms part of the QtGui library.
|
||||
|
||||
If a user instantiates a version functions object directly (i.e. not via QOpenGLContext)
|
||||
then it bypasses the above checks. However, the same checks are applied in the
|
||||
initializeOpenGLFunctions() method and the result can once again be checked.
|
||||
|
||||
This approach allows maximum flexibility but ensure's safety in that once the user
|
||||
posesses a functions object that has been successfully initialized they can rely upon its
|
||||
member functions being successfully resolved.
|
||||
|
||||
|
||||
OpenGL Extension Classes
|
||||
========================
|
||||
|
||||
In addition, glgen also creates one class for each OpenGL extension that introduces
|
||||
new entry points. These classes are named with the convention
|
||||
|
||||
QOpenGLExtension_<name-of-extension>
|
||||
|
||||
The usage pattern for OpenGL extensions is to just use a small
|
||||
number of extensions out of the large number of those available.
|
||||
|
||||
Prior to Qt 6, these classes were provided as the openglextensions
|
||||
module. Because of the new graphics architecture in Qt 6, that module
|
||||
has been removed.
|
1080
util/glgen/codegenerator.cpp
Normal file
1080
util/glgen/codegenerator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
111
util/glgen/codegenerator.h
Normal file
111
util/glgen/codegenerator.h
Normal file
@ -0,0 +1,111 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef CODEGENERATOR_H
|
||||
#define CODEGENERATOR_H
|
||||
|
||||
#include "specparser.h"
|
||||
|
||||
class QTextStream;
|
||||
|
||||
class CodeGenerator
|
||||
{
|
||||
public:
|
||||
explicit CodeGenerator();
|
||||
|
||||
void setParser(SpecParser *parser) {m_parser = parser;}
|
||||
|
||||
void generateCoreClasses(const QString &baseFileName) const;
|
||||
|
||||
void generateExtensionClasses(const QString &baseFileName) const;
|
||||
|
||||
private:
|
||||
// Generic support
|
||||
enum ClassVisibility {
|
||||
Public,
|
||||
Private
|
||||
};
|
||||
|
||||
enum ClassComponent {
|
||||
Declaration = 0,
|
||||
Definition
|
||||
};
|
||||
|
||||
bool isLegacyVersion(Version v) const;
|
||||
bool versionHasProfiles(Version v) const;
|
||||
|
||||
FunctionCollection functionCollection( const VersionProfile& classVersionProfile ) const;
|
||||
|
||||
void writePreamble(const QString &baseFileName, QTextStream &stream, const QString replacement = QString()) const;
|
||||
void writePostamble(const QString &baseFileName, QTextStream &stream) const;
|
||||
|
||||
QString passByType(const Argument &arg) const;
|
||||
QString safeArgumentName(const QString& arg) const;
|
||||
|
||||
// Core functionality support
|
||||
QString coreClassFileName(const VersionProfile &versionProfile,
|
||||
const QString& fileExtension) const;
|
||||
void writeCoreHelperClasses(const QString &fileName, ClassComponent component) const;
|
||||
void writeCoreClasses(const QString &baseFileName) const;
|
||||
|
||||
void writeCoreFactoryHeader(const QString &fileName) const;
|
||||
void writeCoreFactoryImplementation(const QString &fileName) const;
|
||||
|
||||
QString generateClassName(const VersionProfile &classVersion, ClassVisibility visibility = Public) const;
|
||||
|
||||
void writeBackendClassDeclaration(QTextStream &stream,
|
||||
const VersionProfile &versionProfile,
|
||||
const QString &baseClass) const;
|
||||
void writeBackendClassImplementation(QTextStream &stream,
|
||||
const VersionProfile &versionProfile,
|
||||
const QString &baseClass) const;
|
||||
|
||||
void writePublicClassDeclaration(const QString &baseFileName,
|
||||
const VersionProfile &versionProfile,
|
||||
const QString &baseClass) const;
|
||||
void writePublicClassImplementation(const QString &baseFileName,
|
||||
const VersionProfile &versionProfile,
|
||||
const QString& baseClass) const;
|
||||
|
||||
void writeClassFunctionDeclarations(QTextStream &stream,
|
||||
const FunctionCollection &functionSets,
|
||||
ClassVisibility visibility) const;
|
||||
|
||||
void writeFunctionDeclaration(QTextStream &stream, const Function &f, ClassVisibility visibility) const;
|
||||
|
||||
void writeClassInlineFunctions(QTextStream &stream,
|
||||
const QString &className,
|
||||
const FunctionCollection &functionSet) const;
|
||||
|
||||
void writeInlineFunction(QTextStream &stream, const QString &className,
|
||||
const QString &backendVar, const Function &f) const;
|
||||
|
||||
void writeEntryPointResolutionCode(QTextStream &stream,
|
||||
const FunctionCollection &functionSet) const;
|
||||
|
||||
void writeEntryPointResolutionStatement(QTextStream &stream, const Function &f,
|
||||
const QString &prefix = QString(), bool useGetProcAddress = false) const;
|
||||
|
||||
QList<VersionProfile> backendsForFunctionCollection(const FunctionCollection &functionSet) const;
|
||||
QString backendClassName(const VersionProfile &v) const;
|
||||
QString backendVariableName(const VersionProfile &v) const;
|
||||
void writeBackendVariableDeclarations(QTextStream &stream, const QList<VersionProfile> &backends) const;
|
||||
|
||||
|
||||
// Extension class support
|
||||
void writeExtensionHeader(const QString &fileName) const;
|
||||
void writeExtensionImplementation(const QString &fileName) const;
|
||||
|
||||
void writeExtensionClassDeclaration(QTextStream &stream,
|
||||
const QString &extension,
|
||||
ClassVisibility visibility = Public) const;
|
||||
void writeExtensionClassImplementation(QTextStream &stream, const QString &extension) const;
|
||||
|
||||
QString generateExtensionClassName(const QString &extension, ClassVisibility visibility = Public) const;
|
||||
void writeExtensionInlineFunction(QTextStream &stream, const QString &className, const Function &f) const;
|
||||
|
||||
SpecParser *m_parser;
|
||||
mutable QMap<QString, int> m_extensionIds;
|
||||
};
|
||||
|
||||
#endif // CODEGENERATOR_H
|
38
util/glgen/glgen.pro
Normal file
38
util/glgen/glgen.pro
Normal file
@ -0,0 +1,38 @@
|
||||
QT -= gui
|
||||
QT += core5compat
|
||||
CONFIG += cmdline
|
||||
|
||||
# Uncomment following to enable debug output
|
||||
#DEFINES += SPECPARSER_DEBUG
|
||||
|
||||
TEMPLATE = app
|
||||
TARGET = glgen
|
||||
|
||||
SOURCES += main.cpp \
|
||||
xmlspecparser.cpp \
|
||||
legacyspecparser.cpp \
|
||||
codegenerator.cpp
|
||||
|
||||
HEADERS += \
|
||||
specparser.h \
|
||||
xmlspecparser.h \
|
||||
legacyspecparser.h \
|
||||
codegenerator.h
|
||||
|
||||
OTHER_FILES += \
|
||||
qopenglversionfunctions.h.header \
|
||||
qopenglversionfunctions.h.footer \
|
||||
qopenglversionfunctions.cpp.header \
|
||||
qopenglversionfunctions.cpp.footer \
|
||||
qopenglversionfunctions__VERSION__.cpp.footer \
|
||||
qopenglversionfunctions__VERSION__.cpp.header \
|
||||
qopenglversionfunctions__VERSION__.h.footer \
|
||||
qopenglversionfunctions__VERSION__.h.header \
|
||||
qopenglversionfunctionsfactory_p.h.header \
|
||||
qopenglextensions.cpp.header \
|
||||
qopenglextensions.cpp.footer \
|
||||
qopenglextensions.h.header \
|
||||
qopenglextensions.h.footer \
|
||||
qopenglversionfunctionsfactory.cpp.header \
|
||||
qopenglversionfunctionsfactory.cpp.footer \
|
||||
README.txt
|
275
util/glgen/legacyspecparser.cpp
Normal file
275
util/glgen/legacyspecparser.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "legacyspecparser.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
|
||||
#ifdef SPECPARSER_DEBUG
|
||||
#define qLegacySpecParserDebug qDebug
|
||||
#else
|
||||
#define qLegacySpecParserDebug QT_NO_QDEBUG_MACRO
|
||||
#endif
|
||||
|
||||
bool LegacySpecParser::parse()
|
||||
{
|
||||
// Get the mapping form generic types to specific types suitable for use in C-headers
|
||||
if (!parseTypeMap())
|
||||
return false;
|
||||
|
||||
// Open up a stream on the actual OpenGL function spec file
|
||||
QFile file(specFileName());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Failed to open spec file:" << specFileName() << "Aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
|
||||
// Extract the info that we need
|
||||
parseFunctions(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LegacySpecParser::parseTypeMap()
|
||||
{
|
||||
QFile file(typeMapFileName());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Failed to open type file:" << typeMapFileName() << "Aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
|
||||
static QRegExp typeMapRegExp("([^,]+)\\W+([^,]+)");
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
|
||||
if (line.startsWith(QLatin1Char('#')))
|
||||
continue;
|
||||
|
||||
if (typeMapRegExp.indexIn(line) != -1) {
|
||||
QString key = typeMapRegExp.cap(1).simplified();
|
||||
QString value = typeMapRegExp.cap(2).simplified();
|
||||
|
||||
// Special case for void
|
||||
if (value == QLatin1String("*"))
|
||||
value = QStringLiteral("void");
|
||||
|
||||
m_typeMap.insert(key, value);
|
||||
qLegacySpecParserDebug() << "Found type mapping from" << key << "=>" << value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LegacySpecParser::parseEnums()
|
||||
{
|
||||
}
|
||||
|
||||
void LegacySpecParser::parseFunctions(QTextStream &stream)
|
||||
{
|
||||
static QRegExp functionRegExp("^(\\w+)\\(.*\\)");
|
||||
static QRegExp returnRegExp("^\\treturn\\s+(\\S+)");
|
||||
static QRegExp argumentRegExp("param\\s+(\\S+)\\s+(\\S+) (\\S+) (\\S+)");
|
||||
static QRegExp versionRegExp("^\\tversion\\s+(\\S+)");
|
||||
static QRegExp deprecatedRegExp("^\\tdeprecated\\s+(\\S+)");
|
||||
static QRegExp categoryRegExp("^\\tcategory\\s+(\\S+)");
|
||||
static QRegExp categoryVersionRegExp("VERSION_(\\d)_(\\d)");
|
||||
static QRegExp extToCoreVersionRegExp("passthru:\\s/\\*\\sOpenGL\\s(\\d)\\.(\\d)\\s.*\\sextensions:");
|
||||
static QRegExp extToCoreRegExp("passthru:\\s/\\*\\s(ARB_\\S*)\\s.*\\*/");
|
||||
|
||||
Function currentFunction;
|
||||
VersionProfile currentVersionProfile;
|
||||
QString currentCategory;
|
||||
bool haveVersionInfo = false;
|
||||
bool acceptCurrentFunctionInCore = false;
|
||||
bool acceptCurrentFunctionInExtension = false;
|
||||
|
||||
QHash<QString, Version> extensionsNowInCore;
|
||||
Version extToCoreCurrentVersion;
|
||||
int functionCount = 0;
|
||||
|
||||
QSet<Version> versions;
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
if (line.startsWith("#"))
|
||||
continue;
|
||||
|
||||
if (functionRegExp.indexIn(line) != -1) {
|
||||
|
||||
if (!currentFunction.name.isEmpty()) {
|
||||
|
||||
// NB - Special handling!
|
||||
// Versions 4.2 and 4.3 (and probably newer) add functionality by
|
||||
// subsuming extensions such as ARB_texture_storage. However, some extensions
|
||||
// also include functions to interact with the EXT_direct_state_access
|
||||
// extension. These functions should be added to the DSA extension rather
|
||||
// than the core functionality. The core will already contain non-DSA
|
||||
// versions of these functions.
|
||||
if (acceptCurrentFunctionInCore && currentFunction.name.endsWith(QLatin1String("EXT"))) {
|
||||
acceptCurrentFunctionInCore = false;
|
||||
acceptCurrentFunctionInExtension = true;
|
||||
currentCategory = QStringLiteral("EXT_direct_state_access");
|
||||
}
|
||||
|
||||
// Finish off previous function (if any) by inserting it into the core
|
||||
// functionality or extension functionality (or both)
|
||||
if (acceptCurrentFunctionInCore) {
|
||||
m_functions.insert(currentVersionProfile, currentFunction);
|
||||
versions.insert(currentVersionProfile.version);
|
||||
}
|
||||
|
||||
if (acceptCurrentFunctionInExtension) {
|
||||
FunctionProfile fp;
|
||||
fp.profile = currentVersionProfile.profile;
|
||||
fp.function = currentFunction;
|
||||
m_extensionFunctions.insert(currentCategory, fp);
|
||||
}
|
||||
}
|
||||
|
||||
// Start a new function
|
||||
++functionCount;
|
||||
haveVersionInfo = false;
|
||||
acceptCurrentFunctionInCore = true;
|
||||
acceptCurrentFunctionInExtension = false;
|
||||
currentCategory = QString();
|
||||
currentFunction = Function();
|
||||
|
||||
// We assume a core function unless we find a deprecated flag (see below)
|
||||
currentVersionProfile = VersionProfile();
|
||||
currentVersionProfile.profile = VersionProfile::CoreProfile;
|
||||
|
||||
// Extract the function name
|
||||
QString functionName = functionRegExp.cap(1);
|
||||
currentFunction.name = functionName;
|
||||
qLegacySpecParserDebug() << "Found function:" << functionName;
|
||||
|
||||
} else if (argumentRegExp.indexIn(line) != -1) {
|
||||
// Extract info about this function argument
|
||||
Argument arg;
|
||||
arg.name = argumentRegExp.cap(1);
|
||||
|
||||
QString type = argumentRegExp.cap(2); // Lookup in type map
|
||||
arg.type = m_typeMap.value(type);
|
||||
|
||||
QString direction = argumentRegExp.cap(3);
|
||||
if (direction == QLatin1String("in")) {
|
||||
arg.direction = Argument::In;
|
||||
} else if (direction == QLatin1String("out")) {
|
||||
arg.direction = Argument::Out;
|
||||
} else {
|
||||
qWarning() << "Invalid argument direction found:" << direction;
|
||||
acceptCurrentFunctionInCore = false;
|
||||
}
|
||||
|
||||
QString mode = argumentRegExp.cap(4);
|
||||
if (mode == QLatin1String("value")) {
|
||||
arg.mode = Argument::Value;
|
||||
} else if (mode == QLatin1String("array")) {
|
||||
arg.mode = Argument::Array;
|
||||
} else if (mode == QLatin1String("reference")) {
|
||||
arg.mode = Argument::Reference;
|
||||
} else {
|
||||
qWarning() << "Invalid argument mode found:" << mode;
|
||||
acceptCurrentFunctionInCore = false;
|
||||
}
|
||||
|
||||
qLegacySpecParserDebug() << " argument:" << arg.type << arg.name;
|
||||
currentFunction.arguments.append(arg);
|
||||
|
||||
} else if (returnRegExp.indexIn(line) != -1) {
|
||||
// Lookup the return type from the typemap
|
||||
QString returnTypeKey = returnRegExp.cap(1).simplified();
|
||||
if (!m_typeMap.contains(returnTypeKey)) {
|
||||
qWarning() << "Unknown return type found:" << returnTypeKey;
|
||||
acceptCurrentFunctionInCore = false;
|
||||
}
|
||||
QString returnType = m_typeMap.value(returnTypeKey);
|
||||
qLegacySpecParserDebug() << " return type:" << returnType;
|
||||
currentFunction.returnType = returnType;
|
||||
|
||||
} else if (versionRegExp.indexIn(line) != -1 && !haveVersionInfo) { // Only use version line if no other source
|
||||
// Extract the OpenGL version in which this function was introduced
|
||||
QString version = versionRegExp.cap(1);
|
||||
qLegacySpecParserDebug() << " version:" << version;
|
||||
QStringList parts = version.split(QLatin1Char('.'));
|
||||
if (parts.size() != 2) {
|
||||
qWarning() << "Found invalid version number";
|
||||
continue;
|
||||
}
|
||||
int majorVersion = parts.first().toInt();
|
||||
int minorVersion = parts.last().toInt();
|
||||
Version v;
|
||||
v.major = majorVersion;
|
||||
v.minor = minorVersion;
|
||||
currentVersionProfile.version = v;
|
||||
|
||||
} else if (deprecatedRegExp.indexIn(line) != -1) {
|
||||
// Extract the OpenGL version in which this function was deprecated.
|
||||
// If it is OpenGL 3.1 then it must be a compatibility profile function
|
||||
QString deprecatedVersion = deprecatedRegExp.cap(1).simplified();
|
||||
if (deprecatedVersion == QLatin1String("3.1") && !inDeprecationException(currentFunction.name))
|
||||
currentVersionProfile.profile = VersionProfile::CompatibilityProfile;
|
||||
|
||||
} else if (categoryRegExp.indexIn(line) != -1) {
|
||||
// Extract the category for this function
|
||||
QString category = categoryRegExp.cap(1).simplified();
|
||||
qLegacySpecParserDebug() << " category:" << category;
|
||||
|
||||
if (categoryVersionRegExp.indexIn(category) != -1) {
|
||||
// Use the version info in the category in preference to the version
|
||||
// entry as this is more applicable and consistent
|
||||
int majorVersion = categoryVersionRegExp.cap(1).toInt();
|
||||
int minorVersion = categoryVersionRegExp.cap(2).toInt();
|
||||
|
||||
Version v;
|
||||
v.major = majorVersion;
|
||||
v.minor = minorVersion;
|
||||
currentVersionProfile.version = v;
|
||||
haveVersionInfo = true;
|
||||
|
||||
} else {
|
||||
// Make a note of the extension name and tag this function as being part of an extension
|
||||
qLegacySpecParserDebug() << "Found category =" << category;
|
||||
currentCategory = category;
|
||||
acceptCurrentFunctionInExtension = true;
|
||||
|
||||
// See if this category (extension) is in our set of extensions that
|
||||
// have now been folded into the core feature set
|
||||
if (extensionsNowInCore.contains(category)) {
|
||||
currentVersionProfile.version = extensionsNowInCore.value(category);
|
||||
haveVersionInfo = true;
|
||||
} else {
|
||||
acceptCurrentFunctionInCore = false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (extToCoreVersionRegExp.indexIn(line) != -1) {
|
||||
qLegacySpecParserDebug() << line;
|
||||
int majorVersion = extToCoreVersionRegExp.cap(1).toInt();
|
||||
int minorVersion = extToCoreVersionRegExp.cap(2).toInt();
|
||||
extToCoreCurrentVersion.major = majorVersion;
|
||||
extToCoreCurrentVersion.minor = minorVersion;
|
||||
|
||||
} else if (extToCoreRegExp.indexIn(line) != -1) {
|
||||
QString extension = extToCoreRegExp.cap(1);
|
||||
extensionsNowInCore.insert(extension, extToCoreCurrentVersion);
|
||||
}
|
||||
}
|
||||
|
||||
m_versions = versions.values();
|
||||
std::sort(m_versions.begin(), m_versions.end());
|
||||
}
|
||||
|
||||
bool LegacySpecParser::inDeprecationException(const QString &functionName) const
|
||||
{
|
||||
return functionName == QLatin1String("TexImage3D");
|
||||
}
|
40
util/glgen/legacyspecparser.h
Normal file
40
util/glgen/legacyspecparser.h
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef LEGACYSPECPARSER_H
|
||||
#define LEGACYSPECPARSER_H
|
||||
|
||||
#include "specparser.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
class QTextStream;
|
||||
|
||||
class LegacySpecParser : public SpecParser
|
||||
{
|
||||
public:
|
||||
virtual QList<Version> versions() const {return m_versions;}
|
||||
|
||||
virtual bool parse();
|
||||
|
||||
protected:
|
||||
const QMultiHash<VersionProfile, Function> &versionFunctions() const { return m_functions; }
|
||||
const QMultiMap<QString, FunctionProfile> &extensionFunctions() const { return m_extensionFunctions; }
|
||||
|
||||
private:
|
||||
QMap<QString, QString> m_typeMap;
|
||||
QMultiHash<VersionProfile, Function> m_functions;
|
||||
|
||||
QList<Version> m_versions;
|
||||
|
||||
// Extension support
|
||||
QMultiMap<QString, FunctionProfile> m_extensionFunctions;
|
||||
|
||||
bool parseTypeMap();
|
||||
void parseEnums();
|
||||
void parseFunctions(QTextStream &stream);
|
||||
bool inDeprecationException(const QString &functionName) const;
|
||||
};
|
||||
|
||||
#endif // LEGACYSPECPARSER_H
|
40
util/glgen/main.cpp
Normal file
40
util/glgen/main.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "codegenerator.h"
|
||||
#include "legacyspecparser.h"
|
||||
#include "xmlspecparser.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
QCommandLineParser cmdParser;
|
||||
|
||||
// flag whether to use legacy or not
|
||||
QCommandLineOption legacyOption(QStringList() << "l" << "legacy", "Use legacy parser.");
|
||||
cmdParser.addOption(legacyOption);
|
||||
cmdParser.process(app);
|
||||
|
||||
SpecParser *parser;
|
||||
|
||||
if (cmdParser.isSet(legacyOption)) {
|
||||
parser = new LegacySpecParser();
|
||||
parser->setTypeMapFileName(QStringLiteral("gl.tm"));
|
||||
parser->setSpecFileName(QStringLiteral("gl.spec"));
|
||||
} else {
|
||||
parser = new XmlSpecParser();
|
||||
parser->setSpecFileName(QStringLiteral("gl.xml"));
|
||||
}
|
||||
|
||||
parser->parse();
|
||||
|
||||
CodeGenerator generator;
|
||||
generator.setParser(parser);
|
||||
generator.generateCoreClasses(QStringLiteral("qopenglversionfunctions"));
|
||||
generator.generateExtensionClasses(QStringLiteral("qopenglextensions"));
|
||||
|
||||
delete parser;
|
||||
return 0;
|
||||
}
|
792
util/glgen/qopenglextensions.cpp.footer
Normal file
792
util/glgen/qopenglextensions.cpp.footer
Normal file
@ -0,0 +1,792 @@
|
||||
|
||||
#else
|
||||
|
||||
QOpenGLExtension_OES_EGL_image::QOpenGLExtension_OES_EGL_image()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_OES_EGL_imagePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_OES_EGL_image::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_OES_EGL_image);
|
||||
|
||||
d->EGLImageTargetTexture2DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLeglImageOES image))context->getProcAddress("glEGLImageTargetTexture2DOES");
|
||||
d->EGLImageTargetRenderbufferStorageOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLeglImageOES image))context->getProcAddress("glEGLImageTargetRenderbufferStorageOES");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_OES_get_program_binary::QOpenGLExtension_OES_get_program_binary()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_OES_get_program_binaryPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_OES_get_program_binary::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_OES_get_program_binary);
|
||||
|
||||
d->GetProgramBinaryOES = (void (QOPENGLF_APIENTRYP)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary))context->getProcAddress("glGetProgramBinaryOES");
|
||||
d->ProgramBinaryOES = (void (QOPENGLF_APIENTRYP)(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length))context->getProcAddress("glProgramBinaryOES");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_OES_mapbuffer::QOpenGLExtension_OES_mapbuffer()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_OES_mapbufferPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_OES_mapbuffer::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_OES_mapbuffer);
|
||||
|
||||
d->MapBufferOES = (void* (QOPENGLF_APIENTRYP)(GLenum target, GLenum access))context->getProcAddress("glMapBufferOES");
|
||||
d->UnmapBufferOES = (GLboolean (QOPENGLF_APIENTRYP)(GLenum target))context->getProcAddress("glUnmapBufferOES");
|
||||
d->GetBufferPointervOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLenum pname, GLvoid** params))context->getProcAddress("glGetBufferPointervOES");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_OES_texture_3D::QOpenGLExtension_OES_texture_3D()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_OES_texture_3DPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_OES_texture_3D::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_OES_texture_3D);
|
||||
|
||||
d->TexImage3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels))context->getProcAddress("glTexImage3DOES");
|
||||
d->TexSubImage3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels))context->getProcAddress("glTexSubImage3DOES");
|
||||
d->CopyTexSubImage3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height))context->getProcAddress("glCopyTexSubImage3DOES");
|
||||
d->CompressedTexImage3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data))context->getProcAddress("glCompressedTexImage3DOES");
|
||||
d->CompressedTexSubImage3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data))context->getProcAddress("glCompressedTexSubImage3DOES");
|
||||
d->FramebufferTexture3DOES = (void (QOPENGLF_APIENTRYP)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset))context->getProcAddress("glFramebufferTexture3DOES");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_OES_vertex_array_object::QOpenGLExtension_OES_vertex_array_object()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_OES_vertex_array_objectPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_OES_vertex_array_object::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_OES_vertex_array_object);
|
||||
|
||||
d->BindVertexArrayOES = (void (QOPENGLF_APIENTRYP)(GLuint array))context->getProcAddress("glBindVertexArrayOES");
|
||||
d->DeleteVertexArraysOES = (void (QOPENGLF_APIENTRYP)(GLsizei n, const GLuint *arrays))context->getProcAddress("glDeleteVertexArraysOES");
|
||||
d->GenVertexArraysOES = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *arrays))context->getProcAddress("glGenVertexArraysOES");
|
||||
d->IsVertexArrayOES = (GLboolean (QOPENGLF_APIENTRYP)(GLuint array))context->getProcAddress("glIsVertexArrayOES");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_AMD_performance_monitor::QOpenGLExtension_AMD_performance_monitor()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_AMD_performance_monitorPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_AMD_performance_monitor::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_AMD_performance_monitor);
|
||||
|
||||
d->GetPerfMonitorGroupsAMD = (void (QOPENGLF_APIENTRYP)(GLint *numGroups, GLsizei groupsSize, GLuint *groups))context->getProcAddress("glGetPerfMonitorGroupsAMD");
|
||||
d->GetPerfMonitorCountersAMD = (void (QOPENGLF_APIENTRYP)(GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters))context->getProcAddress("glGetPerfMonitorCountersAMD");
|
||||
d->GetPerfMonitorGroupStringAMD = (void (QOPENGLF_APIENTRYP)(GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString))context->getProcAddress("glGetPerfMonitorGroupStringAMD");
|
||||
d->GetPerfMonitorCounterStringAMD = (void (QOPENGLF_APIENTRYP)(GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString))context->getProcAddress("glGetPerfMonitorCounterStringAMD");
|
||||
d->GetPerfMonitorCounterInfoAMD = (void (QOPENGLF_APIENTRYP)(GLuint group, GLuint counter, GLenum pname, GLvoid *data))context->getProcAddress("glGetPerfMonitorCounterInfoAMD");
|
||||
d->GenPerfMonitorsAMD = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *monitors))context->getProcAddress("glGenPerfMonitorsAMD");
|
||||
d->DeletePerfMonitorsAMD = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *monitors))context->getProcAddress("glDeletePerfMonitorsAMD");
|
||||
d->SelectPerfMonitorCountersAMD = (void (QOPENGLF_APIENTRYP)(GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList))context->getProcAddress("glSelectPerfMonitorCountersAMD");
|
||||
d->BeginPerfMonitorAMD = (void (QOPENGLF_APIENTRYP)(GLuint monitor))context->getProcAddress("glBeginPerfMonitorAMD");
|
||||
d->EndPerfMonitorAMD = (void (QOPENGLF_APIENTRYP )(GLuint monitor))context->getProcAddress("glEndPerfMonitorAMD");
|
||||
d->GetPerfMonitorCounterDataAMD = (void (QOPENGLF_APIENTRYP)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten))context->getProcAddress("glGetPerfMonitorCounterDataAMD");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_ANGLE_framebuffer_blit::QOpenGLExtension_ANGLE_framebuffer_blit()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_ANGLE_framebuffer_blitPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_ANGLE_framebuffer_blit::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_ANGLE_framebuffer_blit);
|
||||
|
||||
d->BlitFramebufferANGLE = (void (QOPENGLF_APIENTRYP)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter))context->getProcAddress("glBlitFramebufferANGLE");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_ANGLE_framebuffer_multisample::QOpenGLExtension_ANGLE_framebuffer_multisample()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_ANGLE_framebuffer_multisamplePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_ANGLE_framebuffer_multisample::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_ANGLE_framebuffer_multisample);
|
||||
|
||||
d->RenderbufferStorageMultisampleANGLE = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height))context->getProcAddress("glRenderbufferStorageMultisampleANGLE");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_ANGLE_instanced_arrays::QOpenGLExtension_ANGLE_instanced_arrays()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_ANGLE_instanced_arraysPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_ANGLE_instanced_arrays::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_ANGLE_instanced_arrays);
|
||||
|
||||
d->DrawArraysInstancedANGLE = (void (QOPENGLF_APIENTRYP)(GLenum mode, GLint first, GLsizei count, GLsizei primcount))context->getProcAddress("glDrawArraysInstancedANGLE");
|
||||
d->DrawElementsInstancedANGLE = (void (QOPENGLF_APIENTRYP)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount))context->getProcAddress("glDrawElementsInstancedANGLE");
|
||||
d->VertexAttribDivisorANGLE = (void (QOPENGLF_APIENTRYP)(GLuint index, GLuint divisor))context->getProcAddress("glVertexAttribDivisorANGLE");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_ANGLE_translated_shader_source::QOpenGLExtension_ANGLE_translated_shader_source()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_ANGLE_translated_shader_sourcePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_ANGLE_translated_shader_source::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_ANGLE_translated_shader_source);
|
||||
|
||||
d->GetTranslatedShaderSourceANGLE = (void (QOPENGLF_APIENTRYP)(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source))context->getProcAddress("glGetTranslatedShaderSourceANGLE");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_APPLE_framebuffer_multisample::QOpenGLExtension_APPLE_framebuffer_multisample()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_APPLE_framebuffer_multisamplePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_APPLE_framebuffer_multisample::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_APPLE_framebuffer_multisample);
|
||||
|
||||
d->RenderbufferStorageMultisampleAPPLE = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei))context->getProcAddress("glRenderbufferStorageMultisampleAPPLE");
|
||||
d->ResolveMultisampleFramebufferAPPLE = (void (QOPENGLF_APIENTRYP)(void))context->getProcAddress("glResolveMultisampleFramebufferAPPLE");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_debug_label::QOpenGLExtension_EXT_debug_label()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_debug_labelPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_debug_label::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_debug_label);
|
||||
|
||||
d->LabelObjectEXT = (void (QOPENGLF_APIENTRYP)(GLenum type, GLuint object, GLsizei length, const GLchar *label))context->getProcAddress("glLabelObjectEXT");
|
||||
d->GetObjectLabelEXT = (void (QOPENGLF_APIENTRYP)(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label))context->getProcAddress("glGetObjectLabelEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_debug_marker::QOpenGLExtension_EXT_debug_marker()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_debug_markerPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_debug_marker::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_debug_marker);
|
||||
|
||||
d->InsertEventMarkerEXT = (void (QOPENGLF_APIENTRYP)(GLsizei length, const GLchar *marker))context->getProcAddress("glInsertEventMarkerEXT");
|
||||
d->PushGroupMarkerEXT = (void (QOPENGLF_APIENTRYP)(GLsizei length, const GLchar *marker))context->getProcAddress("glPushGroupMarkerEXT");
|
||||
d->PopGroupMarkerEXT = (void (QOPENGLF_APIENTRYP)(void))context->getProcAddress("glPopGroupMarkerEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_discard_framebuffer::QOpenGLExtension_EXT_discard_framebuffer()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_discard_framebufferPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_discard_framebuffer::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_discard_framebuffer);
|
||||
|
||||
d->DiscardFramebufferEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei numAttachments, const GLenum *attachments))context->getProcAddress("glDiscardFramebufferEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_multisampled_render_to_texture::QOpenGLExtension_EXT_multisampled_render_to_texture()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_multisampled_render_to_texturePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_multisampled_render_to_texture::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_multisampled_render_to_texture);
|
||||
|
||||
d->RenderbufferStorageMultisampleEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height))context->getProcAddress("glRenderbufferStorageMultisampleEXT");
|
||||
d->FramebufferTexture2DMultisampleEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples))context->getProcAddress("glFramebufferTexture2DMultisampleEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_multi_draw_arrays::QOpenGLExtension_EXT_multi_draw_arrays()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_multi_draw_arraysPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_multi_draw_arrays::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_multi_draw_arrays);
|
||||
|
||||
d->MultiDrawArraysEXT = (void (QOPENGLF_APIENTRYP)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount))context->getProcAddress("glMultiDrawArraysEXT");
|
||||
d->MultiDrawElementsEXT = (void (QOPENGLF_APIENTRYP)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount))context->getProcAddress("glMultiDrawElementsEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_occlusion_query_boolean::QOpenGLExtension_EXT_occlusion_query_boolean()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_occlusion_query_booleanPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_occlusion_query_boolean::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_occlusion_query_boolean);
|
||||
|
||||
d->GenQueriesEXT = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *ids))context->getProcAddress("glGenQueriesEXT");
|
||||
d->DeleteQueriesEXT = (void (QOPENGLF_APIENTRYP)(GLsizei n, const GLuint *ids))context->getProcAddress("glDeleteQueriesEXT");
|
||||
d->IsQueryEXT = (GLboolean (QOPENGLF_APIENTRYP)(GLuint id))context->getProcAddress("glIsQueryEXT");
|
||||
d->BeginQueryEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLuint id))context->getProcAddress("glBeginQueryEXT");
|
||||
d->EndQueryEXT = (void (QOPENGLF_APIENTRYP)(GLenum target))context->getProcAddress("glEndQueryEXT");
|
||||
d->GetQueryivEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLenum pname, GLint *params))context->getProcAddress("glGetQueryivEXT");
|
||||
d->GetQueryObjectuivEXT = (void (QOPENGLF_APIENTRYP)(GLuint id, GLenum pname, GLuint *params))context->getProcAddress("glGetQueryObjectuivEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_robustness::QOpenGLExtension_EXT_robustness()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_robustnessPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_robustness::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_robustness);
|
||||
|
||||
d->GetGraphicsResetStatusEXT = (GLenum (QOPENGLF_APIENTRYP)(void))context->getProcAddress("glGetGraphicsResetStatusEXT");
|
||||
d->ReadnPixelsEXT = (void (QOPENGLF_APIENTRYP)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data))context->getProcAddress("glReadnPixelsEXT");
|
||||
d->GetnUniformfvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei bufSize, float *params))context->getProcAddress("glGetnUniformfvEXT");
|
||||
d->GetnUniformivEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei bufSize, GLint *params))context->getProcAddress("glGetnUniformivEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_separate_shader_objects::QOpenGLExtension_EXT_separate_shader_objects()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_separate_shader_objectsPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_separate_shader_objects::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_separate_shader_objects);
|
||||
|
||||
d->UseProgramStagesEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline, GLbitfield stages, GLuint program))context->getProcAddress("glUseProgramStagesEXT");
|
||||
d->ActiveShaderProgramEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline, GLuint program))context->getProcAddress("glActiveShaderProgramEXT");
|
||||
d->CreateShaderProgramvEXT = (GLuint (QOPENGLF_APIENTRYP)(GLenum type, GLsizei count, const GLchar **strings))context->getProcAddress("glCreateShaderProgramvEXT");
|
||||
d->BindProgramPipelineEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline))context->getProcAddress("glBindProgramPipelineEXT");
|
||||
d->DeleteProgramPipelinesEXT = (void (QOPENGLF_APIENTRYP)(GLsizei n, const GLuint *pipelines))context->getProcAddress("glDeleteProgramPipelinesEXT");
|
||||
d->GenProgramPipelinesEXT = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *pipelines))context->getProcAddress("glGenProgramPipelinesEXT");
|
||||
d->IsProgramPipelineEXT = (GLboolean (QOPENGLF_APIENTRYP)(GLuint pipeline))context->getProcAddress("glIsProgramPipelineEXT");
|
||||
d->ProgramParameteriEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLenum pname, GLint value))context->getProcAddress("glProgramParameteriEXT");
|
||||
d->GetProgramPipelineivEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline, GLenum pname, GLint *params))context->getProcAddress("glGetProgramPipelineivEXT");
|
||||
d->ProgramUniform1iEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLint x))context->getProcAddress("glProgramUniform1iEXT");
|
||||
d->ProgramUniform2iEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLint x, GLint y))context->getProcAddress("glProgramUniform2iEXT");
|
||||
d->ProgramUniform3iEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLint x, GLint y, GLint z))context->getProcAddress("glProgramUniform3iEXT");
|
||||
d->ProgramUniform4iEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w))context->getProcAddress("glProgramUniform4iEXT");
|
||||
d->ProgramUniform1fEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLfloat x))context->getProcAddress("glProgramUniform1fEXT");
|
||||
d->ProgramUniform2fEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLfloat x, GLfloat y))context->getProcAddress("glProgramUniform2fEXT");
|
||||
d->ProgramUniform3fEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z))context->getProcAddress("glProgramUniform3fEXT");
|
||||
d->ProgramUniform4fEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w))context->getProcAddress("glProgramUniform4fEXT");
|
||||
d->ProgramUniform1ivEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLint *value))context->getProcAddress("glProgramUniform1ivEXT");
|
||||
d->ProgramUniform2ivEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLint *value))context->getProcAddress("glProgramUniform2ivEXT");
|
||||
d->ProgramUniform3ivEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLint *value))context->getProcAddress("glProgramUniform3ivEXT");
|
||||
d->ProgramUniform4ivEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLint *value))context->getProcAddress("glProgramUniform4ivEXT");
|
||||
d->ProgramUniform1fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLfloat *value))context->getProcAddress("glProgramUniform1fvEXT");
|
||||
d->ProgramUniform2fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLfloat *value))context->getProcAddress("glProgramUniform2fvEXT");
|
||||
d->ProgramUniform3fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLfloat *value))context->getProcAddress("glProgramUniform3fvEXT");
|
||||
d->ProgramUniform4fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, const GLfloat *value))context->getProcAddress("glProgramUniform4fvEXT");
|
||||
d->ProgramUniformMatrix2fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))context->getProcAddress("glProgramUniformMatrix2fvEXT");
|
||||
d->ProgramUniformMatrix3fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))context->getProcAddress("glProgramUniformMatrix3fvEXT");
|
||||
d->ProgramUniformMatrix4fvEXT = (void (QOPENGLF_APIENTRYP)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value))context->getProcAddress("glProgramUniformMatrix4fvEXT");
|
||||
d->ValidateProgramPipelineEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline))context->getProcAddress("glValidateProgramPipelineEXT");
|
||||
d->GetProgramPipelineInfoLogEXT = (void (QOPENGLF_APIENTRYP)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog))context->getProcAddress("glGetProgramPipelineInfoLogEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_EXT_texture_storage::QOpenGLExtension_EXT_texture_storage()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_EXT_texture_storagePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_EXT_texture_storage::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_EXT_texture_storage);
|
||||
|
||||
d->TexStorage1DEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width))context->getProcAddress("glTexStorage1DEXT");
|
||||
d->TexStorage2DEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height))context->getProcAddress("glTexStorage2DEXT");
|
||||
d->TexStorage3DEXT = (void (QOPENGLF_APIENTRYP)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth))context->getProcAddress("glTexStorage3DEXT");
|
||||
d->TextureStorage1DEXT = (void (QOPENGLF_APIENTRYP)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width))context->getProcAddress("glTextureStorage1DEXT");
|
||||
d->TextureStorage2DEXT = (void (QOPENGLF_APIENTRYP)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height))context->getProcAddress("glTextureStorage2DEXT");
|
||||
d->TextureStorage3DEXT = (void (QOPENGLF_APIENTRYP)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth))context->getProcAddress("glTextureStorage3DEXT");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_IMG_multisampled_render_to_texture::QOpenGLExtension_IMG_multisampled_render_to_texture()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_IMG_multisampled_render_to_texturePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_IMG_multisampled_render_to_texture::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_IMG_multisampled_render_to_texture);
|
||||
|
||||
d->RenderbufferStorageMultisampleIMG = (void (QOPENGLF_APIENTRYP)(GLenum, GLsizei, GLenum, GLsizei, GLsizei))context->getProcAddress("glRenderbufferStorageMultisampleIMG");
|
||||
d->FramebufferTexture2DMultisampleIMG = (void (QOPENGLF_APIENTRYP)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei))context->getProcAddress("glFramebufferTexture2DMultisampleIMG");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_NV_coverage_sample::QOpenGLExtension_NV_coverage_sample()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_NV_coverage_samplePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_NV_coverage_sample::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_NV_coverage_sample);
|
||||
|
||||
d->CoverageMaskNV = (void (QOPENGLF_APIENTRYP)(GLboolean mask))context->getProcAddress("glCoverageMaskNV");
|
||||
d->CoverageOperationNV = (void (QOPENGLF_APIENTRYP)(GLenum operation))context->getProcAddress("glCoverageOperationNV");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_NV_draw_buffers::QOpenGLExtension_NV_draw_buffers()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_NV_draw_buffersPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_NV_draw_buffers::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_NV_draw_buffers);
|
||||
|
||||
d->DrawBuffersNV = (void (QOPENGLF_APIENTRYP)(GLsizei n, const GLenum *bufs))context->getProcAddress("glDrawBuffersNV");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_NV_fence::QOpenGLExtension_NV_fence()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_NV_fencePrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_NV_fence::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_NV_fence);
|
||||
|
||||
d->DeleteFencesNV = (void (QOPENGLF_APIENTRYP)(GLsizei n, const GLuint *fences))context->getProcAddress("glDeleteFencesNV");
|
||||
d->GenFencesNV = (void (QOPENGLF_APIENTRYP)(GLsizei n, GLuint *fences))context->getProcAddress("glGenFencesNV");
|
||||
d->IsFenceNV = (GLboolean (QOPENGLF_APIENTRYP)(GLuint fence))context->getProcAddress("glIsFenceNV");
|
||||
d->TestFenceNV = (GLboolean (QOPENGLF_APIENTRYP)(GLuint fence))context->getProcAddress("glTestFenceNV");
|
||||
d->GetFenceivNV = (void (QOPENGLF_APIENTRYP)(GLuint fence, GLenum pname, GLint *params))context->getProcAddress("glGetFenceivNV");
|
||||
d->FinishFenceNV = (void (QOPENGLF_APIENTRYP)(GLuint fence))context->getProcAddress("glFinishFenceNV");
|
||||
d->SetFenceNV = (void (QOPENGLF_APIENTRYP)(GLuint fence, GLenum condition))context->getProcAddress("glSetFenceNV");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_NV_read_buffer::QOpenGLExtension_NV_read_buffer()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_NV_read_bufferPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_NV_read_buffer::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_NV_read_buffer);
|
||||
|
||||
d->ReadBufferNV = (void (QOPENGLF_APIENTRYP)(GLenum mode))context->getProcAddress("glReadBufferNV");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_QCOM_alpha_test::QOpenGLExtension_QCOM_alpha_test()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_QCOM_alpha_testPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_QCOM_alpha_test::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_QCOM_alpha_test);
|
||||
|
||||
d->AlphaFuncQCOM = (void (QOPENGLF_APIENTRYP )(GLenum func, GLclampf ref))context->getProcAddress("glAlphaFuncQCOM");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_QCOM_driver_control::QOpenGLExtension_QCOM_driver_control()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_QCOM_driver_controlPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_QCOM_driver_control::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_QCOM_driver_control);
|
||||
|
||||
d->GetDriverControlsQCOM = (void (QOPENGLF_APIENTRYP)(GLint *num, GLsizei size, GLuint *driverControls))context->getProcAddress("glGetDriverControlsQCOM");
|
||||
d->GetDriverControlStringQCOM = (void (QOPENGLF_APIENTRYP)(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString))context->getProcAddress("glGetDriverControlStringQCOM");
|
||||
d->EnableDriverControlQCOM = (void (QOPENGLF_APIENTRYP)(GLuint driverControl))context->getProcAddress("glEnableDriverControlQCOM");
|
||||
d->DisableDriverControlQCOM = (void (QOPENGLF_APIENTRYP)(GLuint driverControl))context->getProcAddress("glDisableDriverControlQCOM");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_QCOM_extended_get::QOpenGLExtension_QCOM_extended_get()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_QCOM_extended_getPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_QCOM_extended_get::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_QCOM_extended_get);
|
||||
|
||||
d->ExtGetTexturesQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *textures, GLint maxTextures, GLint *numTextures))context->getProcAddress("glExtGetTexturesQCOM");
|
||||
d->ExtGetBuffersQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *buffers, GLint maxBuffers, GLint *numBuffers))context->getProcAddress("glExtGetBuffersQCOM");
|
||||
d->ExtGetRenderbuffersQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers))context->getProcAddress("glExtGetRenderbuffersQCOM");
|
||||
d->ExtGetFramebuffersQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers))context->getProcAddress("glExtGetFramebuffersQCOM");
|
||||
d->ExtGetTexLevelParameterivQCOM = (void (QOPENGLF_APIENTRYP)(GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params))context->getProcAddress("glExtGetTexLevelParameterivQCOM");
|
||||
d->ExtTexObjectStateOverrideiQCOM = (void (QOPENGLF_APIENTRYP)(GLenum target, GLenum pname, GLint param))context->getProcAddress("glExtTexObjectStateOverrideiQCOM");
|
||||
d->ExtGetTexSubImageQCOM = (void (QOPENGLF_APIENTRYP)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels))context->getProcAddress("glExtGetTexSubImageQCOM");
|
||||
d->ExtGetBufferPointervQCOM = (void (QOPENGLF_APIENTRYP)(GLenum target, GLvoid **params))context->getProcAddress("glExtGetBufferPointervQCOM");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_QCOM_extended_get2::QOpenGLExtension_QCOM_extended_get2()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_QCOM_extended_get2Private))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_QCOM_extended_get2::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_QCOM_extended_get2);
|
||||
|
||||
d->ExtGetShadersQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *shaders, GLint maxShaders, GLint *numShaders))context->getProcAddress("glExtGetShadersQCOM");
|
||||
d->ExtGetProgramsQCOM = (void (QOPENGLF_APIENTRYP)(GLuint *programs, GLint maxPrograms, GLint *numPrograms))context->getProcAddress("glExtGetProgramsQCOM");
|
||||
d->ExtIsProgramBinaryQCOM = (GLboolean (QOPENGLF_APIENTRYP)(GLuint program))context->getProcAddress("glExtIsProgramBinaryQCOM");
|
||||
d->ExtGetProgramBinarySourceQCOM = (void (QOPENGLF_APIENTRYP)(GLuint program, GLenum shadertype, GLchar *source, GLint *length))context->getProcAddress("glExtGetProgramBinarySourceQCOM");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
QOpenGLExtension_QCOM_tiled_rendering::QOpenGLExtension_QCOM_tiled_rendering()
|
||||
: QAbstractOpenGLExtension(*(new QOpenGLExtension_QCOM_tiled_renderingPrivate))
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLExtension_QCOM_tiled_rendering::initializeOpenGLFunctions()
|
||||
{
|
||||
if (isInitialized())
|
||||
return true;
|
||||
|
||||
QOpenGLContext *context = QOpenGLContext::currentContext();
|
||||
if (!context) {
|
||||
qWarning("A current OpenGL context is required to resolve OpenGL extension functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the functions
|
||||
Q_D(QOpenGLExtension_QCOM_tiled_rendering);
|
||||
|
||||
d->StartTilingQCOM = (void (QOPENGLF_APIENTRYP)(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask))context->getProcAddress("glStartTilingQCOM");
|
||||
d->EndTilingQCOM = (void (QOPENGLF_APIENTRYP)(GLbitfield preserveMask))context->getProcAddress("glEndTilingQCOM");
|
||||
return QAbstractOpenGLExtension::initializeOpenGLFunctions();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
38
util/glgen/qopenglextensions.cpp.header
Normal file
38
util/glgen/qopenglextensions.cpp.header
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qopenglextensions.h"
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QAbstractOpenGLExtension::~QAbstractOpenGLExtension()
|
||||
{
|
||||
if (d_ptr)
|
||||
delete d_ptr;
|
||||
}
|
||||
|
||||
bool QAbstractOpenGLExtension::initializeOpenGLFunctions()
|
||||
{
|
||||
Q_D(QAbstractOpenGLExtension);
|
||||
d->initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QAbstractOpenGLExtension::isInitialized() const
|
||||
{
|
||||
Q_D(const QAbstractOpenGLExtension);
|
||||
return d->initialized;
|
||||
}
|
||||
|
||||
#if !QT_CONFIG(opengles2)
|
1520
util/glgen/qopenglextensions.h.footer
Normal file
1520
util/glgen/qopenglextensions.h.footer
Normal file
File diff suppressed because it is too large
Load Diff
58
util/glgen/qopenglextensions.h.header
Normal file
58
util/glgen/qopenglextensions.h.header
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QOPENGLEXTENSIONS_H
|
||||
#define QOPENGLEXTENSIONS_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
#include <QtGui/qopengl.h>
|
||||
|
||||
class QOpenGLContext;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#if 0
|
||||
// silence syncqt warnings
|
||||
#pragma qt_class(QOpenGLExtensions)
|
||||
#pragma qt_sync_stop_processing
|
||||
#endif
|
||||
|
||||
|
||||
class QAbstractOpenGLExtensionPrivate
|
||||
{
|
||||
public:
|
||||
QAbstractOpenGLExtensionPrivate() : initialized(false) {}
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
class QAbstractOpenGLExtension
|
||||
{
|
||||
public:
|
||||
virtual ~QAbstractOpenGLExtension();
|
||||
|
||||
virtual bool initializeOpenGLFunctions();
|
||||
|
||||
Q_DECLARE_PRIVATE(QAbstractOpenGLExtension)
|
||||
|
||||
protected:
|
||||
bool isInitialized() const;
|
||||
|
||||
QAbstractOpenGLExtension() {}
|
||||
QAbstractOpenGLExtension(QAbstractOpenGLExtensionPrivate &dd) : d_ptr(&dd) {}
|
||||
QAbstractOpenGLExtensionPrivate *d_ptr;
|
||||
};
|
||||
|
||||
#if !QT_CONFIG(opengles2)
|
8
util/glgen/qopenglversionfunctions.cpp.footer
Normal file
8
util/glgen/qopenglversionfunctions.cpp.footer
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#else
|
||||
|
||||
// No backends for OpenGL ES 2
|
||||
|
||||
#endif // !QT_CONFIG(opengles2)
|
||||
|
||||
QT_END_NAMESPACE
|
183
util/glgen/qopenglversionfunctions.cpp.header
Normal file
183
util/glgen/qopenglversionfunctions.cpp.header
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qopenglversionfunctions.h"
|
||||
#include "qopenglcontext.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QOpenGLVersionFunctionsBackend *QAbstractOpenGLFunctionsPrivate::functionsBackend(QOpenGLContext *context,
|
||||
const QOpenGLVersionStatus &v)
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
return context->functionsBackend(v);
|
||||
}
|
||||
|
||||
void QAbstractOpenGLFunctionsPrivate::insertFunctionsBackend(QOpenGLContext *context,
|
||||
const QOpenGLVersionStatus &v,
|
||||
QOpenGLVersionFunctionsBackend *backend)
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
context->insertFunctionsBackend(v, backend);
|
||||
}
|
||||
|
||||
void QAbstractOpenGLFunctionsPrivate::removeFunctionsBackend(QOpenGLContext *context, const QOpenGLVersionStatus &v)
|
||||
{
|
||||
Q_ASSERT(context);
|
||||
context->removeFunctionsBackend(v);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\class QAbstractOpenGLFunctions
|
||||
\inmodule QtGui
|
||||
\since 5.1
|
||||
\brief The QAbstractOpenGLFunctions class is the base class of a family of
|
||||
classes that expose all functions for each OpenGL version and
|
||||
profile.
|
||||
|
||||
OpenGL implementations on different platforms are able to link to a variable
|
||||
number of OpenGL functions depending upon the OpenGL ABI on that platform.
|
||||
For example, on Microsoft Windows only functions up to those in OpenGL 1.1
|
||||
can be linked to at build time. All other functions must be resolved at
|
||||
runtime. The traditional solution to this has been to use either
|
||||
QOpenGLContext::getProcAddress() or QOpenGLFunctions. The former is tedious
|
||||
and error prone and means dealing directly with function pointers. The
|
||||
latter only exposes those functions common to OpenGL ES 2 and desktop
|
||||
OpenGL. There is however much new OpenGL functionality that is useful when
|
||||
writing real world OpenGL applications.
|
||||
|
||||
Qt now provides a family of classes which all inherit from
|
||||
QAbstractOpenGLFunctions which expose every core OpenGL function by way of a
|
||||
corresponding member function. There is a class for every valid combination
|
||||
of OpenGL version and profile. Each class follows the naming convention
|
||||
QOpenGLFunctions_<MAJOR VERSION>_<MINOR VERSION>[_PROFILE].
|
||||
|
||||
For OpenGL versions 1.0 through to 3.0 there are no profiles, leading to the
|
||||
classes:
|
||||
|
||||
\list
|
||||
\li QOpenGLFunctions_1_0
|
||||
\li QOpenGLFunctions_1_1
|
||||
\li QOpenGLFunctions_1_2
|
||||
\li QOpenGLFunctions_1_3
|
||||
\li QOpenGLFunctions_1_4
|
||||
\li QOpenGLFunctions_1_5
|
||||
\li QOpenGLFunctions_2_0
|
||||
\li QOpenGLFunctions_2_1
|
||||
\li QOpenGLFunctions_3_0
|
||||
\endlist
|
||||
|
||||
where each class inherits from QAbstractOpenGLFunctions.
|
||||
|
||||
OpenGL version 3.1 removed many deprecated functions leading to a much
|
||||
simpler and generic API.
|
||||
|
||||
With OpenGL 3.2 the concept of profiles was introduced. Two profiles are
|
||||
currently defined for OpenGL: Core and Compatibility.
|
||||
|
||||
The Core profile does not include any of the functions that were removed
|
||||
in OpenGL 3.1. The Compatibility profile contains all functions in the
|
||||
Core profile of the same version plus all of the functions that were
|
||||
removed in OpenGL 3.1. In this way the Compatibility profile classes allow
|
||||
use of newer OpenGL functionality but also allows you to keep using your
|
||||
legacy OpenGL code. For new OpenGL code the Core profile should be
|
||||
preferred.
|
||||
|
||||
Please note that some vendors, notably Apple, do not implement the
|
||||
Compatibility profile. Therefore if you wish to target new OpenGL features
|
||||
on OS X then you should ensure that you request a Core profile context via
|
||||
QSurfaceFormat::setProfile().
|
||||
|
||||
Qt provides classes for all version and Core and Compatibility profile
|
||||
combinations. The classes for OpenGL versions 3.1 through to 4.3 are:
|
||||
|
||||
\list
|
||||
\li QOpenGLFunctions_3_1
|
||||
\li QOpenGLFunctions_3_2_Core
|
||||
\li QOpenGLFunctions_3_2_Compatibility
|
||||
\li QOpenGLFunctions_3_3_Core
|
||||
\li QOpenGLFunctions_3_3_Compatibility
|
||||
\li QOpenGLFunctions_4_0_Core
|
||||
\li QOpenGLFunctions_4_0_Compatibility
|
||||
\li QOpenGLFunctions_4_1_Core
|
||||
\li QOpenGLFunctions_4_1_Compatibility
|
||||
\li QOpenGLFunctions_4_2_Core
|
||||
\li QOpenGLFunctions_4_2_Compatibility
|
||||
\li QOpenGLFunctions_4_3_Core
|
||||
\li QOpenGLFunctions_4_3_Compatibility
|
||||
\endlist
|
||||
|
||||
where each class inherits from QAbstractOpenGLFunctions.
|
||||
|
||||
A pointer to an object of the class corresponding to the version and
|
||||
profile of OpenGL in use can be obtained from
|
||||
QOpenGLFunctions::versionFunctions(). If obtained in this way, note that
|
||||
the QOpenGLContext retains ownership of the object. This is so that only
|
||||
one instance need be created.
|
||||
|
||||
Before calling any of the exposed OpenGL functions you must ensure that the
|
||||
object has resolved the function pointers to the OpenGL functions. This
|
||||
only needs to be done once per instance with initializeOpenGLFunctions().
|
||||
Once initialized, the object can be used to call any OpenGL function for
|
||||
the corresponding version and profile. Note that initializeOpenGLFunctions()
|
||||
can fail in some circumstances so check the return value. Situations in
|
||||
which initialization can fail are if you have a functions object for a version
|
||||
or profile that contains functions that are not part of the context being
|
||||
used to resolve the function pointers.
|
||||
|
||||
If you exclusively use function objects then you will get compile time
|
||||
errors if you attempt to use a function not included in that version and
|
||||
profile. This is obviously a lot easier to debug than undefined behavior
|
||||
at run time.
|
||||
|
||||
\sa QOpenGLContext::versionFunctions()
|
||||
*/
|
||||
QAbstractOpenGLFunctions::QAbstractOpenGLFunctions()
|
||||
: d_ptr(new QAbstractOpenGLFunctionsPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
QAbstractOpenGLFunctions::~QAbstractOpenGLFunctions()
|
||||
{
|
||||
delete d_ptr;
|
||||
}
|
||||
|
||||
bool QAbstractOpenGLFunctions::initializeOpenGLFunctions()
|
||||
{
|
||||
Q_D(QAbstractOpenGLFunctions);
|
||||
d->initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QAbstractOpenGLFunctions::isInitialized() const
|
||||
{
|
||||
Q_D(const QAbstractOpenGLFunctions);
|
||||
return d->initialized;
|
||||
}
|
||||
|
||||
void QAbstractOpenGLFunctions::setOwningContext(const QOpenGLContext *context)
|
||||
{
|
||||
Q_D(QAbstractOpenGLFunctions);
|
||||
d->owningContext = const_cast<QOpenGLContext*>(context);
|
||||
}
|
||||
|
||||
QOpenGLContext *QAbstractOpenGLFunctions::owningContext() const
|
||||
{
|
||||
Q_D(const QAbstractOpenGLFunctions);
|
||||
return d->owningContext;
|
||||
}
|
||||
|
||||
#if !QT_CONFIG(opengles2)
|
||||
|
13
util/glgen/qopenglversionfunctions.h.footer
Normal file
13
util/glgen/qopenglversionfunctions.h.footer
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#else
|
||||
|
||||
// No need for backend classes with function pointers with ES2.
|
||||
// All function addresses are independent of context and display.
|
||||
|
||||
#endif // !QT_CONFIG(opengles2)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
#endif
|
127
util/glgen/qopenglversionfunctions.h.header
Normal file
127
util/glgen/qopenglversionfunctions.h.header
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QOPENGLVERSIONFUNCTIONS_H
|
||||
#define QOPENGLVERSIONFUNCTIONS_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qpair.h>
|
||||
#include <QtGui/qopengl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QOpenGLContext;
|
||||
|
||||
#if 0
|
||||
// silence syncqt warnings
|
||||
#pragma qt_class(QOpenGLVersionFunctions)
|
||||
#pragma qt_sync_stop_processing
|
||||
#endif
|
||||
|
||||
struct QOpenGLVersionStatus
|
||||
{
|
||||
enum OpenGLStatus {
|
||||
CoreStatus,
|
||||
DeprecatedStatus,
|
||||
InvalidStatus
|
||||
};
|
||||
|
||||
QOpenGLVersionStatus()
|
||||
: version(qMakePair(0, 0)),
|
||||
status(InvalidStatus)
|
||||
{}
|
||||
|
||||
QOpenGLVersionStatus(int majorVersion, int minorVersion, QOpenGLVersionStatus::OpenGLStatus functionStatus)
|
||||
: version(qMakePair(majorVersion, minorVersion)),
|
||||
status(functionStatus)
|
||||
{}
|
||||
|
||||
QPair<int, int> version;
|
||||
OpenGLStatus status;
|
||||
};
|
||||
|
||||
inline size_t qHash(const QOpenGLVersionStatus &v, size_t seed)
|
||||
{
|
||||
return qHash(static_cast<int>(v.status * 1000)
|
||||
+ v.version.first * 100 + v.version.second * 10, seed);
|
||||
}
|
||||
|
||||
inline bool operator==(const QOpenGLVersionStatus &lhs, const QOpenGLVersionStatus &rhs)
|
||||
{
|
||||
if (lhs.status != rhs.status)
|
||||
return false;
|
||||
return lhs.version == rhs.version;
|
||||
}
|
||||
|
||||
inline bool operator!=(const QOpenGLVersionStatus &lhs, const QOpenGLVersionStatus &rhs)
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
class QOpenGLVersionFunctionsBackend
|
||||
{
|
||||
public:
|
||||
QOpenGLVersionFunctionsBackend(QOpenGLContext *ctx)
|
||||
: context(ctx)
|
||||
{}
|
||||
|
||||
QOpenGLContext *context;
|
||||
QAtomicInt refs;
|
||||
};
|
||||
|
||||
class QAbstractOpenGLFunctionsPrivate
|
||||
{
|
||||
public:
|
||||
QAbstractOpenGLFunctionsPrivate()
|
||||
: owningContext(0),
|
||||
initialized(false)
|
||||
{}
|
||||
|
||||
static QOpenGLVersionFunctionsBackend *functionsBackend(QOpenGLContext *context,
|
||||
const QOpenGLVersionStatus &v);
|
||||
static void insertFunctionsBackend(QOpenGLContext *context,
|
||||
const QOpenGLVersionStatus &v,
|
||||
QOpenGLVersionFunctionsBackend *backend);
|
||||
static void removeFunctionsBackend(QOpenGLContext *context, const QOpenGLVersionStatus &v);
|
||||
|
||||
QOpenGLContext *owningContext;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
class QAbstractOpenGLFunctions
|
||||
{
|
||||
public:
|
||||
virtual ~QAbstractOpenGLFunctions();
|
||||
|
||||
virtual bool initializeOpenGLFunctions();
|
||||
|
||||
Q_DECLARE_PRIVATE(QAbstractOpenGLFunctions)
|
||||
|
||||
protected:
|
||||
QAbstractOpenGLFunctions();
|
||||
QAbstractOpenGLFunctionsPrivate *d_ptr;
|
||||
|
||||
bool isInitialized() const;
|
||||
|
||||
void setOwningContext(const QOpenGLContext *context);
|
||||
QOpenGLContext *owningContext() const;
|
||||
|
||||
friend class QOpenGLContext;
|
||||
};
|
||||
|
||||
#if !QT_CONFIG(opengles2)
|
||||
|
2
util/glgen/qopenglversionfunctions__VERSION__.cpp.footer
Normal file
2
util/glgen/qopenglversionfunctions__VERSION__.cpp.footer
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
QT_END_NAMESPACE
|
18
util/glgen/qopenglversionfunctions__VERSION__.cpp.header
Normal file
18
util/glgen/qopenglversionfunctions__VERSION__.cpp.header
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qopenglfunctions__VERSION__.h"
|
||||
#include "qopenglcontext.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
6
util/glgen/qopenglversionfunctions__VERSION__.h.footer
Normal file
6
util/glgen/qopenglversionfunctions__VERSION__.h.footer
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_OPENGL && !QT_CONFIG(opengles2)
|
||||
|
||||
#endif
|
25
util/glgen/qopenglversionfunctions__VERSION__.h.header
Normal file
25
util/glgen/qopenglversionfunctions__VERSION__.h.header
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QOPENGLVERSIONFUNCTIONS__VERSION___H
|
||||
#define QOPENGLVERSIONFUNCTIONS__VERSION___H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#if !defined(QT_NO_OPENGL) && !QT_CONFIG(opengles2)
|
||||
|
||||
#include <QtGui/QOpenGLVersionFunctions>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
2
util/glgen/qopenglversionfunctionsfactory.cpp.footer
Normal file
2
util/glgen/qopenglversionfunctionsfactory.cpp.footer
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
QT_END_NAMESPACE
|
15
util/glgen/qopenglversionfunctionsfactory.cpp.header
Normal file
15
util/glgen/qopenglversionfunctionsfactory.cpp.header
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qopenglversionfunctionsfactory_p.h"
|
||||
|
36
util/glgen/qopenglversionfunctionsfactory_p.h.header
Normal file
36
util/glgen/qopenglversionfunctionsfactory_p.h.header
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
/***************************************************************************
|
||||
** This file was generated by glgen version 0.1
|
||||
** Command line was: glgen
|
||||
**
|
||||
** glgen is Copyright (C) 2012 Klaralvdalens Datakonsult AB (KDAB)
|
||||
**
|
||||
** This is an auto-generated file.
|
||||
** Do not edit! All changes made to it will be lost.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QOPENGLVERSIONFUNCTIONFACTORY_P_H
|
||||
#define QOPENGLVERSIONFUNCTIONFACTORY_P_H
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QAbstractOpenGLFunctions;
|
||||
|
||||
class QOpenGLVersionFunctionsFactory
|
||||
{
|
||||
public:
|
||||
static QAbstractOpenGLFunctions *create(const QOpenGLVersionProfile &versionProfile);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
#endif
|
224
util/glgen/specparser.h
Normal file
224
util/glgen/specparser.h
Normal file
@ -0,0 +1,224 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef SPECPARSER_H
|
||||
#define SPECPARSER_H
|
||||
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
class QTextStream;
|
||||
class QXmlStreamReader;
|
||||
|
||||
struct Version {
|
||||
int major;
|
||||
int minor;
|
||||
};
|
||||
|
||||
inline bool operator == (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
return (lhs.major == rhs.major && lhs.minor == rhs.minor);
|
||||
}
|
||||
|
||||
inline bool operator != (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator < (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
if (lhs.major != rhs.major)
|
||||
return (lhs.major < rhs.major);
|
||||
else
|
||||
return (lhs.minor < rhs.minor);
|
||||
}
|
||||
|
||||
inline bool operator > (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
if (lhs.major != rhs.major)
|
||||
return (lhs.major > rhs.major);
|
||||
else
|
||||
return (lhs.minor > rhs.minor);
|
||||
}
|
||||
|
||||
inline bool operator >= (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
|
||||
inline bool operator <= (const Version &lhs, const Version &rhs)
|
||||
{
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
inline size_t qHash(const Version &v)
|
||||
{
|
||||
return qHash(v.major * 100 + v.minor * 10);
|
||||
}
|
||||
|
||||
struct VersionProfile
|
||||
{
|
||||
enum OpenGLProfile {
|
||||
CoreProfile = 0,
|
||||
CompatibilityProfile
|
||||
};
|
||||
|
||||
inline bool hasProfiles() const
|
||||
{
|
||||
return ( version.major > 3
|
||||
|| (version.major == 3 && version.minor > 1));
|
||||
}
|
||||
|
||||
Version version;
|
||||
OpenGLProfile profile;
|
||||
};
|
||||
|
||||
inline bool operator == (const VersionProfile &lhs, const VersionProfile &rhs)
|
||||
{
|
||||
if (lhs.profile != rhs.profile)
|
||||
return false;
|
||||
return lhs.version == rhs.version;
|
||||
}
|
||||
|
||||
inline bool operator != (const VersionProfile &lhs, const VersionProfile &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator < (const VersionProfile &lhs, const VersionProfile &rhs)
|
||||
{
|
||||
if (lhs.profile != rhs.profile)
|
||||
return (lhs.profile < rhs.profile);
|
||||
return (lhs.version < rhs.version);
|
||||
}
|
||||
|
||||
inline size_t qHash(const VersionProfile &v)
|
||||
{
|
||||
return qHash(static_cast<int>(v.profile * 1000) + v.version.major * 100 + v.version.minor * 10);
|
||||
}
|
||||
|
||||
struct Argument
|
||||
{
|
||||
enum Direction {
|
||||
In = 0,
|
||||
Out
|
||||
};
|
||||
|
||||
enum Mode {
|
||||
Value = 0,
|
||||
Array,
|
||||
Reference
|
||||
};
|
||||
|
||||
QString type;
|
||||
QString name;
|
||||
Direction direction;
|
||||
Mode mode;
|
||||
};
|
||||
|
||||
struct Function
|
||||
{
|
||||
QString returnType;
|
||||
QString name;
|
||||
QList<Argument> arguments;
|
||||
};
|
||||
|
||||
inline bool operator== (const Argument &lhs, const Argument &rhs)
|
||||
{
|
||||
if ((lhs.type != rhs.type) || (lhs.name != rhs.name) || (lhs.direction != rhs.direction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (lhs.mode != rhs.mode);
|
||||
}
|
||||
|
||||
inline bool operator!= (const Argument &lhs, const Argument &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline bool operator== (const Function &lhs, const Function &rhs)
|
||||
{
|
||||
if ((lhs.returnType != rhs.returnType) || (lhs.name != rhs.name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (lhs.arguments == rhs.arguments);
|
||||
}
|
||||
|
||||
inline bool operator!= (const Function &lhs, const Function &rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
typedef QList<Function> FunctionList;
|
||||
typedef QMap<VersionProfile, FunctionList> FunctionCollection;
|
||||
|
||||
struct FunctionProfile
|
||||
{
|
||||
VersionProfile::OpenGLProfile profile;
|
||||
Function function;
|
||||
};
|
||||
|
||||
class SpecParser
|
||||
{
|
||||
public:
|
||||
virtual ~SpecParser() {}
|
||||
|
||||
QString specFileName() const
|
||||
{
|
||||
return m_specFileName;
|
||||
}
|
||||
|
||||
QString typeMapFileName() const
|
||||
{
|
||||
return m_typeMapFileName;
|
||||
}
|
||||
|
||||
virtual QList<Version> versions() const = 0;
|
||||
|
||||
QList<VersionProfile> versionProfiles() const {return versionFunctions().uniqueKeys();}
|
||||
|
||||
QList<Function> functionsForVersion(const VersionProfile &v) const
|
||||
{
|
||||
return versionFunctions().values(v);
|
||||
}
|
||||
|
||||
QStringList extensions() const
|
||||
{
|
||||
return QStringList(extensionFunctions().uniqueKeys());
|
||||
}
|
||||
|
||||
QList<Function> functionsForExtension(const QString &extension)
|
||||
{
|
||||
QList<Function> func;
|
||||
|
||||
Q_FOREACH (const FunctionProfile &f, extensionFunctions().values(extension))
|
||||
func.append(f.function);
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
void setSpecFileName(QString arg)
|
||||
{
|
||||
m_specFileName = arg;
|
||||
}
|
||||
|
||||
void setTypeMapFileName(QString arg)
|
||||
{
|
||||
m_typeMapFileName = arg;
|
||||
}
|
||||
|
||||
virtual bool parse() = 0;
|
||||
|
||||
protected:
|
||||
virtual const QMultiHash<VersionProfile, Function> &versionFunctions() const = 0;
|
||||
virtual const QMultiMap<QString, FunctionProfile> &extensionFunctions() const = 0;
|
||||
|
||||
private:
|
||||
QString m_specFileName;
|
||||
QString m_typeMapFileName;
|
||||
};
|
||||
|
||||
#endif // SPECPARSER_H
|
402
util/glgen/xmlspecparser.cpp
Normal file
402
util/glgen/xmlspecparser.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "xmlspecparser.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#ifdef SPECPARSER_DEBUG
|
||||
#define qXmlSpecParserDebug qDebug
|
||||
#else
|
||||
#define qXmlSpecParserDebug QT_NO_QDEBUG_MACRO
|
||||
#endif
|
||||
|
||||
bool XmlSpecParser::parse()
|
||||
{
|
||||
// Open up a stream on the actual OpenGL function spec file
|
||||
QFile file(specFileName());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Failed to open spec file:" << specFileName() << "Aborting";
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamReader stream(&file);
|
||||
|
||||
// Extract the info that we need
|
||||
parseFunctions(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseParam(QXmlStreamReader &stream, Function &func)
|
||||
{
|
||||
Argument arg;
|
||||
arg.type = QString();
|
||||
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "ptype") {
|
||||
if (stream.readNext() == QXmlStreamReader::Characters)
|
||||
arg.type.append(stream.text().toString());
|
||||
}
|
||||
|
||||
else if (tag == "name") {
|
||||
if (stream.readNext() == QXmlStreamReader::Characters)
|
||||
arg.name = stream.text().toString().trimmed();
|
||||
}
|
||||
} else if (stream.isCharacters()) {
|
||||
arg.type.append(stream.text().toString());
|
||||
} else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "param") {
|
||||
// compatibility with old spec
|
||||
QRegularExpression typeRegExp("(const )?(.+)(?<!\\*)((?:(?!\\*$)\\*)*)(\\*)?");
|
||||
|
||||
// remove extra whitespace
|
||||
arg.type = arg.type.trimmed();
|
||||
|
||||
// set default
|
||||
arg.direction = Argument::In;
|
||||
arg.mode = Argument::Value;
|
||||
|
||||
QRegularExpressionMatch exp = typeRegExp.match(arg.type);
|
||||
if (exp.hasMatch()) {
|
||||
if (!exp.captured(4).isEmpty()) {
|
||||
arg.mode = Argument::Reference;
|
||||
|
||||
if (exp.captured(1).isEmpty())
|
||||
arg.direction = Argument::Out;
|
||||
}
|
||||
|
||||
arg.type = exp.captured(2) + exp.captured(3);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove any excess whitespace
|
||||
arg.type = arg.type.trimmed();
|
||||
arg.name = arg.name.trimmed();
|
||||
|
||||
// maybe some checks?
|
||||
func.arguments.append(arg);
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseCommand(QXmlStreamReader &stream)
|
||||
{
|
||||
Function func;
|
||||
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "proto") {
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
if (stream.isStartElement() && (stream.name().toString() == "name")) {
|
||||
if (stream.readNext() == QXmlStreamReader::Characters)
|
||||
func.name = stream.text().toString();
|
||||
} else if (stream.isCharacters()) {
|
||||
func.returnType.append(stream.text().toString());
|
||||
} else if (stream.isEndElement() && (stream.name().toString() == "proto")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tag == "param")
|
||||
parseParam(stream, func);
|
||||
}
|
||||
|
||||
else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "command")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// maybe checks?
|
||||
func.returnType = func.returnType.trimmed();
|
||||
|
||||
// for compatibility with old spec
|
||||
if (func.name.startsWith("gl"))
|
||||
func.name.remove(0, 2);
|
||||
|
||||
m_functionList.insert(func.name, func);
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseCommands(QXmlStreamReader &stream)
|
||||
{
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "command")
|
||||
parseCommand(stream);
|
||||
}
|
||||
|
||||
else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "commands")
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseRequire(QXmlStreamReader &stream, FunctionList &funcs)
|
||||
{
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "command") {
|
||||
QString func = stream.attributes().value("name").toString();
|
||||
|
||||
// for compatibility with old spec
|
||||
if (func.startsWith("gl"))
|
||||
func.remove(0, 2);
|
||||
|
||||
funcs.append(m_functionList[func]);
|
||||
}
|
||||
} else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "require")
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseRemoveCore(QXmlStreamReader &stream)
|
||||
{
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "command") {
|
||||
QString func = stream.attributes().value("name").toString();
|
||||
|
||||
// for compatibility with old spec
|
||||
if (func.startsWith("gl"))
|
||||
func.remove(0, 2);
|
||||
|
||||
// go through list of version and mark as incompatible
|
||||
Q_FOREACH (const Version& v, m_versions) {
|
||||
// Combine version and profile for this subset of functions
|
||||
VersionProfile version;
|
||||
version.version = v;
|
||||
version.profile = VersionProfile::CoreProfile;
|
||||
|
||||
// Fetch the functions and add to collection for this class
|
||||
Q_FOREACH (const Function& f, m_functions.values(version)) {
|
||||
if (f.name == func) {
|
||||
VersionProfile newVersion;
|
||||
newVersion.version = v;
|
||||
newVersion.profile = VersionProfile::CompatibilityProfile;
|
||||
|
||||
m_functions.insert(newVersion, f);
|
||||
m_functions.remove(version, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "remove")
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseFeature(QXmlStreamReader &stream)
|
||||
{
|
||||
QRegularExpression versionRegExp("(\\d).(\\d)");
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
|
||||
QRegularExpressionMatch match = versionRegExp.match(attributes.value("number").toString());
|
||||
|
||||
if (!match.hasMatch()) {
|
||||
qWarning() << "Malformed version indicator";
|
||||
return;
|
||||
}
|
||||
|
||||
if (attributes.value("api").toString() != "gl")
|
||||
return;
|
||||
|
||||
int majorVersion = match.captured(1).toInt();
|
||||
int minorVersion = match.captured(2).toInt();
|
||||
|
||||
Version v;
|
||||
VersionProfile core, compat;
|
||||
|
||||
v.major = majorVersion;
|
||||
v.minor = minorVersion;
|
||||
core.version = compat.version = v;
|
||||
core.profile = VersionProfile::CoreProfile;
|
||||
compat.profile = VersionProfile::CompatibilityProfile;
|
||||
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "require") {
|
||||
FunctionList funcs;
|
||||
|
||||
if (stream.attributes().value("profile").toString() == "compatibility") {
|
||||
parseRequire(stream, funcs);
|
||||
Q_FOREACH (const Function& f, funcs) {
|
||||
m_functions.insert(compat, f);
|
||||
}
|
||||
} else {
|
||||
parseRequire(stream, funcs);
|
||||
Q_FOREACH (const Function& f, funcs) {
|
||||
m_functions.insert(core, f);
|
||||
}
|
||||
}
|
||||
} else if (tag == "remove") {
|
||||
if (stream.attributes().value("profile").toString() == "core")
|
||||
parseRemoveCore(stream);
|
||||
}
|
||||
} else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "feature")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_versions.append(v);
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseExtension(QXmlStreamReader &stream)
|
||||
{
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
QString name = attributes.value("name").toString();
|
||||
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "require") {
|
||||
if (stream.attributes().value("profile").toString() == "compatibility") {
|
||||
FunctionList funcs;
|
||||
parseRequire(stream, funcs);
|
||||
|
||||
Q_FOREACH (const Function& f, funcs) {
|
||||
FunctionProfile fp;
|
||||
fp.function = f;
|
||||
fp.profile = VersionProfile::CompatibilityProfile;
|
||||
m_extensionFunctions.insert(name, fp);
|
||||
}
|
||||
} else {
|
||||
FunctionList funcs;
|
||||
parseRequire(stream, funcs);
|
||||
Q_FOREACH (const Function& f, funcs) {
|
||||
FunctionProfile fp;
|
||||
fp.function = f;
|
||||
fp.profile = VersionProfile::CoreProfile;
|
||||
m_extensionFunctions.insert(name, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} else if (stream.isEndElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "extension")
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XmlSpecParser::parseFunctions(QXmlStreamReader &stream)
|
||||
{
|
||||
while (!stream.isEndDocument()) {
|
||||
stream.readNext();
|
||||
|
||||
if (stream.isStartElement()) {
|
||||
QString tag = stream.name().toString();
|
||||
|
||||
if (tag == "feature") {
|
||||
parseFeature(stream);
|
||||
} else if (tag == "commands") {
|
||||
parseCommands(stream);
|
||||
} else if (tag == "extension") {
|
||||
parseExtension(stream);
|
||||
}
|
||||
} else if (stream.isEndElement()) {
|
||||
stream.readNext();
|
||||
}
|
||||
}
|
||||
|
||||
// hack - add GL_ARB_imaging to every version after 1.2 inclusive
|
||||
Version versionThreshold;
|
||||
versionThreshold.major = 1;
|
||||
versionThreshold.minor = 2;
|
||||
QList<FunctionProfile> funcs = m_extensionFunctions.values("GL_ARB_imaging");
|
||||
|
||||
VersionProfile vp;
|
||||
vp.version = versionThreshold;
|
||||
|
||||
Q_FOREACH (const FunctionProfile& fp, funcs) {
|
||||
vp.profile = fp.profile;
|
||||
m_functions.insert(vp, fp.function);
|
||||
}
|
||||
|
||||
// now we will prune any duplicates
|
||||
QSet<QString> funcset;
|
||||
|
||||
Q_FOREACH (const Version& v, m_versions) {
|
||||
// check compatibility first
|
||||
VersionProfile vp;
|
||||
vp.version = v;
|
||||
|
||||
vp.profile = VersionProfile::CompatibilityProfile;
|
||||
|
||||
Q_FOREACH (const Function& f, m_functions.values(vp)) {
|
||||
// remove duplicate
|
||||
if (funcset.contains(f.name))
|
||||
m_functions.remove(vp, f);
|
||||
|
||||
funcset.insert(f.name);
|
||||
}
|
||||
|
||||
vp.profile = VersionProfile::CoreProfile;
|
||||
|
||||
Q_FOREACH (const Function& f, m_functions.values(vp)) {
|
||||
|
||||
// remove duplicate
|
||||
if (funcset.contains(f.name))
|
||||
m_functions.remove(vp, f);
|
||||
|
||||
funcset.insert(f.name);
|
||||
}
|
||||
}
|
||||
}
|
45
util/glgen/xmlspecparser.h
Normal file
45
util/glgen/xmlspecparser.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef XMLSPECPARSER_H
|
||||
#define XMLSPECPARSER_H
|
||||
|
||||
#include "specparser.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
class QXmlStreamReader;
|
||||
|
||||
class XmlSpecParser : public SpecParser
|
||||
{
|
||||
public:
|
||||
virtual QList<Version> versions() const { return m_versions; }
|
||||
|
||||
virtual bool parse();
|
||||
|
||||
protected:
|
||||
const QMultiHash<VersionProfile, Function> &versionFunctions() const { return m_functions; }
|
||||
const QMultiMap<QString, FunctionProfile> &extensionFunctions() const { return m_extensionFunctions; }
|
||||
|
||||
private:
|
||||
void parseFunctions(QXmlStreamReader &stream);
|
||||
void parseCommands(QXmlStreamReader &stream);
|
||||
void parseCommand(QXmlStreamReader &stream);
|
||||
void parseParam(QXmlStreamReader &stream, Function &func);
|
||||
void parseFeature(QXmlStreamReader &stream);
|
||||
void parseExtension(QXmlStreamReader &stream);
|
||||
void parseRequire(QXmlStreamReader &stream, FunctionList& profile);
|
||||
void parseRemoveCore(QXmlStreamReader &stream);
|
||||
|
||||
QMultiHash<VersionProfile, Function> m_functions;
|
||||
|
||||
QList<Version> m_versions;
|
||||
|
||||
// Extension support
|
||||
QMultiMap<QString, FunctionProfile> m_extensionFunctions;
|
||||
|
||||
QMap<QString, Function> m_functionList;
|
||||
};
|
||||
|
||||
#endif // XMLSPECPARSER_H
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user