Finish 0.4.5

This commit is contained in:
cuke 2015-09-15 22:23:09 +02:00
commit 719dceef69
111 changed files with 20 additions and 6583 deletions

View File

@ -18,12 +18,6 @@ install:
- wget http://www.cmake.org/files/v3.3/cmake-3.3.1-Linux-x86_64.tar.gz
- tar xf cmake-3.3.1-Linux-x86_64.tar.gz
- export CMAKE_EXECUTABLE=/tmp/cmake-3.3.1-Linux-x86_64/bin/cmake
- wget http://downloads.dlang.org/releases/2015/dmd_2.068.0-0_amd64.deb
- echo "Installing D"
- sudo dpkg -i dmd_2.068.0-0_amd64.deb
- echo "Installing Nim"
- wget http://cz.archive.ubuntu.com/ubuntu/pool/universe/n/nim/nim_0.11.2+dfsg1-4_amd64.deb
- sudo dpkg -i nim_0.11.2+dfsg1-4_amd64.deb
- cd -
before_script:

View File

@ -1,3 +1,7 @@
# Version 0.4.5
* Removed the D bindings
* Removed the Nim bindings
# Version 0.4.2
* [DOtherSide] Code cleanup and little refactoring
* [NimQml] Made nim compiles with the "cpp" option by default. This should fix C/C++ interop problems

View File

@ -1,4 +1,2 @@
cmake_minimum_required(VERSION 3.0)
add_subdirectory(DOtherSide)
add_subdirectory(Nim)
add_subdirectory(D)
add_subdirectory(src)

View File

@ -1,3 +0,0 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/D)
add_subdirectory(DQml)
add_subdirectory(Examples)

View File

@ -1,17 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQml C D )
add_library(${PROJECT_NAME} STATIC
dqml.d
qobject.d
qvariant.d
qmetatype.d
qquickview.d
qqmlapplicationengine.d
qqmlcontext.d
qguiapplication.d
qapplication.d
qmodelindex.d
qabstractlistmodel.d
qobjectgenerators.d
)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -1,126 +0,0 @@
extern(C)
{
// QApplication
void dos_qapplication_create();
void dos_qapplication_exec();
void dos_qapplication_delete();
void dos_qapplication_quit();
// QGuiApplication
void dos_qguiapplication_create();
void dos_qguiapplication_exec();
void dos_qguiapplication_delete();
void dos_qguiapplication_quit();
// QQmlApplicationEngine
void dos_qqmlapplicationengine_create(ref void*);
void dos_qqmlapplicationengine_load(void*, immutable (char)* filename);
void dos_qqmlapplicationengine_context(void*, ref void*);
void dos_qqmlapplicationengine_delete(void*);
// QQuickView
void dos_qquickview_create(ref void*);
void dos_qquickview_show(void*);
void dos_qquickview_source(void*, ref char *);
void dos_qquickview_set_source(void*, immutable (char)* filename);
void dos_qquickview_rootContext(void*, ref void*);
void dos_qquickview_delete(void*);
// CharArray
void dos_chararray_delete(char*);
// QQmlContext
void dos_qqmlcontext_baseUrl(void*, ref char*);
void dos_qqmlcontext_setcontextproperty(void*, immutable (char)*, void*);
// QVariant
void dos_qvariant_create(ref void*);
void dos_qvariant_create_int(ref void*, int);
void dos_qvariant_create_bool(ref void*, bool);
void dos_qvariant_create_string(ref void*, immutable(char)*);
void dos_qvariant_create_qobject(ref void*, void*);
void dos_qvariant_create_float(ref void*, float);
void dos_qvariant_create_double(ref void*, double);
void dos_qvariant_toInt(void*, ref int);
void dos_qvariant_setInt(void*, int);
void dos_qvariant_toBool(void*, ref bool);
void dos_qvariant_setBool(void*, bool);
void dos_qvariant_toString(void*, ref char*);
void dos_qvariant_setString(void*, immutable(char)*);
void dos_qvariant_toFloat(void*, ref float);
void dos_qvariant_setFloat(void*, float);
void dos_qvariant_toDouble(void*, ref double);
void dos_qvariant_setDouble(void*, double);
void dos_qvariant_isnull(void*, ref bool);
void dos_qvariant_delete(void*);
void dos_qvariant_assign(void*, void*);
void dos_qvariant_setQObject(void*, void*);
// QObject
void dos_qobject_create(ref void*,
void* dobject,
void function (void*, void*, int , void**));
void dos_qobject_slot_create(void*,
immutable (char)* name,
int parametersCount,
int* parametersMetaTypes,
ref int slotIndex);
void dos_qobject_signal_create(void*,
immutable(char)* name,
int parametersCount,
int* parametersMetaTypes,
ref int signalIndex);
void dos_qobject_signal_emit(void*, immutable(char)* name,
int parametersCount,
void** parameters);
void dos_qobject_property_create(void*,
immutable(char)* name,
int propertyMetaType,
immutable(char)* readSlot,
immutable(char)* writeSlot,
immutable(char)* notifySignal);
void dos_qobject_delete(void*);
// QModelIndex
void dos_qmodelindex_create(ref void* index);
void dos_qmodelindex_delete(void* index);
void dos_qmodelindex_row(void*, ref int result);
void dos_qmodelindex_column(void*, ref int result);
void dos_qmodelindex_isValid(void* index, ref bool result);
void dos_qmodelindex_data(void* index, int role, void* variant);
void dos_qmodelindex_parent(void* index, void* parent);
void dos_qmodelindex_child(void* index, int r, int c, void* child);
void dos_qmodelindex_sibling(void* index, int r, int c, void* sibling);
// QHashIntByteArray
void dos_qhash_int_qbytearray_create(ref void*);
void dos_qhash_int_qbytearray_delete(void*);
void dos_qhash_int_qbytearray_insert(void*, int, immutable(char)*);
void dos_qhash_int_qbytearray_value(void*, int, ref char*);
// QAbstractListModel
void dos_qabstractlistmodel_create(ref void*,
void*,
void function (void*, void*, int, void**),
void function (void*, void*, ref int),
void function (void*, void*, ref int),
void function (void*, void*, int, void*),
void function (void*, void*, void*, int, ref bool),
void function (void*, void*),
void function (void*, void*, ref int),
void function (void*, int, int, int, void*));
void dos_qabstractlistmodel_beginInsertRows(void* vptr, void* parent, int first, int last);
void dos_qabstractlistmodel_endInsertRows(void* vptr);
void dos_qabstractlistmodel_beginRemoveRows(void* vptr, void* parent, int first, int last);
void dos_qabstractlistmodel_endRemoveRows(void* vptr);
void dos_qabstractlistmodel_beginResetModel(void* vptr);
void dos_qabstractlistmodel_endResetModel(void* vptr);
void dos_qabstractlistmodel_dataChanged(void* vptr, void* topLeft, void* bottomRight, int* rolesPtr, int rolesLength);
void dos_qabstractlistmodel_delete(void*);
}

View File

@ -1,14 +0,0 @@
public import qvariant;
public import qguiapplication;
public import qapplication;
public import qqmlcontext;
public import qobject;
public import qqmlapplicationengine;
public import qquickview;
public import qmetatype;
public import qmodelindex;
public import qabstractlistmodel;
public import qobjectgenerators;
public import std.traits;
public import std.algorithm;
public import std.stdio;

View File

@ -1,184 +0,0 @@
import dothersideinterface;
import qobject;
import qmodelindex;
import qvariant;
import std.string;
class QAbstractListModel : QObject
{
this()
{
super(true);
dos_qabstractlistmodel_create(this.vptr,
cast(void*)this,
&staticSlotCallback,
&rowCountCallback,
&columnCountCallback,
&dataCallback,
&setDataCallback,
&roleNamesCallback,
&flagsCallback,
&headerDataCallback);
qobjectInit();
}
~this()
{
dos_qabstractlistmodel_delete(this.vptr);
}
public int rowCount(QModelIndex parentIndex)
{
return 0;
}
public int columnCount(QModelIndex parentIndex)
{
return 1;
}
public QVariant data(QModelIndex index, int role)
{
return null;
}
public bool setData(QModelIndex index, QVariant value, int role)
{
return false;
}
public string[int] roleNames()
{
return null;
}
public int flags(QModelIndex index)
{
return 0;
}
public QVariant headerData(int section, int orienation, int role)
{
return null;
}
protected final void beginInsertRows(QModelIndex parent, int first, int last)
{
dos_qabstractlistmodel_beginInsertRows(this.vptr,
parent.voidPointer(),
first,
last);
}
protected final void endInsertRows()
{
dos_qabstractlistmodel_endInsertRows(this.vptr);
}
protected final void beginRemoveRows(QModelIndex parent, int first, int last)
{
dos_qabstractlistmodel_beginRemoveRows(this.vptr,
parent.voidPointer(),
first,
last);
}
protected final void endRemoveRows()
{
dos_qabstractlistmodel_endRemoveRows(this.vptr);
}
protected final void beginResetModel()
{
dos_qabstractlistmodel_beginResetModel(this.vptr);
}
protected final void endResetModel()
{
dos_qabstractlistmodel_endResetModel(this.vptr);
}
protected final void dataChanged(QModelIndex topLeft, QModelIndex bottomRight, int[] roles)
{
dos_qabstractlistmodel_dataChanged(this.vptr,
topLeft.voidPointer(),
bottomRight.voidPointer(),
roles.ptr,
cast(int)(roles.length));
}
private extern (C) static void rowCountCallback(void* modelPtr,
void* indexPtr,
ref int result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto index = new QModelIndex(indexPtr);
result = model.rowCount(index);
}
private extern (C) static void columnCountCallback(void* modelPtr,
void* indexPtr,
ref int result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto index = new QModelIndex(indexPtr);
result = model.columnCount(index);
}
private extern (C) static void dataCallback(void* modelPtr,
void* indexPtr,
int role,
void* result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto index = new QModelIndex(indexPtr);
auto value = model.data(index, role);
if (value is null)
return;
dos_qvariant_assign(result, value.voidPointer());
}
private extern (C) static void setDataCallback(void* modelPtr,
void* indexPtr,
void* valuePtr,
int role,
ref bool result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto index = new QModelIndex(indexPtr);
auto value = new QVariant(valuePtr);
result = model.setData(index, value, role);
}
private extern (C) static void roleNamesCallback(void* modelPtr,
void* result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto roles = model.roleNames();
foreach(int key; roles.keys) {
dos_qhash_int_qbytearray_insert(result, key, roles[key].toStringz());
}
}
private extern (C) static void flagsCallback(void* modelPtr,
void* indexPtr,
ref int result)
{
auto model = cast(QAbstractListModel)(modelPtr);
auto index = new QModelIndex(indexPtr);
result = model.flags(index);
}
private extern (C) static void headerDataCallback(void* modelPtr,
int section,
int orientation,
int role,
void* result)
{
auto model = cast(QAbstractListModel)(modelPtr);
QVariant value = model.headerData(section, orientation, role);
if (value is null)
return;
dos_qvariant_assign(result, value.voidPointer());
}
}

View File

@ -1,24 +0,0 @@
import dothersideinterface;
class QApplication
{
this()
{
dos_qapplication_create();
}
~this()
{
dos_qapplication_delete();
}
void exec()
{
dos_qapplication_exec();
}
void quit()
{
dos_qapplication_quit();
}
}

View File

@ -1,24 +0,0 @@
import dothersideinterface;
class QGuiApplication
{
this()
{
dos_qguiapplication_create();
}
~this()
{
dos_qguiapplication_delete();
}
void exec()
{
dos_qguiapplication_exec();
}
void quit()
{
dos_qguiapplication_quit();
}
}

View File

@ -1,42 +0,0 @@
import dothersideinterface;
import qvariant;
import std.string;
class QHashIntByteArray
{
this()
{
dos_qhash_int_qbytearray_create(this.vptr);
}
this(void* vptr)
{
this.vptr = vptr;
}
~this()
{
dos_qhash_int_qbytearray_delete(this.vptr);
}
public void* voidPointer()
{
return vptr;
}
public void insert(int key, string value)
{
dos_qhash_int_qbytearray_insert(this.vptr, key, value.toStringz());
}
public string value(int key)
{
char* array;
dos_qhash_int_qbytearray_value(this.vptr, key, array);
string result = fromStringz(array).dup;
dos_chararray_delete(array);
return result;
}
private void* vptr;
}

View File

@ -1,42 +0,0 @@
import qobject;
import qvariant;
/*
enum Type {
UnknownType = 0, Bool = 1, Int = 2, UInt = 3, LongLong = 4, ULongLong = 5,
Double = 6, Long = 32, Short = 33, Char = 34, ULong = 35, UShort = 36,
UChar = 37, Float = 38,
VoidStar = 31,
QChar = 7, QString = 10, QStringList = 11, QByteArray = 12,
QBitArray = 13, QDate = 14, QTime = 15, QDateTime = 16, QUrl = 17,
QLocale = 18, QRect = 19, QRectF = 20, QSize = 21, QSizeF = 22,
QLine = 23, QLineF = 24, QPoint = 25, QPointF = 26, QRegExp = 27,
QEasingCurve = 29, QUuid = 30, QVariant = 41, QModelIndex = 42,
QRegularExpression = 44,
QJsonValue = 45, QJsonObject = 46, QJsonArray = 47, QJsonDocument = 48,
QObjectStar = 39, SChar = 40,
Void = 43,
QVariantMap = 8, QVariantList = 9, QVariantHash = 28,
QFont = 64, QPixmap = 65, QBrush = 66, QColor = 67, QPalette = 68,
QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73,
QCursor = 74, QKeySequence = 75, QPen = 76, QTextLength = 77, QTextFormat = 78,
QMatrix = 79, QTransform = 80, QMatrix4x4 = 81, QVector2D = 82,
QVector3D = 83, QVector4D = 84, QQuaternion = 85, QPolygonF = 86,
QSizePolicy = 121,
User = 1024
};
*/
public enum QMetaType
{
Unknown = 0,
Bool = 1,
Int = 2,
Double = 6,
String = 10,
VoidStr = 31,
Float = 38,
QObject = 39,
QVariant = 41,
Void = 43
}

View File

@ -1,77 +0,0 @@
import dothersideinterface;
import qvariant;
class QModelIndex
{
this()
{
dos_qmodelindex_create(this.ptr);
}
this(void* ptr)
{
this.ptr = ptr;
}
~this()
{
dos_qmodelindex_delete(this.ptr);
ptr = null;
}
public void* voidPointer()
{
return this.ptr;
}
public int row()
{
int result = -1;
dos_qmodelindex_row(this.ptr, result);
return result;
}
public int column()
{
int result = -1;
dos_qmodelindex_column(this.ptr, result);
return result;
}
public bool isValid()
{
bool result = false;
dos_qmodelindex_isValid(this.ptr, result);
return result;
}
public QVariant data(int role)
{
auto result = new QVariant();
dos_qmodelindex_data(this.ptr, role, result.voidPointer());
return result;
}
public QModelIndex parent()
{
auto result = new QModelIndex();
dos_qmodelindex_parent(this.ptr, result.ptr);
return result;
}
public QModelIndex child(int row, int column)
{
auto result = new QModelIndex();
dos_qmodelindex_child(this.ptr, row, column, result.ptr);
return result;
}
public QModelIndex sibling(int row, int column)
{
auto result = new QModelIndex();
dos_qmodelindex_sibling(this.ptr, row, column, result.ptr);
return result;
}
private void* ptr;
}

View File

@ -1,129 +0,0 @@
import std.stdio;
import std.format;
import std.conv;
import std.container;
import std.traits;
import std.string;
import std.algorithm;
import dothersideinterface;
import qmetatype;
import qvariant;
public class QObject
{
public this()
{
this(false);
}
protected this(bool disableDosCalls)
{
this.disableDosCalls = disableDosCalls;
if (!this.disableDosCalls)
{
dos_qobject_create(this.vptr, cast(void*)this, &staticSlotCallback);
qobjectInit();
}
}
~this()
{
if (!this.disableDosCalls)
{
dos_qobject_delete(this.vptr);
this.vptr = null;
}
}
public void* voidPointer()
{
return this.vptr;
}
protected void qobjectInit()
{}
protected void onSlotCalled(QVariant slotName, QVariant[] parameters)
{
}
protected void registerSlot(string name, QMetaType[] types)
{
int index = -1;
int length = cast(int)types.length;
int[] array = to!(int[])(types);
dos_qobject_slot_create(this.vptr,
name.toStringz(),
length,
array.ptr,
index);
}
protected void registerSignal(string name, QMetaType[] types)
{
int index = -1;
int length = cast(int)types.length;
int[] array = length > 0 ? to!(int[])(types) : null;
dos_qobject_signal_create(this.vptr,
name.toStringz(),
length,
array.ptr,
index);
}
protected void registerProperty(string name,
QMetaType type,
string readSlotName,
string writeSlotName,
string notifySignalName)
{
dos_qobject_property_create(this.vptr,
name.toStringz(),
type,
readSlotName.toStringz(),
writeSlotName.toStringz(),
notifySignalName.toStringz());
}
protected void emit(T)(string signalName, T t)
{
emit(signalName, new QVariant(t));
}
protected void emit(string signalName, QVariant value)
{
QVariant[] array = [value];
emit(signalName, array);
}
protected void emit(string signalName, QVariant[] arguments = null)
{
int length = cast(int)arguments.length;
void*[] array = null;
if (length > 0) {
array = new void*[length];
foreach (int i, QVariant v; arguments)
array[i] = v.voidPointer();
}
dos_qobject_signal_emit(this.vptr,
signalName.toStringz(),
length,
array.ptr);
}
protected extern (C) static void staticSlotCallback(void* qObjectPtr,
void* rawSlotName,
int numParameters,
void** parametersArray)
{
QVariant[] parameters = new QVariant[numParameters];
for (int i = 0; i < numParameters; ++i)
parameters[i] = new QVariant(parametersArray[i]);
QObject qObject = cast(QObject) qObjectPtr;
QVariant slotName = new QVariant(rawSlotName);
qObject.onSlotCalled(slotName, parameters);
}
protected void* vptr;
protected bool disableDosCalls;
}

View File

@ -1,265 +0,0 @@
import std.traits;
import std.algorithm;
import std.string;
import std.stdio;
struct QtProperty
{
public string type;
public string name;
public string read;
public string write;
public string notify;
this(string type, string name, string read, string write, string notify)
{
this.type = type;
this.name = name;
this.read = read;
this.write = write;
this.notify = notify;
}
}
struct QtSlot {};
struct QtSignal {};
string GenerateVariantConversionCall(string typeName)
{
switch (typeName)
{
case "string":
return ".toString()";
case "int":
return ".toInt()";
case "bool":
return ".toBool()";
case "float":
return ".toFloat()";
case "double":
return ".toDouble()";
case "QVariant":
return "";
default:
throw new Exception("Unknown conversion function from Qvariant to " ~ typeName);
}
}
string GenerateArgumentList(string[] typeNames)
{
string result = "";
for (int i = 0; i < typeNames.length; ++i)
{
auto typeName = typeNames[i];
auto variantCall = GenerateVariantConversionCall(typeName);
result ~= i > 0 ? "," : "";
result ~= format("arguments[%d]%s", i+1, variantCall);
}
return result;
}
string GenerateSlotCall(FunctionInfo info)
{
auto args = GenerateArgumentList(info.parameterTypes);
auto call = format("%s(%s)", info.name, args);
auto formatStr = info.returnType != "void" ? "arguments[0].setValue(%s)" : "%s";
return format(formatStr, call);
}
string GenerateCaseBlock(FunctionInfo info)
{
string result = "";
result ~= format("case \"%s\":\n", info.name);
result ~= format("%s;\n", GenerateSlotCall(info));
result ~= "break;\n";
return result;
}
string GenerateOnSlotCalled(QtInfo info)
{
string result = "protected override void onSlotCalled(QVariant slotName, QVariant[] arguments)\n";
result ~= "{\n";
result ~= "switch(slotName.toString())\n";
result ~= "{\n";
foreach (slot; info.slots)
result ~= GenerateCaseBlock(slot);
result ~= "default: super.onSlotCalled(slotName, arguments);\n";
result ~= "}\n"; //
result ~= "}";
return result;
}
string GenerateSignalCall(FunctionInfo info)
{
string args = "";
string vars = "";
for (int i = 0; i < info.parameterTypes.length; ++i) {
if (i > 0) {
args ~= ",";
vars ~= ",";
}
args ~= format("%s val%d", info.parameterTypes[i], i);
vars ~= format("val%d", i);
}
auto result = format("public %s %s(%s) { emit(\"%s\", %s); }", info.returnType, info.name, args, info.name, vars);
return result;
}
string GenerateQtSignals(QtInfo info)
{
string result = "";
foreach (signal; info.signals)
result ~= GenerateSignalCall(signal) ~ "\n";
return result;
}
string GenerateMetaType(string typeName)
{
switch(typeName)
{
case "void":
return "QMetaType.Void";
case "int":
return "QMetaType.Int";
case "string":
return "QMetaType.String";
case "QObject":
return "QMetaType.QObject";
case "QVariant":
return "QMetaType.QVariant";
case "bool":
return "QMetaType.Bool";
case "float":
return "QMetaType.Float";
case "double":
return "QMetaType.Double";
default:
throw new Exception(format("Unknown conversion from %s to QMetaType", typeName));
}
}
string GenerateMetaTypesListForSlot(FunctionInfo info)
{
string result = GenerateMetaType(info.returnType);
result ~= ", ";
result ~= GenerateMetaTypesListForSignal(info);
return result;
}
string GenerateMetaTypesListForSignal(FunctionInfo info)
{
string result = "";
for (int i = 0; i < info.parameterTypes.length; ++i)
{
if (i > 0)
result ~= ", ";
result ~= GenerateMetaType(info.parameterTypes[i]);
}
return result;
}
string GenerateQObjectInit(QtInfo info)
{
string result = "";
result ~= "protected override void qobjectInit()\n";
result ~= "{\n";
foreach (slot; info.slots)
{
auto metaTypes = GenerateMetaTypesListForSlot(slot);
result ~= format("registerSlot(\"%s\", [%s]);\n", slot.name, metaTypes);
}
foreach (signal; info.signals)
{
auto metaTypes = GenerateMetaTypesListForSignal(signal);
result ~= format("registerSignal(\"%s\", [%s]);\n", signal.name, metaTypes);
}
foreach (property; info.properties)
{
result ~= format("registerProperty(\"%s\", %s, \"%s\", \"%s\", \"%s\");\n", property.name, GenerateMetaType(property.type), property.read, property.write, property.notify);
}
result ~= "super.qobjectInit();\n";
result ~= "}";
return result;
}
struct FunctionInfo
{
string name;
string returnType;
string[] parameterTypes;
}
struct QtInfo
{
FunctionInfo[] slots;
FunctionInfo[] signals;
QtProperty[] properties;
}
mixin template InjectQObjectMacro()
{
private static QtInfo GetQtUDA(T)()
{
QtInfo result;
foreach (attribute; __traits(getAttributes, T)) {
static if (is (typeof(attribute) == QtProperty)) {
result.properties ~= attribute;
}
}
foreach (member; __traits(allMembers, T))
{
static if (__traits(compiles, __traits(getMember, T, member))
&& isSomeFunction!(__traits(getMember, T, member)))
{
// Retrieve the UDA
auto attributes = __traits(getAttributes, __traits(getMember, T, member));
// Turn the tuple in an array of strings
string[] attributeNames;
foreach (attribute; attributes)
attributeNames ~= typeof(attribute).stringof;
bool isSlot = attributeNames.canFind("QtSlot");
bool isSignal = attributeNames.canFind("QtSignal");
// Extract the Function Return Type and Arguments
if (isSlot || isSignal)
{
FunctionInfo info;
info.name = member;
info.returnType = ReturnType!(__traits(getMember, T, member)).stringof;
foreach (param; ParameterTypeTuple!(__traits(getMember, T, member)))
info.parameterTypes ~= param.stringof;
if (isSlot)
result.slots ~= info;
if (isSignal)
result.signals ~= info;
}
}
}
return result;
}
private static string Q_OBJECT(T)()
{
string result = "";
auto info = T.GetQtUDA!(T);
result ~= GenerateOnSlotCalled(info) ~ "\n";
result ~= GenerateQObjectInit(info) ~ "\n";
result ~= GenerateQtSignals(info) ~ "\n";
return result;
}
}

View File

@ -1,35 +0,0 @@
import dothersideinterface;
import qqmlcontext;
import std.string;
class QQmlApplicationEngine
{
this()
{
dos_qqmlapplicationengine_create(this.vptr);
}
~this()
{
dos_qqmlapplicationengine_delete(this.vptr);
}
public void* voidPointer()
{
return this.vptr;
}
public QQmlContext rootContext()
{
void* contextVPtr;
dos_qqmlapplicationengine_context(this.vptr, contextVPtr);
return new QQmlContext(contextVPtr);
}
public void load(string filename)
{
dos_qqmlapplicationengine_load(this.vptr, filename.toStringz());
}
private void* vptr;
}

View File

@ -1,32 +0,0 @@
import dothersideinterface;
import qvariant;
import std.string;
class QQmlContext
{
this(void* vptr)
{
this.vptr = vptr;
}
public void* voidPointer()
{
return vptr;
}
public string baseUrl()
{
char* array;
dos_qqmlcontext_baseUrl(this.vptr, array);
string result = fromStringz(array).dup;
dos_chararray_delete(array);
return result;
}
public void setContextProperty(string name, QVariant value)
{
dos_qqmlcontext_setcontextproperty(this.vptr, name.ptr, value.voidPointer());
}
private void* vptr;
}

View File

@ -1,50 +0,0 @@
import dothersideinterface;
import qqmlcontext;
import std.string;
class QQuickView
{
this()
{
dos_qquickview_create(this.vptr);
}
~this()
{
dos_qquickview_delete(this.vptr);
}
public void* voidPointer()
{
return this.vptr;
}
public void show()
{
dos_qquickview_show(this.vptr);
}
public QQmlContext rootContext()
{
void* contextData;
dos_qquickview_rootContext(this.vptr, contextData);
return new QQmlContext(contextData);
}
public string source()
{
char* array;
dos_qquickview_source(this.vptr, array);
string result = fromStringz(array).dup;
dos_chararray_delete(array);
return result;
}
public void setSource(string filename)
{
immutable(char)* filenameAsCString = filename.toStringz();
dos_qquickview_set_source(this.vptr, filenameAsCString);
}
private void* vptr;
}

View File

@ -1,160 +0,0 @@
import dothersideinterface;
import qobject;
import std.string;
class QVariant
{
public this()
{
dos_qvariant_create(this.vptr);
}
public this(int value)
{
dos_qvariant_create_int(this.vptr, value);
}
public this(bool value)
{
dos_qvariant_create_bool(this.vptr, value);
}
public this(string value)
{
dos_qvariant_create_string(this.vptr, value.toStringz());
}
public this(float value)
{
dos_qvariant_create_float(this.vptr, value);
}
public this(double value)
{
dos_qvariant_create_double(this.vptr, value);
}
public this(QObject value)
{
dos_qvariant_create_qobject(this.vptr, value.voidPointer());
}
public this(void* vptr, bool hasOwnership = false)
{
this.vptr = vptr;
this.hasOwnership = hasOwnership;
}
~this()
{
if (this.hasOwnership)
dos_qvariant_delete(this.vptr);
}
public void* voidPointer()
{
return this.vptr;
}
public void setValue(int value)
{
dos_qvariant_setInt(this.vptr, value);
}
public void setValue(bool value)
{
dos_qvariant_setBool(this.vptr, value);
}
public void setValue(string value)
{
dos_qvariant_setString(this.vptr, value.toStringz());
}
public void setValue(QObject value)
{
dos_qvariant_setQObject(this.vptr, value.voidPointer());
}
public void setValue(float value)
{
dos_qvariant_setFloat(this.vptr, value);
}
public void setValue(double value)
{
dos_qvariant_setDouble(this.vptr, value);
}
public void getValue(ref int value)
{
value = toInt();
}
public void getValue(ref bool value)
{
value = toBool();
}
public void getValue(ref string value)
{
value = toString();
}
public void getValue(ref float value)
{
value = toFloat();
}
public void getValue(ref double value)
{
value = toDouble();
}
public bool isNull()
{
bool result;
dos_qvariant_isnull(this.vptr, result);
return result;
}
public bool toBool()
{
bool result;
dos_qvariant_toBool(this.vptr, result);
return result;
}
public int toInt()
{
int result;
dos_qvariant_toInt(this.vptr, result);
return result;
}
public float toFloat()
{
float result;
dos_qvariant_toFloat(this.vptr, result);
return result;
}
public double toDouble()
{
double result;
dos_qvariant_toDouble(this.vptr, result);
return result;
}
public override string toString()
{
char* array;
dos_qvariant_toString(this.vptr, array);
string result = fromStringz(array).dup;
dos_chararray_delete(array);
return result;
}
private void* vptr = null;
private bool hasOwnership = true;
}

View File

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQmlAbstractItemModel C D )
add_executable(${PROJECT_NAME} main.d model.d)
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -1,26 +0,0 @@
import dqml;
import model;
void main()
{
try
{
auto app = new QGuiApplication();
scope(exit) destroy(app);
auto model = new ListModel();
scope(exit) destroy(model);
auto variant = new QVariant();
variant.setValue(model);
auto engine = new QQmlApplicationEngine();
scope(exit) destroy(engine);
engine.rootContext().setContextProperty("myListModel", variant);
engine.load("main.qml");
app.exec();
}
catch
{}
}

View File

@ -1,25 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "AbstractItemModel"
Component.onCompleted: visible = true
Component
{
id: myListModelDelegate
Label { text: "Name:" + name }
}
ListView
{
anchors.fill: parent
model: myListModel
delegate: myListModelDelegate
}
}

View File

@ -1,48 +0,0 @@
import dqml;
import std.stdio;
class ListModel : QAbstractListModel
{
this()
{
this.names = ["John", "Max", "Paul", "Anna"];
this.roles[Roles.Name] = "name";
}
public override int rowCount(QModelIndex parent = null)
{
if (parent && parent.isValid())
return 0;
return cast(int)(names.length);
}
public override QVariant data(QModelIndex index, int role)
{
if (index is null)
return null;
if (!index.isValid())
return null;
if (index.row() < 0 || index.row() >= rowCount())
return null;
switch(role)
{
case Roles.Name:
return new QVariant(names[index.row]);
default:
return null;
}
}
public override string[int] roleNames()
{
return roles;
}
private string[] names;
private string[int] roles;
private enum Roles : int { Name = 0 };
}

View File

@ -1,5 +0,0 @@
add_subdirectory(HelloWorld)
add_subdirectory(SimpleData)
add_subdirectory(SlotsAndProperties)
add_subdirectory(AbstractItemModel)
add_subdirectory(ContactApp)

View File

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQmlContactApp C D )
add_executable(${PROJECT_NAME} main.d applicationlogic.d contact.d contactlist.d)
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -1,44 +0,0 @@
import dqml;
import contactlist;
import std.stdio;
@QtProperty(QObject.stringof, "contactList", "contactList", null, null)
class ApplicationLogic : QObject
{
mixin InjectQObjectMacro;
mixin(Q_OBJECT!(ApplicationLogic));
this(QApplication app)
{
this.m_app = app;
this.m_contactList = new ContactList();
}
@QtSlot()
public QObject contactList()
{
return this.m_contactList;
}
@QtSlot()
public void onLoadTriggered()
{
writefln("Load Triggered");
}
@QtSlot()
public void onSaveTriggered()
{
writefln("Save Triggered");
}
@QtSlot()
public void onExitTriggered()
{
this.m_app.quit();
}
private QApplication m_app;
private ContactList m_contactList;
}

View File

@ -1,56 +0,0 @@
import dqml;
@QtProperty(string.stringof, "firstName", "firstName", "setFirstName", "firstNameChanged")
@QtProperty(string.stringof, "lastName", "lastName", "setLastName", "lastNameChanged")
class Contact : QObject
{
mixin InjectQObjectMacro;
mixin(Q_OBJECT!(Contact));
this(string firstName = "", string lastName = "")
{
this.m_firstName = firstName;
this.m_lastName = lastName;
}
@QtSlot()
public string firstName()
{
return this.m_firstName;
}
@QtSlot()
public void setFirstName(string firstName)
{
if (this.m_firstName != firstName)
{
this.m_firstName = firstName;
firstNameChanged(firstName);
}
}
@QtSignal()
public void firstNameChanged(string);
@QtSlot()
public string lastName()
{
return this.m_lastName;
}
@QtSlot()
public void setLastName(string lastName)
{
if (this.m_lastName != lastName)
{
this.m_lastName = lastName;
lastNameChanged(lastName);
}
}
@QtSignal()
public void lastNameChanged(string);
private string m_firstName;
private string m_lastName;
}

View File

@ -1,80 +0,0 @@
import dqml;
import contact;
import std.stdio;
import std.algorithm;
class ContactList : QAbstractListModel
{
mixin InjectQObjectMacro;
mixin(Q_OBJECT!(ContactList));
this()
{
this.m_contacts = [];
this.m_roleNames[Roles.FirstName] = "firstName";
this.m_roleNames[Roles.LastName] = "lastName";
}
public override int rowCount(QModelIndex parent = null)
{
if (parent && parent.isValid())
return 0;
return cast(int)(this.m_contacts.length);
}
public override QVariant data(QModelIndex index, int role)
{
if (index is null)
return null;
if (!index.isValid())
return null;
if (index.row() < 0 || index.row() >= rowCount())
return null;
auto contact = this.m_contacts[index.row];
switch(role)
{
case Roles.FirstName:
return new QVariant(contact.firstName());
case Roles.LastName:
return new QVariant(contact.lastName());
default:
return null;
}
}
public override string[int] roleNames()
{
return this.m_roleNames;
}
@QtSlot()
public void add(string firstName, string lastName)
{
auto index = new QModelIndex();
auto pos = rowCount();
writefln("Adding %s %s in pos %d", firstName, lastName, pos);
beginInsertRows(index, pos, pos);
this.m_contacts ~= new Contact(firstName, lastName);
endInsertRows();
}
@QtSlot()
public void del(int pos)
{
if (pos < 0 || pos >= rowCount())
return;
auto index = new QModelIndex();
writefln("Removing at pos %d", pos);
beginRemoveRows(index, pos, pos);
this.m_contacts = remove(this.m_contacts, pos);
endRemoveRows();
}
private Contact[] m_contacts;
private string[int] m_roleNames;
private enum Roles : int { FirstName = 0, LastName};
}

View File

@ -1,26 +0,0 @@
import dqml;
import applicationlogic;
void main()
{
try
{
auto app = new QApplication();
scope(exit) destroy(app);
auto logic = new ApplicationLogic(app);
scope(exit) destroy(logic);
auto variant = new QVariant();
variant.setValue(logic);
auto engine = new QQmlApplicationEngine();
scope(exit) destroy(engine);
engine.rootContext().setContextProperty("logic", variant);
engine.load("main.qml");
app.exec();
}
catch
{}
}

View File

@ -1,93 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow {
width: 500
height: 300
title: "ContactApp"
visible: true
menuBar: MenuBar {
Menu {
title: "&File"
MenuItem { text: "&Load"; onTriggered: logic.onLoadTriggered() }
MenuItem { text: "&Save"; onTriggered: logic.onSaveTriggered() }
MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() }
}
}
ColumnLayout {
anchors.fill: parent
Component {
id: tableTextDelegate
Label {
id: tableTextDelegateInstance
property var styleData: undefined
states: State {
when: styleData !== undefined
PropertyChanges {
target: tableTextDelegateInstance;
text: styleData.value;
color: styleData.textColor
}
}
}
}
Component {
id: tableButtonDelegate
Button {
id: tableButtonDelegateInstance
property var styleData: undefined
text: "Delete"
onClicked: logic.contactList.del(styleData.row)
}
}
Component {
id: tableItemDelegate
Loader {
id: tableItemDelegateInstance
sourceComponent: {
if (styleData.column === 0 || styleData.column === 1)
return tableTextDelegate
else if (styleData.column === 2)
return tableButtonDelegate
else
return tableTextDelegate
}
Binding {
target: tableItemDelegateInstance.item
property: "styleData"
value: styleData
}
}
}
TableView {
model: logic.contactList
Layout.fillWidth: true
Layout.fillHeight: true
TableViewColumn { role: "firstName"; title: "FirstName"; width: 200 }
TableViewColumn { role: "lastName"; title: "LastName"; width: 200}
TableViewColumn { width: 100; }
itemDelegate: tableItemDelegate
}
RowLayout {
Label { text: "FirstName" }
TextField { id: nameTextField; Layout.fillWidth: true; text: "" }
Label { text: "LastName" }
TextField { id: surnameTextField; Layout.fillWidth: true; text: "" }
Button {
text: "Add"
onClicked: logic.contactList.add(nameTextField.text, surnameTextField.text)
enabled: nameTextField.text !== "" && surnameTextField.text !== ""
}
}
}
}

View File

@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQmlHelloWorld C D )
add_executable(${PROJECT_NAME} main.d)
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -1,19 +0,0 @@
import std.stdio;
import dqml;
void main()
{
try
{
auto app = new QGuiApplication();
scope(exit) destroy(app);
auto engine = new QQmlApplicationEngine();
scope(exit) destroy(engine);
engine.load("main.qml");
app.exec();
}
catch
{}
}

View File

@ -1,12 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "Hello World"
Component.onCompleted: visible = true
}

View File

@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQmlSimpleData C D )
add_executable(${PROJECT_NAME} main.d)
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -1,36 +0,0 @@
import std.stdio;
import dqml;
void main()
{
try
{
auto app = new QGuiApplication();
scope(exit) destroy(app);
auto engine = new QQmlApplicationEngine();
scope(exit) destroy(engine);
auto qVar1 = new QVariant(10);
scope(exit) destroy(qVar1);
auto qVar2 = new QVariant("Hello World");
scope(exit) destroy(qVar1);
auto qVar3 = new QVariant(false);
scope(exit) destroy(qVar1);
auto qVar4 = new QVariant(3.5f);
scope(exit) destroy(qVar1);
engine.rootContext().setContextProperty("qVar1", qVar1);
engine.rootContext().setContextProperty("qVar2", qVar2);
engine.rootContext().setContextProperty("qVar3", qVar3);
engine.rootContext().setContextProperty("qVar4", qVar4);
engine.load("main.qml");
app.exec();
}
catch
{}
}

View File

@ -1,21 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "SimpleData"
Component.onCompleted: visible = true
ColumnLayout
{
anchors.fill: parent
SpinBox { value: qVar1}
TextField { text: qVar2}
CheckBox { checked: qVar3}
SpinBox { value: qVar4; decimals: 1 }
}
}

View File

@ -1,12 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project (DQmlSlotsAndProperties C D )
add_executable(${PROJECT_NAME} main.d contact.d)
target_include_directories(${PROJECT_NAME} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/../../DQml"
${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}/../../../DOtherSide/libDOtherSide.so"
"${CMAKE_CURRENT_BINARY_DIR}/../../DQml/libDQml.a"
)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -1,52 +0,0 @@
import dqml;
@QtProperty(string.stringof, "name", "getName", "setName", "nameChanged")
@QtProperty(string.stringof, "surname", "getSurname", "setSurname", "surnameChanged")
class Contact : QObject
{
mixin InjectQObjectMacro;
mixin(Q_OBJECT!(Contact));
this()
{}
~this()
{}
@QtSlot()
public string getName()
{
return m_name;
}
@QtSlot()
public void setName(string name)
{
if (m_name != name)
{
m_name = name;
emit("nameChanged", name);
}
}
@QtSignal()
public void nameChanged(string name);
@QtSlot()
public string getSurname()
{
return m_surname;
}
@QtSlot()
public void setSurname(string surname)
{
m_surname = surname;
}
@QtSignal()
void surnameChanged(string surname);
private string m_name;
private string m_surname;
}

View File

@ -1,27 +0,0 @@
import std.stdio;
import dqml;
import contact;
void main()
{
try
{
auto app = new QApplication();
scope(exit) destroy(app);
auto contact = new Contact();
scope(exit) destroy(contact);
auto variant = new QVariant(contact);
scope(exit) destroy(variant);
auto engine = new QQmlApplicationEngine();
scope(exit) destroy(engine);
engine.rootContext().setContextProperty("contact", variant);
engine.load("main.qml");
app.exec();
}
catch
{}
}

View File

@ -1,24 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow {
width: 400
height: 300
visible: true
ColumnLayout {
anchors.fill: parent
Label { text: "Current name is:" + contact.name }
TextField { id: textField }
Button{
text: "Change Name"
onClicked: contact.name = textField.text
}
}
}

View File

@ -1,51 +0,0 @@
# < 2.8.10 backward compatibility
if(NOT CMAKE_PLATFORM_INFO_DIR)
set(CMAKE_PLATFORM_INFO_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
endif(NOT CMAKE_PLATFORM_INFO_DIR)
set(CMAKE_D_COMPILER "@CMAKE_D_COMPILER@")
set(CMAKE_D_COMPILER_ARG1 "@CMAKE_D_COMPILER_ARG1@")
set(CMAKE_D_COMPILER_ID "@CMAKE_D_COMPILER_ID@")
set(CMAKE_D_PLATFORM_ID "@CMAKE_D_PLATFORM_ID@")
@SET_MSVC_D_ARCHITECTURE_ID@
set(CMAKE_AR "@CMAKE_AR@")
set(CMAKE_RANLIB "@CMAKE_RANLIB@")
set(CMAKE_LINKER "@CMAKE_LINKER@")
set(CMAKE_COMPILER_IS_GDC @CMAKE_COMPILER_IS_GDC@)
set(CMAKE_COMPILER_IS_DMD @CMAKE_COMPILER_IS_DMD@)
set(CMAKE_D_COMPILER_LOADED 1)
set(CMAKE_COMPILER_IS_MINGW @CMAKE_COMPILER_IS_MINGW@)
set(CMAKE_COMPILER_IS_CYGWIN @CMAKE_COMPILER_IS_CYGWIN@)
if(CMAKE_COMPILER_IS_CYGWIN)
set(CYGWIN 1)
set(UNIX 1)
endif(CMAKE_COMPILER_IS_CYGWIN)
set(CMAKE_D_COMPILER_ENV_VAR "DC")
if(CMAKE_COMPILER_IS_MINGW)
set(MINGW 1)
endif(CMAKE_COMPILER_IS_MINGW)
set(CMAKE_D_SOURCE_FILE_EXTENSIONS d;di)
set(CMAKE_D_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC)
# Prefer to use D's linker.
# The D value 40 beats CXX value of 30 and C value of 10
set(CMAKE_D_LINKER_PREFERENCE 40 )
set(CMAKE_D_LINKER_PREFERENCE_PROPOGATES 1 )
# Save compiler ABI information.
set(CMAKE_D_SIZEOF_DATA_PTR "@CMAKE_D_SIZEOF_DATA_PTR@")
set(CMAKE_D_COMPILER_ABI "@CMAKE_D_COMPILER_ABI@")
if(CMAKE_D_SIZEOF_DATA_PTR)
set(CMAKE_SIZEOF_VOID_P "${CMAKE_D_SIZEOF_DATA_PTR}")
endif(CMAKE_D_SIZEOF_DATA_PTR)
if(CMAKE_D_COMPILER_ABI)
set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_D_COMPILER_ABI}")
endif(CMAKE_D_COMPILER_ABI)
set(CMAKE_D_HAS_ISYSROOT "@CMAKE_D_HAS_ISYSROOT@")
@CMAKE_D_OSX_DEPLOYMENT_TARGET_FLAG_CODE@
set(CMAKE_D_IMPLICIT_LINK_LIBRARIES "@CMAKE_D_IMPLICIT_LINK_LIBRARIES@")
set(CMAKE_D_IMPLICIT_LINK_DIRECTORIES "@CMAKE_D_IMPLICIT_LINK_DIRECTORIES@")

View File

@ -1,5 +0,0 @@
int main(string[] args)
{
int require = 0;
return require;
}

View File

@ -1,39 +0,0 @@
version(DigitalMars)
{
const string COMPILER_ID = "DigitalMars";
}
else version(GNU)
{
const string COMPILER_ID = "GNU";
}
else version(LDC)
{
const string COMPILER_ID = "LDC";
}
else version(SDC)
{
const string COMPILER_ID = "SDC";
}
else
{
const string COMPILER_ID = "";
}
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
string info_compiler = "INFO" ":" "compiler[" ~ COMPILER_ID ~ "]";
@CMAKE_D_COMPILER_ID_PLATFORM_CONTENT@
/*--------------------------------------------------------------------------*/
int main(string[] args)
{
int require = 0;
require += info_compiler[args.length];
require += info_platform[args.length];
require += info_arch[args.length];
return require;
}

View File

