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 <QStyleFactory>
|
||||
#include <QJsonValue>
|
||||
#include <QMessageBox>
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
# include <windows.h>
|
||||
|
@ -51,11 +52,126 @@ using pIsWow64Process2_t = BOOL (WINAPI *)(
|
|||
);
|
||||
#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 {
|
||||
QString info = AddOn::RaiiLuaState::fetchString(L, 1);
|
||||
qDebug() << info;
|
||||
bool error = false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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.begin(), arches.end()};
|
||||
QStringList result = arches.toList();
|
||||
QStringList result = arches.values();
|
||||
AddOn::RaiiLuaState::push(L, result);
|
||||
return 1;
|
||||
#endif
|
||||
|
@ -291,15 +405,37 @@ extern "C" int luaApi_System_readRegistry(lua_State *L) noexcept
|
|||
}
|
||||
#endif
|
||||
|
||||
// C_Util.format(string, ...) -> string
|
||||
extern "C" int luaApi_Util_format(lua_State *L) noexcept
|
||||
void luaApiImpl_Util_format(lua_State *L)
|
||||
{
|
||||
QString s = AddOn::RaiiLuaState::fetchString(L, 1);
|
||||
int nArgs = lua_gettop(L);
|
||||
for (int i = 2; i <= nArgs; ++i) {
|
||||
QJsonValue arg = AddOn::RaiiLuaState::fetch(L, i);
|
||||
s = s.arg(arg.toString());
|
||||
QJsonValue arg;
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
struct lua_State;
|
||||
|
||||
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_language(lua_State *L) noexcept;
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace AddOn {
|
|||
static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
|
||||
{"C_Debug",
|
||||
{
|
||||
{"debug", &luaApi_Debug_debug}, // (string) -> ()
|
||||
{"debug", &luaApi_Debug_debug}, // (string, ...) -> ()
|
||||
{"messageBox", &luaApi_Debug_messageBox}, // (string, ...) -> ()
|
||||
}},
|
||||
{"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,
|
||||
const QString &name) {
|
||||
|
@ -92,28 +97,74 @@ QJsonObject ThemeExecutor::operator()(const QByteArray &script,
|
|||
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,
|
||||
const QString &name,
|
||||
std::chrono::microseconds timeLimit) {
|
||||
RaiiLuaState L(name, timeLimit);
|
||||
L.openLibs();
|
||||
for (auto &api : mApis)
|
||||
registerApiGroup(L, api);
|
||||
|
||||
int retLoad = L.loadBuffer(script, name);
|
||||
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.setTimeStart();
|
||||
int callResult = L.pCall(0, 1, 0);
|
||||
int callResult = L.pCall(0, 0, 0);
|
||||
if (callResult != 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
using namespace std::chrono_literals;
|
||||
|
|
|
@ -27,13 +27,17 @@ namespace AddOn {
|
|||
// simple, stateless Lua executor
|
||||
class SimpleExecutor {
|
||||
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,
|
||||
std::chrono::microseconds timeLimit);
|
||||
|
||||
private:
|
||||
QString mKind;
|
||||
int mMajor;
|
||||
int mMinor;
|
||||
QStringList mApis;
|
||||
};
|
||||
|
||||
|
|
|
@ -68,6 +68,11 @@ QString RaiiLuaState::fetchString(int index)
|
|||
return lua_tostring(mLua, index);
|
||||
}
|
||||
|
||||
QJsonObject RaiiLuaState::fetchObject(int index)
|
||||
{
|
||||
return fetchTableImpl(mLua, index, 0).toObject();
|
||||
}
|
||||
|
||||
QJsonValue RaiiLuaState::fetch(int index)
|
||||
{
|
||||
return fetchValueImpl(mLua, index, 0);
|
||||
|
@ -93,6 +98,11 @@ QString RaiiLuaState::fetchString(lua_State *L, int 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)
|
||||
{
|
||||
return fetchValueImpl(L, index, 0);
|
||||
|
@ -112,6 +122,13 @@ QString RaiiLuaState::popString()
|
|||
return value;
|
||||
}
|
||||
|
||||
QJsonObject RaiiLuaState::popObject()
|
||||
{
|
||||
QJsonObject value = fetchObject(-1);
|
||||
lua_pop(mLua, 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
QJsonValue RaiiLuaState::pop()
|
||||
{
|
||||
QJsonValue value = fetch(-1);
|
||||
|
@ -191,6 +208,11 @@ int RaiiLuaState::pCall(int nargs, int nresults, int 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)
|
||||
{
|
||||
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
|
||||
bool processingArrayPart = true;
|
||||
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)
|
||||
// we are still in array part
|
||||
arrayPart.push_back(v);
|
||||
|
@ -275,8 +306,11 @@ QJsonValue RaiiLuaState::fetchValueImpl(lua_State *L, int index, int depth)
|
|||
return fetchString(L, index);
|
||||
else if (lua_istable(L, index))
|
||||
return fetchTableImpl(L, index, depth + 1);
|
||||
else
|
||||
throw LuaError(QString("Lua type error: unknown type %1.").arg(lua_typename(L, index)));
|
||||
else {
|
||||
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;
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
static long long fetchInteger(lua_State *L, int index);
|
||||
static double fetchNumber(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);
|
||||
|
||||
bool popBoolean();
|
||||
|
@ -94,6 +95,7 @@ public:
|
|||
int loadBuffer(const QByteArray &buff, const QString &name);
|
||||
void openLibs();
|
||||
int pCall(int nargs, int nresults, int msgh);
|
||||
int getGlobal(const QString &name);
|
||||
void setGlobal(const QString &name);
|
||||
void setHook(lua_Hook f, int mask, int count);
|
||||
|
||||
|
|
|
@ -3279,7 +3279,9 @@ void Settings::CompilerSets::findSets()
|
|||
try {
|
||||
compilerHint = AddOn::CompilerHintExecutor{}(script);
|
||||
} 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()) {
|
||||
QJsonArray compilerList = compilerHint["compilerList"].toArray();
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
function apiVersion()
|
||||
return {
|
||||
kind = "theme",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
en_US = "Contrast",
|
||||
pt_BR = "Contraste",
|
||||
zh_CN = "高对比度",
|
||||
zh_TW = "高對比度"
|
||||
zh_TW = "高對比度",
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
function main()
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
return {
|
||||
["name"] = nameMap[lang] or nameMap.en_US,
|
||||
["style"] = "RedPandaDarkFusion",
|
||||
["default scheme"] = "Twilight",
|
||||
|
@ -38,6 +47,7 @@ return {
|
|||
PaletteTextDisabled = "#9DA9B5",
|
||||
PaletteMid = "#FFFFFF",
|
||||
PaletteLight = "#505050",
|
||||
PaletteMidLight = "#00ff00"
|
||||
PaletteMidlight = "#00ff00",
|
||||
},
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
function apiVersion()
|
||||
return {
|
||||
kind = "theme",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
en_US = "Dark",
|
||||
pt_BR = "Escura",
|
||||
zh_CN = "深色",
|
||||
zh_TW = "深色"
|
||||
zh_TW = "深色",
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
function main()
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
return {
|
||||
["name"] = nameMap[lang] or nameMap.en_US,
|
||||
["style"] = "RedPandaDarkFusion",
|
||||
["default scheme"] = "VS Code",
|
||||
|
@ -38,6 +47,7 @@ return {
|
|||
PaletteTextDisabled = "#9DA9B5",
|
||||
PaletteMid = "#707070",
|
||||
PaletteLight = "#505050",
|
||||
PaletteMidLight = "#00ff00"
|
||||
PaletteMidlight = "#00ff00",
|
||||
},
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
function apiVersion()
|
||||
return {
|
||||
kind = "theme",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
en_US = "Light",
|
||||
pt_BR = "Clara",
|
||||
zh_CN = "浅色",
|
||||
zh_TW = "淺色"
|
||||
zh_TW = "淺色",
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
function main()
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
return {
|
||||
["name"] = nameMap[lang] or nameMap.en_US,
|
||||
["style"] = "RedPandaLightFusion",
|
||||
["default scheme"] = "Intellij Classic",
|
||||
|
@ -26,7 +35,7 @@ return {
|
|||
PaletteLink = "#0000ff",
|
||||
PaletteLinkVisited = "#ff00ff",
|
||||
PaletteLight = "#ffffff",
|
||||
PaletteMidLight = "#cacaca",
|
||||
PaletteMidlight = "#cacaca",
|
||||
PaletteDark = "#9f9f9f",
|
||||
PaletteMid = "#b8b8b8",
|
||||
PaletteWindowDisabled = "#efefef",
|
||||
|
@ -36,6 +45,7 @@ return {
|
|||
PaletteButtonDisabled = "#efefef",
|
||||
PaletteButtonTextDisabled = "#bebebe",
|
||||
PaletteHighlight = "#dddddd",
|
||||
PaletteHighlightedText = "#000000"
|
||||
PaletteHighlightedText = "#000000",
|
||||
},
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,13 +1,22 @@
|
|||
function apiVersion()
|
||||
return {
|
||||
kind = "theme",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
en_US = "MoLo",
|
||||
pt_BR = "Molo",
|
||||
zh_CN = "墨落",
|
||||
zh_TW = "墨落"
|
||||
zh_TW = "墨落",
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
function main()
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
return {
|
||||
["name"] = nameMap[lang] or nameMap.en_US,
|
||||
["style"] = "RedPandaDarkFusion",
|
||||
["default scheme"] = "MoLo CodeBlack",
|
||||
|
@ -38,6 +47,7 @@ return {
|
|||
PaletteTextDisabled = "#9DA9B5",
|
||||
PaletteMid = "#FFFFFF",
|
||||
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)")
|
||||
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
|
||||
|
||||
function rgbToString(rgb)
|
||||
return string.format("#%02x%02x%02x",
|
||||
math.floor(rgb[1] * 255), math.floor(rgb[2] * 255), math.floor(rgb[3] * 255)
|
||||
)
|
||||
local function rgbToString(rgb)
|
||||
return string.format(
|
||||
"#%02x%02x%02x",
|
||||
math.floor(rgb.r * 255),
|
||||
math.floor(rgb.g * 255),
|
||||
math.floor(rgb.b * 255))
|
||||
|
||||
end
|
||||
|
||||
function hsvToRgb(h, s, v)
|
||||
local function hsvToRgb(hsv)
|
||||
local r, g, b
|
||||
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)
|
||||
|
@ -30,29 +58,26 @@ function hsvToRgb(h, s, v)
|
|||
elseif i == 5 then
|
||||
r, g, b = v, p, q
|
||||
end
|
||||
return {r, g, b}
|
||||
return { r = r, g = g, b = b }
|
||||
end
|
||||
|
||||
function blend(lower, upper, alpha)
|
||||
local r = (1 - alpha) * lower[1] + alpha * upper[1]
|
||||
local g = (1 - alpha) * lower[2] + alpha * upper[2]
|
||||
local b = (1 - alpha) * lower[3] + alpha * upper[3]
|
||||
return {r, g, b}
|
||||
local function blend(lower, upper, alpha)
|
||||
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 hue = math.random()
|
||||
local upperColor = hsvToRgb(hue, 0.6, 1)
|
||||
|
||||
function transform(color)
|
||||
local function transform(color, upperColor)
|
||||
local lowerColor = rgbFromString(color)
|
||||
local blended = blend(lowerColor, upperColor, 0.1)
|
||||
return rgbToString(blended)
|
||||
end
|
||||
|
||||
function transformPalette(palette)
|
||||
local function transformPalette(palette, upperColor)
|
||||
local transformed = {}
|
||||
for key, value in pairs(palette) do
|
||||
transformed[key] = transform(value)
|
||||
transformed[key] = transform(value, upperColor)
|
||||
end
|
||||
return transformed
|
||||
end
|
||||
|
@ -71,7 +96,7 @@ local originalPalette = {
|
|||
PaletteLink = "#0000ff",
|
||||
PaletteLinkVisited = "#ff00ff",
|
||||
PaletteLight = "#ffffff",
|
||||
PaletteMidLight = "#cacaca",
|
||||
PaletteMidlight = "#cacaca",
|
||||
PaletteDark = "#9f9f9f",
|
||||
PaletteMid = "#b8b8b8",
|
||||
PaletteWindowDisabled = "#efefef",
|
||||
|
@ -81,22 +106,27 @@ local originalPalette = {
|
|||
PaletteButtonDisabled = "#efefef",
|
||||
PaletteButtonTextDisabled = "#bebebe",
|
||||
PaletteHighlight = "#dddddd",
|
||||
PaletteHighlightedText = "#000000"
|
||||
PaletteHighlightedText = "#000000",
|
||||
}
|
||||
|
||||
local nameMap = {
|
||||
en_US = "Random Light",
|
||||
pt_BR = "Clara aleatória",
|
||||
zh_CN = "随机浅色",
|
||||
zh_TW = "隨機淺色"
|
||||
zh_TW = "隨機淺色",
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
function main()
|
||||
local hue = math.random()
|
||||
local upperColor = hsvToRgb({ h = hue, s = 0.6, v = 1 })
|
||||
|
||||
return {
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
["name"] = nameMap[lang] or nameMap.en_US,
|
||||
["style"] = "RedPandaLightFusion",
|
||||
["default scheme"] = "Adaptive",
|
||||
["default iconset"] = "newlook",
|
||||
["palette"] = transformPalette(originalPalette)
|
||||
}
|
||||
["palette"] = transformPalette(originalPalette, upperColor),
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,10 +1,33 @@
|
|||
local desktopEnvironment = C_Desktop.desktopEnvironment()
|
||||
local useSystemStyle = desktopEnvironment == "xdg" or desktopEnvironment == "macos"
|
||||
function apiVersion()
|
||||
return {
|
||||
kind = "theme",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local systemAppMode = C_Desktop.systemAppMode()
|
||||
local isDarkMode = systemAppMode == "dark"
|
||||
local nameMap = {
|
||||
en_US = "System Style and Color",
|
||||
pt_BR = "Estilo e Cor do Sistema",
|
||||
zh_CN = "跟随系统样式和颜色",
|
||||
zh_TW = "跟隨系統樣式和顏色",
|
||||
}
|
||||
|
||||
function getStyle()
|
||||
local nameMapNoStyle = {
|
||||
en_US = "System Color",
|
||||
pt_BR = "Cor do Sistema",
|
||||
zh_CN = "跟随系统颜色",
|
||||
zh_TW = "跟隨系統顏色",
|
||||
}
|
||||
|
||||
function main()
|
||||
local desktopEnvironment = C_Desktop.desktopEnvironment()
|
||||
local useSystemStyle = desktopEnvironment == "xdg" or desktopEnvironment == "macos"
|
||||
|
||||
local systemAppMode = C_Desktop.systemAppMode()
|
||||
local isDarkMode = systemAppMode == "dark"
|
||||
|
||||
local function getStyle()
|
||||
if useSystemStyle then
|
||||
return C_Desktop.systemStyle()
|
||||
else
|
||||
|
@ -14,13 +37,13 @@ function getStyle()
|
|||
return "RedPandaLightFusion"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getPalette()
|
||||
local function getPalette()
|
||||
if useSystemStyle then
|
||||
return {}
|
||||
elseif isDarkMode then
|
||||
return { -- palette from `dark.lua`
|
||||
return {
|
||||
PaletteWindow = "#19232D",
|
||||
PaletteWindowText = "#E0E1E3",
|
||||
PaletteBase = "#1E1E1E",
|
||||
|
@ -46,10 +69,10 @@ function getPalette()
|
|||
PaletteTextDisabled = "#9DA9B5",
|
||||
PaletteMid = "#707070",
|
||||
PaletteLight = "#505050",
|
||||
PaletteMidLight = "#00ff00"
|
||||
PaletteMidlight = "#00ff00",
|
||||
}
|
||||
else
|
||||
return { -- palette from `default.lua`
|
||||
return {
|
||||
PaletteWindow = "#efefef",
|
||||
PaletteWindowText = "#000000",
|
||||
PaletteBase = "#ffffff",
|
||||
|
@ -63,7 +86,7 @@ function getPalette()
|
|||
PaletteLink = "#0000ff",
|
||||
PaletteLinkVisited = "#ff00ff",
|
||||
PaletteLight = "#ffffff",
|
||||
PaletteMidLight = "#cacaca",
|
||||
PaletteMidlight = "#cacaca",
|
||||
PaletteDark = "#9f9f9f",
|
||||
PaletteMid = "#b8b8b8",
|
||||
PaletteWindowDisabled = "#efefef",
|
||||
|
@ -73,31 +96,18 @@ function getPalette()
|
|||
PaletteButtonDisabled = "#efefef",
|
||||
PaletteButtonTextDisabled = "#bebebe",
|
||||
PaletteHighlight = "#dddddd",
|
||||
PaletteHighlightedText = "#000000"
|
||||
PaletteHighlightedText = "#000000",
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
en_US = "System Style and Color",
|
||||
pt_BR = "Estilo e Cor do Sistema",
|
||||
zh_CN = "跟随系统样式和颜色",
|
||||
zh_TW = "跟隨系統樣式和顏色"
|
||||
}
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
local nameMapNoStyle = {
|
||||
en_US = "System Color",
|
||||
pt_BR = "Cor do Sistema",
|
||||
zh_CN = "跟随系统颜色",
|
||||
zh_TW = "跟隨系統顏色"
|
||||
}
|
||||
|
||||
local lang = C_Desktop.language()
|
||||
|
||||
return {
|
||||
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()
|
||||
}
|
||||
["palette"] = getPalette(),
|
||||
}
|
||||
end
|
||||
|
|
|
@ -7110,6 +7110,10 @@
|
|||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error executing platform compiler hint add-on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RegisterModel</name>
|
||||
|
|
|
@ -9679,6 +9679,10 @@ p, li { white-space: pre-wrap; }
|
|||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||
<translation>无法检测适用于 “%1” 的终端参数模式。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error executing platform compiler hint add-on</source>
|
||||
<translation>执行平台编译器提示附加组件错误</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RegisterModel</name>
|
||||
|
|
|
@ -6622,6 +6622,10 @@
|
|||
<source>Failed to detect terminal arguments pattern for “%1”.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error executing platform compiler hint add-on</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>RegisterModel</name>
|
||||
|
|
|
@ -176,4 +176,8 @@ QString defaultShell();
|
|||
QString appArch();
|
||||
QString osArch();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define __builtin_unreachable() (__assume(0))
|
||||
#endif
|
||||
|
||||
#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
|
220
docs/addon.md
220
docs/addon.md
|
@ -14,28 +14,81 @@
|
|||
- Red Panda C++ APIs exposed to add-on are organized by groups.
|
||||
- Each group is a Lua table.
|
||||
- Each API is a function in the table.
|
||||
- Available API groups vary by add-on type.
|
||||
- Localization is handled by add-on. e.g.
|
||||
```lua
|
||||
local lang = C_Desktop.language()
|
||||
local localizedName = {
|
||||
- Available API groups vary by add-on kind.
|
||||
- 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
|
||||
local lang = C_Desktop.language()
|
||||
-- note: explicitly declare as `{string:string}` for Teal
|
||||
local localizedName = {
|
||||
en_US = "System",
|
||||
pt_BR = "Sistema",
|
||||
zh_CN = "系统",
|
||||
zh_TW = "系統",
|
||||
}
|
||||
return {
|
||||
}
|
||||
return {
|
||||
name = localizedName[lang] or localizedName.en_US,
|
||||
-- ...
|
||||
}
|
||||
```
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
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.
|
||||
|
||||
Available API groups:
|
||||
|
@ -45,149 +98,4 @@ Available API groups:
|
|||
- `C_System`
|
||||
- `C_Util`
|
||||
|
||||
Return value schema:
|
||||
```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.
|
||||
`main` function takes no argument and returns `CompilerHint` ([`compiler_hint.d.tl`](../addon/defs/compiler_hint.d.tl)).
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
local arch = C_System.osArch()
|
||||
local libexecDir = C_System.appLibexecDir()
|
||||
local lang = C_Desktop.language()
|
||||
function apiVersion()
|
||||
return {
|
||||
kind = "compiler_hint",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local nameMap = {
|
||||
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 = {
|
||||
cCompiler = cCompiler,
|
||||
cxxCompiler = cxxCompiler,
|
||||
|
@ -82,7 +107,7 @@ function generateConfig(name, cCompiler, cxxCompiler, config)
|
|||
ccCmdOptWarningAll = "on",
|
||||
ccCmdOptWarningExtra = "on",
|
||||
ccCmdOptCheckIsoConformance = "on",
|
||||
binDirs = {"/usr/bin"},
|
||||
binDirs = { "/usr/bin" },
|
||||
}
|
||||
if config.isMultilib then
|
||||
commonOptions.ccCmdOptPointerSize = "32"
|
||||
|
@ -102,7 +127,7 @@ function generateConfig(name, cCompiler, cxxCompiler, config)
|
|||
linkCmdOptStripExe = "on",
|
||||
ccCmdOptOptimize = "2",
|
||||
}
|
||||
local debug = {
|
||||
local debug_ = {
|
||||
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
|
||||
ccCmdOptDebugInfo = "on",
|
||||
}
|
||||
|
@ -111,161 +136,178 @@ function generateConfig(name, cCompiler, cxxCompiler, config)
|
|||
ccCmdOptDebugInfo = "on",
|
||||
ccCmdOptAddressSanitizer = "address",
|
||||
}
|
||||
for k, v in pairs(commonOptions) do
|
||||
release[k] = v
|
||||
debug[k] = v
|
||||
debugWithAsan[k] = v
|
||||
mergeCompilerSet(release, commonOptions)
|
||||
mergeCompilerSet(debug_, commonOptions)
|
||||
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||
return release, debug_, debugWithAsan
|
||||
end
|
||||
|
||||
function main()
|
||||
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
|
||||
return release, debug, debugWithAsan
|
||||
end
|
||||
|
||||
local compilerList = {}
|
||||
|
||||
do
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US,
|
||||
"/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,
|
||||
"/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
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US,
|
||||
"/usr/bin/gcc", "/usr/bin/g++",
|
||||
{isMultilib = true}
|
||||
)
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debugWithAsan)
|
||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US,
|
||||
local release, debug_, debugWithAsan = generateConfig(
|
||||
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang,
|
||||
"/usr/bin/clang", "/usr/bin/clang++",
|
||||
{isClang = true, isMultilib = true}
|
||||
)
|
||||
{ isClang = true })
|
||||
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debug_)
|
||||
table.insert(compilerList, debugWithAsan)
|
||||
end
|
||||
end
|
||||
|
||||
-- cross GCC
|
||||
if (
|
||||
|
||||
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
|
||||
|
||||
|
||||
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, debug, debugWithAsan = generateConfig(
|
||||
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64",
|
||||
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
|
||||
{}
|
||||
)
|
||||
table.insert(compilerList, release)
|
||||
end
|
||||
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")) then
|
||||
|
||||
-- with wine or WSL init registered in binfmt_misc, Windows binaries can run seamlessly
|
||||
if (
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
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",
|
||||
}
|
||||
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++",
|
||||
{
|
||||
isMingw = true,
|
||||
triplet = "x86_64-w64-mingw32",
|
||||
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||
}
|
||||
)
|
||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
-- system Clang can target Windows
|
||||
end
|
||||
|
||||
|
||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64",
|
||||
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"},
|
||||
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",
|
||||
}
|
||||
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++",
|
||||
{
|
||||
isMingw = true,
|
||||
triplet = "i686-w64-mingw32",
|
||||
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||
}
|
||||
)
|
||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
-- system Clang can target Windows
|
||||
end
|
||||
|
||||
|
||||
if C_FileSystem.isExecutable("/usr/bin/clang") then
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686",
|
||||
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"},
|
||||
customCompileParams = { "-target", "i686-w64-mingw32" },
|
||||
customLinkParams = {
|
||||
"-target", "i686-w64-mingw32",
|
||||
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||
"-lstdc++", "-lwinpthread",
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local result = {
|
||||
local result = {
|
||||
compilerList = compilerList,
|
||||
noSearch = {
|
||||
"/usr/bin",
|
||||
"/opt/cuda/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()
|
||||
local appArch = C_System.appArch()
|
||||
local libexecDir = C_System.appLibexecDir()
|
||||
local lang = C_Desktop.language()
|
||||
local supportedAppArches = C_System.supportedAppArchList()
|
||||
function apiVersion()
|
||||
return {
|
||||
kind = "compiler_hint",
|
||||
major = 0,
|
||||
minor = 1,
|
||||
}
|
||||
end
|
||||
|
||||
local gnuArchMap = {
|
||||
i386 = "i686",
|
||||
|
@ -32,8 +34,7 @@ local profileNameMap = {
|
|||
},
|
||||
}
|
||||
|
||||
local nameGenerator = {
|
||||
mingwGcc = function (lang, arch, profile, isUtf8)
|
||||
local function nameGeneratorMingwGcc(lang, arch, profile, isUtf8)
|
||||
local template = {
|
||||
en_US = "MinGW GCC %1 in %2, %3",
|
||||
pt_BR = "GCC MinGW %1 em %2, %3",
|
||||
|
@ -50,15 +51,16 @@ local nameGenerator = {
|
|||
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,
|
||||
clang = function (lang, arch, profile, isMingw)
|
||||
profileNameMap[profile][lang] or profileNameMap[profile].en_US)
|
||||
|
||||
end
|
||||
|
||||
local function nameGeneratorClang(lang, arch, profile, isMingw)
|
||||
local template = {
|
||||
en_US = "%1 Clang %2, %3",
|
||||
pt_BR = "Clang %2 %1, %3",
|
||||
zh_CN = "%1 Clang %2,%3",
|
||||
zh_CN = "%1 Clang %2,%3",
|
||||
zh_TW = "%1 Clang %2,%3",
|
||||
}
|
||||
local msvcCompatible = {
|
||||
en_US = "MSVC-compatible",
|
||||
|
@ -70,12 +72,42 @@ local nameGenerator = {
|
|||
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,
|
||||
}
|
||||
profileNameMap[profile][lang] or profileNameMap[profile].en_US)
|
||||
|
||||
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 = {
|
||||
cCompiler = programs.cCompiler,
|
||||
cxxCompiler = programs.cxxCompiler,
|
||||
|
@ -113,7 +145,7 @@ function generateConfig(nameGen, programs, config)
|
|||
linkCmdOptStripExe = "on",
|
||||
ccCmdOptOptimize = "2",
|
||||
}
|
||||
local debug = {
|
||||
local debug_ = {
|
||||
name = nameGen(config.arch, "debug"),
|
||||
ccCmdOptDebugInfo = "on",
|
||||
}
|
||||
|
@ -122,35 +154,30 @@ function generateConfig(nameGen, programs, config)
|
|||
ccCmdOptDebugInfo = "on",
|
||||
ccCmdOptAddressSanitizer = "address",
|
||||
}
|
||||
for k, v in pairs(commonOptions) do
|
||||
release[k] = v
|
||||
debug[k] = v
|
||||
debugWithAsan[k] = v
|
||||
end
|
||||
return release, debug, debugWithAsan
|
||||
mergeCompilerSet(release, commonOptions)
|
||||
mergeCompilerSet(debug_, commonOptions)
|
||||
mergeCompilerSet(debugWithAsan, commonOptions)
|
||||
return release, debug_, debugWithAsan
|
||||
end
|
||||
|
||||
function contains(t, v)
|
||||
for _, vv in ipairs(t) do
|
||||
if vv == v then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
function main()
|
||||
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 compilerList = {}
|
||||
local noSearch = {}
|
||||
local preferCompiler = 0
|
||||
|
||||
function checkAndAddMingw(arch)
|
||||
local function checkAndAddMingw(arch)
|
||||
local binDir
|
||||
local libDir
|
||||
local excludeBinDir
|
||||
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"
|
||||
excludeBinDir = libexecDir .. "/MinGW32/bin" -- workaround for path check
|
||||
excludeBinDir = libexecDir .. "/MinGW32/bin"
|
||||
elseif arch == "x86_64" then
|
||||
binDir = libexecDir .. "/mingw64/bin"
|
||||
libDir = libexecDir .. "/mingw64/x86_64-w64-mingw32/lib"
|
||||
|
@ -170,49 +197,54 @@ function checkAndAddMingw(arch)
|
|||
debugger = binDir .. "/gdb.exe",
|
||||
debugServer = binDir .. "/gdbserver.exe",
|
||||
resourceCompiler = binDir .. "/windres.exe",
|
||||
binDirs = {binDir},
|
||||
binDirs = { binDir },
|
||||
}
|
||||
local extraObjects = {
|
||||
utf8init = libDir .. "/utf8init.o",
|
||||
utf8manifest = libDir .. "/utf8manifest.o",
|
||||
}
|
||||
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.mingwGcc(lang, arch, profile, true) end,
|
||||
local release, debug_, debugWithAsan = generateConfig(
|
||||
function(arch_, profile)
|
||||
return nameGeneratorMingwGcc(lang, arch_, profile, true)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = arch,
|
||||
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||
}
|
||||
)
|
||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debug_)
|
||||
if preferCompiler == 0 then
|
||||
preferCompiler = 2
|
||||
end
|
||||
|
||||
release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.mingwGcc(lang, arch, profile, false) end,
|
||||
release, debug_, debugWithAsan = generateConfig(
|
||||
function(arch_, profile)
|
||||
return nameGeneratorMingwGcc(lang, arch_, profile, false)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = arch,
|
||||
isAnsi = true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debug_)
|
||||
|
||||
table.insert(noSearch, excludeBinDir)
|
||||
end
|
||||
end
|
||||
|
||||
function checkAndAddClang()
|
||||
local function checkAndAddClang()
|
||||
if not C_FileSystem.isExecutable(libexecDir .. "/llvm-mingw/bin/clang.exe") then
|
||||
return
|
||||
end
|
||||
|
||||
-- appArch is always debuggable
|
||||
local appTriplet = gnuArchMap[appArch] .. "-w64-mingw32"
|
||||
local binDir = libexecDir .. "/llvm-mingw/bin"
|
||||
local appTriplet = gnuArchMap[appArch] .. "-w64-mingw32"
|
||||
do
|
||||
|
||||
local libDir = libexecDir .. "/llvm-mingw/" .. appTriplet .. "/lib"
|
||||
local programs = {
|
||||
cCompiler = binDir .. "/" .. appTriplet .. "-clang.exe",
|
||||
|
@ -221,23 +253,25 @@ function checkAndAddClang()
|
|||
debugger = binDir .. "/lldb-mi.exe",
|
||||
debugServer = binDir .. "/lldb-server.exe",
|
||||
resourceCompiler = binDir .. "/" .. appTriplet .. "-windres.exe",
|
||||
binDirs = {binDir},
|
||||
binDirs = { binDir },
|
||||
}
|
||||
local extraObjects = {
|
||||
utf8init = libDir .. "/utf8init.o",
|
||||
utf8manifest = libDir .. "/utf8manifest.o",
|
||||
}
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, true) end,
|
||||
local release, debug_, debugWithAsan = generateConfig(
|
||||
function(arch_, profile)
|
||||
return nameGeneratorClang(lang, arch_, profile, true)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = appArch,
|
||||
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||
isClang = true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debug_)
|
||||
if appArch ~= "arm64" then
|
||||
table.insert(compilerList, debugWithAsan)
|
||||
if preferCompiler == 0 then
|
||||
|
@ -248,6 +282,7 @@ function checkAndAddClang()
|
|||
preferCompiler = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, foreignArch in ipairs(supportedAppArches) do
|
||||
if foreignArch ~= appArch then
|
||||
|
@ -260,21 +295,23 @@ function checkAndAddClang()
|
|||
debugger = binDir .. "/lldb-mi.exe",
|
||||
debugServer = binDir .. "/lldb-server.exe",
|
||||
resourceCompiler = binDir .. "/" .. foreignTriplet .. "-windres.exe",
|
||||
binDirs = {binDir},
|
||||
binDirs = { binDir },
|
||||
}
|
||||
local extraObjects = {
|
||||
utf8init = libDir .. "/utf8init.o",
|
||||
utf8manifest = libDir .. "/utf8manifest.o",
|
||||
}
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, true) end,
|
||||
local release, _, _ = generateConfig(
|
||||
function(arch_, profile)
|
||||
return nameGeneratorClang(lang, arch_, profile, true)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = foreignArch,
|
||||
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
|
||||
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
|
||||
isClang = true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
end
|
||||
end
|
||||
|
@ -285,8 +322,9 @@ function checkAndAddClang()
|
|||
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 = {
|
||||
|
@ -296,15 +334,17 @@ function checkAndAddClang()
|
|||
debugger = binDir .. "/lldb-mi.exe",
|
||||
debugServer = binDir .. "/lldb-server.exe",
|
||||
resourceCompiler = binDir .. "/" .. appTriplet .. "-windres.exe",
|
||||
binDirs = {llvmOrgBinDir},
|
||||
libDirs = {libDir},
|
||||
binDirs = { llvmOrgBinDir },
|
||||
libDirs = { libDir },
|
||||
}
|
||||
local extraObjects = {
|
||||
utf8init = libDir .. "/utf8init.o",
|
||||
utf8manifest = libDir .. "/utf8manifest.o",
|
||||
}
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, false) end,
|
||||
local release, debug_, _ = generateConfig(
|
||||
function(arch, profile)
|
||||
return nameGeneratorClang(lang, arch, profile, false)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = appArch,
|
||||
|
@ -319,10 +359,11 @@ function checkAndAddClang()
|
|||
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||
},
|
||||
isClang = true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
table.insert(compilerList, debug)
|
||||
table.insert(compilerList, debug_)
|
||||
end
|
||||
|
||||
for _, foreignArch in ipairs(supportedAppArches) do
|
||||
if foreignArch ~= appArch then
|
||||
|
@ -336,15 +377,17 @@ function checkAndAddClang()
|
|||
debugger = binDir .. "/lldb-mi.exe",
|
||||
debugServer = binDir .. "/lldb-server.exe",
|
||||
resourceCompiler = binDir .. "/" .. foreignTriplet .. "-windres.exe",
|
||||
binDirs = {llvmOrgBinDir},
|
||||
libDirs = {libDir},
|
||||
binDirs = { llvmOrgBinDir },
|
||||
libDirs = { libDir },
|
||||
}
|
||||
local extraObjects = {
|
||||
utf8init = libDir .. "/utf8init.o",
|
||||
utf8manifest = libDir .. "/utf8manifest.o",
|
||||
}
|
||||
local release, debug, debugWithAsan = generateConfig(
|
||||
function (arch, profile) return nameGenerator.clang(lang, arch, profile, false) end,
|
||||
local release, _, _ = generateConfig(
|
||||
function(arch, profile)
|
||||
return nameGeneratorClang(lang, arch, profile, false)
|
||||
end,
|
||||
programs,
|
||||
{
|
||||
arch = foreignArch,
|
||||
|
@ -359,28 +402,29 @@ function checkAndAddClang()
|
|||
extraObjects.utf8init, extraObjects.utf8manifest,
|
||||
},
|
||||
isClang = true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
table.insert(compilerList, release)
|
||||
end
|
||||
end
|
||||
table.insert(noSearch, llvmOrgBinDir)
|
||||
end
|
||||
end
|
||||
|
||||
if appArch == "x86_64" then
|
||||
if appArch == "x86_64" then
|
||||
checkAndAddMingw("x86_64")
|
||||
checkAndAddClang()
|
||||
elseif appArch == "arm64" then
|
||||
elseif appArch == "arm64" then
|
||||
checkAndAddClang()
|
||||
else
|
||||
else
|
||||
checkAndAddMingw("i386")
|
||||
checkAndAddClang()
|
||||
end
|
||||
end
|
||||
|
||||
local result = {
|
||||
local result = {
|
||||
compilerList = compilerList,
|
||||
noSearch = noSearch,
|
||||
preferCompiler = preferCompiler,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
return result
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue