add Lua api version check and type defs (#183)
This commit is contained in:
parent
423f87763e
commit
e2a23ed4ee
|
@ -21,6 +21,7 @@
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
@ -51,12 +52,127 @@ using pIsWow64Process2_t = BOOL (WINAPI *)(
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// C_Debug.debug(string) -> ()
|
static QString luaDump(const QJsonValue &value) {
|
||||||
|
if (value.isNull())
|
||||||
|
return "nil";
|
||||||
|
if (value.isBool())
|
||||||
|
return value.toBool() ? "true" : "false";
|
||||||
|
if (value.isDouble())
|
||||||
|
return QString::number(value.toDouble());
|
||||||
|
if (value.isString()) {
|
||||||
|
QString s = value.toString();
|
||||||
|
s.replace('\\', "\\\\");
|
||||||
|
s.replace('"', "\\\"");
|
||||||
|
s.replace('\n', "\\n");
|
||||||
|
s.replace('\r', "\\r");
|
||||||
|
s.replace('\t', "\\t");
|
||||||
|
return '"' + s + '"';
|
||||||
|
}
|
||||||
|
if (value.isArray()) {
|
||||||
|
QString s = "{";
|
||||||
|
for (const QJsonValue &v : value.toArray())
|
||||||
|
s += luaDump(v) + ',';
|
||||||
|
s += '}';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if (value.isObject()) {
|
||||||
|
QJsonObject o = value.toObject();
|
||||||
|
QString s = "{";
|
||||||
|
for (const QString &k : o.keys())
|
||||||
|
s += '[' + luaDump(k) + "]=" + luaDump(o[k]) + ',';
|
||||||
|
s += '}';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return "nil";
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString stringify(const QJsonValue &value) {
|
||||||
|
if (value.isString())
|
||||||
|
return value.toString();
|
||||||
|
if (value.isNull())
|
||||||
|
return "[nil]";
|
||||||
|
if (value.isBool())
|
||||||
|
return value.toBool() ? "[true]" : "[false]";
|
||||||
|
if (value.isDouble())
|
||||||
|
return QString("[number %1]").arg(value.toDouble());
|
||||||
|
if (value.isArray() || value.isObject())
|
||||||
|
return QString("[table %1]").arg(luaDump(value));
|
||||||
|
return "[unknown]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* https://stackoverflow.com/questions/15687223/explicit-call-to-destructor-before-longjmp-croak
|
||||||
|
*
|
||||||
|
* C++11 18.10/4: A setjmp/longjmp call pair has undefined behavior if
|
||||||
|
* replacing the setjmp and longjmp by catch and throw would invoke any
|
||||||
|
* non-trivial destructors for any automatic objects.
|
||||||
|
*
|
||||||
|
* Use impl function so the API boundary contains only POD types.
|
||||||
|
*/
|
||||||
|
void luaApiImpl_Debug_debug(lua_State *L) {
|
||||||
|
QString s = AddOn::RaiiLuaState::fetchString(L, 1);
|
||||||
|
int nArgs = lua_gettop(L);
|
||||||
|
for (int i = 2; i <= nArgs; ++i) {
|
||||||
|
QJsonValue arg;
|
||||||
|
try {
|
||||||
|
arg = AddOn::RaiiLuaState::fetch(L, i);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
QString reason = e.reason() + QString(" ('C_Debug.debug' argument #%1)").arg(i);
|
||||||
|
throw AddOn::LuaError(reason);
|
||||||
|
}
|
||||||
|
s = s.arg(stringify(arg));
|
||||||
|
}
|
||||||
|
qDebug().noquote() << s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// C_Debug.debug(string, ...) -> ()
|
||||||
extern "C" int luaApi_Debug_debug(lua_State *L) noexcept {
|
extern "C" int luaApi_Debug_debug(lua_State *L) noexcept {
|
||||||
QString info = AddOn::RaiiLuaState::fetchString(L, 1);
|
bool error = false;
|
||||||
qDebug() << info;
|
try {
|
||||||
|
luaApiImpl_Debug_debug(L);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
error = true;
|
||||||
|
AddOn::RaiiLuaState::push(L, e.reason());
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
lua_error(L); // longjmp, never returns
|
||||||
|
__builtin_unreachable();
|
||||||
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void luaApiImpl_Debug_messageBox(lua_State *L) {
|
||||||
|
QString s = AddOn::RaiiLuaState::fetchString(L, 1);
|
||||||
|
int nArgs = lua_gettop(L);
|
||||||
|
for (int i = 2; i <= nArgs; ++i) {
|
||||||
|
QJsonValue arg;
|
||||||
|
try {
|
||||||
|
arg = AddOn::RaiiLuaState::fetch(L, i);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
QString reason = e.reason() + QString(" ('C_Debug.messageBox' argument #%1)").arg(i);
|
||||||
|
throw AddOn::LuaError(reason);
|
||||||
|
}
|
||||||
|
s = s.arg(stringify(arg));
|
||||||
|
}
|
||||||
|
QMessageBox::information(nullptr, "Debug", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C_Debug.messageBox(string, ...) -> ()
|
||||||
|
extern "C" int luaApi_Debug_messageBox(lua_State *L) noexcept {
|
||||||
|
bool error = false;
|
||||||
|
try {
|
||||||
|
luaApiImpl_Debug_messageBox(L);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
error = true;
|
||||||
|
AddOn::RaiiLuaState::push(L, e.reason());
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
lua_error(L); // longjmp, never returns
|
||||||
|
__builtin_unreachable();
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// C_Desktop.desktopEnvironment() -> string
|
// C_Desktop.desktopEnvironment() -> string
|
||||||
extern "C" int luaApi_Desktop_desktopEnvironment(lua_State *L) noexcept {
|
extern "C" int luaApi_Desktop_desktopEnvironment(lua_State *L) noexcept {
|
||||||
|
@ -262,9 +378,7 @@ extern "C" int luaApi_System_supportedAppArchList(lua_State *L) noexcept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround for Debian 10 Qt 5.11, better to be
|
QStringList result = arches.values();
|
||||||
// QStringList result{arches.begin(), arches.end()};
|
|
||||||
QStringList result = arches.toList();
|
|
||||||
AddOn::RaiiLuaState::push(L, result);
|
AddOn::RaiiLuaState::push(L, result);
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
|
@ -291,15 +405,37 @@ extern "C" int luaApi_System_readRegistry(lua_State *L) noexcept
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// C_Util.format(string, ...) -> string
|
void luaApiImpl_Util_format(lua_State *L)
|
||||||
extern "C" int luaApi_Util_format(lua_State *L) noexcept
|
|
||||||
{
|
{
|
||||||
QString s = AddOn::RaiiLuaState::fetchString(L, 1);
|
QString s = AddOn::RaiiLuaState::fetchString(L, 1);
|
||||||
int nArgs = lua_gettop(L);
|
int nArgs = lua_gettop(L);
|
||||||
for (int i = 2; i <= nArgs; ++i) {
|
for (int i = 2; i <= nArgs; ++i) {
|
||||||
QJsonValue arg = AddOn::RaiiLuaState::fetch(L, i);
|
QJsonValue arg;
|
||||||
s = s.arg(arg.toString());
|
try {
|
||||||
|
arg = AddOn::RaiiLuaState::fetch(L, i);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
QString reason = e.reason() + QString(" ('C_Util.format' argument #%1)").arg(i);
|
||||||
|
throw AddOn::LuaError(reason);
|
||||||
|
}
|
||||||
|
s = s.arg(stringify(arg));
|
||||||
}
|
}
|
||||||
AddOn::RaiiLuaState::push(L, s);
|
AddOn::RaiiLuaState::push(L, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C_Util.format(string, ...) -> string
|
||||||
|
extern "C" int luaApi_Util_format(lua_State *L) noexcept
|
||||||
|
{
|
||||||
|
bool error = false;
|
||||||
|
try {
|
||||||
|
luaApiImpl_Util_format(L);
|
||||||
|
} catch (const AddOn::LuaError &e) {
|
||||||
|
error = true;
|
||||||
|
AddOn::RaiiLuaState::push(L, e.reason());
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
lua_error(L); // longjmp, never returns
|
||||||
|
__builtin_unreachable();
|
||||||
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
|
|
||||||
extern "C" int luaApi_Debug_debug(lua_State *L) noexcept;
|
extern "C" int luaApi_Debug_debug(lua_State *L) noexcept;
|
||||||
|
extern "C" int luaApi_Debug_messageBox(lua_State *L) noexcept;
|
||||||
|
|
||||||
extern "C" int luaApi_Desktop_desktopEnvironment(lua_State *L) noexcept;
|
extern "C" int luaApi_Desktop_desktopEnvironment(lua_State *L) noexcept;
|
||||||
extern "C" int luaApi_Desktop_language(lua_State *L) noexcept;
|
extern "C" int luaApi_Desktop_language(lua_State *L) noexcept;
|
||||||
|
|
|
@ -26,7 +26,8 @@ namespace AddOn {
|
||||||
static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
|
static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
|
||||||
{"C_Debug",
|
{"C_Debug",
|
||||||
{
|
{
|
||||||
{"debug", &luaApi_Debug_debug}, // (string) -> ()
|
{"debug", &luaApi_Debug_debug}, // (string, ...) -> ()
|
||||||
|
{"messageBox", &luaApi_Debug_messageBox}, // (string, ...) -> ()
|
||||||
}},
|
}},
|
||||||
{"C_Desktop",
|
{"C_Desktop",
|
||||||
{
|
{
|
||||||
|
@ -80,7 +81,11 @@ extern "C" void luaHook_timeoutKiller(lua_State *L, lua_Debug *ar [[maybe_unused
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ThemeExecutor::ThemeExecutor() : SimpleExecutor({"C_Debug", "C_Desktop"}) {}
|
ThemeExecutor::ThemeExecutor() : SimpleExecutor(
|
||||||
|
"theme", 0, 1,
|
||||||
|
{"C_Debug", "C_Desktop", "C_Util"})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject ThemeExecutor::operator()(const QByteArray &script,
|
QJsonObject ThemeExecutor::operator()(const QByteArray &script,
|
||||||
const QString &name) {
|
const QString &name) {
|
||||||
|
@ -92,28 +97,74 @@ QJsonObject ThemeExecutor::operator()(const QByteArray &script,
|
||||||
throw LuaError("Theme script must return an object.");
|
throw LuaError("Theme script must return an object.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimpleExecutor::SimpleExecutor(const QString &kind, int major, int minor, const QList<QString> &apis)
|
||||||
|
: mKind(kind), mMajor(major), mMinor(minor), mApis(apis)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimpleExecutor::apiVersionCheck(const QJsonObject &addonApi) {
|
||||||
|
const QString &addonKind = addonApi["kind"].toString();
|
||||||
|
if (addonKind != mKind)
|
||||||
|
return false;
|
||||||
|
if (!addonApi.contains("major") || !addonApi.contains("minor"))
|
||||||
|
return false;
|
||||||
|
int addonMajor = addonApi["major"].toInt();
|
||||||
|
int addonMinor = addonApi["minor"].toInt();
|
||||||
|
if (mMajor == 0)
|
||||||
|
return addonMajor == mMajor && addonMinor == mMinor;
|
||||||
|
else
|
||||||
|
return addonMajor == mMajor && addonMinor <= mMinor;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue SimpleExecutor::runScript(const QByteArray &script,
|
QJsonValue SimpleExecutor::runScript(const QByteArray &script,
|
||||||
const QString &name,
|
const QString &name,
|
||||||
std::chrono::microseconds timeLimit) {
|
std::chrono::microseconds timeLimit) {
|
||||||
RaiiLuaState L(name, timeLimit);
|
RaiiLuaState L(name, timeLimit);
|
||||||
L.openLibs();
|
|
||||||
for (auto &api : mApis)
|
|
||||||
registerApiGroup(L, api);
|
|
||||||
|
|
||||||
int retLoad = L.loadBuffer(script, name);
|
int retLoad = L.loadBuffer(script, name);
|
||||||
if (retLoad != 0)
|
if (retLoad != 0)
|
||||||
throw LuaError(QString("Lua script load error: %1.").arg(L.popString()));
|
throw LuaError(QString("Lua load error: %1.").arg(L.popString()));
|
||||||
L.setHook(&luaHook_timeoutKiller, LUA_MASKCOUNT, 1'000'000); // ~5ms on early 2020s desktop CPUs
|
L.setHook(&luaHook_timeoutKiller, LUA_MASKCOUNT, 1'000'000); // ~5ms on early 2020s desktop CPUs
|
||||||
L.setTimeStart();
|
L.setTimeStart();
|
||||||
int callResult = L.pCall(0, 1, 0);
|
int callResult = L.pCall(0, 0, 0);
|
||||||
if (callResult != 0) {
|
if (callResult != 0) {
|
||||||
throw LuaError(QString("Lua error: %1.").arg(L.popString()));
|
throw LuaError(QString("Lua error: %1.").arg(L.popString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// call `apiVersion()` to check compatibility
|
||||||
|
int type = L.getGlobal("apiVersion");
|
||||||
|
if (type != LUA_TFUNCTION) {
|
||||||
|
throw LuaError("Add-on interface error: `apiVersion` is not a function.");
|
||||||
|
}
|
||||||
|
callResult = L.pCall(0, 1, 0);
|
||||||
|
if (callResult != 0) {
|
||||||
|
throw LuaError(QString("Lua error: %1.").arg(L.popString()));
|
||||||
|
}
|
||||||
|
QJsonObject addonApi = L.popObject();
|
||||||
|
if (!apiVersionCheck(addonApi)) {
|
||||||
|
throw LuaError(QString("Add-on interface error: API version incompatible with %1:%2.%3.")
|
||||||
|
.arg(mKind).arg(mMajor).arg(mMinor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject APIs and call `main()`
|
||||||
|
L.openLibs();
|
||||||
|
for (auto &api : mApis)
|
||||||
|
registerApiGroup(L, api);
|
||||||
|
type = L.getGlobal("main");
|
||||||
|
if (type != LUA_TFUNCTION) {
|
||||||
|
throw LuaError("Add-on interface error: `main` is not a function.");
|
||||||
|
}
|
||||||
|
callResult = L.pCall(0, 1, 0);
|
||||||
|
if (callResult != 0) {
|
||||||
|
throw LuaError(QString("Lua error: %1.").arg(L.popString()));
|
||||||
|
}
|
||||||
return L.fetch(1);
|
return L.fetch(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilerHintExecutor::CompilerHintExecutor() : SimpleExecutor({"C_Debug", "C_Desktop", "C_FileSystem", "C_System", "C_Util"}) {}
|
CompilerHintExecutor::CompilerHintExecutor() : SimpleExecutor(
|
||||||
|
"compiler_hint", 0, 1,
|
||||||
|
{"C_Debug", "C_Desktop", "C_FileSystem", "C_System", "C_Util"})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QJsonObject CompilerHintExecutor::operator()(const QByteArray &script) {
|
QJsonObject CompilerHintExecutor::operator()(const QByteArray &script) {
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
|
@ -27,13 +27,17 @@ namespace AddOn {
|
||||||
// simple, stateless Lua executor
|
// simple, stateless Lua executor
|
||||||
class SimpleExecutor {
|
class SimpleExecutor {
|
||||||
protected:
|
protected:
|
||||||
SimpleExecutor(const QList<QString> &apis): mApis(apis) {}
|
SimpleExecutor(const QString &kind, int major, int minor, const QList<QString> &apis);
|
||||||
|
|
||||||
|
bool apiVersionCheck(const QJsonObject &addonApi);
|
||||||
|
|
||||||
// run a Lua script and fetch its return value as type R
|
|
||||||
QJsonValue runScript(const QByteArray &script, const QString &name,
|
QJsonValue runScript(const QByteArray &script, const QString &name,
|
||||||
std::chrono::microseconds timeLimit);
|
std::chrono::microseconds timeLimit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString mKind;
|
||||||
|
int mMajor;
|
||||||
|
int mMinor;
|
||||||
QStringList mApis;
|
QStringList mApis;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,11 @@ QString RaiiLuaState::fetchString(int index)
|
||||||
return lua_tostring(mLua, index);
|
return lua_tostring(mLua, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject RaiiLuaState::fetchObject(int index)
|
||||||
|
{
|
||||||
|
return fetchTableImpl(mLua, index, 0).toObject();
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue RaiiLuaState::fetch(int index)
|
QJsonValue RaiiLuaState::fetch(int index)
|
||||||
{
|
{
|
||||||
return fetchValueImpl(mLua, index, 0);
|
return fetchValueImpl(mLua, index, 0);
|
||||||
|
@ -93,6 +98,11 @@ QString RaiiLuaState::fetchString(lua_State *L, int index)
|
||||||
return lua_tostring(L, index);
|
return lua_tostring(L, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject RaiiLuaState::fetchObject(lua_State *L, int index)
|
||||||
|
{
|
||||||
|
return fetchTableImpl(L, index, 0).toObject();
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue RaiiLuaState::fetch(lua_State *L, int index)
|
QJsonValue RaiiLuaState::fetch(lua_State *L, int index)
|
||||||
{
|
{
|
||||||
return fetchValueImpl(L, index, 0);
|
return fetchValueImpl(L, index, 0);
|
||||||
|
@ -112,6 +122,13 @@ QString RaiiLuaState::popString()
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject RaiiLuaState::popObject()
|
||||||
|
{
|
||||||
|
QJsonObject value = fetchObject(-1);
|
||||||
|
lua_pop(mLua, 1);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue RaiiLuaState::pop()
|
QJsonValue RaiiLuaState::pop()
|
||||||
{
|
{
|
||||||
QJsonValue value = fetch(-1);
|
QJsonValue value = fetch(-1);
|
||||||
|
@ -191,6 +208,11 @@ int RaiiLuaState::pCall(int nargs, int nresults, int msgh)
|
||||||
return lua_pcall(mLua, nargs, nresults, msgh);
|
return lua_pcall(mLua, nargs, nresults, msgh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RaiiLuaState::getGlobal(const QString &name)
|
||||||
|
{
|
||||||
|
return lua_getglobal(mLua, name.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
void RaiiLuaState::setGlobal(const QString &name)
|
void RaiiLuaState::setGlobal(const QString &name)
|
||||||
{
|
{
|
||||||
return lua_setglobal(mLua, name.toUtf8().constData());
|
return lua_setglobal(mLua, name.toUtf8().constData());
|
||||||
|
@ -230,7 +252,16 @@ QJsonValue RaiiLuaState::fetchTableImpl(lua_State *L, int index, int depth)
|
||||||
// here we take the fact that Lua iterates array part first
|
// here we take the fact that Lua iterates array part first
|
||||||
bool processingArrayPart = true;
|
bool processingArrayPart = true;
|
||||||
while (lua_next(L, newIndex)) {
|
while (lua_next(L, newIndex)) {
|
||||||
QJsonValue v = pop(L);
|
QJsonValue v;
|
||||||
|
try {
|
||||||
|
v = fetchValueImpl(L, -1, depth);
|
||||||
|
} catch (const LuaError &e) {
|
||||||
|
QString key = fetchString(L, -2);
|
||||||
|
QString reason = e.reason() + QString(" (at table key '%1')").arg(key);
|
||||||
|
lua_pop(L, 2);
|
||||||
|
throw LuaError(reason);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
if (processingArrayPart && lua_isinteger(L, -1) && fetchInteger(L, -1) == arrayPart.size() + 1)
|
if (processingArrayPart && lua_isinteger(L, -1) && fetchInteger(L, -1) == arrayPart.size() + 1)
|
||||||
// we are still in array part
|
// we are still in array part
|
||||||
arrayPart.push_back(v);
|
arrayPart.push_back(v);
|
||||||
|
@ -275,8 +306,11 @@ QJsonValue RaiiLuaState::fetchValueImpl(lua_State *L, int index, int depth)
|
||||||
return fetchString(L, index);
|
return fetchString(L, index);
|
||||||
else if (lua_istable(L, index))
|
else if (lua_istable(L, index))
|
||||||
return fetchTableImpl(L, index, depth + 1);
|
return fetchTableImpl(L, index, depth + 1);
|
||||||
else
|
else {
|
||||||
throw LuaError(QString("Lua type error: unknown type %1.").arg(lua_typename(L, index)));
|
int type = lua_type(L, index);
|
||||||
|
const char *name = lua_typename(L, type);
|
||||||
|
throw LuaError(QString("Lua type error: unknown type %1.").arg(name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<lua_State *, LuaExtraState> RaiiLuaState::mExtraState;
|
QHash<lua_State *, LuaExtraState> RaiiLuaState::mExtraState;
|
||||||
|
|
|
@ -68,6 +68,7 @@ public:
|
||||||
static long long fetchInteger(lua_State *L, int index);
|
static long long fetchInteger(lua_State *L, int index);
|
||||||
static double fetchNumber(lua_State *L, int index);
|
static double fetchNumber(lua_State *L, int index);
|
||||||
static QString fetchString(lua_State *L, int index);
|
static QString fetchString(lua_State *L, int index);
|
||||||
|
static QJsonObject fetchObject(lua_State *L, int index);
|
||||||
static QJsonValue fetch(lua_State *L, int index);
|
static QJsonValue fetch(lua_State *L, int index);
|
||||||
|
|
||||||
bool popBoolean();
|
bool popBoolean();
|
||||||
|
@ -94,6 +95,7 @@ public:
|
||||||
int loadBuffer(const QByteArray &buff, const QString &name);
|
int loadBuffer(const QByteArray &buff, const QString &name);
|
||||||
void openLibs();
|
void openLibs();
|
||||||
int pCall(int nargs, int nresults, int msgh);
|
int pCall(int nargs, int nresults, int msgh);
|
||||||
|
int getGlobal(const QString &name);
|
||||||
void setGlobal(const QString &name);
|
void setGlobal(const QString &name);
|
||||||
void setHook(lua_Hook f, int mask, int count);
|
void setHook(lua_Hook f, int mask, int count);
|
||||||
|
|
||||||
|
|
|
@ -3279,7 +3279,9 @@ void Settings::CompilerSets::findSets()
|
||||||
try {
|
try {
|
||||||
compilerHint = AddOn::CompilerHintExecutor{}(script);
|
compilerHint = AddOn::CompilerHintExecutor{}(script);
|
||||||
} catch (const AddOn::LuaError &e) {
|
} catch (const AddOn::LuaError &e) {
|
||||||
qDebug() << "Error in compiler_hint.lua:" << e.reason();
|
QMessageBox::critical(nullptr,
|
||||||
|
QObject::tr("Error executing platform compiler hint add-on"),
|
||||||
|
e.reason());
|
||||||
}
|
}
|
||||||
if (!compilerHint.empty()) {
|
if (!compilerHint.empty()) {
|
||||||
QJsonArray compilerList = compilerHint["compilerList"].toArray();
|
QJsonArray compilerList = compilerHint["compilerList"].toArray();
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
en_US = "Contrast",
|
en_US = "Contrast",
|
||||||
pt_BR = "Contraste",
|
pt_BR = "Contraste",
|
||||||
zh_CN = "高对比度",
|
zh_CN = "高对比度",
|
||||||
zh_TW = "高對比度"
|
zh_TW = "高對比度",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -38,6 +47,7 @@ return {
|
||||||
PaletteTextDisabled = "#9DA9B5",
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
PaletteMid = "#FFFFFF",
|
PaletteMid = "#FFFFFF",
|
||||||
PaletteLight = "#505050",
|
PaletteLight = "#505050",
|
||||||
PaletteMidLight = "#00ff00"
|
PaletteMidlight = "#00ff00",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
en_US = "Dark",
|
en_US = "Dark",
|
||||||
pt_BR = "Escura",
|
pt_BR = "Escura",
|
||||||
zh_CN = "深色",
|
zh_CN = "深色",
|
||||||
zh_TW = "深色"
|
zh_TW = "深色",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -38,6 +47,7 @@ return {
|
||||||
PaletteTextDisabled = "#9DA9B5",
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
PaletteMid = "#707070",
|
PaletteMid = "#707070",
|
||||||
PaletteLight = "#505050",
|
PaletteLight = "#505050",
|
||||||
PaletteMidLight = "#00ff00"
|
PaletteMidlight = "#00ff00",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
en_US = "Light",
|
en_US = "Light",
|
||||||
pt_BR = "Clara",
|
pt_BR = "Clara",
|
||||||
zh_CN = "浅色",
|
zh_CN = "浅色",
|
||||||
zh_TW = "淺色"
|
zh_TW = "淺色",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -26,7 +35,7 @@ return {
|
||||||
PaletteLink = "#0000ff",
|
PaletteLink = "#0000ff",
|
||||||
PaletteLinkVisited = "#ff00ff",
|
PaletteLinkVisited = "#ff00ff",
|
||||||
PaletteLight = "#ffffff",
|
PaletteLight = "#ffffff",
|
||||||
PaletteMidLight = "#cacaca",
|
PaletteMidlight = "#cacaca",
|
||||||
PaletteDark = "#9f9f9f",
|
PaletteDark = "#9f9f9f",
|
||||||
PaletteMid = "#b8b8b8",
|
PaletteMid = "#b8b8b8",
|
||||||
PaletteWindowDisabled = "#efefef",
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
@ -36,6 +45,7 @@ return {
|
||||||
PaletteButtonDisabled = "#efefef",
|
PaletteButtonDisabled = "#efefef",
|
||||||
PaletteButtonTextDisabled = "#bebebe",
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
PaletteHighlight = "#dddddd",
|
PaletteHighlight = "#dddddd",
|
||||||
PaletteHighlightedText = "#000000"
|
PaletteHighlightedText = "#000000",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
en_US = "MoLo",
|
en_US = "MoLo",
|
||||||
pt_BR = "Molo",
|
pt_BR = "Molo",
|
||||||
zh_CN = "墨落",
|
zh_CN = "墨落",
|
||||||
zh_TW = "墨落"
|
zh_TW = "墨落",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -38,6 +47,7 @@ return {
|
||||||
PaletteTextDisabled = "#9DA9B5",
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
PaletteMid = "#FFFFFF",
|
PaletteMid = "#FFFFFF",
|
||||||
PaletteLight = "#505050",
|
PaletteLight = "#505050",
|
||||||
PaletteMidLight = "#00ff00"
|
PaletteMidlight = "#00ff00",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -1,16 +1,44 @@
|
||||||
function rgbFromString(color)
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function rgbFromString(color)
|
||||||
local r, g, b = color:match("#(%x%x)(%x%x)(%x%x)")
|
local r, g, b = color:match("#(%x%x)(%x%x)(%x%x)")
|
||||||
return {tonumber(r, 16) / 255, tonumber(g, 16) / 255, tonumber(b, 16) / 255}
|
return {
|
||||||
|
r = tonumber(r, 16) / 255,
|
||||||
|
g = tonumber(g, 16) / 255,
|
||||||
|
b = tonumber(b, 16) / 255,
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function rgbToString(rgb)
|
local function rgbToString(rgb)
|
||||||
return string.format("#%02x%02x%02x",
|
return string.format(
|
||||||
math.floor(rgb[1] * 255), math.floor(rgb[2] * 255), math.floor(rgb[3] * 255)
|
"#%02x%02x%02x",
|
||||||
)
|
math.floor(rgb.r * 255),
|
||||||
|
math.floor(rgb.g * 255),
|
||||||
|
math.floor(rgb.b * 255))
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function hsvToRgb(h, s, v)
|
local function hsvToRgb(hsv)
|
||||||
local r, g, b
|
local r, g, b
|
||||||
|
local h, s, v = hsv.h, hsv.s, hsv.v
|
||||||
local i = math.floor(h * 6)
|
local i = math.floor(h * 6)
|
||||||
local f = h * 6 - i
|
local f = h * 6 - i
|
||||||
local p = v * (1 - s)
|
local p = v * (1 - s)
|
||||||
|
@ -30,29 +58,26 @@ function hsvToRgb(h, s, v)
|
||||||
elseif i == 5 then
|
elseif i == 5 then
|
||||||
r, g, b = v, p, q
|
r, g, b = v, p, q
|
||||||
end
|
end
|
||||||
return {r, g, b}
|
return { r = r, g = g, b = b }
|
||||||
end
|
end
|
||||||
|
|
||||||
function blend(lower, upper, alpha)
|
local function blend(lower, upper, alpha)
|
||||||
local r = (1 - alpha) * lower[1] + alpha * upper[1]
|
local r = (1 - alpha) * lower.r + alpha * upper.r
|
||||||
local g = (1 - alpha) * lower[2] + alpha * upper[2]
|
local g = (1 - alpha) * lower.g + alpha * upper.g
|
||||||
local b = (1 - alpha) * lower[3] + alpha * upper[3]
|
local b = (1 - alpha) * lower.b + alpha * upper.b
|
||||||
return {r, g, b}
|
return { r = r, g = g, b = b }
|
||||||
end
|
end
|
||||||
|
|
||||||
local hue = math.random()
|
local function transform(color, upperColor)
|
||||||
local upperColor = hsvToRgb(hue, 0.6, 1)
|
|
||||||
|
|
||||||
function transform(color)
|
|
||||||
local lowerColor = rgbFromString(color)
|
local lowerColor = rgbFromString(color)
|
||||||
local blended = blend(lowerColor, upperColor, 0.1)
|
local blended = blend(lowerColor, upperColor, 0.1)
|
||||||
return rgbToString(blended)
|
return rgbToString(blended)
|
||||||
end
|
end
|
||||||
|
|
||||||
function transformPalette(palette)
|
local function transformPalette(palette, upperColor)
|
||||||
local transformed = {}
|
local transformed = {}
|
||||||
for key, value in pairs(palette) do
|
for key, value in pairs(palette) do
|
||||||
transformed[key] = transform(value)
|
transformed[key] = transform(value, upperColor)
|
||||||
end
|
end
|
||||||
return transformed
|
return transformed
|
||||||
end
|
end
|
||||||
|
@ -71,7 +96,7 @@ local originalPalette = {
|
||||||
PaletteLink = "#0000ff",
|
PaletteLink = "#0000ff",
|
||||||
PaletteLinkVisited = "#ff00ff",
|
PaletteLinkVisited = "#ff00ff",
|
||||||
PaletteLight = "#ffffff",
|
PaletteLight = "#ffffff",
|
||||||
PaletteMidLight = "#cacaca",
|
PaletteMidlight = "#cacaca",
|
||||||
PaletteDark = "#9f9f9f",
|
PaletteDark = "#9f9f9f",
|
||||||
PaletteMid = "#b8b8b8",
|
PaletteMid = "#b8b8b8",
|
||||||
PaletteWindowDisabled = "#efefef",
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
@ -81,16 +106,20 @@ local originalPalette = {
|
||||||
PaletteButtonDisabled = "#efefef",
|
PaletteButtonDisabled = "#efefef",
|
||||||
PaletteButtonTextDisabled = "#bebebe",
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
PaletteHighlight = "#dddddd",
|
PaletteHighlight = "#dddddd",
|
||||||
PaletteHighlightedText = "#000000"
|
PaletteHighlightedText = "#000000",
|
||||||
}
|
}
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
en_US = "Random Light",
|
en_US = "Random Light",
|
||||||
pt_BR = "Clara aleatória",
|
pt_BR = "Clara aleatória",
|
||||||
zh_CN = "随机浅色",
|
zh_CN = "随机浅色",
|
||||||
zh_TW = "隨機淺色"
|
zh_TW = "隨機淺色",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
|
local hue = math.random()
|
||||||
|
local upperColor = hsvToRgb({ h = hue, s = 0.6, v = 1 })
|
||||||
|
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -98,5 +127,6 @@ return {
|
||||||
["style"] = "RedPandaLightFusion",
|
["style"] = "RedPandaLightFusion",
|
||||||
["default scheme"] = "Adaptive",
|
["default scheme"] = "Adaptive",
|
||||||
["default iconset"] = "newlook",
|
["default iconset"] = "newlook",
|
||||||
["palette"] = transformPalette(originalPalette)
|
["palette"] = transformPalette(originalPalette, upperColor),
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -1,10 +1,33 @@
|
||||||
|
function apiVersion()
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap = {
|
||||||
|
en_US = "System Style and Color",
|
||||||
|
pt_BR = "Estilo e Cor do Sistema",
|
||||||
|
zh_CN = "跟随系统样式和颜色",
|
||||||
|
zh_TW = "跟隨系統樣式和顏色",
|
||||||
|
}
|
||||||
|
|
||||||
|
local nameMapNoStyle = {
|
||||||
|
en_US = "System Color",
|
||||||
|
pt_BR = "Cor do Sistema",
|
||||||
|
zh_CN = "跟随系统颜色",
|
||||||
|
zh_TW = "跟隨系統顏色",
|
||||||
|
}
|
||||||
|
|
||||||
|
function main()
|
||||||
local desktopEnvironment = C_Desktop.desktopEnvironment()
|
local desktopEnvironment = C_Desktop.desktopEnvironment()
|
||||||
local useSystemStyle = desktopEnvironment == "xdg" or desktopEnvironment == "macos"
|
local useSystemStyle = desktopEnvironment == "xdg" or desktopEnvironment == "macos"
|
||||||
|
|
||||||
local systemAppMode = C_Desktop.systemAppMode()
|
local systemAppMode = C_Desktop.systemAppMode()
|
||||||
local isDarkMode = systemAppMode == "dark"
|
local isDarkMode = systemAppMode == "dark"
|
||||||
|
|
||||||
function getStyle()
|
local function getStyle()
|
||||||
if useSystemStyle then
|
if useSystemStyle then
|
||||||
return C_Desktop.systemStyle()
|
return C_Desktop.systemStyle()
|
||||||
else
|
else
|
||||||
|
@ -16,11 +39,11 @@ function getStyle()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function getPalette()
|
local function getPalette()
|
||||||
if useSystemStyle then
|
if useSystemStyle then
|
||||||
return {}
|
return {}
|
||||||
elseif isDarkMode then
|
elseif isDarkMode then
|
||||||
return { -- palette from `dark.lua`
|
return {
|
||||||
PaletteWindow = "#19232D",
|
PaletteWindow = "#19232D",
|
||||||
PaletteWindowText = "#E0E1E3",
|
PaletteWindowText = "#E0E1E3",
|
||||||
PaletteBase = "#1E1E1E",
|
PaletteBase = "#1E1E1E",
|
||||||
|
@ -46,10 +69,10 @@ function getPalette()
|
||||||
PaletteTextDisabled = "#9DA9B5",
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
PaletteMid = "#707070",
|
PaletteMid = "#707070",
|
||||||
PaletteLight = "#505050",
|
PaletteLight = "#505050",
|
||||||
PaletteMidLight = "#00ff00"
|
PaletteMidlight = "#00ff00",
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return { -- palette from `default.lua`
|
return {
|
||||||
PaletteWindow = "#efefef",
|
PaletteWindow = "#efefef",
|
||||||
PaletteWindowText = "#000000",
|
PaletteWindowText = "#000000",
|
||||||
PaletteBase = "#ffffff",
|
PaletteBase = "#ffffff",
|
||||||
|
@ -63,7 +86,7 @@ function getPalette()
|
||||||
PaletteLink = "#0000ff",
|
PaletteLink = "#0000ff",
|
||||||
PaletteLinkVisited = "#ff00ff",
|
PaletteLinkVisited = "#ff00ff",
|
||||||
PaletteLight = "#ffffff",
|
PaletteLight = "#ffffff",
|
||||||
PaletteMidLight = "#cacaca",
|
PaletteMidlight = "#cacaca",
|
||||||
PaletteDark = "#9f9f9f",
|
PaletteDark = "#9f9f9f",
|
||||||
PaletteMid = "#b8b8b8",
|
PaletteMid = "#b8b8b8",
|
||||||
PaletteWindowDisabled = "#efefef",
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
@ -73,25 +96,11 @@ function getPalette()
|
||||||
PaletteButtonDisabled = "#efefef",
|
PaletteButtonDisabled = "#efefef",
|
||||||
PaletteButtonTextDisabled = "#bebebe",
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
PaletteHighlight = "#dddddd",
|
PaletteHighlight = "#dddddd",
|
||||||
PaletteHighlightedText = "#000000"
|
PaletteHighlightedText = "#000000",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local nameMap = {
|
|
||||||
en_US = "System Style and Color",
|
|
||||||
pt_BR = "Estilo e Cor do Sistema",
|
|
||||||
zh_CN = "跟随系统样式和颜色",
|
|
||||||
zh_TW = "跟隨系統樣式和顏色"
|
|
||||||
}
|
|
||||||
|
|
||||||
local nameMapNoStyle = {
|
|
||||||
en_US = "System Color",
|
|
||||||
pt_BR = "Cor do Sistema",
|
|
||||||
zh_CN = "跟随系统颜色",
|
|
||||||
zh_TW = "跟隨系統顏色"
|
|
||||||
}
|
|
||||||
|
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -99,5 +108,6 @@ return {
|
||||||
["style"] = getStyle(),
|
["style"] = getStyle(),
|
||||||
["default scheme"] = "Adaptive",
|
["default scheme"] = "Adaptive",
|
||||||
["default iconset"] = "newlook",
|
["default iconset"] = "newlook",
|
||||||
["palette"] = getPalette()
|
["palette"] = getPalette(),
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
|
|
@ -7110,6 +7110,10 @@
|
||||||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Error executing platform compiler hint add-on</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RegisterModel</name>
|
<name>RegisterModel</name>
|
||||||
|
|
|
@ -9679,6 +9679,10 @@ p, li { white-space: pre-wrap; }
|
||||||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||||
<translation>无法检测适用于 “%1” 的终端参数模式。</translation>
|
<translation>无法检测适用于 “%1” 的终端参数模式。</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Error executing platform compiler hint add-on</source>
|
||||||
|
<translation>执行平台编译器提示附加组件错误</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RegisterModel</name>
|
<name>RegisterModel</name>
|
||||||
|
|
|
@ -6622,6 +6622,10 @@
|
||||||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Error executing platform compiler hint add-on</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RegisterModel</name>
|
<name>RegisterModel</name>
|
||||||
|
|
|
@ -176,4 +176,8 @@ QString defaultShell();
|
||||||
QString appArch();
|
QString appArch();
|
||||||
QString osArch();
|
QString osArch();
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define __builtin_unreachable() (__assume(0))
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // UTILS_H
|
#endif // UTILS_H
|
||||||
|
|
|
@ -0,0 +1,313 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "compiler_hint",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:{string:string}} = {
|
||||||
|
systemGcc = {
|
||||||
|
en_US = "System GCC",
|
||||||
|
pt_BR = "GCC do sistema",
|
||||||
|
zh_CN = "系统 GCC",
|
||||||
|
zh_TW = "系統 GCC",
|
||||||
|
},
|
||||||
|
systemClang = {
|
||||||
|
en_US = "System Clang",
|
||||||
|
pt_BR = "Clang do sistema",
|
||||||
|
zh_CN = "系统 Clang",
|
||||||
|
zh_TW = "系統 Clang",
|
||||||
|
},
|
||||||
|
multilibGcc = {
|
||||||
|
en_US = "Multilib GCC",
|
||||||
|
pt_BR = "GCC multilib",
|
||||||
|
zh_CN = "Multilib GCC",
|
||||||
|
zh_TW = "Multilib GCC",
|
||||||
|
},
|
||||||
|
multilibClang = {
|
||||||
|
en_US = "Multilib Clang",
|
||||||
|
pt_BR = "Clang multilib",
|
||||||
|
zh_CN = "Multilib Clang",
|
||||||
|
zh_TW = "Multilib Clang",
|
||||||
|
},
|
||||||
|
crossGcc = {
|
||||||
|
en_US = "Cross GCC",
|
||||||
|
pt_BR = "GCC cruzado",
|
||||||
|
zh_CN = "交叉编译 GCC",
|
||||||
|
zh_TW = "交叉編譯 GCC",
|
||||||
|
},
|
||||||
|
mingwGcc = {
|
||||||
|
en_US = "MinGW GCC",
|
||||||
|
pt_BR = "GCC MinGW",
|
||||||
|
zh_CN = "MinGW GCC",
|
||||||
|
zh_TW = "MinGW GCC",
|
||||||
|
},
|
||||||
|
mingwClang = {
|
||||||
|
en_US = "MinGW Clang",
|
||||||
|
pt_BR = "Clang MinGW",
|
||||||
|
zh_CN = "MinGW Clang",
|
||||||
|
zh_TW = "MinGW Clang",
|
||||||
|
},
|
||||||
|
release = {
|
||||||
|
en_US = ", release",
|
||||||
|
pt_BR = ", lançamento",
|
||||||
|
zh_CN = ",发布",
|
||||||
|
zh_TW = ",發佈",
|
||||||
|
},
|
||||||
|
debug = {
|
||||||
|
en_US = ", debug",
|
||||||
|
pt_BR = ", depuração",
|
||||||
|
zh_CN = ",调试",
|
||||||
|
zh_TW = ",偵錯",
|
||||||
|
},
|
||||||
|
debugWithAsan = {
|
||||||
|
en_US = ", debug with ASan",
|
||||||
|
pt_BR = ", depuração com ASan",
|
||||||
|
zh_CN = ",ASan 调试",
|
||||||
|
zh_TW = ",ASan 偵錯",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet)
|
||||||
|
local c = compilerSet as {string:any}
|
||||||
|
local o = other as {string:any}
|
||||||
|
for k, v in pairs(o) do
|
||||||
|
c[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Config
|
||||||
|
isMultilib: boolean | nil
|
||||||
|
isMingw: boolean | nil
|
||||||
|
isClang: boolean | nil
|
||||||
|
customCompileParams: {string} | nil
|
||||||
|
customLinkParams: {string} | nil
|
||||||
|
triplet: string | nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateConfig(
|
||||||
|
name: string, lang: string,
|
||||||
|
cCompiler: string, cxxCompiler: string,
|
||||||
|
config: Config
|
||||||
|
): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet
|
||||||
|
local commonOptions: CompilerHint.CompilerSet = {
|
||||||
|
cCompiler = cCompiler,
|
||||||
|
cxxCompiler = cxxCompiler,
|
||||||
|
debugger = "/usr/bin/gdb",
|
||||||
|
debugServer = "/usr/bin/gdbserver",
|
||||||
|
make = "/usr/bin/make",
|
||||||
|
compilerType = config.isClang and "Clang" or "GCC_UTF8",
|
||||||
|
preprocessingSuffix = ".i",
|
||||||
|
compilationProperSuffix = ".s",
|
||||||
|
assemblingSuffix = ".o",
|
||||||
|
executableSuffix = config.isMingw and ".exe" or "",
|
||||||
|
compilationStage = 3,
|
||||||
|
ccCmdOptUsePipe = "on",
|
||||||
|
ccCmdOptWarningAll = "on",
|
||||||
|
ccCmdOptWarningExtra = "on",
|
||||||
|
ccCmdOptCheckIsoConformance = "on",
|
||||||
|
binDirs = {"/usr/bin"},
|
||||||
|
}
|
||||||
|
if config.isMultilib then
|
||||||
|
commonOptions.ccCmdOptPointerSize = "32"
|
||||||
|
end
|
||||||
|
if config.isMingw then
|
||||||
|
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
|
||||||
|
end
|
||||||
|
if config.customCompileParams then
|
||||||
|
commonOptions.customCompileParams = config.customCompileParams
|
||||||
|
end
|
||||||
|
if config.customLinkParams then
|
||||||
|
commonOptions.customLinkParams = config.customLinkParams
|
||||||
|
end
|
||||||
|
local release = {
|
||||||
|
name = name .. (nameMap.release[lang] or nameMap.release.en_US),
|
||||||
|
staticLink = true,
|
||||||
|
linkCmdOptStripExe = "on",
|
||||||
|
ccCmdOptOptimize = "2",
|
||||||
|
}
|
||||||
|
local debug_ = {
|
||||||
|
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
|
||||||
|
ccCmdOptDebugInfo = "on",
|
||||||
|
}
|
||||||
|
local debugWithAsan = {
|
||||||
|
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US),
|
||||||
|
ccCmdOptDebugInfo = "on",
|
||||||
|
ccCmdOptAddressSanitizer = "address",
|
||||||
|
}
|
||||||
|
mergeCompilerSet(release, commonOptions)
|
||||||
|
mergeCompilerSet(debug_, commonOptions)
|
||||||
|
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||||
|
return release, debug_, debugWithAsan
|
||||||
|
end
|
||||||
|
|
||||||
|
global function main(): CompilerHint
|
||||||
|
local arch = C_System.osArch()
|
||||||
|
local libexecDir = C_System.appLibexecDir()
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
local compilerList = {}
|
||||||
|
|
||||||
|
do
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang,
|
||||||
|
"/usr/bin/gcc", "/usr/bin/g++",
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
end
|
||||||
|
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang,
|
||||||
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
|
{isClang = true}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- with lib32-gcc-libs installed, system GCC and Clang can target 32-bit
|
||||||
|
if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then
|
||||||
|
do
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang,
|
||||||
|
"/usr/bin/gcc", "/usr/bin/g++",
|
||||||
|
{isMultilib = true}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
end
|
||||||
|
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang,
|
||||||
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
|
{isClang = true, isMultilib = true}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- cross GCC
|
||||||
|
if (
|
||||||
|
arch == "x86_64" and
|
||||||
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/qemu-aarch64") and
|
||||||
|
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")
|
||||||
|
) then
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64", lang,
|
||||||
|
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- with wine or WSL init registered in binfmt_misc, Windows binaries can run seamlessly
|
||||||
|
if (
|
||||||
|
arch == "x86_64" and (
|
||||||
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/DOSWin") or
|
||||||
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/WSLInterop")
|
||||||
|
)
|
||||||
|
) then
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/x86_64-w64-mingw32-gcc") then
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libexecDir .. "/x86_64-w64-mingw32/utf8init.o",
|
||||||
|
utf8manifest = libexecDir .. "/x86_64-w64-mingw32/utf8manifest.o",
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang,
|
||||||
|
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
|
||||||
|
{
|
||||||
|
isMingw = true,
|
||||||
|
triplet = "x86_64-w64-mingw32",
|
||||||
|
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- system Clang can target Windows
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64", lang,
|
||||||
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
|
{
|
||||||
|
isClang = true,
|
||||||
|
isMingw = true,
|
||||||
|
triplet = "x86_64-w64-mingw32",
|
||||||
|
customCompileParams = {"-target", "x86_64-w64-mingw32"},
|
||||||
|
customLinkParams = {
|
||||||
|
"-target", "x86_64-w64-mingw32",
|
||||||
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
|
"-lstdc++", "-lwinpthread",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/i686-w64-mingw32-gcc") then
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libexecDir .. "/i686-w64-mingw32/utf8init.o",
|
||||||
|
utf8manifest = libexecDir .. "/i686-w64-mingw32/utf8manifest.o",
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang,
|
||||||
|
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
|
||||||
|
{
|
||||||
|
isMingw = true,
|
||||||
|
triplet = "i686-w64-mingw32",
|
||||||
|
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- system Clang can target Windows
|
||||||
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686", lang,
|
||||||
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
|
{
|
||||||
|
isClang = true,
|
||||||
|
isMingw = true,
|
||||||
|
triplet = "i686-w64-mingw32",
|
||||||
|
customCompileParams = {"-target", "i686-w64-mingw32"},
|
||||||
|
customLinkParams = {
|
||||||
|
"-target", "i686-w64-mingw32",
|
||||||
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
|
"-lstdc++", "-lwinpthread",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = {
|
||||||
|
compilerList = compilerList,
|
||||||
|
noSearch = {
|
||||||
|
"/usr/bin",
|
||||||
|
"/opt/cuda/bin",
|
||||||
|
"/usr/lib/ccache/bin",
|
||||||
|
},
|
||||||
|
preferCompiler = 3, -- System GCC Debug with ASan
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,430 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "compiler_hint",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local gnuArchMap: {string:string} = {
|
||||||
|
i386 = "i686",
|
||||||
|
x86_64 = "x86_64",
|
||||||
|
arm = "armv7",
|
||||||
|
arm64 = "aarch64",
|
||||||
|
}
|
||||||
|
|
||||||
|
local profileNameMap: {string:{string:string}} = {
|
||||||
|
release = {
|
||||||
|
en_US = "release",
|
||||||
|
pt_BR = "lançamento",
|
||||||
|
zh_CN = "发布",
|
||||||
|
zh_TW = "發佈",
|
||||||
|
},
|
||||||
|
debug = {
|
||||||
|
en_US = "debug",
|
||||||
|
pt_BR = "depuração",
|
||||||
|
zh_CN = "调试",
|
||||||
|
zh_TW = "偵錯",
|
||||||
|
},
|
||||||
|
debugWithAsan = {
|
||||||
|
en_US = "debug with ASan",
|
||||||
|
pt_BR = "depuração com ASan",
|
||||||
|
zh_CN = "ASan 调试",
|
||||||
|
zh_TW = "ASan 偵錯",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local function nameGeneratorMingwGcc(lang: string, arch: string, profile: string, isUtf8: boolean): string
|
||||||
|
local template: {string:string} = {
|
||||||
|
en_US = "MinGW GCC %1 in %2, %3",
|
||||||
|
pt_BR = "GCC MinGW %1 em %2, %3",
|
||||||
|
zh_CN = "%2 MinGW GCC %1,%3",
|
||||||
|
zh_TW = "%2 MinGW GCC %1,%3",
|
||||||
|
}
|
||||||
|
local systemCodePage: {string:string} = {
|
||||||
|
en_US = "system code page",
|
||||||
|
pt_Br = "página de código do sistema",
|
||||||
|
zh_CN = "系统代码页",
|
||||||
|
zh_TW = "系統代碼頁",
|
||||||
|
}
|
||||||
|
return C_Util.format(
|
||||||
|
template[lang] or template.en_US,
|
||||||
|
gnuArchMap[arch],
|
||||||
|
isUtf8 and "UTF-8" or systemCodePage[lang] or systemCodePage.en_US,
|
||||||
|
profileNameMap[profile][lang] or profileNameMap[profile].en_US
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function nameGeneratorClang(lang: string, arch: string, profile: string, isMingw: boolean): string
|
||||||
|
local template: {string:string} = {
|
||||||
|
en_US = "%1 Clang %2, %3",
|
||||||
|
pt_BR = "Clang %2 %1, %3",
|
||||||
|
zh_CN = "%1 Clang %2,%3",
|
||||||
|
zh_TW = "%1 Clang %2,%3",
|
||||||
|
}
|
||||||
|
local msvcCompatible: {string:string} = {
|
||||||
|
en_US = "MSVC-compatible",
|
||||||
|
pt_BR = "compatível com MSVC",
|
||||||
|
zh_CN = "兼容 MSVC 的",
|
||||||
|
zh_TW = "相容 MSVC 的",
|
||||||
|
}
|
||||||
|
return C_Util.format(
|
||||||
|
template[lang] or template.en_US,
|
||||||
|
isMingw and "LLVM-MinGW" or msvcCompatible[lang] or msvcCompatible.en_US,
|
||||||
|
gnuArchMap[arch],
|
||||||
|
profileNameMap[profile][lang] or profileNameMap[profile].en_US
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet)
|
||||||
|
local c = compilerSet as {string:any}
|
||||||
|
local o = other as {string:any}
|
||||||
|
for k, v in pairs(o) do
|
||||||
|
c[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Programs
|
||||||
|
cCompiler: string
|
||||||
|
cxxCompiler: string
|
||||||
|
make: string
|
||||||
|
debugger: string
|
||||||
|
debugServer: string
|
||||||
|
resourceCompiler: string
|
||||||
|
binDirs: {string}
|
||||||
|
libDirs: {string} | nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Config
|
||||||
|
arch: string
|
||||||
|
isAnsi: boolean | nil
|
||||||
|
isClang: boolean | nil
|
||||||
|
customCompileParams: {string} | nil
|
||||||
|
customLinkParams: {string} | nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generateConfig(
|
||||||
|
nameGen: (function (arch: string, profile: string): string),
|
||||||
|
programs: Programs,
|
||||||
|
config: Config
|
||||||
|
): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet
|
||||||
|
local commonOptions : CompilerHint.CompilerSet = {
|
||||||
|
cCompiler = programs.cCompiler,
|
||||||
|
cxxCompiler = programs.cxxCompiler,
|
||||||
|
debugger = programs.debugger,
|
||||||
|
debugServer = programs.debugServer,
|
||||||
|
make = programs.make,
|
||||||
|
resourceCompiler = programs.resourceCompiler,
|
||||||
|
binDirs = programs.binDirs,
|
||||||
|
compilerType = config.isClang and "Clang" or "GCC_UTF8",
|
||||||
|
preprocessingSuffix = ".i",
|
||||||
|
compilationProperSuffix = ".s",
|
||||||
|
assemblingSuffix = ".o",
|
||||||
|
executableSuffix = ".exe",
|
||||||
|
compilationStage = 3,
|
||||||
|
ccCmdOptUsePipe = "on",
|
||||||
|
ccCmdOptWarningAll = "on",
|
||||||
|
ccCmdOptWarningExtra = "on",
|
||||||
|
ccCmdOptCheckIsoConformance = "on",
|
||||||
|
}
|
||||||
|
if programs.libDirs then
|
||||||
|
commonOptions.libDirs = programs.libDirs
|
||||||
|
end
|
||||||
|
if config.isAnsi then
|
||||||
|
commonOptions.execCharset = "SYSTEM"
|
||||||
|
end
|
||||||
|
if config.customCompileParams then
|
||||||
|
commonOptions.customCompileParams = config.customCompileParams
|
||||||
|
end
|
||||||
|
if config.customLinkParams then
|
||||||
|
commonOptions.customLinkParams = config.customLinkParams
|
||||||
|
end
|
||||||
|
local release: CompilerHint.CompilerSet = {
|
||||||
|
name = nameGen(config.arch, "release"),
|
||||||
|
staticLink = true,
|
||||||
|
linkCmdOptStripExe = "on",
|
||||||
|
ccCmdOptOptimize = "2",
|
||||||
|
}
|
||||||
|
local debug_: CompilerHint.CompilerSet = {
|
||||||
|
name = nameGen(config.arch, "debug"),
|
||||||
|
ccCmdOptDebugInfo = "on",
|
||||||
|
}
|
||||||
|
local debugWithAsan: CompilerHint.CompilerSet = {
|
||||||
|
name = nameGen(config.arch, "debugWithAsan"),
|
||||||
|
ccCmdOptDebugInfo = "on",
|
||||||
|
ccCmdOptAddressSanitizer = "address",
|
||||||
|
}
|
||||||
|
mergeCompilerSet(release, commonOptions)
|
||||||
|
mergeCompilerSet(debug_, commonOptions)
|
||||||
|
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||||
|
return release, debug_, debugWithAsan
|
||||||
|
end
|
||||||
|
|
||||||
|
global function main(): CompilerHint
|
||||||
|
local appArch = C_System.appArch()
|
||||||
|
local libexecDir = C_System.appLibexecDir()
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
local supportedAppArches = C_System.supportedAppArchList()
|
||||||
|
|
||||||
|
local compilerList = {}
|
||||||
|
local noSearch = {}
|
||||||
|
local preferCompiler = 0
|
||||||
|
|
||||||
|
local function checkAndAddMingw(arch: string)
|
||||||
|
local binDir: string
|
||||||
|
local libDir: string
|
||||||
|
local excludeBinDir: string
|
||||||
|
if arch == "i386" then
|
||||||
|
binDir = libexecDir .. "/mingw32/bin" -- must match case because Windows filesystem can be case sensitive
|
||||||
|
libDir = libexecDir .. "/mingw32/i686-w64-mingw32/lib"
|
||||||
|
excludeBinDir = libexecDir .. "/MinGW32/bin" -- workaround for path check
|
||||||
|
elseif arch == "x86_64" then
|
||||||
|
binDir = libexecDir .. "/mingw64/bin"
|
||||||
|
libDir = libexecDir .. "/mingw64/x86_64-w64-mingw32/lib"
|
||||||
|
excludeBinDir = libexecDir .. "/MinGW64/bin"
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not C_FileSystem.isExecutable(binDir .. "/gcc.exe") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local programs: Programs = {
|
||||||
|
cCompiler = binDir .. "/gcc.exe",
|
||||||
|
cxxCompiler = binDir .. "/g++.exe",
|
||||||
|
make = binDir .. "/mingw32-make.exe",
|
||||||
|
debugger = binDir .. "/gdb.exe",
|
||||||
|
debugServer = binDir .. "/gdbserver.exe",
|
||||||
|
resourceCompiler = binDir .. "/windres.exe",
|
||||||
|
binDirs = {binDir},
|
||||||
|
}
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libDir .. "/utf8init.o",
|
||||||
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
|
}
|
||||||
|
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
function (arch_: string, profile: string): string
|
||||||
|
return nameGeneratorMingwGcc(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = arch,
|
||||||
|
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
if preferCompiler == 0 then
|
||||||
|
preferCompiler = 2
|
||||||
|
end
|
||||||
|
|
||||||
|
release, debug_, debugWithAsan = generateConfig(
|
||||||
|
function (arch_: string, profile: string): string
|
||||||
|
return nameGeneratorMingwGcc(lang, arch_, profile, false)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = arch,
|
||||||
|
isAnsi = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
|
||||||
|
table.insert(noSearch, excludeBinDir)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function checkAndAddClang()
|
||||||
|
if not C_FileSystem.isExecutable(libexecDir .. "/llvm-mingw/bin/clang.exe") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local binDir = libexecDir .. "/llvm-mingw/bin"
|
||||||
|
local appTriplet = gnuArchMap[appArch] .. "-w64-mingw32"
|
||||||
|
do
|
||||||
|
-- appArch is always debuggable
|
||||||
|
local libDir = libexecDir .. "/llvm-mingw/" .. appTriplet .. "/lib"
|
||||||
|
local programs: Programs = {
|
||||||
|
cCompiler = binDir .. "/" .. appTriplet .. "-clang.exe",
|
||||||
|
cxxCompiler = binDir .. "/" .. appTriplet .. "-clang++.exe",
|
||||||
|
make = binDir .. "/mingw32-make.exe",
|
||||||
|
debugger = binDir .. "/lldb-mi.exe",
|
||||||
|
debugServer = binDir .. "/lldb-server.exe",
|
||||||
|
resourceCompiler = binDir .. "/" .. appTriplet .. "-windres.exe",
|
||||||
|
binDirs = {binDir},
|
||||||
|
}
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libDir .. "/utf8init.o",
|
||||||
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
|
}
|
||||||
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
function (arch_: string, profile: string): string
|
||||||
|
return nameGeneratorClang(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = appArch,
|
||||||
|
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||||
|
isClang = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
if appArch ~= "arm64" then
|
||||||
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
if preferCompiler == 0 then
|
||||||
|
preferCompiler = 3
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if preferCompiler == 0 then
|
||||||
|
preferCompiler = 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, foreignArch in ipairs(supportedAppArches) do
|
||||||
|
if foreignArch ~= appArch then
|
||||||
|
local foreignTriplet = gnuArchMap[foreignArch] .. "-w64-mingw32"
|
||||||
|
local libDir = libexecDir .. "/llvm-mingw/" .. foreignTriplet .. "/lib"
|
||||||
|
local programs: Programs = {
|
||||||
|
cCompiler = binDir .. "/" .. foreignTriplet .. "-clang.exe",
|
||||||
|
cxxCompiler = binDir .. "/" .. foreignTriplet .. "-clang++.exe",
|
||||||
|
make = binDir .. "/mingw32-make.exe",
|
||||||
|
debugger = binDir .. "/lldb-mi.exe",
|
||||||
|
debugServer = binDir .. "/lldb-server.exe",
|
||||||
|
resourceCompiler = binDir .. "/" .. foreignTriplet .. "-windres.exe",
|
||||||
|
binDirs = {binDir},
|
||||||
|
}
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libDir .. "/utf8init.o",
|
||||||
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
|
}
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
function (arch_: string, profile: string): string
|
||||||
|
return nameGeneratorClang(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = foreignArch,
|
||||||
|
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||||
|
isClang = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(noSearch, binDir)
|
||||||
|
|
||||||
|
local llvmOrgPath = C_System.readRegistry([[Software\LLVM\LLVM]], "") or C_System.readRegistry([[Software\Wow6432Node\LLVM\LLVM]], "")
|
||||||
|
if not llvmOrgPath then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local llvmOrgBinDir = llvmOrgPath .. "/bin"
|
||||||
|
|
||||||
|
do
|
||||||
|
local msvcTriplet = gnuArchMap[appArch] .. "-pc-windows-msvc"
|
||||||
|
local libDir = libexecDir .. "/llvm-mingw/" .. msvcTriplet .. "/lib"
|
||||||
|
local programs: Programs = {
|
||||||
|
cCompiler = llvmOrgBinDir .. "/clang.exe",
|
||||||
|
cxxCompiler = llvmOrgBinDir .. "/clang++.exe",
|
||||||
|
make = binDir .. "/mingw32-make.exe",
|
||||||
|
debugger = binDir .. "/lldb-mi.exe",
|
||||||
|
debugServer = binDir .. "/lldb-server.exe",
|
||||||
|
resourceCompiler = binDir .. "/" .. appTriplet .. "-windres.exe",
|
||||||
|
binDirs = {llvmOrgBinDir},
|
||||||
|
libDirs = {libDir},
|
||||||
|
}
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libDir .. "/utf8init.o",
|
||||||
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
|
}
|
||||||
|
local release, debug_, _ = generateConfig(
|
||||||
|
function (arch: string, profile: string): string
|
||||||
|
return nameGeneratorClang(lang, arch, profile, false)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = appArch,
|
||||||
|
customCompileParams = {
|
||||||
|
"-target", msvcTriplet,
|
||||||
|
"-fms-extensions",
|
||||||
|
"-fms-compatibility",
|
||||||
|
"-fdelayed-template-parsing",
|
||||||
|
},
|
||||||
|
customLinkParams = {
|
||||||
|
"-target", msvcTriplet,
|
||||||
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
|
},
|
||||||
|
isClang = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
table.insert(compilerList, debug_)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, foreignArch in ipairs(supportedAppArches) do
|
||||||
|
if foreignArch ~= appArch then
|
||||||
|
local foreignTriplet = gnuArchMap[foreignArch] .. "-w64-mingw32"
|
||||||
|
local msvcTriplet = gnuArchMap[foreignArch] .. "-pc-windows-msvc"
|
||||||
|
local libDir = libexecDir .. "/llvm-mingw/" .. msvcTriplet .. "/lib"
|
||||||
|
local programs: Programs = {
|
||||||
|
cCompiler = llvmOrgBinDir .. "/clang.exe",
|
||||||
|
cxxCompiler = llvmOrgBinDir .. "/clang++.exe",
|
||||||
|
make = binDir .. "/mingw32-make.exe",
|
||||||
|
debugger = binDir .. "/lldb-mi.exe",
|
||||||
|
debugServer = binDir .. "/lldb-server.exe",
|
||||||
|
resourceCompiler = binDir .. "/" .. foreignTriplet .. "-windres.exe",
|
||||||
|
binDirs = {llvmOrgBinDir},
|
||||||
|
libDirs = {libDir},
|
||||||
|
}
|
||||||
|
local extraObjects = {
|
||||||
|
utf8init = libDir .. "/utf8init.o",
|
||||||
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
|
}
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
function (arch: string, profile: string): string
|
||||||
|
return nameGeneratorClang(lang, arch, profile, false)
|
||||||
|
end,
|
||||||
|
programs,
|
||||||
|
{
|
||||||
|
arch = foreignArch,
|
||||||
|
customCompileParams = {
|
||||||
|
"-target", msvcTriplet,
|
||||||
|
"-fms-extensions",
|
||||||
|
"-fms-compatibility",
|
||||||
|
"-fdelayed-template-parsing",
|
||||||
|
},
|
||||||
|
customLinkParams = {
|
||||||
|
"-target", msvcTriplet,
|
||||||
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
|
},
|
||||||
|
isClang = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
table.insert(compilerList, release)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.insert(noSearch, llvmOrgBinDir)
|
||||||
|
end
|
||||||
|
|
||||||
|
if appArch == "x86_64" then
|
||||||
|
checkAndAddMingw("x86_64")
|
||||||
|
checkAndAddClang()
|
||||||
|
elseif appArch == "arm64" then
|
||||||
|
checkAndAddClang()
|
||||||
|
else
|
||||||
|
checkAndAddMingw("i386")
|
||||||
|
checkAndAddClang()
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = {
|
||||||
|
compilerList = compilerList,
|
||||||
|
noSearch = noSearch,
|
||||||
|
preferCompiler = preferCompiler,
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
|
@ -0,0 +1,107 @@
|
||||||
|
local env = require("defs.global_env")
|
||||||
|
|
||||||
|
global C_Debug = env.C_Debug
|
||||||
|
global C_Desktop = env.C_Desktop
|
||||||
|
global C_FileSystem = env.C_FileSystem
|
||||||
|
global C_System = env.C_System
|
||||||
|
global C_Util = env.C_Util
|
||||||
|
|
||||||
|
global record CompilerHint
|
||||||
|
-- found compiler sets
|
||||||
|
compilerList: {CompilerSet}
|
||||||
|
|
||||||
|
-- do not search in these directories anymore
|
||||||
|
noSearch: {string}
|
||||||
|
|
||||||
|
-- prefer compiler set index (in Lua, 1-based) in compilerList
|
||||||
|
-- 0 for no preference
|
||||||
|
preferCompiler: integer
|
||||||
|
|
||||||
|
record CompilerSet
|
||||||
|
name: string
|
||||||
|
|
||||||
|
-- internal
|
||||||
|
|
||||||
|
-- e.g. "x86_64-linux-gnu", "x86_64-w64-mingw32"
|
||||||
|
dumpMachine: string
|
||||||
|
-- e.g. "13.2.1", "17.0.6"
|
||||||
|
version: string
|
||||||
|
-- e.g. "TDM-GCC", "MinGW"
|
||||||
|
type: string
|
||||||
|
-- e.g. "x86_64", "aarch64"
|
||||||
|
target: string
|
||||||
|
compilerType: CompilerType
|
||||||
|
|
||||||
|
-- general
|
||||||
|
|
||||||
|
staticLink: boolean
|
||||||
|
-- automatically sets useCustomCompileParams
|
||||||
|
customCompileParams: {string}
|
||||||
|
-- automatically sets useCustomLinkParams
|
||||||
|
customLinkParams: {string}
|
||||||
|
-- automatically sets autoAddCharsetParams
|
||||||
|
execCharset: string
|
||||||
|
|
||||||
|
-- setting: code generation
|
||||||
|
|
||||||
|
ccCmdOptOptimize: string
|
||||||
|
ccCmdOptStd: string
|
||||||
|
cCmdOptStd: string
|
||||||
|
ccCmdOptInstruction: string
|
||||||
|
ccCmdOptPointerSize: string
|
||||||
|
ccCmdOptDebugInfo: string
|
||||||
|
ccCmdOptProfileInfo: string
|
||||||
|
ccCmdOptSyntaxOnly: string
|
||||||
|
|
||||||
|
-- setting: warnings
|
||||||
|
|
||||||
|
ccCmdOptInhibitAllWarning: string
|
||||||
|
ccCmdOptWarningAll: string
|
||||||
|
ccCmdOptWarningExtra: string
|
||||||
|
ccCmdOptCheckIsoConformance: string
|
||||||
|
ccCmdOptWarningAsError: string
|
||||||
|
ccCmdOptAbortOnError: string
|
||||||
|
ccCmdOptStackProtector: string
|
||||||
|
ccCmdOptAddressSanitizer: string
|
||||||
|
|
||||||
|
-- setting: linker
|
||||||
|
|
||||||
|
ccCmdOptUsePipe: string
|
||||||
|
linkCmdOptNoLinkStdlib: string
|
||||||
|
linkCmdOptNoConsole: string
|
||||||
|
linkCmdOptStripExe: string
|
||||||
|
|
||||||
|
-- directory
|
||||||
|
|
||||||
|
binDirs: {string}
|
||||||
|
cIncludeDirs: {string}
|
||||||
|
cxxIncludeDirs: {string}
|
||||||
|
libDirs: {string}
|
||||||
|
defaultLibDirs: {string}
|
||||||
|
defaultCIncludeDirs: {string}
|
||||||
|
defaultCxxIncludeDirs: {string}
|
||||||
|
|
||||||
|
-- program
|
||||||
|
|
||||||
|
cCompiler: string
|
||||||
|
cxxCompiler: string
|
||||||
|
make: string
|
||||||
|
debugger: string
|
||||||
|
debugServer: string
|
||||||
|
resourceCompiler: string
|
||||||
|
|
||||||
|
-- output
|
||||||
|
|
||||||
|
preprocessingSuffix: string
|
||||||
|
compilationProperSuffix: string
|
||||||
|
assemblingSuffix: string
|
||||||
|
executableSuffix: string
|
||||||
|
compilationStage: integer
|
||||||
|
|
||||||
|
enum CompilerType
|
||||||
|
"GCC"
|
||||||
|
"GCC_UTF8"
|
||||||
|
"Clang"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,100 @@
|
||||||
|
global record ApiVersion
|
||||||
|
kind: Kind
|
||||||
|
major: integer
|
||||||
|
minor: integer
|
||||||
|
|
||||||
|
enum Kind
|
||||||
|
"theme"
|
||||||
|
"compiler_hint"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local record env
|
||||||
|
record C_Debug
|
||||||
|
-- print message to console, with Qt-style string format
|
||||||
|
debug: function (format: string, ...: any): nil
|
||||||
|
|
||||||
|
-- show message box, with Qt-style string format
|
||||||
|
messageBox: function (format: string, ...: any): nil
|
||||||
|
end
|
||||||
|
|
||||||
|
record C_Desktop
|
||||||
|
-- return desktoop environment name
|
||||||
|
desktopEnvironment: function (): DesktopEnvironment
|
||||||
|
|
||||||
|
-- return language code, e.g. "en_US", "zh_CN"
|
||||||
|
language: function (): string
|
||||||
|
|
||||||
|
-- return available Qt styles, e.g. {"breeze", "fusion", "windows"}
|
||||||
|
qtStyleList: function (): {string}
|
||||||
|
|
||||||
|
-- return system app mode, light or dark
|
||||||
|
systemAppMode: function (): AppMode
|
||||||
|
|
||||||
|
-- return default Qt style, e.g. "fusion"
|
||||||
|
systemStyle: function (): string
|
||||||
|
|
||||||
|
enum DesktopEnvironment
|
||||||
|
"windows" -- Windows Win32
|
||||||
|
"macos" -- macOS
|
||||||
|
"xdg" -- XDG-compliant desktop environment (e.g. GNOME, KDE Plasma)
|
||||||
|
"unknown" -- other desktops or non-desktop environments (e.g. Windows UWP, Android)
|
||||||
|
end
|
||||||
|
|
||||||
|
enum AppMode
|
||||||
|
"light"
|
||||||
|
"dark"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
record C_FileSystem
|
||||||
|
-- return whether the path exists
|
||||||
|
exists: function (path: string): boolean
|
||||||
|
|
||||||
|
-- return whether the path is executable
|
||||||
|
isExecutable: function (path: string): boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
record C_System
|
||||||
|
-- returns the architecture of Red Panda C++, name following `QSysInfo`
|
||||||
|
-- e.g. "i386", "x86_64", "arm", "arm64", "riscv64", "loongarch64"
|
||||||
|
-- though unsupported, MSVC arm64ec is handled correctly (returns "arm64ec")
|
||||||
|
appArch: function (): string
|
||||||
|
|
||||||
|
-- returns the directory of Red Panda C++
|
||||||
|
-- e.g. "/usr/bin", "C:/Program Files/RedPanda-Cpp", "C:/Users/中文/AppData/Local/RedPanda-CPP"
|
||||||
|
appDir: function (): string
|
||||||
|
|
||||||
|
-- returns the libexec directory of Red Panda C++
|
||||||
|
-- e.g. "/usr/libexec/RedPandaCPP", "C:/Program Files/RedPanda-Cpp"
|
||||||
|
appLibexecDir: function (): string
|
||||||
|
|
||||||
|
-- returns the resource directory of Red Panda C++
|
||||||
|
-- e.g. "/usr/share/RedPandaCPP", "C:/Program Files/RedPanda-Cpp"
|
||||||
|
appResourceDir: function (): string
|
||||||
|
|
||||||
|
-- returns the architecture of the OS, name following `QSysInfo`
|
||||||
|
-- e.g. "i386", "x86_64", "arm", "arm64"
|
||||||
|
-- Windows arm64 is handled correctly even if Red Panda C++ runs under emulation
|
||||||
|
osArch: function (): string
|
||||||
|
|
||||||
|
-- returns supported application architectures by OS, name following `QSysInfo`
|
||||||
|
-- e.g. {"i386", "x86_64", "arm64"}
|
||||||
|
-- Windows 10 1709 or later: accurate result
|
||||||
|
-- Legacy Windows: hardcoded result, i.e. "i386" is always included even though WoW64 is not available
|
||||||
|
-- macOS: accurate result supposed, but not tested
|
||||||
|
-- Linux: osArch + appArch + QEMU user mode emulation, no multilib detection
|
||||||
|
-- other (BSD): osArch + appArch, no multilib detection
|
||||||
|
supportedAppArchList: function (): {string}
|
||||||
|
|
||||||
|
-- read `subKey\name` from HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE in order (Windows only)
|
||||||
|
readRegistry: function (subKey: string, name: string): string | nil
|
||||||
|
end
|
||||||
|
|
||||||
|
record C_Util
|
||||||
|
-- Qt-style string format, replace %1, %2, etc. with arguments
|
||||||
|
format: function (format: string, ...: any): string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return env
|
|
@ -0,0 +1,63 @@
|
||||||
|
local env = require("defs.global_env")
|
||||||
|
|
||||||
|
global C_Debug = env.C_Debug
|
||||||
|
global C_Desktop = env.C_Desktop
|
||||||
|
global C_Util = env.C_Util
|
||||||
|
|
||||||
|
global record Theme
|
||||||
|
name: string
|
||||||
|
style: string
|
||||||
|
["default scheme"]: string
|
||||||
|
["default iconset"]: BuiltInIconSet
|
||||||
|
palette: Palette
|
||||||
|
|
||||||
|
enum BuiltInIconSet
|
||||||
|
"newlook"
|
||||||
|
"contrast"
|
||||||
|
"bluesky"
|
||||||
|
end
|
||||||
|
|
||||||
|
record Palette
|
||||||
|
PaletteWindow: string | nil
|
||||||
|
PaletteWindowText: string | nil
|
||||||
|
PaletteBase: string | nil
|
||||||
|
PaletteAlternateBase: string | nil
|
||||||
|
PaletteToolTipBase: string | nil
|
||||||
|
PaletteToolTipText: string | nil
|
||||||
|
PaletteText: string | nil
|
||||||
|
PaletteButton: string | nil
|
||||||
|
PaletteButtonText: string | nil
|
||||||
|
PaletteBrightText: string | nil
|
||||||
|
PaletteHighlight: string | nil
|
||||||
|
PaletteHighlightedText: string | nil
|
||||||
|
PaletteLink: string | nil
|
||||||
|
PaletteLinkVisited: string | nil
|
||||||
|
|
||||||
|
PaletteLight: string | nil
|
||||||
|
PaletteMidlight: string | nil
|
||||||
|
PaletteDark: string | nil
|
||||||
|
PaletteMid: string | nil
|
||||||
|
PaletteShadow: string | nil
|
||||||
|
|
||||||
|
PaletteWindowDisabled: string | nil
|
||||||
|
PaletteWindowTextDisabled: string | nil
|
||||||
|
PaletteBaseDisabled: string | nil
|
||||||
|
PaletteAlternateBaseDisabled: string | nil
|
||||||
|
PaletteToolTipBaseDisabled: string | nil
|
||||||
|
PaletteToolTipTextDisabled: string | nil
|
||||||
|
PaletteTextDisabled: string | nil
|
||||||
|
PaletteButtonDisabled: string | nil
|
||||||
|
PaletteButtonTextDisabled: string | nil
|
||||||
|
PaletteBrightTextDisabled: string | nil
|
||||||
|
PaletteHighlightDisabled: string | nil
|
||||||
|
PaletteHighlightedTextDisabled: string | nil
|
||||||
|
PaletteLinkDisabled: string | nil
|
||||||
|
PaletteLinkVisitedDisabled: string | nil
|
||||||
|
|
||||||
|
PaletteLightDisabled: string | nil
|
||||||
|
PaletteMidlightDisabled: string | nil
|
||||||
|
PaletteDarkDisabled: string | nil
|
||||||
|
PaletteMidDisabled: string | nil
|
||||||
|
PaletteShadowDisabled: string | nil
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
function gen-theme() {
|
||||||
|
local file="$1"
|
||||||
|
local bn="$(basename $file)"
|
||||||
|
local out="RedPandaIDE/themes/${bn%.tl}.lua"
|
||||||
|
echo -e "\033[1;33mChecking $file\033[0m"
|
||||||
|
tl check --include-dir addon --global-env-def defs/theme --quiet "$file"
|
||||||
|
echo -e "\033[1;32mCompiling $file\033[0m"
|
||||||
|
tl gen --include-dir addon --global-env-def defs/theme --gen-compat off --gen-target 5.4 -o "$out" "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in addon/theme/*.tl; do
|
||||||
|
gen-theme "$file"
|
||||||
|
done
|
||||||
|
|
||||||
|
function gen-compiler-hint() {
|
||||||
|
local file="$1"
|
||||||
|
local out="$2"
|
||||||
|
echo -e "\033[1;33mChecking $file\033[0m"
|
||||||
|
tl check --include-dir addon --global-env-def defs/compiler_hint --quiet "$file"
|
||||||
|
echo -e "\033[1;32mCompiling $file\033[0m"
|
||||||
|
tl gen --include-dir addon --global-env-def defs/compiler_hint --gen-compat off --gen-target 5.4 -o "$out" "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
gen-compiler-hint addon/compiler_hint/windows_domain.tl packages/msys/domain/compiler_hint.lua
|
||||||
|
gen-compiler-hint addon/compiler_hint/archlinux.tl packages/archlinux/compiler_hint.lua
|
|
@ -0,0 +1,53 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "Contrast",
|
||||||
|
pt_BR = "Contraste",
|
||||||
|
zh_CN = "高对比度",
|
||||||
|
zh_TW = "高對比度",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = nameMap[lang] or nameMap.en_US,
|
||||||
|
["style"] = "RedPandaDarkFusion",
|
||||||
|
["default scheme"] = "Twilight",
|
||||||
|
["default iconset"] = "contrast",
|
||||||
|
["palette"] = {
|
||||||
|
PaletteWindow = "#000000",
|
||||||
|
PaletteWindowText = "#FFFFFF",
|
||||||
|
PaletteBase = "#141414",
|
||||||
|
PaletteAlternateBase = "#191919",
|
||||||
|
PaletteButton = "#141414",
|
||||||
|
PaletteButtonDisabled = "#141414",
|
||||||
|
PaletteBrightText = "#ff0000",
|
||||||
|
PaletteText = "#FFFFFF",
|
||||||
|
PaletteButtonText = "#FFFFFF",
|
||||||
|
PaletteButtonTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlight = "#aa1f75cc",
|
||||||
|
PaletteDark = "#232323",
|
||||||
|
PaletteHighlightedText = "#e7e7e7",
|
||||||
|
PaletteToolTipBase = "#66000000",
|
||||||
|
PaletteToolTipText = "#e7e7e7",
|
||||||
|
PaletteLink = "#007af4",
|
||||||
|
PaletteLinkVisited = "#a57aff",
|
||||||
|
PaletteWindowDisabled = "#0A0A0A",
|
||||||
|
PaletteWindowTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightedTextDisabled = "#9DA9B5",
|
||||||
|
PaletteBaseDisabled = "#000000",
|
||||||
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
|
PaletteMid = "#FFFFFF",
|
||||||
|
PaletteLight = "#505050",
|
||||||
|
PaletteMidlight = "#00ff00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,53 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "Dark",
|
||||||
|
pt_BR = "Escura",
|
||||||
|
zh_CN = "深色",
|
||||||
|
zh_TW = "深色",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = nameMap[lang] or nameMap.en_US,
|
||||||
|
["style"] = "RedPandaDarkFusion",
|
||||||
|
["default scheme"] = "VS Code",
|
||||||
|
["default iconset"] = "contrast",
|
||||||
|
["palette"] = {
|
||||||
|
PaletteWindow = "#19232D",
|
||||||
|
PaletteWindowText = "#E0E1E3",
|
||||||
|
PaletteBase = "#1E1E1E",
|
||||||
|
PaletteAlternateBase = "#303030",
|
||||||
|
PaletteButton = "#19232D",
|
||||||
|
PaletteButtonDisabled = "#19232D",
|
||||||
|
PaletteBrightText = "#ff0000",
|
||||||
|
PaletteText = "#e7e7e7",
|
||||||
|
PaletteButtonText = "#d3d3d3",
|
||||||
|
PaletteButtonTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlight = "#aa1f75cc",
|
||||||
|
PaletteDark = "#232323",
|
||||||
|
PaletteHighlightedText = "#e7e7e7",
|
||||||
|
PaletteToolTipBase = "#66000000",
|
||||||
|
PaletteToolTipText = "#e7e7e7",
|
||||||
|
PaletteLink = "#007af4",
|
||||||
|
PaletteLinkVisited = "#a57aff",
|
||||||
|
PaletteWindowDisabled = "#333333",
|
||||||
|
PaletteWindowTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightDisabled = "#26486B",
|
||||||
|
PaletteHighlightedTextDisabled = "#9DA9B5",
|
||||||
|
PaletteBaseDisabled = "#19232D",
|
||||||
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
|
PaletteMid = "#707070",
|
||||||
|
PaletteLight = "#505050",
|
||||||
|
PaletteMidlight = "#00ff00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,51 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "Light",
|
||||||
|
pt_BR = "Clara",
|
||||||
|
zh_CN = "浅色",
|
||||||
|
zh_TW = "淺色",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = nameMap[lang] or nameMap.en_US,
|
||||||
|
["style"] = "RedPandaLightFusion",
|
||||||
|
["default scheme"] = "Intellij Classic",
|
||||||
|
["default iconset"] = "newlook",
|
||||||
|
["palette"] = {
|
||||||
|
PaletteWindow = "#efefef",
|
||||||
|
PaletteWindowText = "#000000",
|
||||||
|
PaletteBase = "#ffffff",
|
||||||
|
PaletteAlternateBase = "#f7f7f7",
|
||||||
|
PaletteToolTipBase = "#ffffdc",
|
||||||
|
PaletteToolTipText = "#000000",
|
||||||
|
PaletteText = "#000000",
|
||||||
|
PaletteButton = "#efefef",
|
||||||
|
PaletteButtonText = "#000000",
|
||||||
|
PaletteBrightText = "#ffffff",
|
||||||
|
PaletteLink = "#0000ff",
|
||||||
|
PaletteLinkVisited = "#ff00ff",
|
||||||
|
PaletteLight = "#ffffff",
|
||||||
|
PaletteMidlight = "#cacaca",
|
||||||
|
PaletteDark = "#9f9f9f",
|
||||||
|
PaletteMid = "#b8b8b8",
|
||||||
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
PaletteWindowTextDisabled = "#bebebe",
|
||||||
|
PaletteBaseDisabled = "#efefef",
|
||||||
|
PaletteTextDisabled = "#bebebe",
|
||||||
|
PaletteButtonDisabled = "#efefef",
|
||||||
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
|
PaletteHighlight = "#dddddd",
|
||||||
|
PaletteHighlightedText = "#000000",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,53 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "MoLo",
|
||||||
|
pt_BR = "Molo",
|
||||||
|
zh_CN = "墨落",
|
||||||
|
zh_TW = "墨落",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = nameMap[lang] or nameMap.en_US,
|
||||||
|
["style"] = "RedPandaDarkFusion",
|
||||||
|
["default scheme"] = "MoLo CodeBlack",
|
||||||
|
["default iconset"] = "newlook",
|
||||||
|
["palette"] = {
|
||||||
|
PaletteWindow = "#000000",
|
||||||
|
PaletteWindowText = "#FFFFFF",
|
||||||
|
PaletteBase = "#141414",
|
||||||
|
PaletteAlternateBase = "#191919",
|
||||||
|
PaletteButton = "#141414",
|
||||||
|
PaletteButtonDisabled = "#141414",
|
||||||
|
PaletteBrightText = "#ff0000",
|
||||||
|
PaletteText = "#FFFFFF",
|
||||||
|
PaletteButtonText = "#FFFFFF",
|
||||||
|
PaletteButtonTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlight = "#aa1f75cc",
|
||||||
|
PaletteDark = "#232323",
|
||||||
|
PaletteHighlightedText = "#e7e7e7",
|
||||||
|
PaletteToolTipBase = "#66000000",
|
||||||
|
PaletteToolTipText = "#e7e7e7",
|
||||||
|
PaletteLink = "#007af4",
|
||||||
|
PaletteLinkVisited = "#a57aff",
|
||||||
|
PaletteWindowDisabled = "#0A0A0A",
|
||||||
|
PaletteWindowTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightedTextDisabled = "#9DA9B5",
|
||||||
|
PaletteBaseDisabled = "#000000",
|
||||||
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
|
PaletteMid = "#FFFFFF",
|
||||||
|
PaletteLight = "#505050",
|
||||||
|
PaletteMidlight = "#00ff00",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,132 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Rgb
|
||||||
|
r: number
|
||||||
|
g: number
|
||||||
|
b: number
|
||||||
|
end
|
||||||
|
|
||||||
|
local record Hsv
|
||||||
|
h: number
|
||||||
|
s: number
|
||||||
|
v: number
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rgbFromString(color: string): Rgb
|
||||||
|
local r, g, b = color:match("#(%x%x)(%x%x)(%x%x)")
|
||||||
|
return {
|
||||||
|
r = tonumber(r, 16) / 255,
|
||||||
|
g = tonumber(g, 16) / 255,
|
||||||
|
b = tonumber(b, 16) / 255,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rgbToString(rgb: Rgb): string
|
||||||
|
return string.format(
|
||||||
|
"#%02x%02x%02x",
|
||||||
|
math.floor(rgb.r * 255),
|
||||||
|
math.floor(rgb.g * 255),
|
||||||
|
math.floor(rgb.b * 255)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function hsvToRgb(hsv: Hsv): Rgb
|
||||||
|
local r, g, b: number, number, number
|
||||||
|
local h, s, v = hsv.h, hsv.s, hsv.v
|
||||||
|
local i = math.floor(h * 6)
|
||||||
|
local f = h * 6 - i
|
||||||
|
local p = v * (1 - s)
|
||||||
|
local q = v * (1 - f * s)
|
||||||
|
local t = v * (1 - (1 - f) * s)
|
||||||
|
i = i % 6
|
||||||
|
if i == 0 then
|
||||||
|
r, g, b = v, t, p
|
||||||
|
elseif i == 1 then
|
||||||
|
r, g, b = q, v, p
|
||||||
|
elseif i == 2 then
|
||||||
|
r, g, b = p, v, t
|
||||||
|
elseif i == 3 then
|
||||||
|
r, g, b = p, q, v
|
||||||
|
elseif i == 4 then
|
||||||
|
r, g, b = t, p, v
|
||||||
|
elseif i == 5 then
|
||||||
|
r, g, b = v, p, q
|
||||||
|
end
|
||||||
|
return {r = r, g = g, b = b}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function blend(lower: Rgb, upper: Rgb, alpha: number): Rgb
|
||||||
|
local r = (1 - alpha) * lower.r + alpha * upper.r
|
||||||
|
local g = (1 - alpha) * lower.g + alpha * upper.g
|
||||||
|
local b = (1 - alpha) * lower.b + alpha * upper.b
|
||||||
|
return {r = r, g = g, b = b}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function transform(color: string, upperColor: Rgb): string
|
||||||
|
local lowerColor = rgbFromString(color)
|
||||||
|
local blended = blend(lowerColor, upperColor, 0.1)
|
||||||
|
return rgbToString(blended)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function transformPalette(palette: Theme.Palette, upperColor: Rgb): Theme.Palette
|
||||||
|
local transformed = {}
|
||||||
|
for key, value in pairs(palette as {string:string}) do
|
||||||
|
transformed[key] = transform(value, upperColor)
|
||||||
|
end
|
||||||
|
return transformed as Theme.Palette
|
||||||
|
end
|
||||||
|
|
||||||
|
local originalPalette: Theme.Palette = {
|
||||||
|
PaletteWindow = "#efefef",
|
||||||
|
PaletteWindowText = "#000000",
|
||||||
|
PaletteBase = "#ffffff",
|
||||||
|
PaletteAlternateBase = "#f7f7f7",
|
||||||
|
PaletteToolTipBase = "#ffffdc",
|
||||||
|
PaletteToolTipText = "#000000",
|
||||||
|
PaletteText = "#000000",
|
||||||
|
PaletteButton = "#efefef",
|
||||||
|
PaletteButtonText = "#000000",
|
||||||
|
PaletteBrightText = "#ffffff",
|
||||||
|
PaletteLink = "#0000ff",
|
||||||
|
PaletteLinkVisited = "#ff00ff",
|
||||||
|
PaletteLight = "#ffffff",
|
||||||
|
PaletteMidlight = "#cacaca",
|
||||||
|
PaletteDark = "#9f9f9f",
|
||||||
|
PaletteMid = "#b8b8b8",
|
||||||
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
PaletteWindowTextDisabled = "#bebebe",
|
||||||
|
PaletteBaseDisabled = "#efefef",
|
||||||
|
PaletteTextDisabled = "#bebebe",
|
||||||
|
PaletteButtonDisabled = "#efefef",
|
||||||
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
|
PaletteHighlight = "#dddddd",
|
||||||
|
PaletteHighlightedText = "#000000",
|
||||||
|
}
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "Random Light",
|
||||||
|
pt_BR = "Clara aleatória",
|
||||||
|
zh_CN = "随机浅色",
|
||||||
|
zh_TW = "隨機淺色",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local hue = math.random()
|
||||||
|
local upperColor = hsvToRgb({h = hue, s = 0.6, v = 1})
|
||||||
|
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = nameMap[lang] or nameMap.en_US,
|
||||||
|
["style"] = "RedPandaLightFusion",
|
||||||
|
["default scheme"] = "Adaptive",
|
||||||
|
["default iconset"] = "newlook",
|
||||||
|
["palette"] = transformPalette(originalPalette, upperColor),
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,113 @@
|
||||||
|
global function apiVersion(): ApiVersion
|
||||||
|
return {
|
||||||
|
kind = "theme",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local nameMap: {string:string} = {
|
||||||
|
en_US = "System Style and Color",
|
||||||
|
pt_BR = "Estilo e Cor do Sistema",
|
||||||
|
zh_CN = "跟随系统样式和颜色",
|
||||||
|
zh_TW = "跟隨系統樣式和顏色",
|
||||||
|
}
|
||||||
|
|
||||||
|
local nameMapNoStyle: {string:string} = {
|
||||||
|
en_US = "System Color",
|
||||||
|
pt_BR = "Cor do Sistema",
|
||||||
|
zh_CN = "跟随系统颜色",
|
||||||
|
zh_TW = "跟隨系統顏色",
|
||||||
|
}
|
||||||
|
|
||||||
|
global function main(): Theme
|
||||||
|
local desktopEnvironment = C_Desktop.desktopEnvironment()
|
||||||
|
local useSystemStyle = desktopEnvironment == "xdg" or desktopEnvironment == "macos"
|
||||||
|
|
||||||
|
local systemAppMode = C_Desktop.systemAppMode()
|
||||||
|
local isDarkMode = systemAppMode == "dark"
|
||||||
|
|
||||||
|
local function getStyle(): string
|
||||||
|
if useSystemStyle then
|
||||||
|
return C_Desktop.systemStyle()
|
||||||
|
else
|
||||||
|
if isDarkMode then
|
||||||
|
return "RedPandaDarkFusion"
|
||||||
|
else
|
||||||
|
return "RedPandaLightFusion"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getPalette(): Theme.Palette
|
||||||
|
if useSystemStyle then
|
||||||
|
return {}
|
||||||
|
elseif isDarkMode then
|
||||||
|
return { -- palette from `dark.lua`
|
||||||
|
PaletteWindow = "#19232D",
|
||||||
|
PaletteWindowText = "#E0E1E3",
|
||||||
|
PaletteBase = "#1E1E1E",
|
||||||
|
PaletteAlternateBase = "#303030",
|
||||||
|
PaletteButton = "#19232D",
|
||||||
|
PaletteButtonDisabled = "#19232D",
|
||||||
|
PaletteBrightText = "#ff0000",
|
||||||
|
PaletteText = "#e7e7e7",
|
||||||
|
PaletteButtonText = "#d3d3d3",
|
||||||
|
PaletteButtonTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlight = "#aa1f75cc",
|
||||||
|
PaletteDark = "#232323",
|
||||||
|
PaletteHighlightedText = "#e7e7e7",
|
||||||
|
PaletteToolTipBase = "#66000000",
|
||||||
|
PaletteToolTipText = "#e7e7e7",
|
||||||
|
PaletteLink = "#007af4",
|
||||||
|
PaletteLinkVisited = "#a57aff",
|
||||||
|
PaletteWindowDisabled = "#333333",
|
||||||
|
PaletteWindowTextDisabled = "#9DA9B5",
|
||||||
|
PaletteHighlightDisabled = "#26486B",
|
||||||
|
PaletteHighlightedTextDisabled = "#9DA9B5",
|
||||||
|
PaletteBaseDisabled = "#19232D",
|
||||||
|
PaletteTextDisabled = "#9DA9B5",
|
||||||
|
PaletteMid = "#707070",
|
||||||
|
PaletteLight = "#505050",
|
||||||
|
PaletteMidlight = "#00ff00",
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return { -- palette from `default.lua`
|
||||||
|
PaletteWindow = "#efefef",
|
||||||
|
PaletteWindowText = "#000000",
|
||||||
|
PaletteBase = "#ffffff",
|
||||||
|
PaletteAlternateBase = "#f7f7f7",
|
||||||
|
PaletteToolTipBase = "#ffffdc",
|
||||||
|
PaletteToolTipText = "#000000",
|
||||||
|
PaletteText = "#000000",
|
||||||
|
PaletteButton = "#efefef",
|
||||||
|
PaletteButtonText = "#000000",
|
||||||
|
PaletteBrightText = "#ffffff",
|
||||||
|
PaletteLink = "#0000ff",
|
||||||
|
PaletteLinkVisited = "#ff00ff",
|
||||||
|
PaletteLight = "#ffffff",
|
||||||
|
PaletteMidlight = "#cacaca",
|
||||||
|
PaletteDark = "#9f9f9f",
|
||||||
|
PaletteMid = "#b8b8b8",
|
||||||
|
PaletteWindowDisabled = "#efefef",
|
||||||
|
PaletteWindowTextDisabled = "#bebebe",
|
||||||
|
PaletteBaseDisabled = "#efefef",
|
||||||
|
PaletteTextDisabled = "#bebebe",
|
||||||
|
PaletteButtonDisabled = "#efefef",
|
||||||
|
PaletteButtonTextDisabled = "#bebebe",
|
||||||
|
PaletteHighlight = "#dddddd",
|
||||||
|
PaletteHighlightedText = "#000000",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
|
return {
|
||||||
|
["name"] = useSystemStyle and (nameMap[lang] or nameMap.en_US) or (nameMapNoStyle[lang] or nameMapNoStyle.en_US),
|
||||||
|
["style"] = getStyle(),
|
||||||
|
["default scheme"] = "Adaptive",
|
||||||
|
["default iconset"] = "newlook",
|
||||||
|
["palette"] = getPalette()
|
||||||
|
}
|
||||||
|
end
|
206
docs/addon.md
206
docs/addon.md
|
@ -14,10 +14,50 @@
|
||||||
- Red Panda C++ APIs exposed to add-on are organized by groups.
|
- Red Panda C++ APIs exposed to add-on are organized by groups.
|
||||||
- Each group is a Lua table.
|
- Each group is a Lua table.
|
||||||
- Each API is a function in the table.
|
- Each API is a function in the table.
|
||||||
- Available API groups vary by add-on type.
|
- Available API groups vary by add-on kind.
|
||||||
- Localization is handled by add-on. e.g.
|
- See [`env.d.tl`](../addon/defs/global_env.d.tl) for API definitions.
|
||||||
|
- Add-on can be executed only if the API version is compatible.
|
||||||
|
- Localization is handled by add-on.
|
||||||
|
|
||||||
|
### API Version Check
|
||||||
|
|
||||||
|
Add-on must implement `apiVersion` that takes no argument and returns `ApiVersion` ([`env.d.tl`](../addon/defs/global_env.d.tl)).
|
||||||
|
|
||||||
|
Before execution, Red Panda C++ will call `apiVersion()` _without injecting any API group_[^1] to check whether the add-on is compatible with current Red Panda C++ (host).
|
||||||
|
|
||||||
|
[^1]: Thus do not call any API (incl. Lua standard library) in `apiVersion` and file scope.
|
||||||
|
|
||||||
|
Add-on is compatible with host if and only if:
|
||||||
|
```
|
||||||
|
(add-on kind = host kind) ∧ (
|
||||||
|
((add-on major = host major = 0) ∧ (add-on minor = host minor)) ∨
|
||||||
|
((add-on major = host major ≥ 1) ∧ (add-on minor ≤ host minor))
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
That is to say:
|
||||||
|
- API version is kind-specific.
|
||||||
|
- For a given kind, API major reported by add-on must be equal to host major.
|
||||||
|
- API major = 0 means unstable, minor updates may break backward compatibility.
|
||||||
|
- API major ≥ 1 means stable, minor updates keep backward compatibility.
|
||||||
|
|
||||||
|
### Types
|
||||||
|
|
||||||
|
Types in Red Panda C++ add-on interface are defined in [Teal](https://github.com/teal-language/tl) language, a typed dialect of Lua.
|
||||||
|
|
||||||
|
To make use of the type definitions, add-on can be written in Teal. To check and compile Teal add-on:
|
||||||
|
```bash
|
||||||
|
tl check --include-dir /path/to/RedPanda-CPP/addon --global-env-def defs/theme addon.tl
|
||||||
|
tl gen --include-dir /path/to/RedPanda-CPP/addon --global-env-def defs/theme --gen-compat off --gen-target 5.4 addon.tl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Localization
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local lang = C_Desktop.language()
|
local lang = C_Desktop.language()
|
||||||
|
-- note: explicitly declare as `{string:string}` for Teal
|
||||||
local localizedName = {
|
local localizedName = {
|
||||||
en_US = "System",
|
en_US = "System",
|
||||||
pt_BR = "Sistema",
|
pt_BR = "Sistema",
|
||||||
|
@ -32,10 +72,23 @@
|
||||||
|
|
||||||
## Simple Add-on
|
## Simple Add-on
|
||||||
|
|
||||||
A simple add-on is a Lua script that returns a single value.
|
A simple add-on is a Lua script with a `main` function returning single value.
|
||||||
|
|
||||||
|
### Theme Add-on
|
||||||
|
|
||||||
|
Current API version: `theme:0.1`.
|
||||||
|
|
||||||
|
Available API groups:
|
||||||
|
- `C_Debug`
|
||||||
|
- `C_Desktop`
|
||||||
|
- `C_Util`
|
||||||
|
|
||||||
|
`main` function takes no argument and returns `Theme` ([`theme.d.tl`](../addon/defs/theme.d.tl)).
|
||||||
|
|
||||||
### Compiler Hint Add-on
|
### Compiler Hint Add-on
|
||||||
|
|
||||||
|
Current API version: `compiler_hint:0.1`.
|
||||||
|
|
||||||
If `$appLibexecDir/compiler_hint.lua` exists, it will be executed as compiler hint add-on when searching for compiler.
|
If `$appLibexecDir/compiler_hint.lua` exists, it will be executed as compiler hint add-on when searching for compiler.
|
||||||
|
|
||||||
Available API groups:
|
Available API groups:
|
||||||
|
@ -45,149 +98,4 @@ Available API groups:
|
||||||
- `C_System`
|
- `C_System`
|
||||||
- `C_Util`
|
- `C_Util`
|
||||||
|
|
||||||
Return value schema:
|
`main` function takes no argument and returns `CompilerHint` ([`compiler_hint.d.tl`](../addon/defs/compiler_hint.d.tl)).
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
// found compiler sets
|
|
||||||
compilerList: [compilerSet],
|
|
||||||
|
|
||||||
// do not search in these directories anymore
|
|
||||||
noSearch: [string],
|
|
||||||
|
|
||||||
// prefer compiler set index (in Lua, 1-based) in compilerList
|
|
||||||
// 0 for no preference
|
|
||||||
preferCompiler: number,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`compilerSet` schema:
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
name: string,
|
|
||||||
|
|
||||||
// internal
|
|
||||||
dumpMachine: string, // e.g. "x86_64-linux-gnu", "x86_64-w64-mingw32"
|
|
||||||
version: string, // e.g. "13.2.1", "17.0.6"
|
|
||||||
type: string, // e.g. "TDM-GCC", "MinGW"
|
|
||||||
target: string, // e.g. "x86_64", "aarch64"
|
|
||||||
compilerType: string, // "GCC" or "Clang"
|
|
||||||
|
|
||||||
// general
|
|
||||||
staticLink: boolean,
|
|
||||||
customCompileParams: [string], // automatically sets useCustomCompileParams
|
|
||||||
customLinkParams: [string], // automatically sets useCustomLinkParams
|
|
||||||
execCharset: string, // automatically sets autoAddCharsetParams
|
|
||||||
|
|
||||||
// setting
|
|
||||||
// - code generation
|
|
||||||
ccCmdOptOptimize: string,
|
|
||||||
ccCmdOptStd: string,
|
|
||||||
cCmdOptStd: string,
|
|
||||||
ccCmdOptInstruction: string,
|
|
||||||
ccCmdOptPointerSize: string,
|
|
||||||
ccCmdOptDebugInfo: string,
|
|
||||||
ccCmdOptProfileInfo: string,
|
|
||||||
ccCmdOptSyntaxOnly: string,
|
|
||||||
// - warnings
|
|
||||||
ccCmdOptInhibitAllWarning: string,
|
|
||||||
ccCmdOptWarningAll: string,
|
|
||||||
ccCmdOptWarningExtra: string,
|
|
||||||
ccCmdOptCheckIsoConformance: string,
|
|
||||||
ccCmdOptWarningAsError: string,
|
|
||||||
ccCmdOptAbortOnError: string,
|
|
||||||
ccCmdOptStackProtector: string,
|
|
||||||
ccCmdOptAddressSanitizer: string,
|
|
||||||
// - linker
|
|
||||||
ccCmdOptUsePipe: string,
|
|
||||||
linkCmdOptNoLinkStdlib: string,
|
|
||||||
linkCmdOptNoConsole: string,
|
|
||||||
linkCmdOptStripExe: string,
|
|
||||||
|
|
||||||
// directory
|
|
||||||
binDirs: [string],
|
|
||||||
cIncludeDirs: [string],
|
|
||||||
cxxIncludeDirs: [string],
|
|
||||||
libDirs: [string],
|
|
||||||
defaultLibDirs: [string],
|
|
||||||
defaultCIncludeDirs: [string],
|
|
||||||
defaultCxxIncludeDirs: [string],
|
|
||||||
|
|
||||||
// program
|
|
||||||
cCompiler: string,
|
|
||||||
cxxCompiler: string,
|
|
||||||
make: string,
|
|
||||||
debugger: string,
|
|
||||||
debugServer: string,
|
|
||||||
resourceCompiler: string,
|
|
||||||
|
|
||||||
// output
|
|
||||||
preprocessingSuffix: string,
|
|
||||||
compilationProperSuffix: string,
|
|
||||||
assemblingSuffix: string,
|
|
||||||
executableSuffix: string,
|
|
||||||
compilationStage: number,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Groups
|
|
||||||
|
|
||||||
### `C_Debug`
|
|
||||||
|
|
||||||
`C_Debug` is available to all add-on types.
|
|
||||||
|
|
||||||
- `C_Debug.debug`: `(message: string) -> ()`, print message to console (via `qDebug()`).
|
|
||||||
|
|
||||||
### `C_Desktop`
|
|
||||||
|
|
||||||
- `C_Desktop.desktopEnvironment`: `() -> string`, return desktop environment name.
|
|
||||||
- `windows`: Windows (Win32 only)
|
|
||||||
- `macos`: macOS
|
|
||||||
- `xdg`: XDG-compliant desktop environment (e.g. GNOME, KDE Plasma)
|
|
||||||
- `unknown`: other desktops or non-desktop environments (e.g. Windows UWP, Android)
|
|
||||||
- `C_Desktop.language`: `() -> string`, return language code.
|
|
||||||
- e.g. `en_US`, `zh_CN`
|
|
||||||
- `C_Desktop.qtStyleList`: `() -> [string]`, return available Qt styles.
|
|
||||||
- e.g. `{"breeze", "fusion", "windows"}`
|
|
||||||
- `C_Desktop.systemAppMode`: `() -> string`, return system app mode.
|
|
||||||
- `light`: light mode
|
|
||||||
- `dark`: dark mode
|
|
||||||
- `C_Desktop.systemStyle`: `() -> string`, return default Qt style.
|
|
||||||
- e.g. `fusion`
|
|
||||||
|
|
||||||
### `C_FileSystem`
|
|
||||||
|
|
||||||
- `C_FileSystem.exists`: `(path: string) -> boolean`, return whether the path exists.
|
|
||||||
- `C_FileSystem.isExecutable`: `(path: string) -> boolean`, return whether the path is executable.
|
|
||||||
|
|
||||||
### `C_System`
|
|
||||||
|
|
||||||
- `C_System.appArch`: `() -> string`, return the architecture of Red Panda C++, name following `QSysInfo`.
|
|
||||||
- e.g. `i386`, `x86_64`, `arm`, `arm64`, `riscv64`, `loongarch64`
|
|
||||||
- Though unsupprted, MSVC arm64ec is handled correctly (returns `arm64ec`)
|
|
||||||
- `C_System.appDir`: `() -> string`, return the directory of Red Panda C++.
|
|
||||||
- e.g. `/usr/bin`, `C:/Program Files/RedPanda-Cpp`
|
|
||||||
- `C_System.appLibexecDir`: `() -> string`, return the libexec directory of Red Panda C++.
|
|
||||||
- e.g. `/usr/libexec/RedPandaCPP`, `C:/Program Files/RedPanda-Cpp`
|
|
||||||
- `C_System.appResourceDir`: `() -> string`, return the resource directory of Red Panda C++.
|
|
||||||
- e.g. `/usr/share/RedPandaCPP`, `C:/Program Files/RedPanda-Cpp`
|
|
||||||
- `C_System.osArch`: `() -> string`, return the architecture of the OS, name following `QSysInfo`.
|
|
||||||
- e.g. `i386`, `x86_64`, `arm`, `arm64`
|
|
||||||
- Windows arm64 is handled correctly even if Red Panda C++ runs under emulation
|
|
||||||
- `C_System.supportedAppArchList`: `() -> [string]`, return supported application architectures by OS, name following `QSysInfo`.
|
|
||||||
- e.g. `{"i386", "x86_64", "arm64"}`
|
|
||||||
- Windows 10 1709 or later: accurate result
|
|
||||||
- Legacy Windows: hardcoded
|
|
||||||
- `{"i386", "x86_64"}` for x86_64 even though WoW64 is not available
|
|
||||||
- macOS: accurate result supposed, but not tested
|
|
||||||
- Linux: osArch + appArch + QEMU user mode emulation
|
|
||||||
- No multilib detection. It’s packager’s responsibility to detect multilib support in `compiler_hint.lua`
|
|
||||||
- other (BSD): osArch + appArch (no multilib)
|
|
||||||
|
|
||||||
Windows specific:
|
|
||||||
|
|
||||||
- `C_System.readRegistry`: `(subKey: string, name: string) -> string | nil`, read `subKey\name` from `HKEY_CURRENT_USER` and `HKEY_LOCAL_MACHINE` in order.
|
|
||||||
- `name` can be empty string for default value
|
|
||||||
|
|
||||||
### `C_Util`
|
|
||||||
|
|
||||||
- `C_Util.format`: `(format: string, ...) -> string`, Qt-style string format, replace `%1`, `%2`, etc. with arguments.
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
local arch = C_System.osArch()
|
function apiVersion()
|
||||||
local libexecDir = C_System.appLibexecDir()
|
return {
|
||||||
local lang = C_Desktop.language()
|
kind = "compiler_hint",
|
||||||
|
major = 0,
|
||||||
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local nameMap = {
|
local nameMap = {
|
||||||
systemGcc = {
|
systemGcc = {
|
||||||
|
@ -65,7 +69,28 @@ local nameMap = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateConfig(name, cCompiler, cxxCompiler, config)
|
local function mergeCompilerSet(compilerSet, other)
|
||||||
|
local c = compilerSet
|
||||||
|
local o = other
|
||||||
|
for k, v in pairs(o) do
|
||||||
|
c[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function generateConfig(
|
||||||
|
name, lang,
|
||||||
|
cCompiler, cxxCompiler,
|
||||||
|
config)
|
||||||
|
|
||||||
local commonOptions = {
|
local commonOptions = {
|
||||||
cCompiler = cCompiler,
|
cCompiler = cCompiler,
|
||||||
cxxCompiler = cxxCompiler,
|
cxxCompiler = cxxCompiler,
|
||||||
|
@ -102,7 +127,7 @@ function generateConfig(name, cCompiler, cxxCompiler, config)
|
||||||
linkCmdOptStripExe = "on",
|
linkCmdOptStripExe = "on",
|
||||||
ccCmdOptOptimize = "2",
|
ccCmdOptOptimize = "2",
|
||||||
}
|
}
|
||||||
local debug = {
|
local debug_ = {
|
||||||
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
|
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
|
||||||
ccCmdOptDebugInfo = "on",
|
ccCmdOptDebugInfo = "on",
|
||||||
}
|
}
|
||||||
|
@ -111,100 +136,110 @@ function generateConfig(name, cCompiler, cxxCompiler, config)
|
||||||
ccCmdOptDebugInfo = "on",
|
ccCmdOptDebugInfo = "on",
|
||||||
ccCmdOptAddressSanitizer = "address",
|
ccCmdOptAddressSanitizer = "address",
|
||||||
}
|
}
|
||||||
for k, v in pairs(commonOptions) do
|
mergeCompilerSet(release, commonOptions)
|
||||||
release[k] = v
|
mergeCompilerSet(debug_, commonOptions)
|
||||||
debug[k] = v
|
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||||
debugWithAsan[k] = v
|
return release, debug_, debugWithAsan
|
||||||
end
|
|
||||||
return release, debug, debugWithAsan
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function main()
|
||||||
|
local arch = C_System.osArch()
|
||||||
|
local libexecDir = C_System.appLibexecDir()
|
||||||
|
local lang = C_Desktop.language()
|
||||||
|
|
||||||
local compilerList = {}
|
local compilerList = {}
|
||||||
|
|
||||||
do
|
do
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US,
|
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang,
|
||||||
"/usr/bin/gcc", "/usr/bin/g++",
|
"/usr/bin/gcc", "/usr/bin/g++",
|
||||||
{}
|
{})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
table.insert(compilerList, debugWithAsan)
|
table.insert(compilerList, debugWithAsan)
|
||||||
end
|
end
|
||||||
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
nameMap.systemClang[lang] or nameMap.systemClang.en_US,
|
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang,
|
||||||
"/usr/bin/clang", "/usr/bin/clang++",
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
{isClang = true}
|
{ isClang = true })
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
table.insert(compilerList, debugWithAsan)
|
table.insert(compilerList, debugWithAsan)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- with lib32-gcc-libs installed, system GCC and Clang can target 32-bit
|
|
||||||
if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then
|
if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
do
|
||||||
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US,
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
|
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang,
|
||||||
"/usr/bin/gcc", "/usr/bin/g++",
|
"/usr/bin/gcc", "/usr/bin/g++",
|
||||||
{isMultilib = true}
|
{ isMultilib = true })
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
table.insert(compilerList, debugWithAsan)
|
table.insert(compilerList, debugWithAsan)
|
||||||
|
end
|
||||||
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US,
|
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang,
|
||||||
"/usr/bin/clang", "/usr/bin/clang++",
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
{isClang = true, isMultilib = true}
|
{ isClang = true, isMultilib = true })
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
table.insert(compilerList, debugWithAsan)
|
table.insert(compilerList, debugWithAsan)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- cross GCC
|
|
||||||
if (
|
if (
|
||||||
arch == "x86_64" and
|
arch == "x86_64" and
|
||||||
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/qemu-aarch64") and
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/qemu-aarch64") and
|
||||||
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")
|
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")) then
|
||||||
) then
|
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, _, _ = generateConfig(
|
||||||
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64",
|
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64", lang,
|
||||||
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
|
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
|
||||||
{}
|
{})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- with wine or WSL init registered in binfmt_misc, Windows binaries can run seamlessly
|
|
||||||
if (
|
if (
|
||||||
arch == "x86_64" and (
|
arch == "x86_64" and (
|
||||||
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/DOSWin") or
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/DOSWin") or
|
||||||
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/WSLInterop")
|
C_FileSystem.exists("/proc/sys/fs/binfmt_misc/WSLInterop"))) then
|
||||||
)
|
|
||||||
) then
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/x86_64-w64-mingw32-gcc") then
|
if C_FileSystem.isExecutable("/usr/bin/x86_64-w64-mingw32-gcc") then
|
||||||
local extraObjects = {
|
local extraObjects = {
|
||||||
utf8init = libexecDir .. "/x86_64-w64-mingw32/utf8init.o",
|
utf8init = libexecDir .. "/x86_64-w64-mingw32/utf8init.o",
|
||||||
utf8manifest = libexecDir .. "/x86_64-w64-mingw32/utf8manifest.o",
|
utf8manifest = libexecDir .. "/x86_64-w64-mingw32/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
|
||||||
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64",
|
do
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang,
|
||||||
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
|
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
|
||||||
{
|
{
|
||||||
isMingw = true,
|
isMingw = true,
|
||||||
triplet = "x86_64-w64-mingw32",
|
triplet = "x86_64-w64-mingw32",
|
||||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
-- system Clang can target Windows
|
end
|
||||||
|
|
||||||
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, _, _ = generateConfig(
|
||||||
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64",
|
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64", lang,
|
||||||
"/usr/bin/clang", "/usr/bin/clang++",
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
{
|
{
|
||||||
isClang = true,
|
isClang = true,
|
||||||
|
@ -216,30 +251,35 @@ if (
|
||||||
extraObjects.utf8init, extraObjects.utf8manifest,
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
"-lstdc++", "-lwinpthread",
|
"-lstdc++", "-lwinpthread",
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/i686-w64-mingw32-gcc") then
|
if C_FileSystem.isExecutable("/usr/bin/i686-w64-mingw32-gcc") then
|
||||||
local extraObjects = {
|
local extraObjects = {
|
||||||
utf8init = libexecDir .. "/i686-w64-mingw32/utf8init.o",
|
utf8init = libexecDir .. "/i686-w64-mingw32/utf8init.o",
|
||||||
utf8manifest = libexecDir .. "/i686-w64-mingw32/utf8manifest.o",
|
utf8manifest = libexecDir .. "/i686-w64-mingw32/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
|
||||||
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686",
|
do
|
||||||
|
local release, _, _ = generateConfig(
|
||||||
|
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang,
|
||||||
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
|
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
|
||||||
{
|
{
|
||||||
isMingw = true,
|
isMingw = true,
|
||||||
triplet = "i686-w64-mingw32",
|
triplet = "i686-w64-mingw32",
|
||||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
-- system Clang can target Windows
|
end
|
||||||
|
|
||||||
|
|
||||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, _, _ = generateConfig(
|
||||||
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686",
|
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686", lang,
|
||||||
"/usr/bin/clang", "/usr/bin/clang++",
|
"/usr/bin/clang", "/usr/bin/clang++",
|
||||||
{
|
{
|
||||||
isClang = true,
|
isClang = true,
|
||||||
|
@ -251,8 +291,8 @@ if (
|
||||||
extraObjects.utf8init, extraObjects.utf8manifest,
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
"-lstdc++", "-lwinpthread",
|
"-lstdc++", "-lwinpthread",
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -265,7 +305,9 @@ local result = {
|
||||||
"/opt/cuda/bin",
|
"/opt/cuda/bin",
|
||||||
"/usr/lib/ccache/bin",
|
"/usr/lib/ccache/bin",
|
||||||
},
|
},
|
||||||
preferCompiler = 3, -- System GCC Debug with ASan
|
preferCompiler = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
local arch = C_System.osArch()
|
function apiVersion()
|
||||||
local appArch = C_System.appArch()
|
return {
|
||||||
local libexecDir = C_System.appLibexecDir()
|
kind = "compiler_hint",
|
||||||
local lang = C_Desktop.language()
|
major = 0,
|
||||||
local supportedAppArches = C_System.supportedAppArchList()
|
minor = 1,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
local gnuArchMap = {
|
local gnuArchMap = {
|
||||||
i386 = "i686",
|
i386 = "i686",
|
||||||
|
@ -32,8 +34,7 @@ local profileNameMap = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local nameGenerator = {
|
local function nameGeneratorMingwGcc(lang, arch, profile, isUtf8)
|
||||||
mingwGcc = function (lang, arch, profile, isUtf8)
|
|
||||||
local template = {
|
local template = {
|
||||||
en_US = "MinGW GCC %1 in %2, %3",
|
en_US = "MinGW GCC %1 in %2, %3",
|
||||||
pt_BR = "GCC MinGW %1 em %2, %3",
|
pt_BR = "GCC MinGW %1 em %2, %3",
|
||||||
|
@ -50,15 +51,16 @@ local nameGenerator = {
|
||||||
template[lang] or template.en_US,
|
template[lang] or template.en_US,
|
||||||
gnuArchMap[arch],
|
gnuArchMap[arch],
|
||||||
isUtf8 and "UTF-8" or systemCodePage[lang] or systemCodePage.en_US,
|
isUtf8 and "UTF-8" or systemCodePage[lang] or systemCodePage.en_US,
|
||||||
profileNameMap[profile][lang] or profileNameMap[profile].en_US
|
profileNameMap[profile][lang] or profileNameMap[profile].en_US)
|
||||||
)
|
|
||||||
end,
|
end
|
||||||
clang = function (lang, arch, profile, isMingw)
|
|
||||||
|
local function nameGeneratorClang(lang, arch, profile, isMingw)
|
||||||
local template = {
|
local template = {
|
||||||
en_US = "%1 Clang %2, %3",
|
en_US = "%1 Clang %2, %3",
|
||||||
pt_BR = "Clang %2 %1, %3",
|
pt_BR = "Clang %2 %1, %3",
|
||||||
zh_CN = "%1 Clang %2,%3",
|
zh_CN = "%1 Clang %2,%3",
|
||||||
zh_CN = "%1 Clang %2,%3",
|
zh_TW = "%1 Clang %2,%3",
|
||||||
}
|
}
|
||||||
local msvcCompatible = {
|
local msvcCompatible = {
|
||||||
en_US = "MSVC-compatible",
|
en_US = "MSVC-compatible",
|
||||||
|
@ -70,12 +72,42 @@ local nameGenerator = {
|
||||||
template[lang] or template.en_US,
|
template[lang] or template.en_US,
|
||||||
isMingw and "LLVM-MinGW" or msvcCompatible[lang] or msvcCompatible.en_US,
|
isMingw and "LLVM-MinGW" or msvcCompatible[lang] or msvcCompatible.en_US,
|
||||||
gnuArchMap[arch],
|
gnuArchMap[arch],
|
||||||
profileNameMap[profile][lang] or profileNameMap[profile].en_US
|
profileNameMap[profile][lang] or profileNameMap[profile].en_US)
|
||||||
)
|
|
||||||
end,
|
end
|
||||||
}
|
|
||||||
|
local function mergeCompilerSet(compilerSet, other)
|
||||||
|
local c = compilerSet
|
||||||
|
local o = other
|
||||||
|
for k, v in pairs(o) do
|
||||||
|
c[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
local function generateConfig(
|
||||||
|
nameGen,
|
||||||
|
programs,
|
||||||
|
config)
|
||||||
|
|
||||||
function generateConfig(nameGen, programs, config)
|
|
||||||
local commonOptions = {
|
local commonOptions = {
|
||||||
cCompiler = programs.cCompiler,
|
cCompiler = programs.cCompiler,
|
||||||
cxxCompiler = programs.cxxCompiler,
|
cxxCompiler = programs.cxxCompiler,
|
||||||
|
@ -113,7 +145,7 @@ function generateConfig(nameGen, programs, config)
|
||||||
linkCmdOptStripExe = "on",
|
linkCmdOptStripExe = "on",
|
||||||
ccCmdOptOptimize = "2",
|
ccCmdOptOptimize = "2",
|
||||||
}
|
}
|
||||||
local debug = {
|
local debug_ = {
|
||||||
name = nameGen(config.arch, "debug"),
|
name = nameGen(config.arch, "debug"),
|
||||||
ccCmdOptDebugInfo = "on",
|
ccCmdOptDebugInfo = "on",
|
||||||
}
|
}
|
||||||
|
@ -122,35 +154,30 @@ function generateConfig(nameGen, programs, config)
|
||||||
ccCmdOptDebugInfo = "on",
|
ccCmdOptDebugInfo = "on",
|
||||||
ccCmdOptAddressSanitizer = "address",
|
ccCmdOptAddressSanitizer = "address",
|
||||||
}
|
}
|
||||||
for k, v in pairs(commonOptions) do
|
mergeCompilerSet(release, commonOptions)
|
||||||
release[k] = v
|
mergeCompilerSet(debug_, commonOptions)
|
||||||
debug[k] = v
|
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||||
debugWithAsan[k] = v
|
return release, debug_, debugWithAsan
|
||||||
end
|
|
||||||
return release, debug, debugWithAsan
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function contains(t, v)
|
function main()
|
||||||
for _, vv in ipairs(t) do
|
local appArch = C_System.appArch()
|
||||||
if vv == v then
|
local libexecDir = C_System.appLibexecDir()
|
||||||
return true
|
local lang = C_Desktop.language()
|
||||||
end
|
local supportedAppArches = C_System.supportedAppArchList()
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local compilerList = {}
|
local compilerList = {}
|
||||||
local noSearch = {}
|
local noSearch = {}
|
||||||
local preferCompiler = 0
|
local preferCompiler = 0
|
||||||
|
|
||||||
function checkAndAddMingw(arch)
|
local function checkAndAddMingw(arch)
|
||||||
local binDir
|
local binDir
|
||||||
local libDir
|
local libDir
|
||||||
local excludeBinDir
|
local excludeBinDir
|
||||||
if arch == "i386" then
|
if arch == "i386" then
|
||||||
binDir = libexecDir .. "/mingw32/bin" -- must match case because Windows filesystem can be case sensitive
|
binDir = libexecDir .. "/mingw32/bin"
|
||||||
libDir = libexecDir .. "/mingw32/i686-w64-mingw32/lib"
|
libDir = libexecDir .. "/mingw32/i686-w64-mingw32/lib"
|
||||||
excludeBinDir = libexecDir .. "/MinGW32/bin" -- workaround for path check
|
excludeBinDir = libexecDir .. "/MinGW32/bin"
|
||||||
elseif arch == "x86_64" then
|
elseif arch == "x86_64" then
|
||||||
binDir = libexecDir .. "/mingw64/bin"
|
binDir = libexecDir .. "/mingw64/bin"
|
||||||
libDir = libexecDir .. "/mingw64/x86_64-w64-mingw32/lib"
|
libDir = libexecDir .. "/mingw64/x86_64-w64-mingw32/lib"
|
||||||
|
@ -177,42 +204,47 @@ function checkAndAddMingw(arch)
|
||||||
utf8manifest = libDir .. "/utf8manifest.o",
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
}
|
}
|
||||||
|
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.mingwGcc(lang, arch, profile, true) end,
|
function(arch_, profile)
|
||||||
|
return nameGeneratorMingwGcc(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = arch,
|
arch = arch,
|
||||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
if preferCompiler == 0 then
|
if preferCompiler == 0 then
|
||||||
preferCompiler = 2
|
preferCompiler = 2
|
||||||
end
|
end
|
||||||
|
|
||||||
release, debug, debugWithAsan = generateConfig(
|
release, debug_, debugWithAsan = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.mingwGcc(lang, arch, profile, false) end,
|
function(arch_, profile)
|
||||||
|
return nameGeneratorMingwGcc(lang, arch_, profile, false)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = arch,
|
arch = arch,
|
||||||
isAnsi = true,
|
isAnsi = true,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
|
|
||||||
table.insert(noSearch, excludeBinDir)
|
table.insert(noSearch, excludeBinDir)
|
||||||
end
|
end
|
||||||
|
|
||||||
function checkAndAddClang()
|
local function checkAndAddClang()
|
||||||
if not C_FileSystem.isExecutable(libexecDir .. "/llvm-mingw/bin/clang.exe") then
|
if not C_FileSystem.isExecutable(libexecDir .. "/llvm-mingw/bin/clang.exe") then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- appArch is always debuggable
|
|
||||||
local appTriplet = gnuArchMap[appArch] .. "-w64-mingw32"
|
|
||||||
local binDir = libexecDir .. "/llvm-mingw/bin"
|
local binDir = libexecDir .. "/llvm-mingw/bin"
|
||||||
|
local appTriplet = gnuArchMap[appArch] .. "-w64-mingw32"
|
||||||
|
do
|
||||||
|
|
||||||
local libDir = libexecDir .. "/llvm-mingw/" .. appTriplet .. "/lib"
|
local libDir = libexecDir .. "/llvm-mingw/" .. appTriplet .. "/lib"
|
||||||
local programs = {
|
local programs = {
|
||||||
cCompiler = binDir .. "/" .. appTriplet .. "-clang.exe",
|
cCompiler = binDir .. "/" .. appTriplet .. "-clang.exe",
|
||||||
|
@ -227,17 +259,19 @@ function checkAndAddClang()
|
||||||
utf8init = libDir .. "/utf8init.o",
|
utf8init = libDir .. "/utf8init.o",
|
||||||
utf8manifest = libDir .. "/utf8manifest.o",
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, debugWithAsan = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, true) end,
|
function(arch_, profile)
|
||||||
|
return nameGeneratorClang(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = appArch,
|
arch = appArch,
|
||||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||||
isClang = true,
|
isClang = true,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
if appArch ~= "arm64" then
|
if appArch ~= "arm64" then
|
||||||
table.insert(compilerList, debugWithAsan)
|
table.insert(compilerList, debugWithAsan)
|
||||||
if preferCompiler == 0 then
|
if preferCompiler == 0 then
|
||||||
|
@ -248,6 +282,7 @@ function checkAndAddClang()
|
||||||
preferCompiler = 2
|
preferCompiler = 2
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
for _, foreignArch in ipairs(supportedAppArches) do
|
for _, foreignArch in ipairs(supportedAppArches) do
|
||||||
if foreignArch ~= appArch then
|
if foreignArch ~= appArch then
|
||||||
|
@ -266,15 +301,17 @@ function checkAndAddClang()
|
||||||
utf8init = libDir .. "/utf8init.o",
|
utf8init = libDir .. "/utf8init.o",
|
||||||
utf8manifest = libDir .. "/utf8manifest.o",
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, _, _ = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, true) end,
|
function(arch_, profile)
|
||||||
|
return nameGeneratorClang(lang, arch_, profile, true)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = foreignArch,
|
arch = foreignArch,
|
||||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||||
isClang = true,
|
isClang = true,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -285,8 +322,9 @@ function checkAndAddClang()
|
||||||
if not llvmOrgPath then
|
if not llvmOrgPath then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local llvmOrgBinDir = llvmOrgPath .. "/bin"
|
local llvmOrgBinDir = llvmOrgPath .. "/bin"
|
||||||
|
|
||||||
|
do
|
||||||
local msvcTriplet = gnuArchMap[appArch] .. "-pc-windows-msvc"
|
local msvcTriplet = gnuArchMap[appArch] .. "-pc-windows-msvc"
|
||||||
local libDir = libexecDir .. "/llvm-mingw/" .. msvcTriplet .. "/lib"
|
local libDir = libexecDir .. "/llvm-mingw/" .. msvcTriplet .. "/lib"
|
||||||
local programs = {
|
local programs = {
|
||||||
|
@ -303,8 +341,10 @@ function checkAndAddClang()
|
||||||
utf8init = libDir .. "/utf8init.o",
|
utf8init = libDir .. "/utf8init.o",
|
||||||
utf8manifest = libDir .. "/utf8manifest.o",
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, debug_, _ = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, false) end,
|
function(arch, profile)
|
||||||
|
return nameGeneratorClang(lang, arch, profile, false)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = appArch,
|
arch = appArch,
|
||||||
|
@ -319,10 +359,11 @@ function checkAndAddClang()
|
||||||
extraObjects.utf8init, extraObjects.utf8manifest,
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
},
|
},
|
||||||
isClang = true,
|
isClang = true,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
table.insert(compilerList, debug)
|
table.insert(compilerList, debug_)
|
||||||
|
end
|
||||||
|
|
||||||
for _, foreignArch in ipairs(supportedAppArches) do
|
for _, foreignArch in ipairs(supportedAppArches) do
|
||||||
if foreignArch ~= appArch then
|
if foreignArch ~= appArch then
|
||||||
|
@ -343,8 +384,10 @@ function checkAndAddClang()
|
||||||
utf8init = libDir .. "/utf8init.o",
|
utf8init = libDir .. "/utf8init.o",
|
||||||
utf8manifest = libDir .. "/utf8manifest.o",
|
utf8manifest = libDir .. "/utf8manifest.o",
|
||||||
}
|
}
|
||||||
local release, debug, debugWithAsan = generateConfig(
|
local release, _, _ = generateConfig(
|
||||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, false) end,
|
function(arch, profile)
|
||||||
|
return nameGeneratorClang(lang, arch, profile, false)
|
||||||
|
end,
|
||||||
programs,
|
programs,
|
||||||
{
|
{
|
||||||
arch = foreignArch,
|
arch = foreignArch,
|
||||||
|
@ -359,8 +402,8 @@ function checkAndAddClang()
|
||||||
extraObjects.utf8init, extraObjects.utf8manifest,
|
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||||
},
|
},
|
||||||
isClang = true,
|
isClang = true,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
table.insert(compilerList, release)
|
table.insert(compilerList, release)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -384,3 +427,4 @@ local result = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue