add support for versioned GCC and Clang in compiler hint (#237)

This commit is contained in:
Cyano Hao 2024-03-07 15:55:51 +08:00 committed by GitHub
parent 6b316b4e52
commit e0d57213ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 732 additions and 332 deletions

View File

@ -22,6 +22,8 @@
#include <QStyleFactory> #include <QStyleFactory>
#include <QJsonValue> #include <QJsonValue>
#include <QMessageBox> #include <QMessageBox>
#include <QRegularExpression>
#include <chrono>
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
# include <windows.h> # include <windows.h>
@ -236,6 +238,23 @@ extern "C" int luaApi_FileSystem_isExecutable(lua_State *L) noexcept {
return 1; return 1;
} }
// C_FileSystem.matchFiles(string, string) -> {string}
extern "C" int luaApi_FileSystem_matchFiles(lua_State *L) noexcept {
QString dir = AddOn::RaiiLuaState::fetchString(L, 1);
QString pattern = AddOn::RaiiLuaState::fetchString(L, 2);
QRegularExpression re(pattern);
QStringList result;
QDirIterator it(dir, QDir::Files);
while (it.hasNext()) {
it.next();
if (re.match(it.fileName()).hasMatch())
result.append(it.fileName());
}
std::sort(result.begin(), result.end());
AddOn::RaiiLuaState::push(L, result);
return 1;
}
// C_System.appArch() -> string // C_System.appArch() -> string
extern "C" int luaApi_System_appArch(lua_State *L) noexcept { extern "C" int luaApi_System_appArch(lua_State *L) noexcept {
AddOn::RaiiLuaState::push(L, appArch()); AddOn::RaiiLuaState::push(L, appArch());
@ -269,6 +288,104 @@ extern "C" int luaApi_System_osArch(lua_State *L) noexcept {
return 1; return 1;
} }
void luaApiImpl_System_popen(lua_State *L) {
using namespace std::chrono;
QMetaEnum exitStatusEnum = QMetaEnum::fromType<QProcess::ExitStatus>();
QMetaEnum processErrorEnum = QMetaEnum::fromType<QProcess::ProcessError>();
QString prog = AddOn::RaiiLuaState::fetchString(L, 1);
QStringList args;
try {
QJsonArray argsArray = AddOn::RaiiLuaState::fetchArray(L, 2);
for (const QJsonValue &arg : argsArray)
args.append(arg.toString());
} catch (const AddOn::LuaError &e) {
QString reason = e.reason() + " ('C_System.popen' argument #2)";
throw AddOn::LuaError(reason);
}
// fetch and normalize timeout
microseconds timeout;
AddOn::LuaExtraState &extraState = AddOn::RaiiLuaState::extraState(L);
try {
QJsonObject option;
if (lua_type(L, 3) == LUA_TTABLE)
option = AddOn::RaiiLuaState::fetchObject(L, 3);
if (option.contains("timeout"))
timeout = milliseconds(option["timeout"].toInt());
else
timeout = AddOn::RaiiLuaState::extraState(L).timeLimit;
} catch (const AddOn::LuaError &e) {
QString reason = e.reason() + " ('C_System.popen' argument #3)";
throw AddOn::LuaError(reason);
}
time_point<system_clock> deadline = system_clock::now() + timeout;
if (deadline > extraState.timeStart + timeout) {
deadline = extraState.timeStart + timeout;
timeout = duration_cast<microseconds>(deadline - system_clock::now());
}
QProcess process;
process.setProgram(prog);
process.setArguments(args);
process.start(QIODevice::ReadOnly);
if (!process.waitForStarted(duration_cast<milliseconds>(timeout).count())) {
QJsonObject result{
{"exitStatus", exitStatusEnum.valueToKey(QProcess::CrashExit)},
{"error", processErrorEnum.valueToKey(process.error())},
};
AddOn::RaiiLuaState::push(L, "");
AddOn::RaiiLuaState::push(L, "");
AddOn::RaiiLuaState::push(L, result);
return;
}
process.closeWriteChannel();
timeout = duration_cast<microseconds>(deadline - system_clock::now());
process.waitForFinished(duration_cast<milliseconds>(timeout).count());
QByteArray stdoutData = process.readAllStandardOutput();
QByteArray stderrData = process.readAllStandardError();
if (
QProcess::ExitStatus exitStatus = process.exitStatus();
exitStatus == QProcess::NormalExit
) {
QJsonObject result{
{"exitStatus", exitStatusEnum.valueToKey(exitStatus)},
{"exitCode", process.exitCode()},
};
AddOn::RaiiLuaState::push(L, QString::fromUtf8(stdoutData));
AddOn::RaiiLuaState::push(L, QString::fromUtf8(stderrData));
AddOn::RaiiLuaState::push(L, result);
} else {
QJsonObject result{
{"exitStatus", exitStatusEnum.valueToKey(exitStatus)},
{"error", processErrorEnum.valueToKey(process.error())},
};
AddOn::RaiiLuaState::push(L, "");
AddOn::RaiiLuaState::push(L, QString::fromUtf8(stderrData));
AddOn::RaiiLuaState::push(L, result);
}
}
// C_System.popen(string, {string}, PopenOption) -> string, string, PopenResult
extern "C" int luaApi_System_popen(lua_State *L) noexcept {
bool error = false;
try {
luaApiImpl_System_popen(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 3;
}
}
static QString qtArchitectureNormalization(const QString &arch) { static QString qtArchitectureNormalization(const QString &arch) {
// adjust QEMU user emulation arches to match QSysInfo::currentCpuArchitecture // adjust QEMU user emulation arches to match QSysInfo::currentCpuArchitecture
if (arch == "aarch64") if (arch == "aarch64")

View File

@ -30,12 +30,14 @@ extern "C" int luaApi_Desktop_systemStyle(lua_State *L) noexcept;
extern "C" int luaApi_FileSystem_exists(lua_State *L) noexcept; extern "C" int luaApi_FileSystem_exists(lua_State *L) noexcept;
extern "C" int luaApi_FileSystem_isExecutable(lua_State *L) noexcept; extern "C" int luaApi_FileSystem_isExecutable(lua_State *L) noexcept;
extern "C" int luaApi_FileSystem_matchFiles(lua_State *L) noexcept;
extern "C" int luaApi_System_appArch(lua_State *L) noexcept; extern "C" int luaApi_System_appArch(lua_State *L) noexcept;
extern "C" int luaApi_System_appDir(lua_State *L) noexcept; extern "C" int luaApi_System_appDir(lua_State *L) noexcept;
extern "C" int luaApi_System_appLibexecDir(lua_State *L) noexcept; extern "C" int luaApi_System_appLibexecDir(lua_State *L) noexcept;
extern "C" int luaApi_System_appResourceDir(lua_State *L) noexcept; extern "C" int luaApi_System_appResourceDir(lua_State *L) noexcept;
extern "C" int luaApi_System_osArch(lua_State *L) noexcept; extern "C" int luaApi_System_osArch(lua_State *L) noexcept;
extern "C" int luaApi_System_popen(lua_State *L) noexcept;
extern "C" int luaApi_System_supportedAppArchList(lua_State *L) noexcept; extern "C" int luaApi_System_supportedAppArchList(lua_State *L) noexcept;
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
extern "C" int luaApi_System_readRegistry(lua_State *L) noexcept; extern "C" int luaApi_System_readRegistry(lua_State *L) noexcept;

View File

@ -42,6 +42,7 @@ static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
{ {
{"exists", &luaApi_FileSystem_exists}, // (string) -> bool {"exists", &luaApi_FileSystem_exists}, // (string) -> bool
{"isExecutable", &luaApi_FileSystem_isExecutable}, // (string) -> bool {"isExecutable", &luaApi_FileSystem_isExecutable}, // (string) -> bool
{"matchFiles", &luaApi_FileSystem_matchFiles}, // (string, string) -> [string]
}}, }},
{"C_System", {"C_System",
{ {
@ -50,6 +51,7 @@ static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
{"appLibexecDir", &luaApi_System_appLibexecDir}, // () -> string {"appLibexecDir", &luaApi_System_appLibexecDir}, // () -> string
{"appResourceDir", &luaApi_System_appResourceDir}, // () -> string {"appResourceDir", &luaApi_System_appResourceDir}, // () -> string
{"osArch", &luaApi_System_osArch}, // () -> string {"osArch", &luaApi_System_osArch}, // () -> string
{"popen", &luaApi_System_popen},
{"supportedAppArchList", {"supportedAppArchList",
&luaApi_System_supportedAppArchList}, // () -> string &luaApi_System_supportedAppArchList}, // () -> string
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
@ -161,7 +163,7 @@ QJsonValue SimpleExecutor::runScript(const QByteArray &script,
} }
CompilerHintExecutor::CompilerHintExecutor() : SimpleExecutor( CompilerHintExecutor::CompilerHintExecutor() : SimpleExecutor(
"compiler_hint", 0, 1, "compiler_hint", 0, 2,
{"C_Debug", "C_Desktop", "C_FileSystem", "C_System", "C_Util"}) {"C_Debug", "C_Desktop", "C_FileSystem", "C_System", "C_Util"})
{ {
} }

View File

@ -98,6 +98,11 @@ QString RaiiLuaState::fetchString(lua_State *L, int index)
return lua_tostring(L, index); return lua_tostring(L, index);
} }
QJsonArray RaiiLuaState::fetchArray(lua_State *L, int index)
{
return fetchTableImpl(L, index, 0).toArray();
}
QJsonObject RaiiLuaState::fetchObject(lua_State *L, int index) QJsonObject RaiiLuaState::fetchObject(lua_State *L, int index)
{ {
return fetchTableImpl(L, index, 0).toObject(); return fetchTableImpl(L, index, 0).toObject();
@ -183,6 +188,16 @@ void RaiiLuaState::push(lua_State *L, const QStringList &value)
} }
} }
void RaiiLuaState::push(lua_State *L, const QJsonArray &value)
{
pushArrayImpl(L, value, 0);
}
void RaiiLuaState::push(lua_State *L, const QJsonObject &value)
{
pushObjectImpl(L, value, 0);
}
int RaiiLuaState::getTop() int RaiiLuaState::getTop()
{ {
return lua_gettop(mLua); return lua_gettop(mLua);
@ -313,6 +328,56 @@ QJsonValue RaiiLuaState::fetchValueImpl(lua_State *L, int index, int depth)
} }
} }
void RaiiLuaState::pushArrayImpl(lua_State *L, const QJsonArray &value, int depth)
{
if (depth == 1)
// check stack size at first recursion to avoid multiple reallocations
lua_checkstack(L, LUA_STACK_SIZE);
if (depth > TABLE_MAX_DEPTH)
throw LuaError("Lua runtime error: table nested too deeply");
lua_newtable(L);
for (int i = 0; i < value.size(); i++) {
push(L, i + 1);
pushValueImpl(L, value[i], depth);
lua_settable(L, -3);
}
}
void RaiiLuaState::pushObjectImpl(lua_State *L, const QJsonObject &value, int depth)
{
if (depth == 1)
// check stack size at first recursion to avoid multiple reallocations
lua_checkstack(L, LUA_STACK_SIZE);
if (depth > TABLE_MAX_DEPTH)
throw LuaError("Lua runtime error: table nested too deeply");
lua_newtable(L);
for (auto it = value.begin(); it != value.end(); ++it) {
push(L, it.key());
pushValueImpl(L, it.value(), depth);
lua_settable(L, -3);
}
}
void RaiiLuaState::pushValueImpl(lua_State *L, const QJsonValue &value, int depth)
{
if (value.isNull())
lua_pushnil(L);
else if (value.isBool())
lua_pushboolean(L, value.toBool());
else if (value.isDouble())
lua_pushnumber(L, value.toDouble());
else if (value.isString())
lua_pushstring(L, value.toString().toUtf8().constData());
else if (value.isObject())
pushObjectImpl(L, value.toObject(), depth + 1);
else if (value.isArray())
pushArrayImpl(L, value.toArray(), depth + 1);
else
throw LuaError("Lua type error: unknown type.");
}
QHash<lua_State *, LuaExtraState> RaiiLuaState::mExtraState; QHash<lua_State *, LuaExtraState> RaiiLuaState::mExtraState;
} // namespace AddOn } // namespace AddOn

View File

@ -68,6 +68,7 @@ public:
static long long fetchInteger(lua_State *L, int index); static long long fetchInteger(lua_State *L, int index);
static double fetchNumber(lua_State *L, int index); static double fetchNumber(lua_State *L, int index);
static QString fetchString(lua_State *L, int index); static QString fetchString(lua_State *L, int index);
static QJsonArray fetchArray(lua_State *L, int index);
static QJsonObject fetchObject(lua_State *L, int index); static QJsonObject fetchObject(lua_State *L, int index);
static QJsonValue fetch(lua_State *L, int index); static QJsonValue fetch(lua_State *L, int index);
@ -88,6 +89,8 @@ public:
static void push(lua_State *L, bool value); static void push(lua_State *L, bool value);
static void push(lua_State *L, const QString &value); static void push(lua_State *L, const QString &value);
static void push(lua_State *L, const QStringList &value); static void push(lua_State *L, const QStringList &value);
static void push(lua_State *L, const QJsonArray &value);
static void push(lua_State *L, const QJsonObject &value);
int getTop(); int getTop();
static int getTop(lua_State *L); static int getTop(lua_State *L);
@ -107,6 +110,10 @@ private:
static QJsonValue fetchTableImpl(lua_State *L, int index, int depth); static QJsonValue fetchTableImpl(lua_State *L, int index, int depth);
static QJsonValue fetchValueImpl(lua_State *L, int index, int depth); static QJsonValue fetchValueImpl(lua_State *L, int index, int depth);
static void pushArrayImpl(lua_State *L, const QJsonArray &value, int depth);
static void pushObjectImpl(lua_State *L, const QJsonObject &value, int depth);
static void pushValueImpl(lua_State *L, const QJsonValue &value, int depth);
private: private:
lua_State *mLua; lua_State *mLua;
static QHash<lua_State *, LuaExtraState> mExtraState; static QHash<lua_State *, LuaExtraState> mExtraState;

View File

@ -2,73 +2,77 @@ global function apiVersion(): ApiVersion
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end
local nameMap: {string:{string:string}} = { local enum CompilerKind
systemGcc = { "system"
en_US = "System GCC", "multilib"
pt_BR = "GCC do sistema", "cross"
zh_CN = "系统 GCC", "mingw"
zh_TW = "系統 GCC", end
local compilerNameTemplate: {CompilerKind:{string:string}} = {
system = {
en_US = "System %1, %2",
pt_BR = "%1 sistema, %2",
zh_CN = "系统 %1%2",
zh_TW = "系統 %1%2",
}, },
systemClang = { multilib = {
en_US = "System Clang", en_US = "Multilib %1, %2",
pt_BR = "Clang do sistema", pt_BR = "%1 multilib, %2",
zh_CN = "系统 Clang", zh_CN = "Multilib %1%2",
zh_TW = "系統 Clang", zh_TW = "Multilib %1%2",
}, },
multilibGcc = { cross = {
en_US = "Multilib GCC", en_US = "Cross %1 %3, %2",
pt_BR = "GCC multilib", pt_BR = "%1 cruzado %3, %2",
zh_CN = "Multilib GCC", zh_CN = "交叉编译 %1 %3%2",
zh_TW = "Multilib GCC", zh_TW = "交叉編譯 %1 %3%2",
}, },
multilibClang = { mingw = {
en_US = "Multilib Clang", en_US = "MinGW %1 %3, %2",
pt_BR = "Clang multilib", pt_BR = "MinGW %1 %3, %2",
zh_CN = "Multilib Clang", zh_CN = "MinGW %1 %3%2",
zh_TW = "Multilib Clang", zh_TW = "MinGW %1 %3%2",
},
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 enum Profile
"release"
"debug"
"debugWithAsan"
end
local profileNameMap: {Profile:{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 nameGenerator(lang: string, name: string, kind: CompilerKind, profile: Profile, arch: string | nil): string
local template = compilerNameTemplate[kind][lang] or compilerNameTemplate[kind].en_US
local profileName = profileNameMap[profile][lang] or profileNameMap[profile].en_US
return C_Util.format(template, name, profileName, arch)
end
local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet) local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet)
local c = compilerSet as {string:any} local c = compilerSet as {string:any}
local o = other as {string:any} local o = other as {string:any}
@ -78,16 +82,14 @@ local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: Co
end end
local record Config local record Config
isMultilib: boolean | nil
isMingw: boolean | nil
isClang: boolean | nil
customCompileParams: {string} | nil customCompileParams: {string} | nil
customLinkParams: {string} | nil customLinkParams: {string} | nil
arch: string | nil
triplet: string | nil triplet: string | nil
end end
local function generateConfig( local function generateConfig(
name: string, lang: string, lang: string, name: string, kind: CompilerKind,
cCompiler: string, cxxCompiler: string, cCompiler: string, cxxCompiler: string,
config: Config config: Config
): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet ): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet
@ -97,11 +99,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb", debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver", debugServer = "/usr/bin/gdbserver",
make = "/usr/bin/make", make = "/usr/bin/make",
compilerType = config.isClang and "Clang" or "GCC_UTF8", compilerType = name:sub(1, 5) == "Clang" and "Clang" or "GCC_UTF8",
preprocessingSuffix = ".i", preprocessingSuffix = ".i",
compilationProperSuffix = ".s", compilationProperSuffix = ".s",
assemblingSuffix = ".o", assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "", executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3, compilationStage = 3,
ccCmdOptUsePipe = "on", ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on", ccCmdOptWarningAll = "on",
@ -109,10 +111,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on", ccCmdOptCheckIsoConformance = "on",
binDirs = {"/usr/bin"}, binDirs = {"/usr/bin"},
} }
if config.isMultilib then if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32" commonOptions.ccCmdOptPointerSize = "32"
end end
if config.isMingw then if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres" commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end end
if config.customCompileParams then if config.customCompileParams then
@ -122,17 +124,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams commonOptions.customLinkParams = config.customLinkParams
end end
local release = { local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US), name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true, staticLink = true,
linkCmdOptStripExe = "on", linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2", ccCmdOptOptimize = "2",
} }
local debug_ = { local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US), name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
} }
local debugWithAsan = { local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US), name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address", ccCmdOptAddressSanitizer = "address",
} }
@ -151,8 +153,20 @@ global function main(): CompilerHint
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang, lang, "GCC", "system", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
local versionedGccs = C_FileSystem.matchFiles("/usr/bin", "^gcc-[0-9]+$")
for _, gcc in ipairs(versionedGccs) do
local version = gcc:sub(5)
local name = "GCC " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. gcc, "/usr/bin/g++-" .. version,
{} {}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
@ -162,9 +176,8 @@ global function main(): CompilerHint
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang, lang, "Clang", "system", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {}
{isClang = true}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -175,9 +188,8 @@ global function main(): CompilerHint
if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang, lang, "GCC", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {}
{isMultilib = true}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -186,9 +198,8 @@ global function main(): CompilerHint
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang, lang, "Clang", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {}
{isClang = true, isMultilib = true}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -203,9 +214,9 @@ global function main(): CompilerHint
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc") C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")
) then ) then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64", lang, lang, "GCC", "cross",
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++", "/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
{} {arch = "aarch64"}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
end end
@ -225,10 +236,10 @@ global function main(): CompilerHint
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang, lang, "GCC", "mingw",
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++", "/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
{ {
isMingw = true, arch = "x86_64",
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest}, customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
} }
@ -239,11 +250,9 @@ global function main(): CompilerHint
-- system Clang can target Windows -- system Clang can target Windows
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64", lang, lang, "Clang", "mingw", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++",
{ {
isClang = true, arch = "x86_64",
isMingw = true,
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customCompileParams = {"-target", "x86_64-w64-mingw32"}, customCompileParams = {"-target", "x86_64-w64-mingw32"},
customLinkParams = { customLinkParams = {
@ -265,10 +274,10 @@ global function main(): CompilerHint
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang, lang, "GCC", "mingw",
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++", "/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
{ {
isMingw = true, arch = "i686",
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest}, customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
} }
@ -279,11 +288,10 @@ global function main(): CompilerHint
-- system Clang can target Windows -- system Clang can target Windows
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686", lang, lang, "Clang", "mingw",
"/usr/bin/clang", "/usr/bin/clang++", "/usr/bin/clang", "/usr/bin/clang++",
{ {
isClang = true, arch = "i686",
isMingw = true,
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customCompileParams = {"-target", "i686-w64-mingw32"}, customCompileParams = {"-target", "i686-w64-mingw32"},
customLinkParams = { customLinkParams = {

View File

@ -2,61 +2,84 @@ global function apiVersion(): ApiVersion
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end
local nameMap: {string:{string:string}} = { local enum CompilerKind
systemGcc = { "system"
en_US = "System GCC", "multilib"
pt_BR = "GCC do sistema", "libx32"
zh_CN = "系统 GCC", "cross"
zh_TW = "系統 GCC", "mingw"
end
local compilerNameTemplate: {CompilerKind:{string:string}} = {
system = {
en_US = "System %1, %2",
pt_BR = "%1 sistema, %2",
zh_CN = "系统 %1%2",
zh_TW = "系統 %1%2",
}, },
systemClang = { multilib = {
en_US = "System Clang", en_US = "Multilib %1, %2",
pt_BR = "Clang do sistema", pt_BR = "%1 multilib, %2",
zh_CN = "系统 Clang", zh_CN = "Multilib %1%2",
zh_TW = "系統 Clang", zh_TW = "Multilib %1%2",
}, },
multilibGcc = { libx32 = {
en_US = "Multilib GCC", en_US = "Libx32 %1, %2",
pt_BR = "GCC multilib", pt_BR = "%1 libx32, %2",
zh_CN = "Multilib GCC", zh_CN = "Libx32 %1%2",
zh_TW = "Multilib GCC", zh_TW = "Libx32 %1%2",
}, },
multilibClang = { cross = {
en_US = "Multilib Clang", en_US = "Cross %1 %3, %2",
pt_BR = "Clang multilib", pt_BR = "%1 cruzado %3, %2",
zh_CN = "Multilib Clang", zh_CN = "交叉编译 %1 %3%2",
zh_TW = "Multilib Clang", zh_TW = "交叉編譯 %1 %3%2",
}, },
mingwGcc = { mingw = {
en_US = "MinGW GCC", en_US = "MinGW %1 %3, %2",
pt_BR = "GCC MinGW", pt_BR = "MinGW %1 %3, %2",
zh_CN = "MinGW GCC", zh_CN = "MinGW %1 %3%2",
zh_TW = "MinGW GCC", zh_TW = "MinGW %1 %3%2",
},
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 enum Profile
"release"
"debug"
"debugWithAsan"
end
local profileNameMap: {Profile:{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 nameGenerator(lang: string, name: string, kind: CompilerKind, profile: Profile, arch: string | nil): string
local template = compilerNameTemplate[kind][lang] or compilerNameTemplate[kind].en_US
local profileName = profileNameMap[profile][lang] or profileNameMap[profile].en_US
return C_Util.format(template, name, profileName, arch)
end
local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet) local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: CompilerHint.CompilerSet)
local c = compilerSet as {string:any} local c = compilerSet as {string:any}
local o = other as {string:any} local o = other as {string:any}
@ -66,16 +89,14 @@ local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: Co
end end
local record Config local record Config
isMultilib: boolean | nil
isMingw: boolean | nil
isClang: boolean | nil
customCompileParams: {string} | nil customCompileParams: {string} | nil
customLinkParams: {string} | nil customLinkParams: {string} | nil
arch: string | nil
triplet: string | nil triplet: string | nil
end end
local function generateConfig( local function generateConfig(
name: string, lang: string, lang: string, name: string, kind: CompilerKind,
cCompiler: string, cxxCompiler: string, cCompiler: string, cxxCompiler: string,
config: Config config: Config
): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet ): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet
@ -85,11 +106,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb", debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver", debugServer = "/usr/bin/gdbserver",
make = "/usr/bin/make", make = "/usr/bin/make",
compilerType = config.isClang and "Clang" or "GCC_UTF8", compilerType = name:sub(1, 5) == "Clang" and "Clang" or "GCC_UTF8",
preprocessingSuffix = ".i", preprocessingSuffix = ".i",
compilationProperSuffix = ".s", compilationProperSuffix = ".s",
assemblingSuffix = ".o", assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "", executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3, compilationStage = 3,
ccCmdOptUsePipe = "on", ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on", ccCmdOptWarningAll = "on",
@ -97,10 +118,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on", ccCmdOptCheckIsoConformance = "on",
binDirs = {"/usr/bin"}, binDirs = {"/usr/bin"},
} }
if config.isMultilib then if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32" commonOptions.ccCmdOptPointerSize = "32"
end end
if config.isMingw then if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres" commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end end
if config.customCompileParams then if config.customCompileParams then
@ -110,17 +131,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams commonOptions.customLinkParams = config.customLinkParams
end end
local release = { local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US), name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true, staticLink = true,
linkCmdOptStripExe = "on", linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2", ccCmdOptOptimize = "2",
} }
local debug_ = { local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US), name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
} }
local debugWithAsan = { local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US), name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address", ccCmdOptAddressSanitizer = "address",
} }
@ -137,10 +158,28 @@ global function main(): CompilerHint
local compilerList = {} local compilerList = {}
local gccDumpVersion = C_System.popen("/usr/bin/gcc", {"-dumpfullversion"})
gccDumpVersion = gccDumpVersion:match("^[0-9.]+")
local gccFsVersion = C_System.popen("/usr/bin/gcc", {"-dumpversion"})
gccFsVersion = gccFsVersion:match("^[0-9.]+")
local clangDumpVersion: string
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang, lang, "GCC (" .. gccDumpVersion .. ")", "system", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
local versionedGccs = C_FileSystem.matchFiles("/usr/bin", "^gcc-[0-9]+$")
for _, gcc in ipairs(versionedGccs) do
local version = gcc:sub(5)
local name = "GCC " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. gcc, "/usr/bin/g++-" .. version,
{} {}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
@ -149,23 +188,36 @@ global function main(): CompilerHint
end end
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
clangDumpVersion = C_System.popen("/usr/bin/clang", {"-dumpversion"})
clangDumpVersion = clangDumpVersion:match("^[0-9.]+")
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang, lang, "Clang (" .. clangDumpVersion .. ")", "system", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {}
{isClang = true}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan) table.insert(compilerList, debugWithAsan)
end end
-- TODO: better to check 32-bit libstdc++.a (lib32stdc++-dev), but its path is not fixed local versionedClangs = C_FileSystem.matchFiles("/usr/bin", "^clang-[0-9]+$")
if arch == "x86_64" and C_FileSystem.exists("/usr/lib32/libc.a") then for _, clang in ipairs(versionedClangs) do
local version = clang:sub(7)
local name = "Clang " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. clang, "/usr/bin/clang++-" .. version,
{}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
-- with lib32stdc++-dev installed, system GCC and Clang can target 32-bit
if arch == "x86_64" and C_FileSystem.exists("/usr/lib/gcc/x86_64-linux-gnu/" .. gccFsVersion .. "/32/libstdc++.a") then
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang, lang, "GCC (" .. gccDumpVersion .. ")", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {}
{isMultilib = true}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -174,9 +226,37 @@ global function main(): CompilerHint
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang, lang, "Clang (" .. clangDumpVersion .. ")", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {}
{isClang = true, isMultilib = true} )
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
end
-- with libx32stdc++-dev installed, system GCC and Clang can target x32
if arch == "x86_64" and C_FileSystem.exists("/usr/lib/gcc/x86_64-linux-gnu/" .. gccFsVersion .. "/x32/libstdc++.a") then
do
local release, debug_, debugWithAsan = generateConfig(
lang, "GCC (" .. gccDumpVersion .. ")", "libx32", "/usr/bin/gcc", "/usr/bin/g++",
{
customCompileParams = {"-mx32"},
customLinkParams = {"-mx32"},
}
)
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(
lang, "Clang (" .. clangDumpVersion .. ")", "libx32", "/usr/bin/clang", "/usr/bin/clang++",
{
customCompileParams = {"-mx32"},
customLinkParams = {"-mx32"},
}
) )
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -199,10 +279,10 @@ global function main(): CompilerHint
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang, lang, "GCC", "mingw",
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++", "/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
{ {
isMingw = true, arch = "x86_64",
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest}, customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
} }
@ -219,10 +299,10 @@ global function main(): CompilerHint
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang, lang, "GCC", "mingw",
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++", "/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
{ {
isMingw = true, arch = "i686",
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest}, customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
} }

View File

@ -2,7 +2,7 @@ global function apiVersion(): ApiVersion
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end

View File

@ -53,6 +53,10 @@ local record env
-- return whether the path is executable -- return whether the path is executable
isExecutable: function (path: string): boolean isExecutable: function (path: string): boolean
-- return matched files in the directory (non-recursive), with Qt-style regex
-- e.g. matchFiles("/usr/bin", "^gcc-[0-9]+$") may return {"gcc-12", "gcc-13"}
matchFiles: function (dir: string, qtRegex: string): {string}
end end
record C_System record C_System
@ -78,6 +82,9 @@ local record env
-- Windows arm64 is handled correctly even if Red Panda C++ runs under emulation -- Windows arm64 is handled correctly even if Red Panda C++ runs under emulation
osArch: function (): string osArch: function (): string
-- returns (1) stdout, (2) stderr and (3) exit status of the program
popen: function(prog: string, args: {string}, option: PopenOption | nil): string, string, PopenResult
-- returns supported application architectures by OS, name following `QSysInfo` -- returns supported application architectures by OS, name following `QSysInfo`
-- e.g. {"i386", "x86_64", "arm64"} -- e.g. {"i386", "x86_64", "arm64"}
-- Windows 10 1709 or later: accurate result -- Windows 10 1709 or later: accurate result
@ -89,6 +96,30 @@ local record env
-- read `subKey\name` from HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE in order (Windows only) -- read `subKey\name` from HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE in order (Windows only)
readRegistry: function (subKey: string, name: string): string | nil readRegistry: function (subKey: string, name: string): string | nil
record PopenOption
timeout: integer | nil -- in milliseconds
end
record PopenResult
exitStatus: QProcessExitStatus
error: QProcessProcessError | nil
exitCode: integer | nil -- only valid if exitStatus is NormalExit
end
enum QProcessExitStatus
"NormalExit"
"CrashExit"
end
enum QProcessProcessError
"FailedToStart"
"Crashed"
"Timedout"
"WriteError"
"ReadError"
"UnknownError"
end
end end
record C_Util record C_Util

View File

@ -2,73 +2,77 @@ function apiVersion()
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end
local nameMap = {
systemGcc = {
en_US = "System GCC",
pt_BR = "GCC do sistema",
zh_CN = "系统 GCC",
zh_TW = "系統 GCC",
local compilerNameTemplate = {
system = {
en_US = "System %1, %2",
pt_BR = "%1 sistema, %2",
zh_CN = "系统 %1%2",
zh_TW = "系統 %1%2",
}, },
systemClang = { multilib = {
en_US = "System Clang", en_US = "Multilib %1, %2",
pt_BR = "Clang do sistema", pt_BR = "%1 multilib, %2",
zh_CN = "系统 Clang", zh_CN = "Multilib %1%2",
zh_TW = "系統 Clang", zh_TW = "Multilib %1%2",
}, },
multilibGcc = { cross = {
en_US = "Multilib GCC", en_US = "Cross %1 %3, %2",
pt_BR = "GCC multilib", pt_BR = "%1 cruzado %3, %2",
zh_CN = "Multilib GCC", zh_CN = "交叉编译 %1 %3%2",
zh_TW = "Multilib GCC", zh_TW = "交叉編譯 %1 %3%2",
}, },
multilibClang = { mingw = {
en_US = "Multilib Clang", en_US = "MinGW %1 %3, %2",
pt_BR = "Clang multilib", pt_BR = "MinGW %1 %3, %2",
zh_CN = "Multilib Clang", zh_CN = "MinGW %1 %3%2",
zh_TW = "Multilib Clang", zh_TW = "MinGW %1 %3%2",
},
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 profileNameMap = {
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 nameGenerator(lang, name, kind, profile, arch)
local template = compilerNameTemplate[kind][lang] or compilerNameTemplate[kind].en_US
local profileName = profileNameMap[profile][lang] or profileNameMap[profile].en_US
return C_Util.format(template, name, profileName, arch)
end
local function mergeCompilerSet(compilerSet, other) local function mergeCompilerSet(compilerSet, other)
local c = compilerSet local c = compilerSet
local o = other local o = other
@ -84,10 +88,8 @@ end
local function generateConfig( local function generateConfig(
name, lang, lang, name, kind,
cCompiler, cxxCompiler, cCompiler, cxxCompiler,
config) config)
@ -97,11 +99,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb", debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver", debugServer = "/usr/bin/gdbserver",
make = "/usr/bin/make", make = "/usr/bin/make",
compilerType = config.isClang and "Clang" or "GCC_UTF8", compilerType = name:sub(1, 5) == "Clang" and "Clang" or "GCC_UTF8",
preprocessingSuffix = ".i", preprocessingSuffix = ".i",
compilationProperSuffix = ".s", compilationProperSuffix = ".s",
assemblingSuffix = ".o", assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "", executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3, compilationStage = 3,
ccCmdOptUsePipe = "on", ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on", ccCmdOptWarningAll = "on",
@ -109,10 +111,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on", ccCmdOptCheckIsoConformance = "on",
binDirs = { "/usr/bin" }, binDirs = { "/usr/bin" },
} }
if config.isMultilib then if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32" commonOptions.ccCmdOptPointerSize = "32"
end end
if config.isMingw then if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres" commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end end
if config.customCompileParams then if config.customCompileParams then
@ -122,17 +124,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams commonOptions.customLinkParams = config.customLinkParams
end end
local release = { local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US), name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true, staticLink = true,
linkCmdOptStripExe = "on", linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2", ccCmdOptOptimize = "2",
} }
local debug_ = { local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US), name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
} }
local debugWithAsan = { local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US), name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address", ccCmdOptAddressSanitizer = "address",
} }
@ -151,8 +153,20 @@ function main()
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang, lang, "GCC", "system", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {})
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
local versionedGccs = C_FileSystem.matchFiles("/usr/bin", "^gcc-[0-9]+$")
for _, gcc in ipairs(versionedGccs) do
local version = gcc:sub(5)
local name = "GCC " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. gcc, "/usr/bin/g++-" .. version,
{}) {})
table.insert(compilerList, release) table.insert(compilerList, release)
@ -162,9 +176,8 @@ function main()
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang, lang, "Clang", "system", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {})
{ isClang = true })
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -175,9 +188,8 @@ function main()
if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then if arch == "x86_64" and C_FileSystem.isExecutable("/usr/lib32/libstdc++.so") then
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang, lang, "GCC", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {})
{ isMultilib = true })
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -186,9 +198,8 @@ function main()
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang, lang, "Clang", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {})
{ isClang = true, isMultilib = true })
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -203,9 +214,9 @@ function main()
C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")) then C_FileSystem.isExecutable("/usr/bin/aarch64-linux-gnu-gcc")) then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.crossGcc[lang] or nameMap.crossGcc.en_US) .. " aarch64", lang, lang, "GCC", "cross",
"/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++", "/usr/bin/aarch64-linux-gnu-gcc", "/usr/bin/aarch64-linux-gnu-g++",
{}) { arch = "aarch64" })
table.insert(compilerList, release) table.insert(compilerList, release)
end end
@ -225,10 +236,10 @@ function main()
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang, lang, "GCC", "mingw",
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++", "/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
{ {
isMingw = true, arch = "x86_64",
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest }, customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
}) })
@ -239,11 +250,9 @@ function main()
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " x86_64", lang, lang, "Clang", "mingw", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++",
{ {
isClang = true, arch = "x86_64",
isMingw = true,
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customCompileParams = { "-target", "x86_64-w64-mingw32" }, customCompileParams = { "-target", "x86_64-w64-mingw32" },
customLinkParams = { customLinkParams = {
@ -265,10 +274,10 @@ function main()
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang, lang, "GCC", "mingw",
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++", "/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
{ {
isMingw = true, arch = "i686",
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest }, customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
}) })
@ -279,11 +288,10 @@ function main()
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwClang[lang] or nameMap.mingwClang.en_US) .. " i686", lang, lang, "Clang", "mingw",
"/usr/bin/clang", "/usr/bin/clang++", "/usr/bin/clang", "/usr/bin/clang++",
{ {
isClang = true, arch = "i686",
isMingw = true,
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customCompileParams = { "-target", "i686-w64-mingw32" }, customCompileParams = { "-target", "i686-w64-mingw32" },
customLinkParams = { customLinkParams = {

View File

@ -2,61 +2,84 @@ function apiVersion()
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end
local nameMap = {
systemGcc = {
en_US = "System GCC",
pt_BR = "GCC do sistema",
zh_CN = "系统 GCC",
zh_TW = "系統 GCC",
local compilerNameTemplate = {
system = {
en_US = "System %1, %2",
pt_BR = "%1 sistema, %2",
zh_CN = "系统 %1%2",
zh_TW = "系統 %1%2",
}, },
systemClang = { multilib = {
en_US = "System Clang", en_US = "Multilib %1, %2",
pt_BR = "Clang do sistema", pt_BR = "%1 multilib, %2",
zh_CN = "系统 Clang", zh_CN = "Multilib %1%2",
zh_TW = "系統 Clang", zh_TW = "Multilib %1%2",
}, },
multilibGcc = { libx32 = {
en_US = "Multilib GCC", en_US = "Libx32 %1, %2",
pt_BR = "GCC multilib", pt_BR = "%1 libx32, %2",
zh_CN = "Multilib GCC", zh_CN = "Libx32 %1%2",
zh_TW = "Multilib GCC", zh_TW = "Libx32 %1%2",
}, },
multilibClang = { cross = {
en_US = "Multilib Clang", en_US = "Cross %1 %3, %2",
pt_BR = "Clang multilib", pt_BR = "%1 cruzado %3, %2",
zh_CN = "Multilib Clang", zh_CN = "交叉编译 %1 %3%2",
zh_TW = "Multilib Clang", zh_TW = "交叉編譯 %1 %3%2",
}, },
mingwGcc = { mingw = {
en_US = "MinGW GCC", en_US = "MinGW %1 %3, %2",
pt_BR = "GCC MinGW", pt_BR = "MinGW %1 %3, %2",
zh_CN = "MinGW GCC", zh_CN = "MinGW %1 %3%2",
zh_TW = "MinGW GCC", zh_TW = "MinGW %1 %3%2",
},
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 profileNameMap = {
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 nameGenerator(lang, name, kind, profile, arch)
local template = compilerNameTemplate[kind][lang] or compilerNameTemplate[kind].en_US
local profileName = profileNameMap[profile][lang] or profileNameMap[profile].en_US
return C_Util.format(template, name, profileName, arch)
end
local function mergeCompilerSet(compilerSet, other) local function mergeCompilerSet(compilerSet, other)
local c = compilerSet local c = compilerSet
local o = other local o = other
@ -72,10 +95,8 @@ end
local function generateConfig( local function generateConfig(
name, lang, lang, name, kind,
cCompiler, cxxCompiler, cCompiler, cxxCompiler,
config) config)
@ -85,11 +106,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb", debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver", debugServer = "/usr/bin/gdbserver",
make = "/usr/bin/make", make = "/usr/bin/make",
compilerType = config.isClang and "Clang" or "GCC_UTF8", compilerType = name:sub(1, 5) == "Clang" and "Clang" or "GCC_UTF8",
preprocessingSuffix = ".i", preprocessingSuffix = ".i",
compilationProperSuffix = ".s", compilationProperSuffix = ".s",
assemblingSuffix = ".o", assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "", executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3, compilationStage = 3,
ccCmdOptUsePipe = "on", ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on", ccCmdOptWarningAll = "on",
@ -97,10 +118,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on", ccCmdOptCheckIsoConformance = "on",
binDirs = { "/usr/bin" }, binDirs = { "/usr/bin" },
} }
if config.isMultilib then if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32" commonOptions.ccCmdOptPointerSize = "32"
end end
if config.isMingw then if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres" commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end end
if config.customCompileParams then if config.customCompileParams then
@ -110,17 +131,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams commonOptions.customLinkParams = config.customLinkParams
end end
local release = { local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US), name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true, staticLink = true,
linkCmdOptStripExe = "on", linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2", ccCmdOptOptimize = "2",
} }
local debug_ = { local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US), name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
} }
local debugWithAsan = { local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US), name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on", ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address", ccCmdOptAddressSanitizer = "address",
} }
@ -137,10 +158,28 @@ function main()
local compilerList = {} local compilerList = {}
local gccDumpVersion = C_System.popen("/usr/bin/gcc", { "-dumpfullversion" })
gccDumpVersion = gccDumpVersion:match("^[0-9.]+")
local gccFsVersion = C_System.popen("/usr/bin/gcc", { "-dumpversion" })
gccFsVersion = gccFsVersion:match("^[0-9.]+")
local clangDumpVersion
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang, lang, "GCC (" .. gccDumpVersion .. ")", "system", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {})
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
local versionedGccs = C_FileSystem.matchFiles("/usr/bin", "^gcc-[0-9]+$")
for _, gcc in ipairs(versionedGccs) do
local version = gcc:sub(5)
local name = "GCC " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. gcc, "/usr/bin/g++-" .. version,
{}) {})
table.insert(compilerList, release) table.insert(compilerList, release)
@ -149,10 +188,24 @@ function main()
end end
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
clangDumpVersion = C_System.popen("/usr/bin/clang", { "-dumpversion" })
clangDumpVersion = clangDumpVersion:match("^[0-9.]+")
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.systemClang[lang] or nameMap.systemClang.en_US, lang, lang, "Clang (" .. clangDumpVersion .. ")", "system", "/usr/bin/clang", "/usr/bin/clang++",
"/usr/bin/clang", "/usr/bin/clang++", {})
{ isClang = true })
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
local versionedClangs = C_FileSystem.matchFiles("/usr/bin", "^clang-[0-9]+$")
for _, clang in ipairs(versionedClangs) do
local version = clang:sub(7)
local name = "Clang " .. version
local release, debug_, debugWithAsan = generateConfig(
lang, name, "system", "/usr/bin/" .. clang, "/usr/bin/clang++-" .. version,
{})
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -160,12 +213,11 @@ function main()
end end
if arch == "x86_64" and C_FileSystem.exists("/usr/lib32/libc.a") then if arch == "x86_64" and C_FileSystem.exists("/usr/lib/gcc/x86_64-linux-gnu/" .. gccFsVersion .. "/32/libstdc++.a") then
do do
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang, lang, "GCC (" .. gccDumpVersion .. ")", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
"/usr/bin/gcc", "/usr/bin/g++", {})
{ isMultilib = true })
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -174,9 +226,37 @@ function main()
if C_FileSystem.isExecutable("/usr/bin/clang") then if C_FileSystem.isExecutable("/usr/bin/clang") then
local release, debug_, debugWithAsan = generateConfig( local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibClang[lang] or nameMap.multilibClang.en_US, lang, lang, "Clang (" .. clangDumpVersion .. ")", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
"/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("/usr/lib/gcc/x86_64-linux-gnu/" .. gccFsVersion .. "/x32/libstdc++.a") then
do
local release, debug_, debugWithAsan = generateConfig(
lang, "GCC (" .. gccDumpVersion .. ")", "libx32", "/usr/bin/gcc", "/usr/bin/g++",
{
customCompileParams = { "-mx32" },
customLinkParams = { "-mx32" },
})
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(
lang, "Clang (" .. clangDumpVersion .. ")", "libx32", "/usr/bin/clang", "/usr/bin/clang++",
{
customCompileParams = { "-mx32" },
customLinkParams = { "-mx32" },
})
table.insert(compilerList, release) table.insert(compilerList, release)
table.insert(compilerList, debug_) table.insert(compilerList, debug_)
@ -199,10 +279,10 @@ function main()
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " x86_64", lang, lang, "GCC", "mingw",
"/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++", "/usr/bin/x86_64-w64-mingw32-gcc", "/usr/bin/x86_64-w64-mingw32-g++",
{ {
isMingw = true, arch = "x86_64",
triplet = "x86_64-w64-mingw32", triplet = "x86_64-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest }, customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
}) })
@ -219,10 +299,10 @@ function main()
do do
local release, _, _ = generateConfig( local release, _, _ = generateConfig(
(nameMap.mingwGcc[lang] or nameMap.mingwGcc.en_US) .. " i686", lang, lang, "GCC", "mingw",
"/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++", "/usr/bin/i686-w64-mingw32-gcc", "/usr/bin/i686-w64-mingw32-g++",
{ {
isMingw = true, arch = "i686",
triplet = "i686-w64-mingw32", triplet = "i686-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest }, customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
}) })

View File

@ -2,7 +2,7 @@ function apiVersion()
return { return {
kind = "compiler_hint", kind = "compiler_hint",
major = 0, major = 0,
minor = 1, minor = 2,
} }
end end