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 <QJsonValue>
#include <QMessageBox>
#include <QRegularExpression>
#include <chrono>
#ifdef Q_OS_WINDOWS
# include <windows.h>
@ -236,6 +238,23 @@ extern "C" int luaApi_FileSystem_isExecutable(lua_State *L) noexcept {
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
extern "C" int luaApi_System_appArch(lua_State *L) noexcept {
AddOn::RaiiLuaState::push(L, appArch());
@ -269,6 +288,104 @@ extern "C" int luaApi_System_osArch(lua_State *L) noexcept {
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) {
// adjust QEMU user emulation arches to match QSysInfo::currentCpuArchitecture
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_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_appDir(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_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;
#ifdef Q_OS_WINDOWS
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
{"isExecutable", &luaApi_FileSystem_isExecutable}, // (string) -> bool
{"matchFiles", &luaApi_FileSystem_matchFiles}, // (string, string) -> [string]
}},
{"C_System",
{
@ -50,6 +51,7 @@ static QMap<QString, QMap<QString, lua_CFunction>> apiGroups{
{"appLibexecDir", &luaApi_System_appLibexecDir}, // () -> string
{"appResourceDir", &luaApi_System_appResourceDir}, // () -> string
{"osArch", &luaApi_System_osArch}, // () -> string
{"popen", &luaApi_System_popen},
{"supportedAppArchList",
&luaApi_System_supportedAppArchList}, // () -> string
#ifdef Q_OS_WINDOWS
@ -161,7 +163,7 @@ QJsonValue SimpleExecutor::runScript(const QByteArray &script,
}
CompilerHintExecutor::CompilerHintExecutor() : SimpleExecutor(
"compiler_hint", 0, 1,
"compiler_hint", 0, 2,
{"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);
}
QJsonArray RaiiLuaState::fetchArray(lua_State *L, int index)
{
return fetchTableImpl(L, index, 0).toArray();
}
QJsonObject RaiiLuaState::fetchObject(lua_State *L, int index)
{
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()
{
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;
} // namespace AddOn

View File

@ -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 QJsonArray fetchArray(lua_State *L, int index);
static QJsonObject fetchObject(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, const QString &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();
static int getTop(lua_State *L);
@ -107,6 +110,10 @@ private:
static QJsonValue fetchTableImpl(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:
lua_State *mLua;
static QHash<lua_State *, LuaExtraState> mExtraState;

View File

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

View File

@ -2,61 +2,84 @@ global function apiVersion(): ApiVersion
return {
kind = "compiler_hint",
major = 0,
minor = 1,
minor = 2,
}
end
local nameMap: {string:{string:string}} = {
systemGcc = {
en_US = "System GCC",
pt_BR = "GCC do sistema",
zh_CN = "系统 GCC",
zh_TW = "系統 GCC",
local enum CompilerKind
"system"
"multilib"
"libx32"
"cross"
"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 = {
en_US = "System Clang",
pt_BR = "Clang do sistema",
zh_CN = "系统 Clang",
zh_TW = "系統 Clang",
multilib = {
en_US = "Multilib %1, %2",
pt_BR = "%1 multilib, %2",
zh_CN = "Multilib %1%2",
zh_TW = "Multilib %1%2",
},
multilibGcc = {
en_US = "Multilib GCC",
pt_BR = "GCC multilib",
zh_CN = "Multilib GCC",
zh_TW = "Multilib GCC",
libx32 = {
en_US = "Libx32 %1, %2",
pt_BR = "%1 libx32, %2",
zh_CN = "Libx32 %1%2",
zh_TW = "Libx32 %1%2",
},
multilibClang = {
en_US = "Multilib Clang",
pt_BR = "Clang multilib",
zh_CN = "Multilib Clang",
zh_TW = "Multilib Clang",
cross = {
en_US = "Cross %1 %3, %2",
pt_BR = "%1 cruzado %3, %2",
zh_CN = "交叉编译 %1 %3%2",
zh_TW = "交叉編譯 %1 %3%2",
},
mingwGcc = {
en_US = "MinGW GCC",
pt_BR = "GCC MinGW",
zh_CN = "MinGW GCC",
zh_TW = "MinGW GCC",
},
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 偵錯",
mingw = {
en_US = "MinGW %1 %3, %2",
pt_BR = "MinGW %1 %3, %2",
zh_CN = "MinGW %1 %3%2",
zh_TW = "MinGW %1 %3%2",
},
}
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 c = compilerSet as {string:any}
local o = other as {string:any}
@ -66,16 +89,14 @@ local function mergeCompilerSet(compilerSet: CompilerHint.CompilerSet, other: Co
end
local record Config
isMultilib: boolean | nil
isMingw: boolean | nil
isClang: boolean | nil
customCompileParams: {string} | nil
customLinkParams: {string} | nil
arch: string | nil
triplet: string | nil
end
local function generateConfig(
name: string, lang: string,
lang: string, name: string, kind: CompilerKind,
cCompiler: string, cxxCompiler: string,
config: Config
): CompilerHint.CompilerSet, CompilerHint.CompilerSet, CompilerHint.CompilerSet
@ -85,11 +106,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver",
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",
compilationProperSuffix = ".s",
assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "",
executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3,
ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on",
@ -97,10 +118,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on",
binDirs = {"/usr/bin"},
}
if config.isMultilib then
if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32"
end
if config.isMingw then
if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end
if config.customCompileParams then
@ -110,17 +131,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams
end
local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US),
name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true,
linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2",
}
local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on",
}
local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US),
name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address",
}
@ -137,10 +158,65 @@ global function main(): CompilerHint
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
local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang,
"/usr/bin/gcc", "/usr/bin/g++",
lang, "GCC (" .. gccDumpVersion .. ")", "system", "/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, debug_)
table.insert(compilerList, debugWithAsan)
end
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(
lang, "Clang (" .. clangDumpVersion .. ")", "system", "/usr/bin/clang", "/usr/bin/clang++",
{}
)
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, 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
local release, debug_, debugWithAsan = generateConfig(
lang, "GCC (" .. gccDumpVersion .. ")", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
{}
)
table.insert(compilerList, release)
@ -150,22 +226,24 @@ global function main(): CompilerHint
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}
lang, "Clang (" .. clangDumpVersion .. ")", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
{}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
end
end
-- TODO: better to check 32-bit libstdc++.a (lib32stdc++-dev), but its path is not fixed
if arch == "x86_64" and C_FileSystem.exists("/usr/lib32/libc.a") then
-- 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(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang,
"/usr/bin/gcc", "/usr/bin/g++",
{isMultilib = true}
lang, "GCC (" .. gccDumpVersion .. ")", "libx32", "/usr/bin/gcc", "/usr/bin/g++",
{
customCompileParams = {"-mx32"},
customLinkParams = {"-mx32"},
}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
@ -174,9 +252,11 @@ global function main(): CompilerHint
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}
lang, "Clang (" .. clangDumpVersion .. ")", "libx32", "/usr/bin/clang", "/usr/bin/clang++",
{
customCompileParams = {"-mx32"},
customLinkParams = {"-mx32"},
}
)
table.insert(compilerList, release)
table.insert(compilerList, debug_)
@ -199,10 +279,10 @@ global function main(): CompilerHint
do
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++",
{
isMingw = true,
arch = "x86_64",
triplet = "x86_64-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
}
@ -219,10 +299,10 @@ global function main(): CompilerHint
do
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++",
{
isMingw = true,
arch = "i686",
triplet = "i686-w64-mingw32",
customLinkParams = {extraObjects.utf8init, extraObjects.utf8manifest},
}

View File

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

View File

@ -53,6 +53,10 @@ local record env
-- return whether the path is executable
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
record C_System
@ -78,6 +82,9 @@ local record env
-- Windows arm64 is handled correctly even if Red Panda C++ runs under emulation
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`
-- e.g. {"i386", "x86_64", "arm64"}
-- 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)
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
record C_Util

View File

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

View File

@ -2,61 +2,84 @@ function apiVersion()
return {
kind = "compiler_hint",
major = 0,
minor = 1,
minor = 2,
}
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 = {
en_US = "System Clang",
pt_BR = "Clang do sistema",
zh_CN = "系统 Clang",
zh_TW = "系統 Clang",
multilib = {
en_US = "Multilib %1, %2",
pt_BR = "%1 multilib, %2",
zh_CN = "Multilib %1%2",
zh_TW = "Multilib %1%2",
},
multilibGcc = {
en_US = "Multilib GCC",
pt_BR = "GCC multilib",
zh_CN = "Multilib GCC",
zh_TW = "Multilib GCC",
libx32 = {
en_US = "Libx32 %1, %2",
pt_BR = "%1 libx32, %2",
zh_CN = "Libx32 %1%2",
zh_TW = "Libx32 %1%2",
},
multilibClang = {
en_US = "Multilib Clang",
pt_BR = "Clang multilib",
zh_CN = "Multilib Clang",
zh_TW = "Multilib Clang",
cross = {
en_US = "Cross %1 %3, %2",
pt_BR = "%1 cruzado %3, %2",
zh_CN = "交叉编译 %1 %3%2",
zh_TW = "交叉編譯 %1 %3%2",
},
mingwGcc = {
en_US = "MinGW GCC",
pt_BR = "GCC MinGW",
zh_CN = "MinGW GCC",
zh_TW = "MinGW GCC",
},
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 偵錯",
mingw = {
en_US = "MinGW %1 %3, %2",
pt_BR = "MinGW %1 %3, %2",
zh_CN = "MinGW %1 %3%2",
zh_TW = "MinGW %1 %3%2",
},
}
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 c = compilerSet
local o = other
@ -72,10 +95,8 @@ end
local function generateConfig(
name, lang,
lang, name, kind,
cCompiler, cxxCompiler,
config)
@ -85,11 +106,11 @@ local function generateConfig(
debugger = "/usr/bin/gdb",
debugServer = "/usr/bin/gdbserver",
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",
compilationProperSuffix = ".s",
assemblingSuffix = ".o",
executableSuffix = config.isMingw and ".exe" or "",
executableSuffix = kind == "mingw" and ".exe" or "",
compilationStage = 3,
ccCmdOptUsePipe = "on",
ccCmdOptWarningAll = "on",
@ -97,10 +118,10 @@ local function generateConfig(
ccCmdOptCheckIsoConformance = "on",
binDirs = { "/usr/bin" },
}
if config.isMultilib then
if kind == "multilib" then
commonOptions.ccCmdOptPointerSize = "32"
end
if config.isMingw then
if kind == "mingw" then
commonOptions.resourceCompiler = "/usr/bin/" .. config.triplet .. "-windres"
end
if config.customCompileParams then
@ -110,17 +131,17 @@ local function generateConfig(
commonOptions.customLinkParams = config.customLinkParams
end
local release = {
name = name .. (nameMap.release[lang] or nameMap.release.en_US),
name = nameGenerator(lang, name, kind, "release", config.arch),
staticLink = true,
linkCmdOptStripExe = "on",
ccCmdOptOptimize = "2",
}
local debug_ = {
name = name .. (nameMap.debug[lang] or nameMap.debug.en_US),
name = nameGenerator(lang, name, kind, "debug", config.arch),
ccCmdOptDebugInfo = "on",
}
local debugWithAsan = {
name = name .. (nameMap.debugWithAsan[lang] or nameMap.debugWithAsan.en_US),
name = nameGenerator(lang, name, kind, "debugWithAsan", config.arch),
ccCmdOptDebugInfo = "on",
ccCmdOptAddressSanitizer = "address",
}
@ -137,10 +158,65 @@ function main()
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
local release, debug_, debugWithAsan = generateConfig(
nameMap.systemGcc[lang] or nameMap.systemGcc.en_US, lang,
"/usr/bin/gcc", "/usr/bin/g++",
lang, "GCC (" .. gccDumpVersion .. ")", "system", "/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, debug_)
table.insert(compilerList, debugWithAsan)
end
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(
lang, "Clang (" .. clangDumpVersion .. ")", "system", "/usr/bin/clang", "/usr/bin/clang++",
{})
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, debug_)
table.insert(compilerList, debugWithAsan)
end
if arch == "x86_64" and C_FileSystem.exists("/usr/lib/gcc/x86_64-linux-gnu/" .. gccFsVersion .. "/32/libstdc++.a") then
do
local release, debug_, debugWithAsan = generateConfig(
lang, "GCC (" .. gccDumpVersion .. ")", "multilib", "/usr/bin/gcc", "/usr/bin/g++",
{})
table.insert(compilerList, release)
@ -150,22 +226,24 @@ function main()
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 })
lang, "Clang (" .. clangDumpVersion .. ")", "multilib", "/usr/bin/clang", "/usr/bin/clang++",
{})
table.insert(compilerList, release)
table.insert(compilerList, debug_)
table.insert(compilerList, debugWithAsan)
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 .. "/x32/libstdc++.a") then
do
local release, debug_, debugWithAsan = generateConfig(
nameMap.multilibGcc[lang] or nameMap.multilibGcc.en_US, lang,
"/usr/bin/gcc", "/usr/bin/g++",
{ isMultilib = true })
lang, "GCC (" .. gccDumpVersion .. ")", "libx32", "/usr/bin/gcc", "/usr/bin/g++",
{
customCompileParams = { "-mx32" },
customLinkParams = { "-mx32" },
})
table.insert(compilerList, release)
table.insert(compilerList, debug_)
@ -174,9 +252,11 @@ function main()
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 })
lang, "Clang (" .. clangDumpVersion .. ")", "libx32", "/usr/bin/clang", "/usr/bin/clang++",
{
customCompileParams = { "-mx32" },
customLinkParams = { "-mx32" },
})
table.insert(compilerList, release)
table.insert(compilerList, debug_)
@ -199,10 +279,10 @@ function main()
do
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++",
{
isMingw = true,
arch = "x86_64",
triplet = "x86_64-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
})
@ -219,10 +299,10 @@ function main()
do
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++",
{
isMingw = true,
arch = "i686",
triplet = "i686-w64-mingw32",
customLinkParams = { extraObjects.utf8init, extraObjects.utf8manifest },
})

View File

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