@ -1,280 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
# Steve King <sk@metrokings.com>
# Dragos Carp <dragos.carp@gmail.com>
# Konstantin Oblaukhov <oblaukhov.konstantin@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 CMakeCInformation.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
# This file sets the basic flags for the D language in CMake.
# It also loads the available platform file for the system-compiler
# if it exists.
# It also loads a system - compiler - processor (or target hardware)
# specific file, which is mainly useful for crosscompiling and embedded systems.
# Load compiler-specific information.
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
if(CMAKE_D_COMPILER_ID)
include(Compiler/${CMAKE_D_COMPILER_ID}-D OPTIONAL)
endif(CMAKE_D_COMPILER_ID)
# set(CMAKE_D_OUTPUT_EXTENSION .o)
set(CMAKE_C_OUTPUT_EXTENSION_REPLACE TRUE )
set(CMAKE_D_OUTPUT_EXTENSION_REPLACE TRUE )
set(CMAKE_BASE_NAME)
get_filename_component(CMAKE_BASE_NAME ${CMAKE_D_COMPILER} NAME_WE)
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
# load a hardware specific file, mostly useful for embedded compilers
if(CMAKE_SYSTEM_PROCESSOR)
if(CMAKE_D_COMPILER_ID)
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_D_COMPILER_ID}-D-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
endif(CMAKE_D_COMPILER_ID)
if(NOT _INCLUDED_FILE)
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL)
endif(NOT _INCLUDED_FILE)
endif(CMAKE_SYSTEM_PROCESSOR)
set(_INCLUDED_FILE 0) # reset the indicator if an include occurred.
# load the system- and compiler specific files
if(CMAKE_D_COMPILER_ID)
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_D_COMPILER_ID}-D
OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
endif(CMAKE_D_COMPILER_ID)
# if no high specificity file was included, then try a more general one
if(NOT _INCLUDED_FILE)
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME}
OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
endif(NOT _INCLUDED_FILE)
# We specify the compiler information in the system file for some
# platforms, but this language may not have been enabled when the file
# was first included. Include it again to get the language info.
# Remove this when all compiler info is removed from system files.
if(NOT _INCLUDED_FILE)
include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
endif(NOT _INCLUDED_FILE)
# This should be included before the _INIT variables are
# used to initialize the cache. Since the rule variables
# have if blocks on them, users can still define them here.
# But, it should still be after the platform file so changes can
# be made to those values.
if(CMAKE_USER_MAKE_RULES_OVERRIDE)
include(${CMAKE_USER_MAKE_RULES_OVERRIDE})
endif(CMAKE_USER_MAKE_RULES_OVERRIDE)
if(CMAKE_USER_MAKE_RULES_OVERRIDE_D)
include(${CMAKE_USER_MAKE_RULES_OVERRIDE_D})
endif(CMAKE_USER_MAKE_RULES_OVERRIDE_D)
# Lines below was taken from CMakeCXXInformation.cmake
# Not all of this flags are available on D compilers for now, but some as OPTIONS_PIC are.
if(NOT CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS)
set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS})
endif()
if(NOT CMAKE_D_COMPILE_OPTIONS_PIC)
set(CMAKE_DCOMPILE_OPTIONS_PIC ${CMAKE_D_COMPILE_OPTIONS_PIC})
endif()
if(NOT CMAKE_D_COMPILE_OPTIONS_PIE)
set(CMAKE_D_COMPILE_OPTIONS_PIE ${CMAKE_D_COMPILE_OPTIONS_PIE})
endif()
if(NOT CMAKE_D_COMPILE_OPTIONS_DLL)
set(CMAKE_D_COMPILE_OPTIONS_DLL ${CMAKE_D_COMPILE_OPTIONS_DLL})
endif()
if(NOT CMAKE_SHARED_LIBRARY_D_FLAGS)
set(CMAKE_SHARED_LIBRARY_D_FLAGS ${CMAKE_SHARED_LIBRARY_D_FLAGS})
endif()
if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_D_FLAGS)
set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_D_FLAGS})
endif()
if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG)
set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG})
endif()
if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP)
set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP})
endif()
if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG)
set(CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG})
endif()
if(NOT DEFINED CMAKE_EXE_EXPORTS_D_FLAG)
set(CMAKE_EXE_EXPORTS_D_FLAG ${CMAKE_EXE_EXPORTS_D_FLAG})
endif()
if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_D_FLAG)
set(CMAKE_SHARED_LIBRARY_SONAME_D_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_D_FLAG})
endif()
if(NOT CMAKE_EXECUTABLE_RUNTIME_D_FLAG)
set(CMAKE_EXECUTABLE_RUNTIME_D_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG})
endif()
if(NOT CMAKE_EXECUTABLE_RUNTIME_D_FLAG_SEP)
set(CMAKE_EXECUTABLE_RUNTIME_D_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP})
endif()
if(NOT CMAKE_EXECUTABLE_RPATH_LINK_D_FLAG)
set(CMAKE_EXECUTABLE_RPATH_LINK_D_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG})
endif()
if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH)
set(CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_D_WITH_RUNTIME_PATH})
endif()
if(NOT CMAKE_INCLUDE_FLAG_D)
set(CMAKE_INCLUDE_FLAG_D ${CMAKE_INCLUDE_FLAG_D})
endif()
if(NOT CMAKE_INCLUDE_FLAG_SEP_D)
set(CMAKE_INCLUDE_FLAG_SEP_D ${CMAKE_INCLUDE_FLAG_SEP_D})
endif()
# for most systems a module is the same as a shared library
# so unless the variable CMAKE_MODULE_EXISTS is set just
# copy the values from the LIBRARY variables
if(NOT CMAKE_MODULE_EXISTS)
set(CMAKE_SHARED_MODULE_D_FLAGS ${CMAKE_SHARED_LIBRARY_D_FLAGS})
set(CMAKE_SHARED_MODULE_CREATE_D_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS})
endif(NOT CMAKE_MODULE_EXISTS)
# repeat for modules
if(NOT CMAKE_SHARED_MODULE_CREATE_D_FLAGS)
set(CMAKE_SHARED_MODULE_CREATE_D_FLAGS ${CMAKE_SHARED_MODULE_CREATE_D_FLAGS})
endif()
if(NOT CMAKE_SHARED_MODULE_D_FLAGS)
set(CMAKE_SHARED_MODULE_D_FLAGS ${CMAKE_SHARED_MODULE_D_FLAGS})
endif()
set(CMAKE_D_FLAGS_INIT "$ENV{DFLAGS} ${CMAKE_D_FLAGS_INIT}")
# avoid just having a space as the initial value for the cache
if(CMAKE_D_FLAGS_INIT STREQUAL " ")
set(CMAKE_D_FLAGS_INIT)
endif(CMAKE_D_FLAGS_INIT STREQUAL " ")
set(CMAKE_D_FLAGS "${CMAKE_D_FLAGS_INIT}" CACHE STRING
"Flags used by the D compiler during all build types.")
if(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
# default build type is none
if(NOT CMAKE_NO_BUILD_TYPE)
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE_INIT} CACHE STRING
"Choose the type of build, options are: None(CMAKE_D_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
endif(NOT CMAKE_NO_BUILD_TYPE)
set(CMAKE_D_FLAGS_DEBUG "${CMAKE_D_FLAGS_DEBUG_INIT}" CACHE STRING
"Flags used by the compiler during debug builds.")
set(CMAKE_D_FLAGS_MINSIZEREL "${CMAKE_D_FLAGS_MINSIZEREL_INIT}" CACHE STRING
"Flags used by the compiler during release minsize builds.")
set(CMAKE_D_FLAGS_RELEASE "${CMAKE_D_FLAGS_RELEASE_INIT}" CACHE STRING
"Flags used by the compiler during release builds (/MD /Ob1 /Oi /Ot /Oy /Gs will produce slightly less optimized but smaller files).")
set(CMAKE_D_FLAGS_RELWITHDEBINFO "${CMAKE_D_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING
"Flags used by the compiler during Release with Debug Info builds.")
endif(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
if(CMAKE_D_STANDARD_LIBRARIES_INIT)
set(CMAKE_D_STANDARD_LIBRARIES "${CMAKE_D_STANDARD_LIBRARIES_INIT}"
CACHE STRING "Libraries linked by default with all D applications.")
mark_as_advanced(CMAKE_D_STANDARD_LIBRARIES)
endif(CMAKE_D_STANDARD_LIBRARIES_INIT)
include(CMakeCommonLanguageInclude)
# now define the following rule variables
# CMAKE_D_CREATE_SHARED_LIBRARY
# CMAKE_D_CREATE_SHARED_MODULE
# CMAKE_D_CREATE_STATIC_LIBRARY
# CMAKE_D_COMPILE_OBJECT
# CMAKE_D_LINK_EXECUTABLE
# variables supplied by the generator at use time
# <TARGET>
# <TARGET_BASE> the target without the suffix
# <OBJECTS>
# <OBJECT>
# <LINK_LIBRARIES>
# <FLAGS>
# <LINK_FLAGS>
# D compiler information
# <CMAKE_D_COMPILER>
# <CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS>
# <CMAKE_SHARED_MODULE_CREATE_D_FLAGS>
# <CMAKE_D_LINK_FLAGS>
# Static library tools
# <CMAKE_AR>
# <CMAKE_RANLIB>
# < 2.8.10 backward compatibility
if(NOT CMAKE_PLATFORM_INFO_DIR)
set(CMAKE_PLATFORM_INFO_DIR ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY})
endif(NOT CMAKE_PLATFORM_INFO_DIR)
# create a D shared library
if(NOT CMAKE_D_CREATE_SHARED_LIBRARY)
set(CMAKE_D_CREATE_SHARED_LIBRARY
"<CMAKE_D_COMPILER> <CMAKE_SHARED_LIBRARY_D_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_D_FLAG><TARGET_SONAME> ${CMAKE_D_DASH_O}<TARGET> <OBJECTS> <LINK_LIBRARIES> ${DSTDLIB_FLAGS} ${CMAKE_D_STDLIBS}")
endif(NOT CMAKE_D_CREATE_SHARED_LIBRARY)
# create a D shared module just copy the shared library rule
if(NOT CMAKE_D_CREATE_SHARED_MODULE)
set(CMAKE_D_CREATE_SHARED_MODULE "${CMAKE_D_CREATE_SHARED_LIBRARY}")
endif(NOT CMAKE_D_CREATE_SHARED_MODULE)
if(NOT CMAKE_D_CREATE_STATIC_LIBRARY AND CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS)
set(CMAKE_D_CREATE_STATIC_LIBRARY
"<CMAKE_D_COMPILER> ${CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS} <OBJECTS> ${CMAKE_D_DASH_O}<TARGET>")
endif(NOT CMAKE_D_CREATE_STATIC_LIBRARY AND CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS)
# Create a static archive incrementally for large object file counts.
# If CMAKE_D_CREATE_STATIC_LIBRARY is set it will override these.
set(CMAKE_D_ARCHIVE_CREATE "<CMAKE_AR> cr <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_D_ARCHIVE_APPEND "<CMAKE_AR> r <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_D_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>")
# compile a D file into an object file
if(NOT CMAKE_D_COMPILE_OBJECT)
set(CMAKE_D_COMPILE_OBJECT
"<CMAKE_D_COMPILER> <FLAGS> ${CMAKE_D_DASH_O}<OBJECT> -c <SOURCE>")
endif(NOT CMAKE_D_COMPILE_OBJECT)
if(NOT CMAKE_D_LINK_EXECUTABLE)
set(CMAKE_D_LINK_EXECUTABLE
"<CMAKE_D_COMPILER> <FLAGS> <CMAKE_D_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> ${CMAKE_D_DASH_O}<TARGET> <LINK_LIBRARIES> ${CMAKE_D_STDLIBS}")
endif(NOT CMAKE_D_LINK_EXECUTABLE)
mark_as_advanced(
CMAKE_D_FLAGS
CMAKE_D_FLAGS_DEBUG
CMAKE_D_FLAGS_MINSIZEREL
CMAKE_D_FLAGS_RELEASE
CMAKE_D_FLAGS_RELWITHDEBINFO
)
set(CMAKE_D_INFORMATION_LOADED 1)

View File

@ -1,163 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
# Dragos Carp <dragos.carp@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 CMakeDetermineCCompiler.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
# determine the compiler to use for D programs
# NOTE, a generator may set CMAKE_D_COMPILER before
# loading this file to force a compiler.
# use environment variable DC first if defined by user, next use
# the cmake variable CMAKE_GENERATOR_D which can be defined by a generator
# as a default compiler
if(NOT CMAKE_D_COMPILER)
set(CMAKE_D_COMPILER_INIT NOTFOUND)
# prefer the environment variable DC
if($ENV{DC} MATCHES ".+")
get_filename_component(CMAKE_D_COMPILER_INIT $ENV{DC} PROGRAM PROGRAM_ARGS CMAKE_D_FLAGS_ENV_INIT)
if(CMAKE_D_FLAGS_ENV_INIT)
set(CMAKE_D_COMPILER_ARG1 "${CMAKE_D_FLAGS_ENV_INIT}" CACHE STRING "First argument to D compiler")
endif(CMAKE_D_FLAGS_ENV_INIT)
if(NOT EXISTS ${CMAKE_D_COMPILER_INIT})
MESSAGE(FATAL_ERROR "Could not find compiler set in environment variable C:\n$ENV{DC}.")
endif(NOT EXISTS ${CMAKE_D_COMPILER_INIT})
endif($ENV{DC} MATCHES ".+")
# next try prefer the compiler specified by the generator
if(CMAKE_GENERATOR_D)
if(NOT CMAKE_D_COMPILER_INIT)
set(CMAKE_D_COMPILER_INIT ${CMAKE_GENERATOR_D})
endif(NOT CMAKE_D_COMPILER_INIT)
endif(CMAKE_GENERATOR_D)
# finally list compilers to try
if(CMAKE_D_COMPILER_INIT)
set(CMAKE_D_COMPILER_LIST ${CMAKE_D_COMPILER_INIT})
else(CMAKE_D_COMPILER_INIT)
set(CMAKE_D_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}gdc ${_CMAKE_TOOLCHAIN_PREFIX}dmd)
endif(CMAKE_D_COMPILER_INIT)
# Find the compiler.
if(_CMAKE_USER_D_COMPILER_PATH)
find_program(CMAKE_D_COMPILER NAMES ${CMAKE_D_COMPILER_LIST} PATHS ${_CMAKE_USER_D_COMPILER_PATH} DOC "D compiler" NO_DEFAULT_PATH)
endif(_CMAKE_USER_D_COMPILER_PATH)
find_program(CMAKE_D_COMPILER NAMES ${CMAKE_D_COMPILER_LIST} DOC "D compiler")
if(CMAKE_D_COMPILER_INIT AND NOT CMAKE_D_COMPILER)
set(CMAKE_D_COMPILER "${CMAKE_D_COMPILER_INIT}" CACHE FILEPATH "D compiler" FORCE)
endif(CMAKE_D_COMPILER_INIT AND NOT CMAKE_D_COMPILER)
else(NOT CMAKE_D_COMPILER)
# we only get here if CMAKE_D_COMPILER was specified using -D or a pre-made CMakeCache.txt
# (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE
# if CMAKE_D_COMPILER is a list of length 2, use the first item as
# CMAKE_D_COMPILER and the 2nd one as CMAKE_D_COMPILER_ARG1
list(LENGTH CMAKE_D_COMPILER _CMAKE_D_COMPILER_LIST_LENGTH)
if("${_CMAKE_D_COMPILER_LIST_LENGTH}" EQUAL 2)
list(GET CMAKE_D_COMPILER 1 CMAKE_D_COMPILER_ARG1)
list(GET CMAKE_D_COMPILER 0 CMAKE_D_COMPILER)
endif("${_CMAKE_D_COMPILER_LIST_LENGTH}" EQUAL 2)
# if a compiler was specified by the user but without path,
# now try to find it with the full path
# if it is found, force it into the cache,
# if not, don't overwrite the setting (which was given by the user) with "NOTFOUND"
# if the C compiler already had a path, reuse it for searching the CXX compiler
get_filename_component(_CMAKE_USER_D_COMPILER_PATH "${CMAKE_D_COMPILER}" PATH)
if(NOT _CMAKE_USER_D_COMPILER_PATH)
find_program(CMAKE_D_COMPILER_WITH_PATH NAMES ${CMAKE_D_COMPILER})
mark_as_advanced(CMAKE_D_COMPILER_WITH_PATH)
if(CMAKE_D_COMPILER_WITH_PATH)
set(CMAKE_D_COMPILER ${CMAKE_D_COMPILER_WITH_PATH} CACHE STRING "D compiler" FORCE)
endif(CMAKE_D_COMPILER_WITH_PATH)
endif(NOT _CMAKE_USER_D_COMPILER_PATH)
endif(NOT CMAKE_D_COMPILER)
mark_as_advanced(CMAKE_D_COMPILER)
if(NOT _CMAKE_TOOLCHAIN_LOCATION)
get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_D_COMPILER}" PATH)
endif(NOT _CMAKE_TOOLCHAIN_LOCATION)
# Build a small source file to identify the compiler.
if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
set(CMAKE_D_COMPILER_ID_RUN 1)
set(CMAKE_D_PLATFORM_ID "Windows")
# TODO: Set the compiler id. It is probably MSVC but
# the user may be using an integrated Intel compiler.
# set(CMAKE_D_COMPILER_ID "MSVC")
endif(${CMAKE_GENERATOR} MATCHES "Visual Studio")
if(NOT CMAKE_D_COMPILER_ID_RUN)
set(CMAKE_D_COMPILER_ID_RUN 1)
# Each entry in this list is a set of extra flags to try
# adding to the compile line to see if it helps produce
# a valid identification file.
set(CMAKE_D_COMPILER_ID_TEST_FLAGS
# Try compiling to an object file only.
"-c"
)
# Try to identify the compiler.
set(CMAKE_D_COMPILER_ID)
find_file(CMAKE_PLATFORM_ID_CONTENT_FILE CMakePlatformId.di.in PATHS ${CMAKE_ROOT}/Modules
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
file(READ ${CMAKE_PLATFORM_ID_CONTENT_FILE} CMAKE_D_COMPILER_ID_PLATFORM_CONTENT)
find_file(CMAKE_D_COMPILER_ID_FILE_IN CMakeDCompilerId.d.in PATHS ${CMAKE_ROOT}/Modules
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
# Workaround for bug http://public.kitware.com/Bug/view.php?id=14481
# if CMAKE_MODULE_PATH is used, then patch ${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake
get_filename_component(CMAKE_D_COMPILER_ID_FILE_IN_PATH ${CMAKE_D_COMPILER_ID_FILE_IN} PATH)
if(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake)
else(CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
file(READ ${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT)
STRING(REPLACE "file(READ \${CMAKE_ROOT}/Modules/\${src}.in ID_CONTENT_IN)"
"find_file(src_in \${src}.in PATHS \${CMAKE_ROOT}/Modules \${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
file(READ \${src_in} ID_CONTENT_IN)
unset(src_in CACHE)"
CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT_PATCHED ${CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT})
file(WRITE ${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerId.cmake
${CMAKE_DETERMINE_COMPILER_ID_CMAKE_CONTENT_PATCHED})
include(${CMAKE_PLATFORM_INFO_DIR}/CMakeDetermineCompilerId.cmake)
endif(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_D_COMPILER_ID_FILE_IN_PATH STREQUAL ${CMAKE_ROOT}/Modules)
CMAKE_DETERMINE_COMPILER_ID(D DFLAGS CMakeDCompilerId.d)
unset(CMAKE_D_COMPILER_ID_FILE_IN CACHE)
unset(CMAKE_PLATFORM_ID_CONTENT_FILE CACHE)
# Set old compiler and platform id variables.
if("${CMAKE_D_COMPILER_ID}" MATCHES "GNU")
set(CMAKE_COMPILER_IS_GDC 1)
endif("${CMAKE_D_COMPILER_ID}" MATCHES "GNU")
if("${CMAKE_D_PLATFORM_ID}" MATCHES "MinGW")
set(CMAKE_COMPILER_IS_MINGW 1)
elseif("${CMAKE_D_PLATFORM_ID}" MATCHES "Cygwin")
set(CMAKE_COMPILER_IS_CYGWIN 1)
endif("${CMAKE_D_PLATFORM_ID}" MATCHES "MinGW")
endif(NOT CMAKE_D_COMPILER_ID_RUN)
include(CMakeFindBinUtils)
if(MSVC_D_ARCHITECTURE_ID)
set(SET_MSVC_D_ARCHITECTURE_ID
"set(MSVC_D_ARCHITECTURE_ID ${MSVC_D_ARCHITECTURE_ID})")
endif(MSVC_D_ARCHITECTURE_ID)
# configure variables set in this file for fast reload later on
find_file(CMAKE_D_COMPILER_CMAKE_IN CMakeDCompiler.cmake.in PATHS ${CMAKE_ROOT}/Modules
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
configure_file(${CMAKE_D_COMPILER_CMAKE_IN}
${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake
@ONLY IMMEDIATE # IMMEDIATE must be here for compatibility mode <= 2.0
)
set(CMAKE_D_COMPILER_ENV_VAR "DC")

View File

@ -1,41 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
# Dragos Carp <dragos.carp@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
PROJECT (cmake-d NONE)
SET (MOD_SRCS
CMakeDCompiler.cmake.in
CMakeDCompilerId.d.in
CMakeDInformation.cmake
CMakeDCompilerABI.d
CMakeTestDCompiler.cmake
CMakeDetermineDCompiler.cmake
FindGDCPath.cmake
UseDDoc.cmake
UseDDeps.cmake
UseDub.cmake
dependencies.cmake
UseDUnittest.cmake
FindPhobos.cmake
CMakePlatformId.di.in
)
SET (PLAT_SRCS
Platform/Linux-dmd.cmake
Platform/Linux-gdc.cmake
Platform/Linux-ldc2.cmake
Platform/Windows-dmd.cmake
Platform/Windows-gdc.cmake
)
INSTALL (FILES ${MOD_SRCS} DESTINATION ${CMAKE_ROOT}/Modules)
INSTALL (FILES ${PLAT_SRCS} DESTINATION ${CMAKE_ROOT}/Modules/Platform)

View File

@ -1,118 +0,0 @@
/* Identify known platforms by name. */
version(linux)
{
const string PLATFORM_ID = "Linux";
}
else version(Cygwin)
{
const string PLATFORM_ID = "Cygwin";
}
else version(MinGW)
{
const string PLATFORM_ID = "MinGW";
}
else version(OSX)
{
const string PLATFORM_ID = "Darwin";
}
else version(Windows)
{
const string PLATFORM_ID = "Windows";
}
else version(FreeBSD)
{
const string PLATFORM_ID = "FreeBSD";
}
else version(NetBSD)
{
const string PLATFORM_ID = "NetBSD";
}
else version(OpenBSD)
{
const string PLATFORM_ID = "OpenBSD";
}
else version(NetBSD)
{
const string PLATFORM_ID = "NetBSD";
}
else version(Solaris)
{
const string PLATFORM_ID = "SunOS";
}
else version(AIX)
{
const string PLATFORM_ID = "AIX";
}
else version(Haiku)
{
const string PLATFORM_ID = "Haiku";
}
else version(AIX)
{
const string PLATFORM_ID = "BeOS";
}
else version(AIX)
{
const string PLATFORM_ID = "QNX";
}
else version(AIX)
{
const string PLATFORM_ID = "Tru64";
}
else version(AIX)
{
const string PLATFORM_ID = "RISCos";
}
else
{
const string PLATFORM_ID = "";
}
/* For windows compilers MSVC and Intel we can determine
the architecture of the compiler being used. This is because
the compilers do not have flags that can change the architecture,
but rather depend on which compiler is being used
*/
version(IA64)
{
const string ARCHITECTURE_ID = "IA64";
}
else version(X86_64)
{
const string ARCHITECTURE_ID = "x64";
}
else version(X86)
{
const string ARCHITECTURE_ID = "X86";
}
else version(ARM)
{
const string ARCHITECTURE_ID = "ARM";
}
else version(MIPS32)
{
const string ARCHITECTURE_ID = "MIPS";
}
else version(MIPS64)
{
const string ARCHITECTURE_ID = "MIPS";
}
else version(SH)
{
const string ARCHITECTURE_ID = "SHx";
}
else version(SH64)
{
const string ARCHITECTURE_ID = "SHx";
}
else
{
const string ARCHITECTURE_ID = "";
}
/* Construct the string literal in pieces to prevent the source from
getting matched. Store it in a pointer rather than an array
because some compilers will just produce instructions to fill the
array rather than assigning a pointer to a static array. */
string info_platform = "INFO" ":" "platform[" ~ PLATFORM_ID ~ "]";
string info_arch = "INFO" ":" "arch[" ~ ARCHITECTURE_ID ~"]";

View File

@ -1,78 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
# Dragos Carp <dragos.carp@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 CMakeTestCCompiler.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
include(CMakeTestCompilerCommon)
# This file is used by EnableLanguage in cmGlobalGenerator to
# determine that that selected D compiler can actually compile
# and link the most basic of programs. If not, a fatal error
# is set and cmake stops processing commands and will not generate
# any makefiles or projects.
if(NOT CMAKE_D_COMPILER_WORKS)
PrintTestCompilerStatus("D" "")
file(WRITE ${CMAKE_PLATFORM_INFO_DIR}/CMakeTmp/testDCompiler.d
"int main(char[][] args)\n"
"{return args.sizeof-1;}\n")
try_compile(CMAKE_D_COMPILER_WORKS ${CMAKE_BINARY_DIR}
${CMAKE_PLATFORM_INFO_DIR}/CMakeTmp/testDCompiler.d
OUTPUT_VARIABLE OUTPUT)
set(D_TEST_WAS_RUN 1)
endif(NOT CMAKE_D_COMPILER_WORKS)
if(NOT CMAKE_D_COMPILER_WORKS)
PrintTestCompilerStatus("D" " -- broken")
message(STATUS "To force a specific D compiler set the DC environment variable")
message(STATUS " ie - export DC=\"/usr/bin/dmd\"")
file(APPEND ${CMAKE_PLATFORM_INFO_DIR}/CMakeError.log
"Determining if the D compiler works failed with "
"the following output:\n${OUTPUT}\n\n")
# if the compiler is broken make sure to remove the platform file
# since Windows-cl configures both c/cxx files both need to be removed
# when c or c++ fails
file(REMOVE ${CMAKE_PLATFORM_INFO_DIR}/CMakeDPlatform.cmake)
message(FATAL_ERROR "The D compiler \"${CMAKE_D_COMPILER}\" "
"is not able to compile a simple test program.\nIt fails "
"with the following output:\n ${OUTPUT}\n\n"
"CMake will not be able to correctly generate this project.")
else(NOT CMAKE_D_COMPILER_WORKS)
if(D_TEST_WAS_RUN)
message(STATUS "Check for working D compiler: ${CMAKE_D_COMPILER} -- works")
file(APPEND ${CMAKE_PLATFORM_INFO_DIR}/CMakeOutput.log
"Determining if the D compiler works passed with "
"the following output:\n${OUTPUT}\n\n")
endif(D_TEST_WAS_RUN)
set(CMAKE_D_COMPILER_WORKS 1 CACHE INTERNAL "")
if(CMAKE_D_COMPILER_FORCED)
# The compiler configuration was forced by the user.
# Assume the user has configured all compiler information.
else(CMAKE_D_COMPILER_FORCED)
# Try to identify the ABI and configure it into CMakeDCompiler.cmake
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake)
find_file(CMAKE_D_COMPILER_ABI_SRC CMakeDCompilerABI.d PATHS ${CMAKE_ROOT}/Modules
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
CMAKE_DETERMINE_COMPILER_ABI(D ${CMAKE_D_COMPILER_ABI_SRC})
find_file(CMAKE_D_COMPILER_CMAKE_IN CMakeDCompiler.cmake.in PATHS ${CMAKE_ROOT}/Modules
${CMAKE_MODULE_PATH} NO_DEFAULT_PATH)
configure_file(
${CMAKE_D_COMPILER_CMAKE_IN}
${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake
@ONLY IMMEDIATE # IMMEDIATE must be here for compatibility mode <= 2.0
)
include(${CMAKE_PLATFORM_INFO_DIR}/CMakeDCompiler.cmake)
unset(CMAKE_D_COMPILER_ABI_SRC CACHE)
unset(CMAKE_D_COMPILER_CMAKE_IN CACHE)
endif(CMAKE_D_COMPILER_FORCED)
endif(NOT CMAKE_D_COMPILER_WORKS)

View File

@ -1,49 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2013, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
# Dragos Carp <dragos.carp@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# - Find GDC Include Path
#
# GDC_INCLUDE_PATH = path to where object.d is found
#
set(GDC_POSSIBLE_INCLUDE_PATHS
/usr/include/d/4.8.2
/usr/include/d/4.8.1
/usr/include/d/4.8.0
/usr/include/d/4.7.3
/usr/include/d/4.7.2
/usr/include/d/4.7.1
/usr/include/d/4.7.0
/usr/include/d/4.2.1
/usr/include/d/4.2.0
/usr/include/d/4.1.2
/usr/include/d/4.1.1
/usr/include/d/4.1.0
/usr/include/d/4.0.4
/usr/include/d/4.0.3
/usr/include/d/4.0.2
/usr/include/d/4.0.1
/usr/include/d/4.0.0
/usr/include/d/4.0.6
/usr/include/d/4.0.5
/usr/include/d/3.4.4
/usr/include/d/3.4.3
/usr/include/d/3.4.2
/usr/include/d/3.4.1
/usr/include/d/3.4.0
)
find_path(GDC_INCLUDE_PATH object.d
${GDC_POSSIBLE_INCLUDE_PATHS})
mark_as_advanced(
GDC_INCLUDE_PATH
)

View File

@ -1,5 +0,0 @@
find_path(PHOBOS_INCLUDE_DIR std/file.d)
find_library(PHOBOS_LIBRARY phobos2)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Phobos DEFAULT_MSG PHOBOS_LIBRARY PHOBOS_INCLUDE_DIR)

View File

@ -1,67 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 gcc.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
#SET(DSTDLIB_FLAGS "-version=Phobos")
IF(CMAKE_D_BUILD_DOCS)
SET(DDOC_FLAGS "-D -Dddocumentation")
#FOREACH(item ${CMAKE_D_DDOC_FILES})
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
#ENDFOREACH(item)
ENDIF(CMAKE_D_BUILD_DOCS)
SET(CMAKE_D_OUTPUT_EXTENSION .o)
SET(CMAKE_D_DASH_O "-of")
SET(CMAKE_BASE_NAME dmd)
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared -defaultlib=libphobos2.so") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
SET(CMAKE_SHARED_LIBRARY_SONAME_D_FLAG "-L-soname=")
SET(CMAKE_SHARED_LIBRARY_RPATH_LINK_D_FLAG "-L-rpath=")
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
SET(CMAKE_D_COMPILE_OPTIONS_PIC "-fPIC")
SET(CMAKE_LINK_LIBRARY_SUFFIX "")
SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
SET(CMAKE_EXECUTABLE_SUFFIX "") # .exe
SET(CMAKE_DL_LIBS "dl")
SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
#SET(CMAKE_D_STDLIBS "-L-lphobos2 -L-lpthread -L-lm -defaultlib=libphobos2.so")
#SET (CMAKE_D_FLAGS_INIT "-version=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS} ${DSTDLIB_TYPE} -I$ENV{D_PATH}/include -I$ENV{D_PATH}/import -I${CMAKE_PROJECT_SOURCE_DIR}")
SET (CMAKE_D_FLAGS_INIT "")
SET (CMAKE_D_LINK_FLAGS "")
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug -L--export-dynamic ${DDOC_FLAGS}")
# SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}")
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")
# SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")

View File

@ -1,41 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 gcc.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
SET(CMAKE_D_DASH_O "-o")
SET(CMAKE_BASE_NAME gdc)
IF(CMAKE_D_USE_TANGO)
SET(DSTDLIB_FLAGS "-fversion=Tango")
ENDIF(CMAKE_D_USE_TANGO)
IF(CMAKE_D_USE_PHOBOS)
SET(DSTDLIB_FLAGS "-fversion=Phobos")
ENDIF(CMAKE_D_USE_PHOBOS)
IF(CMAKE_D_BUILD_DOCS)
SET(DDOC_FLAGS "-fdoc -fdoc-dir=documentation")
FOREACH(item ${CMAKE_D_DDOC_FILES})
SET(DDOC_FLAGS "${DDOC_FLAGS} -fdoc-inc=${item}")
ENDFOREACH(item)
ENDIF(CMAKE_D_BUILD_DOCS)
#SET (CMAKE_D_FLAGS_INIT "-fversion=Posix -fversion=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS}")
SET (CMAKE_D_FLAGS_INIT "")
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O3 -fomit-frame-pointer -fweb -frelease -finline-functions ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}")
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
#SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I

View File

@ -1,63 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 gcc.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
#SET(DSTDLIB_FLAGS "-version=Phobos")
IF(CMAKE_D_BUILD_DOCS)
SET(DDOC_FLAGS "-D -Dddocumentation")
#FOREACH(item ${CMAKE_D_DDOC_FILES})
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
#ENDFOREACH(item)
ENDIF(CMAKE_D_BUILD_DOCS)
SET(CMAKE_D_OUTPUT_EXTENSION .o)
SET(CMAKE_D_DASH_O "-of")
SET(CMAKE_BASE_NAME ldc2)
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
SET(CMAKE_LINK_LIBRARY_SUFFIX "")
SET(CMAKE_STATIC_LIBRARY_PREFIX "lib")
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
SET(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so
SET(CMAKE_EXECUTABLE_SUFFIX "") # .exe
SET(CMAKE_DL_LIBS "dl")
SET(CMAKE_FIND_LIBRARY_PREFIXES "lib")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
#SET(CMAKE_D_STDLIBS "-L-lphobos2 -L-lpthread -L-lm" )
#SET (CMAKE_D_FLAGS_INIT "-version=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS} ${DSTDLIB_TYPE} -I$ENV{D_PATH}/include -I$ENV{D_PATH}/import -I${CMAKE_PROJECT_SOURCE_DIR}")
SET (CMAKE_D_FLAGS_INIT "")
# DMD can only produce 32-bit binaries for now
SET (CMAKE_D_LINK_FLAGS "")
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug -L--export-dynamic ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O -release -inline ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}")
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")
# SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")

View File

@ -1,56 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 gcc.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
#SET(DSTDLIB_FLAGS "-version=Phobos")
IF(CMAKE_D_BUILD_DOCS)
SET(DDOC_FLAGS "-D -Dddocumentation")
#FOREACH(item ${CMAKE_D_DDOC_FILES})
# SET(DDOC_FLAGS "${DDOC_FLAGS} ${item}")
#ENDFOREACH(item)
ENDIF(CMAKE_D_BUILD_DOCS)
SET(CMAKE_D_OUTPUT_EXTENSION .obj)
SET(CMAKE_D_DASH_O "-of")
SET(CMAKE_BASE_NAME dmd)
SET(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib")
SET(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic
SET(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared
SET(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath
SET(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty
SET(CMAKE_INCLUDE_FLAG_D "-I") # -I
SET(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty
SET(CMAKE_LIBRARY_PATH_FLAG "-L-L")
SET(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/"
SET(CMAKE_LINK_LIBRARY_FLAG "-L-l")
SET(CMAKE_STATIC_LIBRARY_PREFIX "") #
SET(CMAKE_STATIC_LIBRARY_SUFFIX ".lib") # lib
SET(CMAKE_SHARED_LIBRARY_PREFIX "") #
SET(CMAKE_SHARED_LIBRARY_SUFFIX ".dll") # .dll
SET(CMAKE_EXECUTABLE_SUFFIX ".exe") # .exe
SET(CMAKE_DL_LIBS "dl")
SET(CMAKE_FIND_LIBRARY_PREFIXES "")
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib" ".dll")
SET (CMAKE_D_FLAGS_INIT "")
# DMD can only produce 32-bit binaries for now
SET (CMAKE_D_LINK_FLAGS "")
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g -debug ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O -release -inline ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g ${DDOC_FLAGS}")
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -of<ASSEMBLY_SOURCE>")

View File

@ -1,35 +0,0 @@
#
# CMakeD - CMake module for D Language
#
# Copyright (c) 2007, Selman Ulug <selman.ulug@gmail.com>
# Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Modified from CMake 2.6.5 gcc.cmake
# See http://www.cmake.org/HTML/Copyright.html for details
#
IF(CMAKE_D_USE_TANGO)
SET(DSTDLIB_FLAGS "-fversion=Tango")
ENDIF(CMAKE_D_USE_TANGO)
IF(CMAKE_D_USE_PHOBOS)
SET(DSTDLIB_FLAGS "-fversion=Phobos")
ENDIF(CMAKE_D_USE_PHOBOS)
IF(CMAKE_D_BUILD_DOCS)
SET(DDOC_FLAGS "-fdoc -fdoc-dir=documentation")
FOREACH(item ${CMAKE_D_DDOC_FILES})
SET(DDOC_FLAGS "${DDOC_FLAGS} -fdoc-inc=${item}")
ENDFOREACH(item)
ENDIF(CMAKE_D_BUILD_DOCS)
SET (CMAKE_D_FLAGS_INIT "-fversion=Win -fversion=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS}")
SET (CMAKE_D_FLAGS_DEBUG_INIT "-g ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELEASE_INIT "-O3 -fomit-frame-pointer -fweb -frelease -finline-functions ${DDOC_FLAGS}")
SET (CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}")
# SET (CMAKE_D_CREATE_PREPROCESSED_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
SET (CMAKE_D_CREATE_ASSEMBLY_SOURCE "<CMAKE_D_COMPILER> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
#SET (CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ")

View File

@ -1,64 +0,0 @@
# Dependency tracking for D
#
# Copyright (c) 2010 Jens Mueller <jens.k.mueller@gmx.de>
#
# All rights reserved.
#
# See LICENSE for details.
#
macro(add_executable_with_dependencies _target)
# extract D source files from arguments
foreach(file ${ARGV})
if(${file} MATCHES "\\.d$")
list(APPEND d_source_files ${file})
endif()
endforeach()
#message("D files in arguments: ${d_source_files}")
foreach(file IN LISTS d_source_files)
set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
set(dependency_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${file}-depend.cmake")
set(dependency_files ${dependency_files} ${dependency_file})
#message("Checking dependencies for ${source_file}")
#message("Put into ${dependency_file}")
# TODO
# better way to get the included directories
get_directory_property(include_dirs INCLUDE_DIRECTORIES)
set(INCLUDES )
foreach(include_dir IN LISTS include_dirs)
list(APPEND INCLUDES "${CMAKE_INCLUDE_FLAG_D}${include_dir}")
endforeach()
execute_process(
COMMAND ${CMAKE_COMMAND}
-D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}"
-D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}"
-D "include_directories:STRING=${INCLUDES}"
-D "source_file:STRING=${source_file}"
-D "dependency_file:STRING=${dependency_file}"
-P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path
)
# load dependencies from file
include(${dependency_file})
#message("DEPENDENCIES ${D_DMD_DEPEND}")
add_custom_command(
OUTPUT ${dependency_file}
DEPENDS ${D_DMD_DEPEND}
COMMAND ${CMAKE_COMMAND}
-D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}"
-D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}"
-D "include_directories:STRING=${INCLUDES}"
-D "source_file:STRING=${source_file}"
-D "dependency_file:STRING=${dependency_file}"
-P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path
COMMENT "Scanning for dependencies"
)
endforeach()
add_executable(${ARGV} ${dependency_files})
endmacro(add_executable_with_dependencies)

View File

@ -1,73 +0,0 @@
# check if the user wants to build ddocs
#
# Copyright (c) 2007 Tim Burrell <tim.burrell@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
# Do not build documentation by default
if (NOT CMAKE_D_BUILD_DOCS)
set(CMAKE_D_BUILD_DOCS False CACHE BOOLEAN TRUE FORCE)
else (NOT CMAKE_D_BUILD_DOCS)
# check for specified ddoc files
# default to the candydoc usual
set(CMAKE_D_BUILD_DOCS True CACHE BOOLEAN FALSE FORCE)
if (NOT CMAKE_D_DDOC_FILES)
set(CMAKE_D_DDOC_FILES "documentation/candydoc/candy.ddoc;documentation/candydoc/modules.ddoc" CACHE STRING FALSE FORCE)
else (NOT CMAKE_D_DDOC_FILES)
set(CMAKE_D_DDOC_FILES "${CMAKE_D_DDOC_FILES}" CACHE STRING FALSE FORCE)
endif (NOT CMAKE_D_DDOC_FILES)
# copy the candydoc files
file(GLOB_RECURSE CANDY_DOC_FILES "${CMAKE_CURRENT_SOURCE_DIR}/candydoc/*")
foreach(item ${CANDY_DOC_FILES})
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" item ${item})
configure_file(${item} ${CMAKE_CURRENT_BINARY_DIR}/documentation/${item} COPYONLY)
endforeach(item)
# create modules.ddoc
file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/*.d")
set(first True)
foreach(item ${sources})
# first make sure we're not config.d
string(REGEX MATCH "config\\.d" ignore ${item})
if (NOT ${ignore} MATCHES "")
# fix up the output
string(REGEX REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" item ${item})
string(REGEX REPLACE "\\.d" ".html" htmlFile ${item})
string(REGEX REPLACE "^.*/" "" htmlFile ${htmlFile})
string(REGEX REPLACE "\\.d" "" item ${item})
string(REGEX REPLACE "/" "." item ${item})
if (first)
set(modules "${item}")
set(first False)
set(CMAKE_D_DDOC_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/documentation/${htmlFile}" CACHE STRING FALSE FORCE)
else (first)
set(modules "${modules};${item}")
set(CMAKE_D_DDOC_CLEAN_FILES "${CMAKE_D_DDOC_CLEAN_FILES}" "${CMAKE_CURRENT_BINARY_DIR}/documentation/${htmlFile}" CACHE STRING FALSE FORCE)
endif (first)
endif (NOT ${ignore} MATCHES "")
endforeach(item)
# create formatted modules string
set(modString "MODULES = \n")
foreach(item ${modules})
set(modString "${modString}\t$(MODULE ${item})\n")
endforeach(item)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/documentation/candydoc/modules.ddoc" ${modString})
# create index.html
set(modString "<html><head><title>${PROJECT_NAME} API Documentation</title></head><body>\n")
set(modString "<h>${PROJECT_NAME} API Documentation:<br /></h>\n")
set(modString "${modString}<ul>\n")
foreach(item ${modules})
string(REGEX REPLACE "[a-z0-9]*\\." "" filename ${item})
set(modString "${modString}\t<li> <a href=\"${filename}.html\">${item}</a> </li>\n")
endforeach(item)
set(modString "${modString}</ul>\n")
set(modString "${modString}</body></html>\n")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/documentation/index.html" ${modString})
endif (NOT CMAKE_D_BUILD_DOCS)

View File

@ -1,37 +0,0 @@
# Adding D unittests
#
# Copyright (c) 2010 Jens Mueller <jens.k.mueller@gmx.de>
#
# All rights reserved.
#
# See LICENSE for details.
#
macro(add_unittests _sourcefile)
set(_testname "${_sourcefile}")
set(main_unittest "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/unittest.d")
set(_source_file "${CMAKE_CURRENT_SOURCE_DIR}/${_sourcefile}")
#message("main_unittest ${main_unittest}")
#message("testname ${_testname}")
#message("_sourcefile ${_source_file}")
if(NOT EXISTS ${main_unittest})
file(WRITE ${main_unittest} "// Generated by UseDUnittest.cmake\nint main() { return 0; }")
endif()
# TODO
# better way to get the included directories
get_directory_property(include_dirs INCLUDE_DIRECTORIES)
set(INCLUDES )
foreach(include_dir IN LISTS include_dirs)
list(APPEND INCLUDES "${CMAKE_INCLUDE_FLAG_D}${include_dir}")
endforeach()
separate_arguments(CMAKE_D_FLAGS)
add_test(NAME ${_testname}
COMMAND ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${INCLUDES} ${main_unittest} -unittest -run ${_source_file})
endmacro(add_unittests)

View File

@ -1,84 +0,0 @@
# This modules add functions for downloading and building dub dependencies.
# This code sets the following variables and functions:
#
# DUB_DIRECTORY = the full path to Dub pacakges
#
# DubProject_Add(<dub_package> [version])
#
#============================================================================
# Copyright (c) 2014 Dragos Carp <dragos.carp@gmail.com>
#
# All rights reserved.
#
# See LICENSE for details.
#
if(NOT DUB_DIRECTORY)
set(DUB_DIRECTORY ${CMAKE_BINARY_DIR}/UseDub CACHE PATH "Dub packages directory")
endif(NOT DUB_DIRECTORY)
set(DUB_REGISTRY "http://code.dlang.org/packages")
file(MAKE_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
if(NOT CMAKE_D_COMPILER)
message(FATAL_ERROR "UseDub needs a D compiler or use it in a D project.")
endif(NOT CMAKE_D_COMPILER)
#compile json parsers
if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl)
find_file(DUB_GET_PACKAGE_URL_D_SRC "DubUrl.d"
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
PATH_SUFFIXES "UseDub")
find_file(SEMVER_SRC "semver.d"
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
PATH_SUFFIXES "UseDub")
get_filename_component(SEMVER_PATH ${SEMVER_SRC} PATH)
execute_process(COMMAND ${CMAKE_D_COMPILER} -I${SEMVER_PATH} ${DUB_GET_PACKAGE_URL_D_SRC} ${SEMVER_SRC}
WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
unset(DUB_GET_PACKAGE_URL_D_SRC CACHE)
endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl)
if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake)
find_file(DUB_PACKAGE_TO_CMAKE_D_SRC "DubToCMake.d"
PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH
PATH_SUFFIXES "UseDub")
execute_process(COMMAND ${CMAKE_D_COMPILER} ${DUB_PACKAGE_TO_CMAKE_D_SRC}
WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp)
unset(DUB_PACKAGE_TO_CMAKE_D_SRC CACHE)
endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake)
include(ExternalProject)
function(DubProject_Add name)
if(NOT EXISTS ${DUB_DIRECTORY}/${name}.json)
file(DOWNLOAD ${DUB_REGISTRY}/${name}.json ${DUB_DIRECTORY}/${name}.json STATUS status)
list(GET status 0 statusCode)
if(NOT statusCode EQUAL 0)
file(REMOVE ${DUB_DIRECTORY}/${name}.json)
message(FATAL_ERROR "Failed to download ${DUB_REGISTRY}/${name}.json")
endif(NOT statusCode EQUAL 0)
endif(NOT EXISTS ${DUB_DIRECTORY}/${name}.json)
if(${ARGC} GREATER 1)
execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -t ${ARGN}
WORKING_DIRECTORY ${DUB_DIRECTORY})
else(${ARGC} GREATER 1)
execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json
WORKING_DIRECTORY ${DUB_DIRECTORY})
endif(${ARGC} GREATER 1)
include(${DUB_DIRECTORY}/${name}.cmake)
ExternalProject_Add(${name}
DOWNLOAD_DIR ${DUB_DIRECTORY}/archive/${name}
SOURCE_DIR ${DUB_DIRECTORY}/source/${name}
URL ${DUB_PACKAGE_URL}
PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -p package.json
INSTALL_DIR ${DUB_DIRECTORY}/export
CMAKE_CACHE_ARGS
-DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DDUB_DIRECTORY:PATH=${DUB_DIRECTORY})
include_directories(${DUB_DIRECTORY}/source/${name}/source ${DUB_DIRECTORY}/source/${name}/src)
endfunction()

View File

@ -1,103 +0,0 @@
import std.file;
import std.getopt;
import std.json;
import std.stdio;
import std.string;
int main(string[] args)
{
string dubFile = "dub.json";
string cmakeFile = "CMakeLists.txt";
getopt(args,
"package|p", &dubFile,
"output|o", &cmakeFile);
if (!exists(dubFile))
{
stderr.writefln("Cannot find file: '%s'", dubFile);
return -1;
}
string json = readText(dubFile);
JSONValue root = parseJSON(json);
string target = root["targetName"].str;
string cmake = q"<
cmake_minimum_required(VERSION 2.8)
project(%1$s D)
find_file(APP_MAIN_FILE
NAMES app.d main.d %1$s/main.d %1$s/app.d
PATHS source src NO_DEFAULT_PATH)
file(GLOB_RECURSE SRC_FILES source/*.d src/*.d)
if(APP_MAIN_FILE)
list(REMOVE_ITEM SRC_FILES ${APP_MAIN_FILE})
endif(APP_MAIN_FILE)
include_directories(source src)
>".format(root["name"].str);
switch ("targetType" in root.object ? root["targetType"].str : "autodetect")
{
case "autodetect":
cmake ~= q"<
if(APP_MAIN_FILE)
add_executable(%1$s ${SRC_FILES} ${APP_MAIN_FILE})
else(APP_MAIN_FILE)
add_library(%1$s ${SRC_FILES})
endif(APP_MAIN_FILE)
>".format(target);
break;
case "none":
break;
case "executable":
cmake ~= q"<
add_executable(%s ${SRC_FILES} ${APP_MAIN_FILE})
>".format(target);
break;
case "library":
cmake ~= q"<
add_library(%s ${SRC_FILES})
>".format(target);
break;
case "sourceLibrary":
break;
case "staticLibrary":
cmake ~= q"<
add_library(%s STATIC ${SRC_FILES})
>".format(target);
break;
case "dynamicLibrary":
cmake ~= q"<
add_library(%s SHARED ${SRC_FILES})
>".format(target);
break;
default:
assert(false, "Unknown targetType");
break;
}
cmake ~= q"<
install(TARGETS %s
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
>".format(target);
if ("dependencies" in root.object)
{
cmake ~= "\ninclude(UseDub)\n";
foreach (dependency, version_; root["dependencies"].object)
{
cmake ~= "DubProject_Add(%s %s)\n".format(dependency, version_.str);
}
cmake ~= "\nadd_dependencies(%s %-(%s %))\n".format(target, root["dependencies"].object.keys);
}
std.file.write(cmakeFile, cmake);
return 0;
}

View File

@ -1,158 +0,0 @@
import std.algorithm;
import std.array;
import std.file;
import std.getopt;
import std.json;
import std.stdio;
import std.string;
import semver;
/**
* Finds the best match of $(D range) in $(D choices) versions list.
*
* Params:
* range = Match criteria.
* choices = Versions list it is matched against.
*
* Returns:
* Best match in $(D choices) or empty string if no match is found.
*
* See_Also:
* $(WEB https://github.com/npm/npm/blob/master/doc/misc/semver.md#ranges Ranges definition)
*/
string matchVersion(string range, string[] choices)
{
foreach (ref choice; choices)
{
choice.skipOver('~');
}
if (range.skipOver('~'))
{
foreach (choice; choices)
{
if (choice.startsWith(range))
return choice;
}
return "";
}
return "";
}
unittest
{
}
int main(string[] args)
{
string registryFile = "";
string packageVersion = "";
bool listVersions;
string outputPath = ".";
getopt(args,
"package|p", &registryFile,
"tag|t", &packageVersion,
"list|l", &listVersions,
"output|o", &outputPath);
if (registryFile.empty)
{
stderr.writeln("Package registry file (<package_name>.json) need to be specified.");
return -1;
}
if (!exists(registryFile) && !registryFile.endsWith(".json"))
registryFile ~= ".json";
if (!exists(registryFile))
{
stderr.writefln("Package registry file '%s' not found.", registryFile);
return -1;
}
string json = readText(registryFile);
JSONValue node;
JSONValue root = parseJSON(json);
if (packageVersion.empty)
{
packageVersion = "*";
}
auto versionRange = SemVerRange(packageVersion);
if (!versionRange.valid)
{
// try exact string match
auto range = root["versions"].array.find!`a["version"].str == b`(packageVersion);
if (!range.empty)
{
node = range[0];
}
else
{
stderr.writefln("%s has no version tagged %s.", root["name"].str, packageVersion);
return -1;
}
}
else
{
string nodeVersionString(JSONValue node)
{
auto ver = node["version"].str;
ver.skipOver('~');
return ver;
}
auto nodes = root["versions"].array.filter!(a => SemVer(nodeVersionString(a)).valid).array;
auto maxVersion = nodes.map!(a => SemVer(nodeVersionString(a))).array.maxSatisfying(versionRange);
if (maxVersion.valid)
{
auto range = nodes.find!((a, b) => SemVer(nodeVersionString(a)) == b)(maxVersion);
assert(!range.empty);
node = range[0];
}
else
{
stderr.writefln("%s has no version %s.", root["name"].str, versionRange);
return -1;
}
}
if (registryFile.endsWith(".json"))
{
registryFile = registryFile[0..$-5];
}
if (listVersions)
{
writefln("Package '%s'", registryFile);
foreach(n; root["versions"].array)
{
writefln(" %s => %s", n["version"].str, n["downloadUrl"].str);
}
}
packageVersion = node["version"].str;
auto packageUrl = node["downloadUrl"].str;
auto packageName = root["name"].str;
if (!outputPath.isDir)
{
stderr.writefln("Output path '%s' need to be a directory.", outputPath);
return -1;
}
string output = "set(DUB_PACKAGE_NAME, \"%s\")\n".format(packageName) ~
"set(DUB_PACKAGE_VERSION \"%s\")\n".format(packageVersion) ~
"set(DUB_PACKAGE_URL \"%s\")\n".format(packageUrl);
std.file.write(outputPath ~ "/" ~ packageName ~ ".cmake", output);
return 0;
}

View File

@ -1,612 +0,0 @@
import std.algorithm;
import std.array;
import std.conv;
import std.range;
import std.regex;
import std.stdio;
import std.string;
enum ReleaseType
{
MAJOR,
MINOR,
PATCH,
PRERELEASE,
};
struct SemVer
{
uint[3] ids;
string[] prerelease;
string[] build;
bool isValid;
@disable this();
this(string semVer)
{
isValid = false;
if (semVer.empty)
return;
if (!semVer.skipOver('v'))
semVer.skipOver('=');
auto re = regex(`^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([a-zA-Z\d-.]+))?(?:\+([a-zA-Z\d-.]+))?$`);
auto m = semVer.matchAll(re);
if (m.empty)
return;
foreach (i, ref id; ids)
{
if (!m.captures[i+1].empty)
id = m.captures[i+1].to!uint;
}
if (!m.captures[4].empty)
{
prerelease = m.captures[4].splitter('.').array;
if (prerelease.any!empty)
return;
}
if (!m.captures[5].empty)
{
build = m.captures[5].splitter('.').array;
if (build.any!empty)
return;
}
isValid = true;
}
string toString() const
{
if (!isValid)
return "<invalid_semver>";
string semVer = "%(%s.%)".format(ids);
if (!prerelease.empty)
semVer ~= "-" ~ "%-(%s.%)".format(prerelease);
if (!build.empty)
semVer ~= "+" ~ "%-(%s.%)".format(build);
return semVer;
}
@property bool valid() const
{
return isValid;
}
SemVer inc(ReleaseType releaseType) const
in
{
assert(this.valid);
}
out(result)
{
assert(result.valid);
}
body
{
SemVer result = "0";
foreach (i; 0..releaseType)
result.ids[i] = this.ids[i];
if (releaseType != ReleaseType.PRERELEASE)
result.ids[releaseType] = this.ids[releaseType]+1;
return result;
}
SemVer appendPrerelease0()
{
if (prerelease.empty)
prerelease ~= "0";
return this;
}
unittest
{
assert(SemVer("1.2.3").inc(ReleaseType.MAJOR) == SemVer("2.0.0"));
assert(SemVer("1.2.3").inc(ReleaseType.MINOR) == SemVer("1.3.0"));
assert(SemVer("1.2.3-alpha").inc(ReleaseType.MINOR) == SemVer("1.3.0"));
assert(SemVer("1.2.3").inc(ReleaseType.PATCH) == SemVer("1.2.4"));
assert(SemVer("1.2.3-alpha").inc(ReleaseType.PATCH) == SemVer("1.2.4"));
assert(SemVer("1.2.3").inc(ReleaseType.PRERELEASE) == SemVer("1.2.3"));
assert(SemVer("1.2.3-alpha").inc(ReleaseType.PRERELEASE) == SemVer("1.2.3"));
}
int opCmp(ref const SemVer v) const
in
{
assert(this.valid);
assert(v.valid);
}
body
{
foreach (i; 0..ids.length)
{
if (ids[i] != v.ids[i])
return ids[i] < v.ids[i] ? -1 : 1;
}
if (!prerelease.empty && v.prerelease.empty)
return -1;
if (prerelease.empty && !v.prerelease.empty)
return 1;
foreach (a, b; lockstep(prerelease, v.prerelease))
{
if (a.isNumeric && b.isNumeric)
{
if (a.to!uint != b.to!uint)
return a.to!uint < b.to!uint ? -1 : 1;
else
continue;
}
if (a != b)
return a < b ? -1 : 1;
}
if (prerelease.length != v.prerelease.length)
return prerelease.length < v.prerelease.length ? -1 : 1;
return 0;
}
int opCmp(const SemVer v) const
{
return this.opCmp(v);
}
bool opEquals(ref const SemVer v) const
{
return this.opCmp(v) == 0;
}
bool opEquals(const SemVer v) const
{
return this.opEquals(v);
}
}
unittest
{
assert(!SemVer("1.2-.alpha.32").valid);
assert(!SemVer("1.2-alpha+").valid);
assert(!SemVer("1.2-alpha_").valid);
assert(!SemVer("1.2+32.").valid);
assert(!SemVer("1.2.5.6").valid);
assert(!SemVer("").valid);
assert(SemVer("1.0.0-alpha") < SemVer("1.0.0-alpha.1"));
assert(SemVer("1.0.0-alpha.1") < SemVer("1.0.0-alpha.beta"));
assert(SemVer("1.0.0-alpha.beta") < SemVer("1.0.0-beta"));
assert(SemVer("1.0.0-beta") < SemVer("1.0.0-beta.2"));
assert(SemVer("1.0.0-beta.2") < SemVer("1.0.0-beta.11"));
assert(SemVer("1.0.0-beta.11") < SemVer("1.0.0-rc.1"));
assert(SemVer("1.0.0-rc.1") < SemVer("1.0.0"));
assert(SemVer("1.0.0-rc.1") == SemVer("1.0.0-rc.1+build.5"));
}
struct SemVerRange
{
struct SimpleRange
{
string op;
SemVer semVer;
string toString() const
{
return op ~ semVer.toString;
}
}
SimpleRange[][] ranges;
invariant()
{
assert(ranges.all!(r => r.all!(r => ["<", "<=", "=", ">=", ">"].canFind(r.op))));
}
bool isValid;
@disable this();
this(string semVerRange)
{
isValid = false;
auto re = regex(`(~|~>|\^|<|<=|=|>=|>)?[v]?(\d+|\*|X|x)(?:\.(\d+|\*|X|x))?(?:\.(\d+|\*|X|x))?([\S]*)`);
ranges = [SimpleRange[].init];
while (!semVerRange.stripLeft.empty)
{
auto m = semVerRange.matchFirst(re);
if (m.empty)
return;
auto operator = m.captures[1];
auto wildcard = wildcardAt([m.captures[2], m.captures[3], m.captures[4]]);
auto expanded = expand([m.captures[2], m.captures[3], m.captures[4], m.captures[5]]);
if (expanded.empty)
return;
auto semVer = SemVer(expanded);
if (!semVer.valid)
return;
switch (m.captures.pre.strip)
{
case "":
break;
case "-":
if (ranges[$-1].empty || ranges[$-1][$-1].op != "=" ||
operator != "" || wildcard != ReleaseType.PRERELEASE)
return;
ranges[$-1][$-1].op = ">=";
operator = "<=";
break;
case "||":
ranges ~= SimpleRange[].init;
break;
default:
return;
}
switch (operator)
{
case "":
case "=":
final switch (wildcard)
{
case ReleaseType.MAJOR:
assert(semVer == SemVer("0.0.0"));
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
break;
case ReleaseType.MINOR:
case ReleaseType.PATCH:
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(--wildcard).appendPrerelease0);
break;
case ReleaseType.PRERELEASE:
ranges[$-1] ~= SimpleRange("=", semVer);
break;
}
break;
case "<":
ranges[$-1] ~= SimpleRange(operator, semVer.appendPrerelease0);
break;
case "<=":
case ">=":
case ">":
if (wildcard < ReleaseType.PRERELEASE)
semVer.appendPrerelease0;
ranges[$-1] ~= SimpleRange(operator, semVer);
break;
case "~":
final switch (wildcard)
{
case ReleaseType.MAJOR:
return;
case ReleaseType.MINOR:
case ReleaseType.PATCH:
--wildcard;
break;
case ReleaseType.PRERELEASE:
--wildcard;
--wildcard;
break;
}
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
break;
case "~>":
final switch (wildcard)
{
case ReleaseType.MAJOR:
return;
case ReleaseType.MINOR:
--wildcard;
break;
case ReleaseType.PATCH:
case ReleaseType.PRERELEASE:
--wildcard;
--wildcard;
break;
}
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(wildcard).appendPrerelease0);
break;
case "^":
if (wildcard == ReleaseType.MAJOR || !semVer.prerelease.empty)
return;
if (semVer.ids[ReleaseType.MAJOR] != 0)
{
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.MAJOR).appendPrerelease0);
}
else if (semVer.ids[ReleaseType.MINOR] != 0)
{
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.MINOR).appendPrerelease0);
}
else
{
ranges[$-1] ~= SimpleRange(">=", semVer.appendPrerelease0);
ranges[$-1] ~= SimpleRange("<", semVer.inc(ReleaseType.PATCH).appendPrerelease0);
}
break;
default:
assert(0);
break;
}
semVerRange = m.captures.post;
}
isValid = true;
}
private static ReleaseType wildcardAt(string[3] semVer)
{
foreach (i; ReleaseType.MAJOR..ReleaseType.PRERELEASE)
{
if (["", "*", "X", "x"].canFind(semVer[i]))
return i;
}
return ReleaseType.PRERELEASE;
}
unittest
{
assert(wildcardAt(["*", "", ""]) == ReleaseType.MAJOR);
assert(wildcardAt(["X", "", ""]) == ReleaseType.MAJOR);
assert(wildcardAt(["1", "", ""]) == ReleaseType.MINOR);
assert(wildcardAt(["1", "x", ""]) == ReleaseType.MINOR);
assert(wildcardAt(["1", "2", ""]) == ReleaseType.PATCH);
assert(wildcardAt(["1", "2", "x"]) == ReleaseType.PATCH);
assert(wildcardAt(["1", "2", "3"]) == ReleaseType.PRERELEASE);
}
private static string expand(string[4] semVer)
{
ReleaseType wildcard = wildcardAt(semVer[0..3]);
if (wildcard != ReleaseType.PRERELEASE)
{
if (semVer[wildcard+1..$].any!`!["", "*", "X", "x"].canFind(a)`)
return "";
foreach (j; wildcard..ReleaseType.PRERELEASE)
semVer[j] = "0";
}
string result = "%-(%s.%)".format(semVer[0..3]);
if (!semVer[3].empty)
result ~= semVer[3];
return result;
}
unittest
{
assert(expand(["*", "", "", ""]) == "0.0.0");
assert(expand(["X", "", "", ""]) == "0.0.0");
assert(expand(["1", "2", "3", ""]) == "1.2.3");
assert(expand(["1", "2", "3", "-abc"]) == "1.2.3-abc");
assert(expand(["1", "2", "", ""]) == "1.2.0");
assert(expand(["1", "2", "", "-abc"]) == "");
assert(expand(["1", "2", "x", ""]) == "1.2.0");
assert(expand(["1", "", "", ""]) == "1.0.0");
assert(expand(["1", "x", "", ""]) == "1.0.0");
}
string toString() const
{
if (!isValid)
return "<invalid_semver_range>";
return "%(%(%s %) || %)".format(ranges);
}
@property bool valid() const
{
return isValid;
}
private static bool simpleRangeSatisfiedBy(SimpleRange simpleRange, SemVer semVer)
in
{
assert(semVer.valid);
assert(["<", "<=", "=", ">=", ">"].canFind(simpleRange.op));
assert(simpleRange.semVer.valid);
}
body
{
switch (simpleRange.op)
{
case "<":
return semVer < simpleRange.semVer;
case "<=":
return semVer <= simpleRange.semVer;
case "=":
return semVer == simpleRange.semVer;
case ">=":
return semVer >= simpleRange.semVer;
case ">":
return semVer > simpleRange.semVer;
default:
return false;
}
}
bool satisfiedBy(SemVer semVer)
in
{
assert(semVer.valid);
assert(valid);
}
body
{
return ranges.any!(r => r.all!(s => simpleRangeSatisfiedBy(s, semVer)));
}
}
bool satisfies(SemVer semVer, SemVerRange semVerRange)
{
return semVerRange.satisfiedBy(semVer);
}
SemVer maxSatisfying(SemVer[] semVers, SemVerRange semVerRange)
in
{
assert(semVers.all!"a.valid");
assert(semVerRange.valid);
}
body
{
auto found = semVers.sort!"a > b".find!(a => satisfies(a, semVerRange));
return found.empty ? SemVer("invalid") : found[0];
}
unittest
{
assert(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3").valid);
assert(!SemVerRange("blerg").valid);
assert(!SemVerRange("git+https://user:password0123@github.com/foo").valid);
assert(SemVer("1.2.3").satisfies(SemVerRange("1.x || >=2.5.0 || 5.0.0 - 7.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
assert(SemVer("1.0.0").satisfies(SemVerRange("1.0.0")));
assert(SemVer("0.2.4").satisfies(SemVerRange(">=*")));
assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
assert(SemVer("v1.2.3-foo").satisfies(SemVerRange("*")));
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.0.1").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.1.0").satisfies(SemVerRange(">=1.0.0")));
assert(SemVer("1.0.1").satisfies(SemVerRange(">1.0.0")));
assert(SemVer("1.1.0").satisfies(SemVerRange(">1.0.0")));
assert(SemVer("2.0.0").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("0.2.9").satisfies(SemVerRange("<=2.0.0")));
assert(SemVer("1.9999.9999").satisfies(SemVerRange("<2.0.0")));
assert(SemVer("0.2.9").satisfies(SemVerRange("<2.0.0")));
assert(SemVer("v0.1.97").satisfies(SemVerRange(">=0.1.97")));
assert(SemVer("0.1.97").satisfies(SemVerRange(">=0.1.97")));
assert(SemVer("1.2.4").satisfies(SemVerRange("0.1.20 || 1.2.4")));
assert(SemVer("0.0.0").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
assert(SemVer("0.2.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
assert(SemVer("0.2.4").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
assert(SemVer("2.1.3").satisfies(SemVerRange("2.x.x")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x")));
assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.x || 2.x")));
assert(SemVer("1.2.3").satisfies(SemVerRange("x")));
assert(SemVer("2.1.3").satisfies(SemVerRange("2.*.*")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.*")));
assert(SemVer("2.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.* || 2.*")));
assert(SemVer("1.2.3").satisfies(SemVerRange("*")));
assert(SemVer("2.1.2").satisfies(SemVerRange("2")));
assert(SemVer("2.3.1").satisfies(SemVerRange("2.3")));
assert(SemVer("2.4.0").satisfies(SemVerRange("~2.4")));
assert(SemVer("2.4.5").satisfies(SemVerRange("~2.4")));
assert(SemVer("3.2.2").satisfies(SemVerRange("~>3.2.1")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~>1")));
assert(SemVer("1.0.2").satisfies(SemVerRange("~1.0")));
assert(SemVer("1.0.12").satisfies(SemVerRange("~1.0.3")));
assert(SemVer("1.0.0").satisfies(SemVerRange(">=1")));
assert(SemVer("1.1.1").satisfies(SemVerRange("<1.2")));
assert(SemVer("1.1.9").satisfies(SemVerRange("<=1.2")));
assert(SemVer("1.0.0-bet").satisfies(SemVerRange("1")));
assert(SemVer("0.5.5").satisfies(SemVerRange("~v0.5.4-pre")));
assert(SemVer("0.5.4").satisfies(SemVerRange("~v0.5.4-pre")));
assert(SemVer("0.7.2").satisfies(SemVerRange("=0.7.x")));
assert(SemVer("0.7.2").satisfies(SemVerRange(">=0.7.x")));
assert(SemVer("0.7.0-asdf").satisfies(SemVerRange("=0.7.x")));
assert(SemVer("0.7.0-asdf").satisfies(SemVerRange(">=0.7.x")));
assert(SemVer("0.6.2").satisfies(SemVerRange("<=0.7.x")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 =1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 >=1.2.3 1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3 >=1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("~1.2.1 1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 1.2.3")));
assert(SemVer("1.2.3").satisfies(SemVerRange("1.2.3 >=1.2.1")));
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.3 >=1.2.1")));
assert(SemVer("1.2.3").satisfies(SemVerRange(">=1.2.1 >=1.2.3")));
assert(SemVer("1.2.3-beta").satisfies(SemVerRange("<=1.2.3")));
assert(SemVer("1.3.0-beta").satisfies(SemVerRange(">1.2")));
assert(SemVer("1.2.8").satisfies(SemVerRange(">=1.2")));
assert(SemVer("1.8.1").satisfies(SemVerRange("^1.2.3")));
assert(SemVer("1.2.3-beta").satisfies(SemVerRange("^1.2.3")));
assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1.2")));
assert(SemVer("0.1.2").satisfies(SemVerRange("^0.1")));
assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2")));
assert(SemVer("1.4.2").satisfies(SemVerRange("^1.2 ^1")));
assert(SemVer("1.2.0-pre").satisfies(SemVerRange("^1.2")));
assert(SemVer("1.2.3-pre").satisfies(SemVerRange("^1.2.3")));
assert(!SemVer("2.2.3").satisfies(SemVerRange("1.0.0 - 2.0.0")));
assert(!SemVer("1.0.1").satisfies(SemVerRange("1.0.0")));
assert(!SemVer("0.0.0").satisfies(SemVerRange(">=1.0.0")));
assert(!SemVer("0.0.1").satisfies(SemVerRange(">=1.0.0")));
assert(!SemVer("0.1.0").satisfies(SemVerRange(">=1.0.0")));
assert(!SemVer("0.0.1").satisfies(SemVerRange(">1.0.0")));
assert(!SemVer("0.1.0").satisfies(SemVerRange(">1.0.0")));
assert(!SemVer("3.0.0").satisfies(SemVerRange("<=2.0.0")));
assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<=2.0.0")));
assert(!SemVer("2.2.9").satisfies(SemVerRange("<=2.0.0")));
assert(!SemVer("2.9999.9999").satisfies(SemVerRange("<2.0.0")));
assert(!SemVer("2.2.9").satisfies(SemVerRange("<2.0.0")));
assert(!SemVer("v0.1.93").satisfies(SemVerRange(">=0.1.97")));
assert(!SemVer("0.1.93").satisfies(SemVerRange(">=0.1.97")));
assert(!SemVer("1.2.3").satisfies(SemVerRange("0.1.20 || 1.2.4")));
assert(!SemVer("0.0.3").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
assert(!SemVer("0.2.2").satisfies(SemVerRange(">=0.2.3 || <0.0.1")));
assert(!SemVer("1.1.3").satisfies(SemVerRange("2.x.x")));
assert(!SemVer("3.1.3").satisfies(SemVerRange("2.x.x")));
assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.x")));
assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.x || 2.x")));
assert(!SemVer("1.1.3").satisfies(SemVerRange("2.*.*")));
assert(!SemVer("3.1.3").satisfies(SemVerRange("2.*.*")));
assert(!SemVer("1.3.3").satisfies(SemVerRange("1.2.*")));
assert(!SemVer("3.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
assert(!SemVer("1.1.3").satisfies(SemVerRange("1.2.* || 2.*")));
assert(!SemVer("1.1.2").satisfies(SemVerRange("2")));
assert(!SemVer("2.4.1").satisfies(SemVerRange("2.3")));
assert(!SemVer("2.5.0").satisfies(SemVerRange("~2.4")));
assert(!SemVer("2.3.9").satisfies(SemVerRange("~2.4")));
assert(!SemVer("3.3.2").satisfies(SemVerRange("~>3.2.1")));
assert(!SemVer("3.2.0").satisfies(SemVerRange("~>3.2.1")));
assert(!SemVer("0.2.3").satisfies(SemVerRange("~1")));
assert(!SemVer("2.2.3").satisfies(SemVerRange("~>1")));
assert(!SemVer("1.1.0").satisfies(SemVerRange("~1.0")));
assert(!SemVer("1.0.0").satisfies(SemVerRange("<1")));
assert(!SemVer("1.1.1").satisfies(SemVerRange(">=1.2")));
assert(!SemVer("1.3.0").satisfies(SemVerRange("<=1.2")));
assert(!SemVer("2.0.0-beta").satisfies(SemVerRange("1")));
assert(!SemVer("0.5.4-alpha").satisfies(SemVerRange("~v0.5.4-beta")));
assert(!SemVer("1.0.0-beta").satisfies(SemVerRange("<1")));
assert(!SemVer("0.8.2").satisfies(SemVerRange("=0.7.x")));
assert(!SemVer("0.6.2").satisfies(SemVerRange(">=0.7.x")));
assert(!SemVer("0.7.2").satisfies(SemVerRange("<=0.7.x")));
assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("<1.2.3")));
assert(!SemVer("1.2.3-beta").satisfies(SemVerRange("=1.2.3")));
assert(!SemVer("1.2.8").satisfies(SemVerRange(">1.3")));
assert(!SemVer("2.0.0-alpha").satisfies(SemVerRange("^1.2.3")));
assert(!SemVer("1.2.2").satisfies(SemVerRange("^1.2.3")));
assert(!SemVer("1.1.9").satisfies(SemVerRange("^1.2")));
assert(!SemVer("2.0.0-pre").satisfies(SemVerRange("^1.2.3")));
auto semVers = [SemVer("0.8.0"), SemVer("1.0.0"), SemVer("1.1.0")];
assert(semVers.maxSatisfying(SemVerRange("<=1.0.0")) == SemVer("1.0.0"));
assert(semVers.maxSatisfying(SemVerRange(">=1.0")) == SemVer("1.1.0"));
}

View File

@ -1,52 +0,0 @@
#message("Adding dependencies")
#message("CMAKE_D_FLAGS: ${CMAKE_D_FLAGS} ")
#message("CMAKE_D_COMPILER: ${CMAKE_D_COMPILER} ")
#message("include_directories: ${include_directories} ")
#message("source file ${source_file}")
#message("dependency file ${dependency_file}")
separate_arguments(CMAKE_D_FLAGS)
# TODO
# need to pass all arguments that are used for building
# can't I use the build rule somehow
execute_process(COMMAND ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${include_directories} -deps=${dependency_file}.tmp -o- ${source_file})
#message("executing: ${CMAKE_D_COMPILER} ${CMAKE_D_FLAGS} ${include_directories} -deps=${dependency_file}.tmp -o- ${source_file}")
if(NOT EXISTS ${dependency_file})
file(WRITE ${dependency_file} "# Generated by: ${CMAKE_CURRENT_LIST_FILE}\nSET(D_DMD_DEPEND\n)\n\n")
endif()
file(READ ${dependency_file}.tmp depend_text)
#message("DEPENDENCIES: ${depend_text}")
# extract dependencies
string(REGEX MATCHALL "\\([^)]*\\)" out ${depend_text})
string(REGEX MATCHALL "[^()]+" out ${out})
list(REMOVE_DUPLICATES out)
list(SORT out)
foreach(file ${out})
set(dependencies "${dependencies} \"${file}\"\n")
endforeach()
# write new dependencies to temporary file
file(WRITE ${dependency_file}.tmp "# Generated by: ${CMAKE_CURRENT_LIST_FILE}\nSET(D_DMD_DEPEND\n ${dependencies})\n\n")
# get old dependencies
include(${dependency_file})
set(old_dependencies ${D_DMD_DEPEND})
# and the new dependencies from temporary file
include(${dependency_file}.tmp)
# did the dependencies change?
if(NOT "${D_DMD_DEPEND}" STREQUAL "${old_dependencies}")
message("Dependencies changed. Need to build.")
execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${source_file})
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${dependency_file}.tmp ${dependency_file})
execute_process(COMMAND ${CMAKE_COMMAND} -E remove ${dependency_file}.tmp)
#message("Finished dependencies")

View File

@ -1,5 +0,0 @@
cmake_minimum_required(VERSION 3.0)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Nim)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Nim/UseNim.cmake)
find_package(Nim)
add_subdirectory(Examples)

View File

@ -1,304 +0,0 @@
:Authors:
Filippo Cucchetto <filippocucchetto@gmail.com>
Will Szumski <will@cowboycoders.org>
:Version: 0.3.0
:Date: 2015/02/15
Introduction
-----------
The NimQml module adds Qt Qml bindings to the Nim programming language
allowing you to create new modern UI by mixing the Qml declarative syntax
and the Nim imperative language.
The NimQml is made by two components:
* The DOtherSide C++ shared library
* The NimQml Nim module
This first component implements the glue code necessary for
communicating with the Qt C++ library, the latter module wraps
the libDOtherSide exported symbols in Nim
Building
--------
At the time of writing the DOtherSide C++ library must be compiled
and installed manually from source.
First clone the DOtherSide git repo
::
git clone https://github.com/filcuc/DOtherSide
than you can proceed with the common CMake build steps
::
mkdir build
cd build
cmake ..
make
If everything goes correctly, you'll have built both
the DOtherSide C++ library and the Nim examples
Installation
----------
The installation is not mandatory, in fact you could try
the built Nim example in the following way
::
cd path/to/build/dir
cd Nim/Examples/HelloWorld
export LD_LIBRARY_PATH=path/to/libDOtherSide.so
./HelloWorld
The DOtherSide project is made of two components
1. The DOtherSide C++ lib
2. The NimQml module
You can procede with the installation of the C++ library
in the following way
::
cd to/build/dir
make install
or by manually copying the library in your system lib directory
::
sudo cp build/dir/path/DOtherSide/libDOtherSide.so /usr/lib
For the NimQml module you can use the ``nimble`` package manager
::
nimble install NimQml
or
::
cd to/build/dir/Nim/NimQml
nimble install
Example 1: HelloWorld
----------
As usual lets start with an HelloWorld example.
Most of the NimQml projects are made by one or more nim and qml
files. Usually the .nim files contains your app logic and data
layer. The qml files contain the presentation layer and expose
the data in your nim files.
``Examples/HelloWorld/main.nim``
.. code-block:: nim
:file: ../Examples/HelloWorld/main.nim
``Examples/HelloWorld/main.qml``
.. code-block:: qml
:file: ../Examples/HelloWorld/main.qml
The following example shows the basic steps of each NimQml app
1. Create the QApplication for initializing the Qt runtime
2. Create the QQmlApplicationEngine and load your main .qml file
3. Call the ``exec`` proc of the QApplication instance for starting
the Qt event loop
Example 2: exposing data to Qml
------------------------------------
The previous example shown you how to create a simple application
window and how to startup the Qt event loop.
It's time to explore how to pass data to Qml, but lets see the
example code first:
``Examples/SimpleData/main.nim``
.. code-block:: nim
:file: ../Examples/SimpleData/main.nim
``Examples/SimpleData/main.qml``
.. code-block:: qml
:file: ../Examples/SimpleData/main.qml
The following example shows how to expose simple data types to Qml:
1. Create a QVariant and set its internal value.
2. Create a property in the Qml root context with a given name.
Once a property is set through the ``setContextProperty`` proc, it's available
globally in all the Qml script loaded by the current engine (see the official Qt
documentation for more details about the engine and context objects)
At the time of writing the QVariant class support the following types:
* int
* string
* bool
* float
* QObject derived classes
Example 3: exposing complex data and procedures to Qml
----------------------------------------------------------
As seen by the second example, simple data is fine. However most
applications need to expose complex data, functions and
update the view when something changes in the data layer.
This is achieved by creating an object that derives from QObject.
A QObject is made of :
1. ``Slots``: slots are functions that could be called from the qml engine and/or connected to Qt signals
2. ``Signals``: signals allow the sending of events and be connected to slots
3. ``Properties``: properties allow the passing of data to
the Qml view and make it aware of changes in the data layer
A QObject property is made of three things:
* a read slot: a method that returns the current value of the property
* a write slot: a method that sets the value of the property
* a notify signal: emitted when the current value of the property is changed
We'll start by looking at the main.nim file
``Examples/SlotsAndProperties/main.nim``
.. code-block:: nim
:file: ../Examples/SlotsAndProperties/main.nim
Here, nothing special happens except:
1. The creation of Contact object
2. The injection of the Contact object to the Qml root context
using the ``setContextProperty`` as seen in the previous
example
The Qml file is as follows:
``Examples/SlotsAndProperties/main.qml``
.. code-block:: qml
:file: ../Examples/SlotsAndProperties/main.qml
The qml is made up of: a Label, a TextInput widget, and a button.
The label displays the contact name - this automatically updates when
the contact name changes.
When clicked, the button updates the contact name with the text from
the TextInput widget.
So where's the magic?
The magic is in the Contact.nim file
``Examples/SlotsAndProperties/Contact.nim``
.. code-block:: nim
:file: ../Examples/SlotsAndProperties/Contact.nim
First we declare a QObject subclass and provide a simple
new method where we:
1. invoke the ``create()`` procedure. This invoke the C++ bridge and allocate
a QObject instance
2. register a slot ``getName`` for reading the Contact name field
3. register a slot ``setName`` for writing the Contact name
4. register a signal ``nameChanged`` for notify the contact name changes
5. register a property called ``name`` of type ``QString`` with the given
read, write slots and notify signal
Looking at the ``getName`` and ``setName`` methods, you can see that slots, as defined in Nim,
are nothing more than standard methods. The method corresponding to the ``setName`` slot
demonstrates how to use the ``emit`` method to emit a signal.
The last thing to consider is the override of the ``onSlotCalled`` method.
This method is called by the NimQml library when an invocation occurs from
the Qml side for one of the slots belonging to the QObject.
The usual implementation for the onSlotCalled method consists of a
switch statement that forwards the arguments to the correct slot.
If the invoked slot has a return value, this is always in the index position
0 of the args array.
Example 4: QtObject macro
-------------------------
The previous example shows how to create a simple QObject, however writing
all those ``register`` procs and writing the ``onSlotCalled`` method
becomes boring pretty soon.
Furthermore all this information can be automatically generated.
For this purpose you can import the NimQmlMacros module that provides
the QtObject macro.
Let's begin as usual with both the main.nim and main.qml files
``Examples/QtObjectMacro/main.nim``
.. code-block:: nim
:file: ../Examples/QtObjectMacro/main.nim
``Examples/QtObjectMacro/main.qml``
.. code-block:: qml
:file: ../Examples/QtObjectMacro/main.qml
Nothing is new in both the ``main.nim`` and ``main.qml`` with respect to
the previous example. What changed is the Contact object:
``Examples/QtObjectMacro/Contact.nim``
.. code-block:: nim
:file: ../Examples/QtObjectMacro/Contact.nim
In details:
1. Each QObject is defined inside the QtObject macro
2. Each slot is annotated with the ``{.slot.}`` pragma
3. Each signal is annotated with the ``{.signal.}`` pragma
4. Each property is created with the ``QtProperty`` macro
The ``QtProperty`` macro has the following syntax
.. code-block:: nim
QtProperty[typeOfProperty] nameOfProperty
Example 5: ContactApp
-------------------------
The last example tries to show you all the stuff presented
in the previous chapters and gives you an introduction to how
to expose lists to qml.
Qt models are a huge topic and explaining how they work is
out of scope. For further information please read the official
Qt documentation.
The main file follows the basic logic of creating a qml
engine and exposing a QObject derived object "ApplicationLogic"
through a global "logic" property
``Examples/ContactApp/main.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/main.nim
The qml file shows a simple app with a central tableview
``Examples/ContactApp/main.qml``
.. code-block:: qml
:file: ../Examples/ContactApp/main.qml
The important things to notice are:
1. The menubar load, save and exit items handlers call the logic load, save and exit slots
2. The TableView model is retrieved by the logic.contactList property
3. The delete and add buttons call the del and add slots of the logic.contactList model
The ApplicationLogic object is as follows:
``Examples/ContactApp/ApplicationLogic.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ApplicationLogic.nim
The ApplicationLogic object,
1. expose some slots for handling the qml menubar triggered signals
2. expose a contactList property that return a QAbstractListModel derived object that manage the list of contacts
The ContactList object is as follows:
``Examples/ContactApp/ContactList.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ContactList.nim
The ContactList object:
1. overrides the ``rowCount`` method for returning the number of rows stored in the model
2. overrides the ``data`` method for returning the value for the exported roles
3. overrides the ``roleNames`` method for returning the names of the roles of the model. This name are then available in the qml item delegates
4. defines two slots ``add`` and ``del`` that add or delete a Contact. During this operations the model execute the ``beginInsertRows`` and ``beginRemoveRows`` for notifing the view of an upcoming change. Once the add or delete operations are done the model execute the ``endInsertRows`` and ``endRemoveRows``.

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlAbstractItemModel SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,37 +0,0 @@
import NimQml, NimQmlMacros, Tables
QtObject:
type
MyListModel* = ref object of QAbstractListModel
names*: seq[string]
RoleNames {.pure.} = enum
Name = 0,
converter toCInt(value: RoleNames): cint = return value.cint
converter toCInt(value: int): cint = return value.cint
converter toInt(value: RoleNames): int = return value.int
converter toInt(value: cint): int = return value.int
converter toQVariant(value: string): QVariant = return value.newQVariant
proc delete(self: MyListModel) =
let model = self.QAbstractListModel
model.delete
proc newMyListModel*(): MyListModel =
new(result, delete)
result.names = @["John", "Max", "Paul", "Anna"]
result.create
method rowCount(self: MyListModel, index: QModelIndex = nil): cint =
return self.names.len
method data(self: MyListModel, index: QModelIndex, role: cint): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.names.len:
return
return self.names[index.row]
method roleNames(self: MyListModel): Table[cint, cstring] =
result = initTable[cint, cstring]()
result[RoleNames.Name] = "name"

View File

@ -1,26 +0,0 @@
import NimQml
import MyListModel
proc mainProc() =
echo "Starting"
var app = newQApplication()
defer: app.delete
var myListModel = newMyListModel();
defer: myListModel.delete
var engine = newQQmlApplicationEngine()
defer: engine.delete
var variant = newQVariant(myListModel)
defer: variant.delete
engine.rootContext.setContextProperty("myListModel", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,25 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "AbstractItemModel"
Component.onCompleted: visible = true
Component
{
id: myListModelDelegate
Label { text: "Name:" + name }
}
ListView
{
anchors.fill: parent
model: myListModel
delegate: myListModelDelegate
}
}

View File

@ -1,6 +0,0 @@
add_subdirectory(HelloWorld)
add_subdirectory(SimpleData)
add_subdirectory(SlotsAndProperties)
add_subdirectory(QtObjectMacro)
add_subdirectory(ContactApp)
add_subdirectory(AbstractItemModel)

View File

@ -1,33 +0,0 @@
import NimQml, NimQmlMacros, ContactList
QtObject:
type ApplicationLogic* = ref object of QObject
contactList: ContactList
app: QApplication
proc delete*(self: ApplicationLogic) =
let qobject = self.QObject
qobject.delete
self.contactList.delete
proc newApplicationLogic*(app: QApplication): ApplicationLogic =
new(result)
result.contactList = newContactList()
result.app = app
result.create()
method getContactList(self: ApplicationLogic): QVariant {.slot.} =
return newQVariant(self.contactList)
method onLoadTriggered(self: ApplicationLogic) {.slot.} =
echo "Load Triggered"
self.contactList.add("John", "Doo")
method onSaveTriggered(self: ApplicationLogic) {.slot.} =
echo "Save Triggered"
method onExitTriggered(self: ApplicationLogic) {.slot.} =
self.app.quit
QtProperty[QVariant] contactList:
read = getContactList

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlContactApp SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,51 +0,0 @@
## Please note we are using templates where ordinarily we would like to use procedures
## due to bug: https://github.com/Araq/Nim/issues/1821
import NimQml, NimQmlMacros
QtObject:
type Contact* = ref object of QObject
name: string
surname: string
proc delete*(self: Contact) =
let qobject = self.QObject
qobject.delete
proc newContact*(): Contact =
new(result)
result.name = ""
result.create
method firstName*(self: Contact): string {.slot.} =
result = self.name
method firstNameChanged*(self: Contact) {.signal.}
method setFirstName(self: Contact, name: string) {.slot.} =
if self.name != name:
self.name = name
self.firstNameChanged()
proc `firstName=`*(self: Contact, name: string) = self.setFirstName(name)
QtProperty[string] firstName:
read = firstName
write = setFirstName
notify = firstNameChanged
method surname*(self: Contact): string {.slot.} =
result = self.surname
method surnameChanged*(self: Contact) {.signal.}
method setSurname(self: Contact, surname: string) {.slot.} =
if self.surname != surname:
self.surname = surname
self.surnameChanged()
proc `surname=`*(self: Contact, surname: string) = self.setSurname(surname)
QtProperty[string] surname:
read = surname
write = setSurname
notify = surnameChanged

View File

@ -1,62 +0,0 @@
import NimQml, NimQmlMacros, Contact, Tables
QtObject:
type
ContactList* = ref object of QAbstractListModel
contacts*: seq[Contact]
ContactRoles {.pure.} = enum
FirstName = 0
Surname = 1
converter toCInt(value: ContactRoles): cint = return value.cint
converter toCInt(value: int): cint = return value.cint
converter toInt(value: ContactRoles): int = return value.int
converter toInt(value: cint): int = return value.int
converter toQVariant(value: string): QVariant = return value.newQVariant
proc delete(self: ContactList) =
let model = self.QAbstractListModel
model.delete
for contact in self.contacts:
contact.delete
self.contacts = @[]
proc newContactList*(): ContactList =
new(result, delete)
result.contacts = @[]
result.create
method rowCount(self: ContactList, index: QModelIndex = nil): cint =
return self.contacts.len
method data(self: ContactList, index: QModelIndex, role: cint): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.contacts.len:
return
let contact = self.contacts[index.row]
let contactRole = role.ContactRoles
case contactRole:
of ContactRoles.FirstName: return contact.firstName
of ContactRoles.Surname: return contact.surname
else: return
method roleNames(self: ContactList): Table[cint, cstring] =
result = initTable[cint, cstring]()
result[ContactRoles.FirstName] = "firstName"
result[ContactRoles.Surname] = "surname"
method add*(self: ContactList, name: string, surname: string) {.slot.} =
let contact = newContact()
contact.firstName = name
contact.surname = surname
self.beginInsertRows(newQModelIndex(), self.contacts.len, self.contacts.len)
self.contacts.add(contact)
self.endInsertRows()
method del*(self: ContactList, pos: int) {.slot.} =
if pos < 0 or pos >= self.contacts.len:
return
self.beginRemoveRows(newQModelIndex(), pos, pos)
self.contacts.del(pos)
self.endRemoveRows

View File

@ -1,17 +0,0 @@
import NimQml, ApplicationLogic
proc mainProc() =
let app = newQApplication()
defer: app.delete
let logic = newApplicationLogic(app)
defer: logic.delete
let engine = newQQmlApplicationEngine()
defer: engine.delete
let logicVariant = newQVariant(logic)
defer: logicVariant.delete
engine.rootContext.setContextProperty("logic", logicVariant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()

View File

@ -1,93 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow {
width: 500
height: 300
title: "ContactApp"
visible: true
menuBar: MenuBar {
Menu {
title: "&File"
MenuItem { text: "&Load"; onTriggered: logic.onLoadTriggered() }
MenuItem { text: "&Save"; onTriggered: logic.onSaveTriggered() }
MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() }
}
}
ColumnLayout {
anchors.fill: parent
Component {
id: tableTextDelegate
Label {
id: tableTextDelegateInstance
property var styleData: undefined
states: State {
when: styleData !== undefined
PropertyChanges {
target: tableTextDelegateInstance;
text: styleData.value;
color: styleData.textColor
}
}
}
}
Component {
id: tableButtonDelegate
Button {
id: tableButtonDelegateInstance
property var styleData: undefined
text: "Delete"
onClicked: logic.contactList.del(styleData.row)
}
}
Component {
id: tableItemDelegate
Loader {
id: tableItemDelegateInstance
sourceComponent: {
if (styleData.column === 0 || styleData.column === 1)
return tableTextDelegate
else if (styleData.column === 2)
return tableButtonDelegate
else
return tableTextDelegate
}
Binding {
target: tableItemDelegateInstance.item
property: "styleData"
value: styleData
}
}
}
TableView {
model: logic.contactList
Layout.fillWidth: true
Layout.fillHeight: true
TableViewColumn { role: "firstName"; title: "FirstName"; width: 200 }
TableViewColumn { role: "surname"; title: "Surname"; width: 200}
TableViewColumn { width: 100; }
itemDelegate: tableItemDelegate
}
RowLayout {
Label { text: "Name" }
TextField { id: nameTextField; Layout.fillWidth: true; text: "" }
Label { text: "Surname" }
TextField { id: surnameTextField; Layout.fillWidth: true; text: "" }
Button {
text: "Add"
onClicked: logic.contactList.add(nameTextField.text, surnameTextField.text)
enabled: nameTextField.text !== "" && surnameTextField.text !== ""
}
}
}
}

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlHelloWorld SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,18 +0,0 @@
import NimQml
import macros
import typeinfo
proc mainProc() =
var app = newQApplication()
defer: app.delete()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,12 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "Hello World"
Component.onCompleted: visible = true
}

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlQtObjectMacro SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,31 +0,0 @@
## Please note we are using templates where ordinarily we would like to use procedures
## due to bug: https://github.com/Araq/Nim/issues/1821
import NimQml, NimQmlMacros
QtObject:
type Contact* = ref object of QObject
m_name: string
proc delete*(self: Contact) =
var qobject = self.QObject
qobject.delete()
proc newContact*(): Contact =
new(result, delete)
result.m_name = "InitialName"
result.create
method getName*(self: Contact): string {.slot.} =
result = self.m_name
method nameChanged*(self: Contact) {.signal.}
method setName*(self: Contact, name: string) {.slot.} =
if self.m_name != name:
self.m_name = name
self.nameChanged()
QtProperty[string] name:
read = getName
write = setName
notify = nameChanged

View File

@ -1,23 +0,0 @@
import NimQml
import Contact
proc mainProc() =
var app = newQApplication()
defer: app.delete()
var contact = newContact()
defer: contact.delete()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var variant = newQVariant(contact)
defer: variant.delete()
engine.rootContext.setContextProperty("contact", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,33 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
Component.onCompleted: visible = true
ColumnLayout
{
anchors.fill: parent
Label
{
text: "Current name is:" + contact.name
}
TextField
{
id: textField
}
Button
{
text: "Change Name"
onClicked: contact.name = textField.text
}
}
}

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlSimpleData SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,34 +0,0 @@
import NimQml
import macros
import typeinfo
proc mainProc() =
var app = newQApplication()
defer: app.delete()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var qVar1 = newQVariant(10)
defer: qVar1.delete()
var qVar2 = newQVariant("Hello World")
defer: qVar2.delete()
var qVar3 = newQVariant(false)
defer: qVar3.delete()
var qVar4 = newQVariant(3.5.float)
defer: qVar4.delete()
engine.rootContext.setContextProperty("qVar1", qVar1)
engine.rootContext.setContextProperty("qVar2", qVar2)
engine.rootContext.setContextProperty("qVar3", qVar3)
engine.rootContext.setContextProperty("qVar4", qVar4)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,21 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "SimpleData"
Component.onCompleted: visible = true
ColumnLayout
{
anchors.fill: parent
SpinBox { value: qVar1}
TextField { text: qVar2}
CheckBox { checked: qVar3}
SpinBox { value: qVar4; decimals: 1 }
}
}

View File

@ -1,2 +0,0 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET NimQmlSlotsAndProperties SOURCES main.nim PATHS ../../NimQml)

View File

@ -1,40 +0,0 @@
## Please note we are using templates where ordinarily we would like to use procedures
## due to bug: https://github.com/Araq/Nim/issues/1821
import NimQml
type Contact = ref object of QObject
m_name: string
proc delete*(self: Contact) =
var qobject = self.QObject
qobject.delete()
proc create*(self: Contact) =
var qobject = self.QObject
qobject.create()
self.m_name = "InitialName"
self.registerSlot("getName", [QMetaType.QString])
self.registerSlot("setName", [QMetaType.Void, QMetaType.QString])
self.registerSignal("nameChanged", [QMetaType.Void])
self.registerProperty("name", QMetaType.QString, "getName", "setName", "nameChanged")
proc newContact*(): Contact =
new(result, delete)
result.create()
method getName*(self: Contact): string =
result = self.m_name
method setName*(self: Contact, name: string) =
if self.m_name != name:
self.m_name = name
self.emit("nameChanged")
method onSlotCalled(self: Contact, slotName: string, args: openarray[QVariant]) =
case slotName:
of "getName":
args[0].stringVal = self.getName()
of "setName":
self.setName(args[1].stringVal)
else:
discard()

View File

@ -1,24 +0,0 @@
import NimQml
import Contact
proc mainProc() =
var app = newQApplication()
defer: app.delete()
var contact = newContact()
defer: contact.delete()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var variant = newQVariant(contact)
defer: variant.delete()
engine.rootContext.setContextProperty("contact", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,33 +0,0 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
Component.onCompleted: visible = true
ColumnLayout
{
anchors.fill: parent
Label
{
text: "Current name is:" + contact.name
}
TextField
{
id: textField
}
Button
{
text: "Change Name"
onClicked: contact.name = textField.text
}
}
}

View File

@ -1,795 +0,0 @@
include NimQmlTypes
when defined(windows):
const dOtherSideDll* = "libDOtherSide.dll"
elif defined(macosx):
const dOtherSideDll* = "libDOtherSide.dylib"
else:
const dOtherSideDll* = "libDOtherSide.so"
## NimQml aims to provide binding to the QML for the Nim programming language
##
## Optional finalizers
## -------------------
## To enable finalizers you must define ``nimqml_use_finalizers`` by passing
## the option, ``-d:nimqml_use_finalizers``, to the Nim compiler. The relevant
## delete method will then be called automatically by the garbage collector.
## Care should be taken when using this approach as there are no guarantees
## when a finalzier will be run, or if, indeed, it will run at all.
type QMetaType* {.pure.} = enum ## \
## Qt metatypes values used for specifing the
## signals and slots argument and return types.
##
## This enum mimic the QMetaType::Type C++ enum
UnknownType = cint(0),
Bool = cint(1),
Int = cint(2),
QString = cint(10),
VoidStar = cint(31),
QObjectStar = cint(39),
QVariant = cint(41),
Void = cint(43),
var qobjectRegistry = initTable[ptr QObjectObj, bool]()
template debugMsg(message: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
echo "NimQml: ", message
else:
{.pop.}
template debugMsg(typeName: string, procName: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
var message = typeName
message &= ": "
message &= procName
debugMsg(message)
else:
{.pop.}
template debugMsg(typeName: string, procName: string, userMessage: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
var message = typeName
message &= ": "
message &= procName
message &= " "
message &= userMessage
debugMsg(message)
else:
{.pop.}
template newWithCondFinalizer(variable: expr, finalizer: expr) =
## calls ``new`` but only setting a finalizer when ``nimqml_use_finalizers``
## is defined
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(nimqml_use_finalizers):
{.pop.}
new(variable, finalizer)
else:
{.pop.}
new(variable)
# QVariant
proc dos_qvariant_create(variant: var RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_int(variant: var RawQVariant, value: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_bool(variant: var RawQVariant, value: bool) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_string(variant: var RawQVariant, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_qobject(variant: var RawQVariant, value: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_qvariant(variant: var RawQVariant, value: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_float(variant: var RawQVariant, value: cfloat) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_create_double(variant: var RawQVariant, value: cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_delete(variant: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_isnull(variant: RawQVariant, isNull: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_toInt(variant: RawQVariant, value: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_toBool(variant: RawQVariant, value: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_toString(variant: RawQVariant, value: var cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setInt(variant: RawQVariant, value: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setBool(variant: RawQVariant, value: bool) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setString(variant: RawQVariant, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_assign(leftValue: RawQVariant, rightValue: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_toFloat(variant: RawQVariant, value: var cfloat) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setFloat(variant: RawQVariant, value: float) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_toDouble(variant: RawQVariant, value: var cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setDouble(variant: RawQVariant, value: cdouble) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qvariant_setQObject(variant: RawQVariant, value: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_chararray_delete(rawCString: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(variant: QVariant) =
## Create a new QVariant
dos_qvariant_create(variant.data)
variant.deleted = false
proc create*(variant: QVariant, value: cint) =
## Create a new QVariant given a cint value
dos_qvariant_create_int(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: bool) =
## Create a new QVariant given a bool value
dos_qvariant_create_bool(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: string) =
## Create a new QVariant given a string value
dos_qvariant_create_string(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: QObject) =
## Create a new QVariant given a QObject
dos_qvariant_create_qobject(variant.data, value.data.RawQObject)
variant.deleted = false
proc create*(variant: QVariant, value: RawQVariant) =
## Create a new QVariant given another QVariant.
## The inner value of the QVariant is copied
dos_qvariant_create_qvariant(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: cfloat) =
## Create a new QVariant given a cfloat value
dos_qvariant_create_float(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: QVariant) =
## Create a new QVariant given another QVariant.
## The inner value of the QVariant is copied
create(variant, value.data)
proc delete*(variant: QVariant) =
## Delete a QVariant
if not variant.deleted:
debugMsg("QVariant", "delete")
dos_qvariant_delete(variant.data)
variant.data = nil.RawQVariant
variant.deleted = true
proc newQVariant*(): QVariant =
## Return a new QVariant
newWithCondFinalizer(result, delete)
result.create()
proc newQVariant*(value: cint): QVariant =
## Return a new QVariant given a cint
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: bool): QVariant =
## Return a new QVariant given a bool
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: string): QVariant =
## Return a new QVariant given a string
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: QObject): QVariant =
## Return a new QVariant given a QObject
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: RawQVariant): QVariant =
## Return a new QVariant given a raw QVariant pointer
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: QVariant): QVariant =
## Return a new QVariant given another QVariant
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: float): QVariant =
## Return a new QVariant given a float
newWithCondFinalizer(result, delete)
result.create(value)
proc isNull*(variant: QVariant): bool =
## Return true if the QVariant value is null, false otherwise
dos_qvariant_isnull(variant.data, result)
proc intVal*(variant: QVariant): int =
## Return the QVariant value as int
var rawValue: cint
dos_qvariant_toInt(variant.data, rawValue)
result = rawValue.cint
proc `intVal=`*(variant: QVariant, value: int) =
## Sets the QVariant value int value
var rawValue = value.cint
dos_qvariant_setInt(variant.data, rawValue)
proc boolVal*(variant: QVariant): bool =
## Return the QVariant value as bool
dos_qvariant_toBool(variant.data, result)
proc `boolVal=`*(variant: QVariant, value: bool) =
## Sets the QVariant bool value
dos_qvariant_setBool(variant.data, value)
proc floatVal*(variant: QVariant): float =
## Return the QVariant value as float
var rawValue: cfloat
dos_qvariant_toFloat(variant.data, rawValue)
result = rawValue.cfloat
proc `floatVal=`*(variant: QVariant, value: float) =
## Sets the QVariant float value
dos_qvariant_setFloat(variant.data, value.cfloat)
proc doubleVal*(variant: QVariant): cdouble =
## Return the QVariant value as double
var rawValue: cdouble
dos_qvariant_toDouble(variant.data, rawValue)
result = rawValue
proc `doubleVal=`*(variant: QVariant, value: cdouble) =
## Sets the QVariant double value
dos_qvariant_setDouble(variant.data, value)
proc stringVal*(variant: QVariant): string =
## Return the QVariant value as string
var rawCString: cstring
dos_qvariant_toString(variant.data, rawCString)
result = $rawCString
dos_chararray_delete(rawCString)
proc `stringVal=`*(variant: QVariant, value: string) =
## Sets the QVariant string value
dos_qvariant_setString(variant.data, value)
proc `qobjectVal=`*(variant: QVariant, value: QObject) =
## Sets the QVariant qobject value
dos_qvariant_setQObject(variant.data, value.data.RawQObject)
proc assign*(leftValue: QVariant, rightValue: QVariant) =
## Assign a QVariant with another. The inner value of the QVariant is copied
dos_qvariant_assign(leftValue.data, rightValue.data)
# QQmlApplicationEngine
proc dos_qqmlapplicationengine_create(engine: var RawQQmlApplicationEngine) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qqmlapplicationengine_load(engine: RawQQmlApplicationEngine, filename: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qqmlapplicationengine_context(engine: RawQQmlApplicationEngine, context: var QQmlContext) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qqmlapplicationengine_delete(engine: RawQQmlApplicationEngine) {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(engine: QQmlApplicationEngine) =
## Create an new QQmlApplicationEngine
dos_qqmlapplicationengine_create(engine.data)
engine.deleted = false
proc load*(engine: QQmlApplicationEngine, filename: cstring) =
## Load the given Qml file
dos_qqmlapplicationengine_load(engine.data, filename)
proc rootContext*(engine: QQmlApplicationEngine): QQmlContext =
## Return the engine root context
dos_qqmlapplicationengine_context(engine.data, result)
proc delete*(engine: QQmlApplicationEngine) =
## Delete the given QQmlApplicationEngine
if not engine.deleted:
debugMsg("QQmlApplicationEngine", "delete")
dos_qqmlapplicationengine_delete(engine.data)
engine.data = nil.RawQQmlApplicationEngine
engine.deleted = true
proc newQQmlApplicationEngine*(): QQmlApplicationEngine =
## Return a new QQmlApplicationEngine
newWithCondFinalizer(result, delete)
result.create()
# QQmlContext
proc dos_qqmlcontext_setcontextproperty(context: QQmlContext, propertyName: cstring, propertyValue: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc setContextProperty*(context: QQmlContext, propertyName: string, propertyValue: QVariant) =
## Sets a new property with the given value
dos_qqmlcontext_setcontextproperty(context, propertyName, propertyValue.data)
# QApplication
proc dos_qapplication_create() {.cdecl, dynlib: dOtherSideDll, importc.}
proc dos_qapplication_exec() {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qapplication_quit() {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qapplication_delete() {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(application: QApplication) =
## Create a new QApplication
dos_qapplication_create()
application.deleted = false
proc exec*(application: QApplication) =
## Start the Qt event loop
dos_qapplication_exec()
proc quit*(application: QApplication) =
## Quit the Qt event loop
dos_qapplication_quit()
proc delete*(application: QApplication) =
## Delete the given QApplication
if not application.deleted:
debugMsg("QApplication", "delete")
dos_qapplication_delete()
application.deleted = true
proc newQApplication*(): QApplication =
## Return a new QApplication
newWithCondFinalizer(result, delete)
result.create()
# QGuiApplication
proc dos_qguiapplication_create() {.cdecl, dynlib: dOtherSideDll, importc.}
proc dos_qguiapplication_exec() {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qguiapplication_quit() {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qguiapplication_delete() {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(application: QGuiApplication) =
## Create a new QApplication
dos_qguiapplication_create()
application.deleted = false
proc exec*(application: QGuiApplication) =
## Start the Qt event loop
dos_qguiapplication_exec()
proc quit*(application: QGuiApplication) =
## Quit the Qt event loop
dos_qguiapplication_quit()
proc delete*(application: QGuiApplication) =
## Delete the given QApplication
if not application.deleted:
debugMsg("QApplication", "delete")
dos_qguiapplication_delete()
application.deleted = true
proc newQGuiApplication*(): QGuiApplication =
## Return a new QApplication
newWithCondFinalizer(result, delete)
result.create()
# QObject
type RawQVariantArray {.unchecked.} = array[0..0, RawQVariant]
type RawQVariantArrayPtr = ptr RawQVariantArray
type RawQVariantSeq = seq[RawQVariant]
proc toVariantSeq(args: RawQVariantArrayPtr, numArgs: cint): seq[QVariant] =
result = @[]
for i in 0..numArgs-1:
result.add(newQVariant(args[i]))
proc toRawVariantSeq(args: openarray[QVariant]): RawQVariantSeq =
result = @[]
for variant in args:
result.add(variant.data)
proc delete(sequence: seq[QVariant]) =
for variant in sequence:
variant.delete
proc toCIntSeq(metaTypes: openarray[QMetaType]): seq[cint] =
result = @[]
for metaType in metaTypes:
result.add(cint(metaType))
type QObjectCallBack = proc(nimobject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl.}
proc dos_qobject_create(qobject: var RawQObject, nimobject: ptr QObjectObj, qobjectCallback: QObjectCallBack) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qobject_delete(qobject: RawQObject) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qobject_slot_create(qobject: RawQObject, slotName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, slotIndex: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qobject_signal_create(qobject: RawQObject, signalName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, signalIndex: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qobject_signal_emit(qobject: RawQObject, signalName: cstring, argumentsCount: cint, arguments: ptr RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qobject_property_create(qobject: RawQObject, propertyName: cstring, propertyType: cint, readSlot: cstring, writeSlot: cstring, notifySignal: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
method onSlotCalled*(nimobject: QObject, slotName: string, args: openarray[QVariant]) =
## Called from the NimQml bridge when a slot is called from Qml.
## Subclasses can override the given method for handling the slot call
discard()
proc qobjectCallback(nimObject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl, exportc.} =
if qobjectRegistry[nimObject]:
let qobject = cast[QObject](nimObject)
GC_ref(qobject)
let slotNameAsQVariant = newQVariant(slotName)
defer: slotNameAsQVariant.delete
let argumentsAsQVariant = arguments.toVariantSeq(numArguments)
defer: argumentsAsQVariant.delete
# Forward to args to the slot
qobject.onSlotCalled(slotNameAsQVariant.stringVal, argumentsAsQVariant)
# Update the slot return value
dos_qvariant_assign(arguments[0], argumentsAsQVariant[0].data)
GC_unref(qobject)
proc create*(qobject: QObject) =
## Create a new QObject
debugMsg("QObject", "create")
qobject.deleted = false
qobject.slots = initTable[string,cint]()
qobject.signals = initTable[string, cint]()
qobject.properties = initTable[string, cint]()
let qobjectPtr = addr(qobject[])
dos_qobject_create(qobject.data, qobjectPtr, qobjectCallback)
qobjectRegistry[qobjectPtr] = true
proc delete*(qobject: QObject) =
## Delete the given QObject
if not qobject.deleted:
debugMsg("QObject", "delete")
let qobjectPtr = addr(qobject[])
qobjectRegistry.del qobjectPtr
dos_qobject_delete(qobject.data)
qobject.data = nil.RawQObject
qobject.deleted = true
proc newQObject*(): QObject =
## Return a new QObject
newWithCondFinalizer(result, delete)
result.create()
proc registerSlot*(qobject: QObject,
slotName: string,
metaTypes: openarray[QMetaType]) =
## Register a slot in the QObject with the given name and signature
# Copy the metatypes array
var copy = toCIntSeq(metatypes)
var index: cint
dos_qobject_slot_create(qobject.data, slotName, cint(copy.len), addr(copy[0].cint), index)
qobject.slots[slotName] = index
proc registerSignal*(qobject: QObject,
signalName: string,
metatypes: openarray[QMetaType]) =
## Register a signal in the QObject with the given name and signature
var index: cint
if metatypes.len > 0:
var copy = toCIntSeq(metatypes)
dos_qobject_signal_create(qobject.data, signalName, copy.len.cint, addr(copy[0].cint), index)
else:
dos_qobject_signal_create(qobject.data, signalName, 0, nil, index)
qobject.signals[signalName] = index
proc registerProperty*(qobject: QObject,
propertyName: string,
propertyType: QMetaType,
readSlot: string,
writeSlot: string,
notifySignal: string) =
## Register a property in the QObject with the given name and type.
assert propertyName != nil, "property name cannot be nil"
# don't convert a nil string, else we get a strange memory address
let cReadSlot: cstring = if readSlot == nil: cast[cstring](nil) else: readSlot
let cWriteSlot: cstring = if writeSlot == nil: cast[cstring](nil) else: writeSlot
let cNotifySignal: cstring = if notifySignal == nil: cast[cstring](nil) else: notifySignal
dos_qobject_property_create(qobject.data, propertyName, propertyType.cint, cReadSlot, cWriteSlot, cNotifySignal)
proc emit*(qobject: QObject, signalName: string, args: openarray[QVariant] = []) =
## Emit the signal with the given name and values
if args.len > 0:
var copy = args.toRawVariantSeq
dos_qobject_signal_emit(qobject.data, signalName, copy.len.cint, addr(copy[0]))
else:
dos_qobject_signal_emit(qobject.data, signalName, 0, nil)
# QQuickView
proc dos_qquickview_create(view: var RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qquickview_delete(view: RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qquickview_show(view: RawQQuickView) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qquickview_source(view: RawQQuickView, filename: var cstring, length: var int) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qquickview_set_source(view: RawQQuickView, filename: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc create(view: var QQuickView) =
## Create a new QQuickView
dos_qquickview_create(view.data)
view.deleted = false
proc source(view: QQuickView): cstring =
## Return the source Qml file loaded by the view
var length: int
dos_qquickview_source(view.data, result, length)
proc `source=`(view: QQuickView, filename: cstring) =
## Sets the source Qml file laoded by the view
dos_qquickview_set_source(view.data, filename)
proc show(view: QQuickView) =
## Sets the view visible
dos_qquickview_show(view.data)
proc delete(view: QQuickView) =
## Delete the given QQuickView
if not view.deleted:
debugMsg("QQuickView", "delete")
dos_qquickview_delete(view.data)
view.data = nil.RawQQuickView
view.deleted = true
proc newQQuickView*(): QQuickView =
## Return a new QQuickView
newWithCondFinalizer(result, delete)
result.create()
# QModelIndex
proc dos_qmodelindex_create(modelIndex: var RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_delete(modelIndex: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_row(modelIndex: RawQModelIndex, row: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_column(modelIndex: RawQModelIndex, column: var cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_isValid(modelIndex: RawQModelIndex, column: var bool) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_data(modelIndex: RawQModelIndex, role: cint, data: RawQVariant) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_parent(modelIndex: RawQModelIndex, parent: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_child(modelIndex: RawQModelIndex, row: cint, column: cint, parent: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qmodelindex_sibling(modelIndex: RawQModelIndex, row: cint, column: cint, sibling: RawQModelIndex) {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(modelIndex: var QModelIndex) =
## Create a new QModelIndex
dos_qmodelindex_create(modelIndex.data)
modelIndex.deleted = false
proc create*(modelIndex: var QModelIndex, rawQModelIndex: RawQModelIndex) =
## Create a new QModelIndex
modelIndex.data = rawQModelIndex
modelIndex.deleted = false
proc delete*(modelIndex: QModelIndex) =
## Delete the given QModelIndex
if not modelIndex.deleted:
debugMsg("QModelIndex", "delete")
dos_qmodelindex_delete(modelIndex.data)
modelIndex.data = nil.RawQModelIndex
modelIndex.deleted = true
proc newQModelIndex*(): QModelIndex =
## Return a new QModelIndex
newWithCondFinalizer(result, delete)
result.create()
proc newQModelIndex*(rawQModelIndex: RawQModelIndex): QModelIndex =
## Return a new QModelIndex given a raw index
newWithCondFinalizer(result, delete)
result.create(rawQModelIndex)
proc row*(modelIndex: QModelIndex): cint =
## Return the index row
dos_qmodelindex_row(modelIndex.data, result)
proc column*(modelIndex: QModelIndex): cint =
## Return the index column
dos_qmodelindex_column(modelIndex.data, result)
proc isValid*(modelIndex: QModelIndex): bool =
## Return true if the index is valid, false otherwise
dos_qmodelindex_isValid(modelIndex.data, result)
proc data*(modelIndex: QModelIndex, role: cint): QVariant =
## Return the model data associated to the given role
result = newQVariant()
dos_qmodelindex_data(modelIndex.data, role, result.data)
proc parent*(modelIndex: QModelIndex): QModelIndex =
## Return the parent index
result = newQModelIndex()
dos_qmodelindex_parent(modelIndex.data, result.data)
proc child*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
## Return the child index associated to the given row and column
result = newQModelIndex()
dos_qmodelindex_child(modelIndex.data, row, column, result.data)
proc sibling*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
## Return the sibling index associated to the given row and column
result = newQModelIndex()
dos_qmodelindex_sibling(modelIndex.data, row, column, result.data)
# QHashIntByteArray
proc dos_qhash_int_qbytearray_create(qHash: var RawQHashIntByteArray) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qhash_int_qbytearray_delete(qHash: RawQHashIntByteArray) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qhash_int_qbytearray_insert(qHash: RawQHashIntByteArray, key: int, value: cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qhash_int_qbytearray_value(qHash: RawQHashIntByteArray, key: int, value: var cstring) {.cdecl, dynlib:dOtherSideDll, importc.}
proc create*(qHash: var QHashIntByteArray) =
## Create the QHash
debugMsg("QHashIntByteArray", "create")
dos_qhash_int_qbytearray_create(qHash.data)
qHash.deleted = false
proc delete*(qHash: QHashIntByteArray) =
## Delete the QHash
if not qHash.deleted:
debugMsg("QHashIntByteArray", "delete")
dos_qhash_int_qbytearray_delete(qHash.data)
qHash.deleted = true
proc insert*(qHash: QHashIntByteArray, key: int, value: cstring) =
## Insert the value at the given key
dos_qhash_int_qbytearray_insert(qHash.data, key, value)
proc value*(qHash: QHashIntByteArray, key: int): string =
## Return the value associated at the given key
var rawString: cstring
dos_qhash_int_qbytearray_value(qHash.data, key, rawString)
result = $rawString
dos_chararray_delete(rawString)
proc newQHashIntQByteArray*(): QHashIntByteArray =
## Create a new QHashIntQByteArray
newWithCondFinalizer(result, delete)
result.create()
# QAbstractListModel
type
RowCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
ColumnCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
DataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl.}
SetDataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, value: RawQVariant, role: cint, result: var bool) {.cdecl.}
RoleNamesCallback = proc(modelObject: ptr QAbstractListModelObj, result: RawQHashIntByteArray) {.cdecl.}
FlagsCallback = proc(modelObject: ptr QAbstractListModelObj, index: RawQModelIndex, result: var cint) {.cdecl.}
HeaderDataCallback = proc(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl.}
proc dos_qabstractlistmodel_create(model: var RawQAbstractListModel,
modelPtr: ptr QAbstractListModelObj,
qobjectCallback: QObjectCallBack,
rowCountCallback: RowCountCallback,
columnCountCallback: ColumnCountCallback,
dataCallback: DataCallback,
setDataCallback: SetDataCallBack,
roleNamesCallback: RoleNamesCallback,
flagsCallback: FlagsCallback,
headerDataCallback: HeaderDataCallback) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_delete(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_beginInsertRows(model: RawQAbstractListModel,
parentIndex: RawQModelIndex,
first: cint,
last: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_endInsertRows(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_beginRemoveRows(model: RawQAbstractListModel,
parentIndex: RawQModelIndex,
first: cint,
last: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_endRemoveRows(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_beginResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_endResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:dOtherSideDll, importc.}
proc dos_qabstractlistmodel_dataChanged(model: RawQAbstractListModel,
parentLeft: RawQModelIndex,
bottomRight: RawQModelIndex,
rolesArrayPtr: ptr cint,
rolesArrayLength: cint) {.cdecl, dynlib:dOtherSideDll, importc.}
method rowCount*(model: QAbstractListModel, index: QModelIndex): cint =
## Return the model's row count
return 0
proc rowCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "rowCountCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.rowCount(index)
method columnCount*(model: QAbstractListModel, index: QModelIndex): cint =
## Return the model's column count
return 1
proc columnCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "columnCountCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.columnCount(index)
method data*(model: QAbstractListModel, index: QModelIndex, role: cint): QVariant =
## Return the data at the given model index and role
return nil
proc dataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "dataCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
let variant = data(model, index, role)
if variant != nil:
dos_qvariant_assign(result, variant.data)
variant.delete
method setData*(model: QAbstractListModel, index: QModelIndex, value: QVariant, role: cint): bool =
## Sets the data at the given index and role. Return true on success, false otherwise
return false
proc setDataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, rawQVariant: RawQVariant, role: cint, result: var bool) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "setDataCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
let variant = newQVariant(rawQVariant)
result = model.setData(index, variant, role)
method roleNames*(model: QAbstractListModel): Table[cint, cstring] =
## Return the model role names
result = initTable[cint, cstring]()
proc roleNamesCallback(modelObject: ptr QAbstractListModelObj, hash: RawQHashIntByteArray) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "roleNamesCallback")
let model = cast[QAbstractListModel](modelObject)
let table = model.roleNames()
for key, val in table.pairs:
dos_qhash_int_qbytearray_insert(hash, key, val)
method flags*(model: QAbstractListModel, index: QModelIndex): QtItemFlag =
## Return the item flags and the given index
return QtItemFlag.None
proc flagsCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "flagsCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.flags(index).cint
method headerData*(model: QAbstractListModel, section: cint, orientation: QtOrientation, role: cint): QVariant =
## Returns the data for the given role and section in the header with the specified orientation
return nil
proc headerDataCallback(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "headerDataCallback")
let model = cast[QAbstractListModel](modelObject)
let variant = model.headerData(section, orientation.QtOrientation, role)
if variant != nil:
dos_qvariant_assign(result, variant.data)
variant.delete
proc create*(model: var QAbstractListModel) =
## Create a new QAbstractListModel
debugMsg("QAbstractListModel", "create")
model.slots = initTable[string,cint]()
model.signals = initTable[string, cint]()
model.properties = initTable[string, cint]()
model.deleted = false
let modelPtr = addr(model[])
dos_qabstractlistmodel_create(model.data.RawQAbstractListModel, modelPtr, qobjectCallback, rowCountCallback, columnCountCallback, dataCallback, setDataCallback, roleNamesCallback, flagsCallback, headerDataCallback)
qobjectRegistry[modelPtr] = true
proc delete*(model: QAbstractListModel) =
## Delete the given QAbstractListModel
if not model.deleted:
debugMsg("QAbstractListModel", "delete")
let modelPtr = addr(model[])
qobjectRegistry.del modelPtr
dos_qabstractlistmodel_delete(model.data.RawQAbstractListModel)
model.data = nil.RawQObject
model.deleted = true
proc newQAbstractListModel*(): QAbstractListModel =
## Return a new QAbstractListModel
newWithCondFinalizer(result, delete)
result.create()
proc beginInsertRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
## Notify the view that the model is about to inserting the given number of rows
dos_qabstractlistmodel_beginInsertRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
proc endInsertRows*(model: QAbstractListModel) =
## Notify the view that the rows have been inserted
dos_qabstractlistmodel_endInsertRows(model.data.RawQAbstractListModel)
proc beginRemoveRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
## Notify the view that the model is about to remove the given number of rows
dos_qabstractlistmodel_beginRemoveRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
proc endRemoveRows*(model: QAbstractListModel) =
## Notify the view that the rows have been removed
dos_qabstractlistmodel_endRemoveRows(model.data.RawQAbstractListModel)
proc beginResetModel*(model: QAbstractListModel) =
## Notify the view that the model is about to resetting
dos_qabstractlistmodel_beginResetModel(model.data.RawQAbstractListModel)
proc endResetModel*(model: QAbstractListModel) =
## Notify the view that model has finished resetting
dos_qabstractlistmodel_endResetModel(model.data.RawQAbstractListModel)
proc dataChanged*(model: QAbstractListModel,
topLeft: QModelIndex,
bottomRight: QModelIndex,
roles: seq[cint]) =
## Notify the view that the model data changed
var copy = roles
dos_qabstractlistmodel_dataChanged(model.data.RawQAbstractListModel, topLeft.data, bottomRight.data, copy[0].addr, copy.len.cint)

View File

@ -1,9 +0,0 @@
[Package]
name = "NimQml"
version = "0.3.0"
author = "Filippo Cucchetto, Will Szumski"
description = "QML bindings for Nimrod"
license = "GPLv3"
[Deps]
Requires: "nimrod >= 0.10.2"

View File

@ -1,502 +0,0 @@
## Contains helper macros for NimQml
import macros
import strutils
import typetraits
import tables
template debug(body: stmt): stmt =
{.push warning[user]: off.}
when defined(debug):
{.pop.}
body
else:
{.pop.}
let nimFromQtVariant {.compileTime.} = {
"int" : "intVal",
"string" : "stringVal",
"bool" : "boolVal",
"float" : "floatVal",
"QObject" : "qobjectVal",
}.toTable
let nim2QtMeta {.compileTime.} = {
"bool": "Bool",
"int" : "Int",
"string" : "QString",
"pointer" : "VoidStar",
"QObject" : "QObjectStar",
"QVariant": "QVariant",
"" : "Void", # no return, which is represented by an nnkEmpty node
}.toTable
proc getNodeOf*(tree: NimNode, kind: NimNodeKind): NimNode {.compileTime.} =
## recursively looks for a node of kind, ``kind``, in the tree provided as ``tree``
## Returns the first node that satisfies this condition
for i in 0.. <tree.len:
var child = tree[i]
if child.kind == kind:
return child
var candidate = getNodeOf(child, kind)
if not candidate.isNil:
return candidate
static:
type Context* = ref object of RootObj
type NullContext* = ref object of Context
type NodeModifier*[T] = proc(context: T, a: var NimNode): NimNode
# had to remove type bound on hook due to recent regression with generics
proc hookOnNode*[T](context: T, code: NimNode, hook: NodeModifier,
recursive: bool = false): NimNode {.compileTime.} =
## Iterates over the tree, ``code``, calling ``hook`` on each ``NimNode``
## encountered. If ``recursive`` is true, it will recurse over the tree, otherwise
## it will only visit ``code``'s children. ``hook`` should return a replacement for
## the node that was passed in via it's return value. `hook` may return nil to remove
## the node from the tree.
if code.len == 0:
return code
var newCode = newNimNode(code.kind)
for i in 0.. <code.len:
var child = code[i].copy()
child = hook(context, child)
if recursive:
child = hookOnNode(context,child,hook,true)
if child != nil:
newCode.add child
return newCode
proc removeOpenSym*(context: NullContext,
a: var NimNode): NimNode {.compileTime.} =
## replaces: ``nnkOpenSymChoice`` and ``nnkSym`` nodes with idents
## corresponding to the symbols string representation.
if a.kind == nnkOpenSymChoice:
return ident($a[0].symbol)
elif a.kind == nnkSym:
return ident($a.symbol)
return a
proc newTemplate*(name = newEmptyNode();
params: openArray[NimNode] = [newEmptyNode()];
body: NimNode = newStmtList()): NimNode {.compileTime.} =
## shortcut for creating a new template
##
## The ``params`` array must start with the return type of the template,
## followed by a list of IdentDefs which specify the params.
result = newNimNode(nnkTemplateDef).add(
name,
newEmptyNode(),
newEmptyNode(),
newNimNode(nnkFormalParams).add(params), ##params
newEmptyNode(), ## pragmas
newEmptyNode(),
body)
#FIXME: changed parent, typ from typedesc to expr to workaround Nim issue #1874
template declareSuperTemplate*(parent: expr, typ: expr): stmt =
template superType*(ofType: typedesc[typ]): typedesc[parent] =
parent
proc getTypeName*(a: NimNode): NimNode {.compileTime.} =
## returns the node containing the name of an object in a
## given type definition block
expectMinLen a, 1
expectKind a, nnkTypeDef
var testee = a
if testee[0].kind == nnkPragmaExpr:
testee = testee[0]
if testee[0].kind in {nnkIdent}:
return testee[0]
elif testee[0].kind in {nnkPostfix}:
return testee[0][1]
proc isExported(def: NimNode): bool {.compileTime.} =
## given a type definition, ``typedef``, determines whether or
## not the type is exported with a '*'
assert def.kind in {nnkTypeDef, nnkProcDef, nnkMethodDef, nnkTemplateDef},
"unsupported type: " & $def.kind
if def[0].kind == nnkPostfix:
return true
proc exportDef(def: NimNode) {.compileTime.} =
## Exports exportable definitions. Currently only supports
## templates, methods and procedures and types.
if def.kind in {nnkProcDef, nnkMethodDef, nnkTemplateDef, nnkTypeDef}:
if def.isExported:
return
def[0] = postfix(def[0], "*")
else:
error("node: " & $def.kind & " not supported")
proc unexportDef(def: NimNode) {.compileTime.} =
## unexports exportable definitions. Currently only supports
## templates, methods and procedures and types.
if def.kind in {nnkProcDef, nnkMethodDef, nnkTemplateDef, nnkTypeDef}:
if not def.isExported:
return
def[0] = ident unpackPostfix(def[0])[1]
else:
error("node: " & $def.kind & " not supported")
proc genSuperTemplate*(typeDecl: NimNode): NimNode {.compileTime.} =
## generates a template, with name: superType, that returns the super type
## of the object defined in the type defintion, ``typeDecl``. ``typeDecl``
## must contain an object inheriting from a base type.
expectKind typeDecl, nnkTypeDef
let inheritStmt = typeDecl.getNodeOf(nnkOfInherit)
let typeName = getTypeName(typeDecl)
if inheritStmt == nil: error("you must declare a super type for " & $typeName)
# ident of superType (have to deal with generics)
let superType = if inheritStmt[0].kind == nnkIdent: inheritStmt[0]
else: inheritStmt[0].getNodeOf(nnkIdent)
let superTemplate = getAst declareSuperTemplate(superType, typeName)
result = superTemplate[0]
if typeDecl.isExported():
result.exportDef()
else:
result.unexportDef()
proc getSuperType*(typeDecl: NimNode): NimNode {.compileTime.} =
## returns ast containing superType info, may not be an ident if generic
let inheritStmt = typeDecl.getNodeOf(nnkOfInherit)
if inheritStmt.isNil: return newEmptyNode()
return inheritStmt[0]
proc getPragmaName*(child: NimNode): NimNode {.compileTime.} =
## name of child in a nnkPragma section
if child.kind == nnkIdent:
return child
# assumes first ident is name of pragma
let ident = child.getNodeOf(nnkIdent)
result = ident
proc removePragma*(pragma: NimNode, toRemove: string): NimNode {.compileTime.} =
## removes a pragma from pragma definition, `pragma`, with name `toRemove`
expectKind pragma, nnkPragma
result = newNimNode(nnkPragma)
for i in 0.. <pragma.len:
let child = pragma[i]
if $child.getPragmaName == toRemove:
continue
result.add child
if result.len == 0:
return newEmptyNode()
proc hasPragma*(node: NimNode, pragmaName: string): bool {.compileTime.} =
## Returns ``true`` iff the method, or proc definition: ``node``, has a pragma
## ``pragmaName``
doAssert node.kind in {nnkMethodDef, nnkProcDef}
result = false
let pragma = node.pragma
if pragma.kind == nnkEmpty:
# denotes no pragma set
return false
for child in pragma.children():
if $child.getPragmaName() == pragmaName:
return true
proc getArgType*(arg: NimNode): NimNode {.compileTime.} =
## returns the ``NimNode`` representing a parameters type
if arg[1].kind == nnkIdent:
arg[1]
else:
arg[1].getNodeOf(nnkIdent)
proc getArgName*(arg: NimNode): NimNode {.compileTime.} =
## returns the ``NimNode`` representing a parameters name
if arg[0].kind == nnkIdent:
arg[0]
else:
arg[0].getNodeOf(nnkIdent)
proc addSignalBody(signal: NimNode): NimNode {.compileTime.} =
# e.g: produces: emit(MyQObject, "nameChanged")
assert signal.kind in {nnkMethodDef, nnkProcDef}
result = newStmtList()
# if exported, will use postfix
let name = if signal.name.kind == nnkIdent: signal.name else: signal.name[1]
let params = signal.params
# type signal defined on is the 1st arg
let self = getArgName(params[1])
var args = newSeq[NimNode]()
args.add(self)
args.add newLit($name)
if params.len > 2: # more args than just type
for i in 2.. <params.len:
args.add getArgName params[i]
result.add newCall("emit", args)
#FIXME: changed typ from typedesc to expr to workaround Nim issue #1874
# This is declared dirty so that identifers are not bound to symbols.
# The alternative is to use `removeOpenSym` as we did for `prototypeCreate`.
# We should decide which method is preferable.
template prototypeOnSlotCalled(typ: expr): stmt {.dirty.} =
method onSlotCalled(myQObject: typ, slotName: string, args: openarray[QVariant]) =
var super = (typ.superType())(myQObject)
procCall onSlotCalled(super, slotName, args)
#FIXME: changed parent, typ from typedesc to expr to workaround Nim issue #1874
template prototypeCreate(typ: expr): stmt {.dirty.}=
proc create*(myQObject: var typ) =
var super = (typ.superType())(myQObject)
procCall create(super)
proc doRemoveOpenSym(a: var NimNode): NimNode {.compileTime.} =
hookOnNode(NullContext(),a, removeOpenSym, true)
proc templateBody*(a: NimNode): NimNode {.compileTime.} =
expectKind a, nnkTemplateDef
result = a[6]
proc genArgTypeArray(params: NimNode): NimNode {.compileTime.} =
expectKind params, nnkFormalParams
result = newNimNode(nnkBracket)
for i in 0 .. <params.len:
if i == 1:
# skip "self" param eg: myQObject: MyQObject
continue
let pType = if i != 0: getArgType params[i] else: params[i]
let pTypeString = if pType.kind == nnkEmpty: "" else: $pType
# function that maps Qvariant type to nim type
let qtMeta = nim2QtMeta[pTypeString]
if qtMeta == nil: error(pTypeString & " not supported yet")
let metaDot = newDotExpr(ident "QMetaType", ident qtMeta)
result.add metaDot
proc getIdentDefName*(a: NimNode): NimNode {.compileTime.} =
## returns object field name from ident def
expectKind a, nnkIdentDefs
if a[0].kind == nnkIdent:
return a[0]
elif a[0].kind == nnkPostFix:
return a[0][1]
proc tryHandleSigSlot(def: NimNode, signals: var seq[NimNode], slots: var seq[NimNode],
generatedCode: var NimNode): bool {.compileTime.} =
## Checks a method/proc definition for signals and slots. On finding a method/proc with
## a {.signal.} or {.slot.} pragma, it will strip the pragma, add the definition to the
## appropriate seq, append the stripped version to the generated code block and return true
## indicating the definition was a signal or a slot. If the method/proc is not a slot
## or a slot it will return false.
expectKind generatedCode, nnkStmtList
assert (not signals.isNil)
assert (not slots.isNil)
assert def.kind in {nnkMethodDef, nnkProcDef}
result = false
if def.hasPragma("slot"):
let pragma = def.pragma()
def.pragma = pragma.removePragma("slot")
slots.add def # we need to gensome code later
generatedCode.add def
result = true
elif def.hasPragma("signal"):
let pragma = def.pragma()
def.pragma = pragma.removePragma("signal")
def.body = addSignalBody(def)
generatedCode.add def
signals.add def
result = true
proc genCreateDecl(typ: NimNode): NimNode {.compileTime.} =
## generates forward declaration for ``create`` procedure
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
result = (getAst prototypeCreate(typeName))[0]
result.body = newEmptyNode()
if typ.isExported:
result.exportDef()
else:
result.unexportDef()
proc genCreate(typ: NimNode, signals: seq[NimNode], slots: seq[NimNode],
properties: seq[NimNode]): NimNode {.compileTime.} =
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
result = (getAst prototypeCreate(typeName))[0]
# the template creates loads of openSyms - replace these with idents
result = doRemoveOpenSym(result)
if typ.isExported:
result.exportDef()
else:
result.unexportDef()
var createBody = result.body
for slot in slots:
let params = slot.params
let regSlotDot = newDotExpr(ident "myQObject", ident "registerSlot")
let name = ($slot.name).replace("*","")
let argTypesArray = genArgTypeArray(params)
let call = newCall(regSlotDot, newLit name, argTypesArray)
createBody.add call
for signal in signals:
let params = signal.params
let regSigDot = newDotExpr(ident "myQObject", ident "registerSignal")
let name = ($signal.name).replace("*","")
let argTypesArray = genArgTypeArray(params)
let call = newCall(regSigDot, newLit name, argTypesArray)
createBody.add call
for property in properties:
let bracket = property[0]
expectKind bracket, nnkBracketExpr
#Command
# BracketExpr
# Ident !"QtProperty"
# Ident !"string"
# Ident !"name"
# StmtList
let nimPropType = bracket[1]
let qtPropMeta = nim2QtMeta[$nimPropType]
if qtPropMeta == nil: error($nimPropType & " not supported")
let metaDot = newDotExpr(ident "QMetaType", ident qtPropMeta)
let propertyName = property[1]
var read, write, notify: NimNode
let stmtList = property[2]
# fields
# StmtList
# Asgn
# Ident !"read"
# Ident !"getName
for asgn in stmtList.children:
let name = asgn[0]
case $name
of "read":
read = asgn[1]
of "write":
write = asgn[1]
of "notify":
notify = asgn[1]
else:
error("unknown property field: " & $name)
let regPropDot = newDotExpr(ident "myQObject", ident "registerProperty")
let readArg = if read == nil: newNilLit() else: newLit($read)
let writeArg = if write == nil: newNilLit() else: newLit($write)
let notifyArg = if notify == nil: newNilLit() else: newLit($notify)
let call = newCall(regPropDot, newLit($propertyName), metaDot, readArg, writeArg, notifyArg)
createBody.add call
proc genOnSlotCalled(typ: NimNode, slots: seq[NimNode]): NimNode {.compileTime.} =
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
result = (getAst prototypeOnSlotCalled(typeName))[0]
var caseStmt = newNimNode(nnkCaseStmt)
caseStmt.add ident("slotName")
for slot in slots:
var ofBranch = newNimNode(nnkOfBranch)
# for exported procedures - strip * marker
let slotName = ($slot.name).replace("*","")
ofBranch.add newLit slotName
let params = slot.params
let hasReturn = not (params[0].kind == nnkEmpty)
var branchStmts = newStmtList()
var args = newSeq[NimNode]()
# first params always the object
args.add ident "myQObject"
for i in 2.. <params.len:
let pType = getArgType params[i]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(i-1)
if $pType == "QVariant":
args.add argAccess
else:
# function that maps QVariant type to nim type
let mapper = nimFromQtVariant[$pType]
let dot = newDotExpr(argAccess, ident mapper)
args.add dot
var call = newCall(ident slotName, args)
if hasReturn:
let retType = params[0]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(0)
if $retType == "QVariant":
# eg: args[0].assign(getName(myQObject))
let dot = newDotExpr(argAccess, ident "assign")
call = newCall(dot, call)
else:
# eg: args[0].strVal = getName(myQObject)
let mapper = nimFromQtVariant[$retType]
let dot = newDotExpr(argAccess, ident mapper)
call = newAssignment(dot, call)
branchStmts.add call
ofBranch.add branchStmts
caseStmt.add ofBranch
# add else: discard
caseStmt.add newNimNode(nnkElse)
.add newStmtList().add newNimNode(nnkDiscardStmt).add newNimNode(nnkEmpty)
result.body.add caseStmt
macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
## Generates boiler plate code for registering signals, slots
## and properties.
##
## Currently generates:
## - create: a method to register signal, slots and properties
## - superType: a template that returns the super type of the
## object defined within the macro body
## - onSlotCalled: a method to dispatch an on slot call to the
## appropiate method.
##
## Current limitations:
## - only one type can be defined within the body of code sent to the
## the macro. It is assumed, but not checked, that somewhere in the
## inheritance hierarchy this object derives from ``QObject``.
## - generics are not currently supported
expectKind(qtDecl, nnkStmtList)
#echo treeRepr qtDecl
result = newStmtList()
var slots = newSeq[NimNode]()
var properties = newSeq[NimNode]()
var signals = newSeq[NimNode]()
# assume only one type per section for now
var typ: NimNode
for it in qtDecl.children():
if it.kind == nnkTypeSection:
let typeDecl = it.findChild(it.kind == nnkTypeDef)
let superType = typeDecl.getSuperType()
if superType.kind == nnkEmpty:
# allow simple types and type aliases
result.add it
else:
# may come in useful if we want to check objects inherit from QObject
#let superName = if superType.kind == nnkIdent: superType
# else: superType.getNodeOf(nnkIdent)
if typ != nil:
error("you may not define more than one type " &
"within the code block passed to this macro")
else: # without this else, it fails to compile
typ = typeDecl
result.add it
result.add genSuperTemplate(typeDecl)
result.add genCreateDecl(typeDecl)
elif it.kind == nnkMethodDef:
if tryHandleSigSlot(it, signals, slots, result): continue
result.add it
elif it.kind == nnkProcDef:
if tryHandleSigSlot(it, signals, slots, result): continue
result.add it
elif it.kind == nnkCommand:
let bracket = it[0]
if bracket.kind != nnkBracketExpr:
error("do not know how to handle: \n" & repr(it))
# BracketExpr
# Ident !"QtProperty"
# Ident !"string"
let cmdIdent = bracket[0]
if cmdIdent == nil or cmdIdent.kind != nnkIdent or
($cmdIdent).toLower() != "qtproperty":
error("do not know how to handle: \n" & repr(it))
properties.add it
else:
# everything else should pass through unchanged
result.add it
if typ == nil:
error("you must declare an object that inherits from QObject")
result.add genOnSlotCalled(typ, slots)
result.add genCreate(typ, signals, slots, properties)
debug:
echo repr result

View File

@ -1,68 +0,0 @@
import tables
type
RawQVariant = distinct pointer
QVariant* = ref object of RootObj ## A QVariant
data: RawQVariant
deleted: bool
RawQQmlApplicationEngine = distinct pointer
QQmlApplicationEngine* = ref object of RootObj ## A QQmlApplicationEngine
data: RawQQmlApplicationEngine
deleted: bool
QApplication* = ref object of RootObj ## A QApplication
deleted: bool
QGuiApplication* = ref object of RootObj ## A QGuiApplication
deleted: bool
RawQObject = distinct pointer
QObjectObj = object of RootObj
data: RawQObject
slots: Table[string, cint]
signals: Table[string, cint]
properties: Table[string, cint]
deleted: bool
QObject* = ref QObjectObj
RawBaseQObjectObj = distinct pointer
BaseQObjectObj = object of QObjectObj
BaseQObject* = ref BaseQObjectObj ## A QObject
RawQAbstractListModel = distinct pointer
QAbstractListModelObj = object of QObjectObj
QAbstractListModel* = ref QAbstractListModelObj ## A QAbstractListModel
RawQQuickView = distinct pointer
QQuickView = ref object of RootObj ## A QQuickView
data: RawQQuickView
deleted: bool
QQmlContext* = distinct pointer ## A QQmlContext
RawQModelIndex = distinct pointer
QModelIndex* = ref object of RootObj ## A QModelIndex
data: RawQModelIndex
deleted: bool
RawQHashIntByteArray = distinct pointer
QHashIntByteArrayObj = object of RootObj
data: RawQHashIntByteArray
deleted: bool
QHashIntByteArray* = ref QHashIntByteArrayObj ## A QHash<int,QByteArray>
QtItemFlag* {.pure.} = enum
None = 0.cint,
IsSelectable = 1.cint,
IsEditable = 2.cint,
IsDragEnabled = 4.cint,
IsDropEnabled = 8.cint,
IsUserCheckable = 16.cint,
IsEnabled = 32.cint,
IsTristate = 64.cint,
NeverHasChildren = 128.cint
QtOrientation {.pure.} = enum
Horizontal = 1.cint,
Vertical = 2.cint

View File

@ -1,22 +0,0 @@
include(CMakeParseArguments)
find_program(NIM_EXECUTABLE nim PATHS ENV PATH)
mark_as_advanced(NIM_EXECUTABLE)
# Determine the nimrod version
if(NIM_EXECUTABLE)
execute_process(COMMAND ${NIM_EXECUTABLE} "--version"
OUTPUT_VARIABLE NIM_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE)
STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" NIM_VERSION ${NIM_VERSION})
endif(NIM_EXECUTABLE)
# Handle the QUIETLY and REQUIRED arguments, which may be given to the find call.
# set NIM_FOUND to TRUE if Nimrod has been found
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Nim
REQUIRED_VARS NIM_EXECUTABLE
VERSION_VAR NIM_VERSION)
set(NIM_USE_FILE "${CMAKE_CURRENT_LIST_DIR}/UseNim.cmake")

View File

@ -1,49 +0,0 @@
include(CMakeParseArguments)
function(add_nim_executable )
set(options )
set(oneValueArgs TARGET)
set(multiValueArgs SOURCES PATHS)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# collect set of input source files
set(in_files "")
foreach(src ${ARGS_SOURCES} ${ARGS_UNPARSED_ARGUMENTS})
list(APPEND in_files "${CMAKE_CURRENT_SOURCE_DIR}/${src}")
endforeach(src ${ARGS_SOURCES} ${ARGS_UNPARSED_ARGUMENTS})
set(in_paths "")
foreach(path ${ARGS_PATHS} ${ARGS_UNPARSED_ARGUMENTS})
list(APPEND in_paths "--path:${CMAKE_CURRENT_SOURCE_DIR}/${path}")
endforeach(path ${ARGS_PATHS} ${ARGS_UNPARSED_ARGUMENTS})
# set the target binary and nim cache directory
set(nim_target "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_TARGET}")
set(nim_cache_dir "${CMAKE_CURRENT_BINARY_DIR}/nimcache")
# compiler
set(nim_compiler "c")
# compiler options
set(nim_compiler_options "")
if (WIN32)
if (MSVC OR MSVC_IDE)
set(nim_compiler_options "--cc:vcc")
endif()
endif()
# thread options
set(nim_thread_options "")
if(UNIX)
set(nim_thread_options "--passL:-lpthread")
endif()
# add target to trigger the nimrod compiler
add_custom_target(
${ARGS_TARGET} ALL
COMMAND
${NIM_EXECUTABLE} ${nim_compiler} ${nim_compiler_options} ${nim_thread_options} ${in_paths} "--nimcache:" ${nim_cache_dir} "--out:" ${nim_target} ${in_files}
DEPENDS
${in_files}
)
endfunction(add_nim_executable)

View File

@ -1,57 +1,33 @@
# DOtherSide
[![License](https://img.shields.io/badge/license-LGPL-green.svg)](https://github.com/filcuc/DOtherSide/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/filcuc/DOtherSide.svg?branch=master)](https://travis-ci.org/filcuc/DOtherSide)
## Description
C language library for creating bindings for the Qt QML language.
Qml bindings for both D and Nim programming languages
Currently the DOtherSide library is used by the following bindings:
* [nimqml](https://github.com/filcuc/nimqml), QML bindings for the Nim programming language
* [dqml](https://github.com/filcuc/dqml), QML bindings for the D programming language
## Change log
The project change log can be read [here](./CHANGELOG.md).
## Documentation
The documentation for the Nim programming language can be
read [here](http://filcuc.github.io/DOtherSide/ "").
For the D programming language is an on going project
and pull request are accepted.
## Supported Platforms and Requirements
## Supported platforms
Currently we support the following platforms/compilers:
- Linux both 32/64bit with gcc
- Windows 32/64bit with Visual Studio 2013 Community Edition
## Change log
The project change log can be read [here](./CHANGELOG.md).
## Build requirements
You need the following software:
* Qt 5.3 or higher
* dmd 2.065 or higher
* Linux: gcc 4.8 or later with c++11 support or higher
* Windows: Visual Studio 2013 Community Edition (Windows) or higher
* Windows: MingGW 4.9.2 or higher
* nim 0.10.3 or higher
## Build Instructions
## Build instructions:
1. Open a shell terminal inside the cloned repo
2. mkdir build && cd build
3. cmake ..
4. make
## Install Instructions
For the DOtherSide C++ bridge:
1. Copy the libDOtherSide.so from the build dir to your system lib i.e /usr/lib
For NimQml use the Nimble package manager:
1. Open a shell and navigate to the NimQml subdirectory
2. Type: nimble install
3. Now you can use it in your .nim files
## Supported features:
* Creation of custom QObject and inject in a qml QtQuick view (both Nim and D)
* Slot and Signal creation for the following types int, bool, string (both Nim and D)
* Creation of properties for databinding (both Nim and D)
* Subclassing of QAbstractListModels
Copy the libDOtherSide.so from the build dir to your system lib i.e /usr/lib

Some files were not shown because too many files have changed in this diff Show More