2021-12-26 23:18:28 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2021-04-20 22:24:33 +08:00
|
|
|
#include "compiler.h"
|
|
|
|
#include "utils.h"
|
2021-06-21 11:21:26 +08:00
|
|
|
#include "compilermanager.h"
|
2021-09-14 12:10:43 +08:00
|
|
|
#include "../systemconsts.h"
|
2021-04-20 22:24:33 +08:00
|
|
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QString>
|
|
|
|
#include <QTextCodec>
|
|
|
|
#include <QTime>
|
2021-09-04 11:37:04 +08:00
|
|
|
#include <QApplication>
|
|
|
|
#include "../editor.h"
|
|
|
|
#include "../mainwindow.h"
|
|
|
|
#include "../editorlist.h"
|
|
|
|
#include "../parser/cppparser.h"
|
|
|
|
#include "../autolinkmanager.h"
|
2021-09-03 20:55:14 +08:00
|
|
|
#include "../platform.h"
|
2021-09-12 22:45:00 +08:00
|
|
|
#include "../project.h"
|
2021-04-20 22:24:33 +08:00
|
|
|
|
2021-06-24 20:43:09 +08:00
|
|
|
#define COMPILE_PROCESS_END "---//END//----"
|
|
|
|
|
|
|
|
Compiler::Compiler(const QString &filename, bool silent, bool onlyCheckSyntax):
|
2021-04-20 22:24:33 +08:00
|
|
|
QThread(),
|
|
|
|
mSilent(silent),
|
2021-06-24 20:43:09 +08:00
|
|
|
mOnlyCheckSyntax(onlyCheckSyntax),
|
2021-06-25 12:40:11 +08:00
|
|
|
mFilename(filename),
|
|
|
|
mRebuild(false)
|
2021-04-20 22:24:33 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compiler::run()
|
|
|
|
{
|
|
|
|
emit compileStarted();
|
2021-09-13 07:49:36 +08:00
|
|
|
auto action = finally([this]{
|
|
|
|
emit compileFinished();
|
|
|
|
});
|
2021-06-21 11:21:26 +08:00
|
|
|
try {
|
2021-09-13 07:49:36 +08:00
|
|
|
if (!prepareForCompile()){
|
|
|
|
return;
|
|
|
|
}
|
2021-06-25 12:40:11 +08:00
|
|
|
if (mRebuild && !prepareForRebuild()) {
|
|
|
|
throw CompileError(tr("Clean before rebuild failed."));
|
|
|
|
}
|
2021-09-13 07:49:36 +08:00
|
|
|
mErrorCount = 0;
|
|
|
|
mWarningCount = 0;
|
|
|
|
QElapsedTimer timer;
|
|
|
|
timer.start();
|
2021-09-13 22:45:50 +08:00
|
|
|
runCommand(mCompiler, mArguments, mDirectory, pipedText());
|
2021-09-13 07:49:36 +08:00
|
|
|
log("");
|
|
|
|
log(tr("Compile Result:"));
|
|
|
|
log("------------------");
|
|
|
|
log(tr("- Errors: %1").arg(mErrorCount));
|
|
|
|
log(tr("- Warnings: %1").arg(mWarningCount));
|
|
|
|
if (!mOutputFile.isEmpty()) {
|
|
|
|
log(tr("- Output Filename: %1").arg(mOutputFile));
|
|
|
|
QLocale locale = QLocale::system();
|
|
|
|
log(tr("- Output Size: %1").arg(locale.formattedDataSize(QFileInfo(mOutputFile).size())));
|
2021-04-21 23:06:55 +08:00
|
|
|
}
|
2021-09-13 07:49:36 +08:00
|
|
|
log(tr("- Compilation Time: %1 secs").arg(timer.elapsed() / 1000.0));
|
2021-06-21 11:21:26 +08:00
|
|
|
} catch (CompileError e) {
|
|
|
|
emit compileErrorOccured(e.reason());
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-09-13 07:49:36 +08:00
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
|
2021-04-24 15:57:45 +08:00
|
|
|
QString Compiler::getFileNameFromOutputLine(QString &line) {
|
|
|
|
QString temp;
|
|
|
|
line = line.trimmed();
|
|
|
|
while (true) {
|
|
|
|
int pos;
|
|
|
|
if (line.length() > 2 && line[1]==':') { // full file path at start, ignore this ':'
|
|
|
|
pos = line.indexOf(':',2);
|
|
|
|
} else {
|
|
|
|
pos = line.indexOf(':');
|
|
|
|
}
|
|
|
|
if ( pos < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
temp = line.mid(0,pos);
|
|
|
|
line.remove(0,pos+1);
|
2021-05-27 01:05:49 +08:00
|
|
|
line=line.trimmed();
|
2021-06-24 20:43:09 +08:00
|
|
|
if (temp.compare("<stdin>", Qt::CaseInsensitive)==0 ) {
|
|
|
|
temp = mFilename;
|
|
|
|
break;
|
|
|
|
}
|
2021-04-24 15:57:45 +08:00
|
|
|
|
2021-05-27 01:05:49 +08:00
|
|
|
if (QFileInfo(temp).fileName() == QLatin1String("ld.exe")) { // skip ld.exe
|
2021-04-24 15:57:45 +08:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Compiler::getLineNumberFromOutputLine(QString &line)
|
|
|
|
{
|
|
|
|
line = line.trimmed();
|
|
|
|
int pos = line.indexOf(':');
|
|
|
|
int result=0;
|
|
|
|
if (pos < 0) {
|
|
|
|
pos = line.indexOf(',');
|
|
|
|
}
|
|
|
|
if (pos>=0) {
|
2021-08-29 10:14:07 +08:00
|
|
|
result = line.midRef(0,pos).toInt();
|
2021-05-27 01:05:49 +08:00
|
|
|
if (result > 0)
|
|
|
|
line.remove(0,pos+1);
|
2021-04-24 15:57:45 +08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Compiler::getColunmnFromOutputLine(QString &line)
|
|
|
|
{
|
|
|
|
line = line.trimmed();
|
|
|
|
int pos = line.indexOf(':');
|
|
|
|
int result=0;
|
|
|
|
if (pos < 0) {
|
|
|
|
pos = line.indexOf(',');
|
|
|
|
}
|
|
|
|
if (pos>=0) {
|
2021-08-29 10:14:07 +08:00
|
|
|
result = line.midRef(0,pos).toInt();
|
2021-06-24 16:05:19 +08:00
|
|
|
if (result > 0)
|
|
|
|
line.remove(0,pos+1);
|
2021-04-24 15:57:45 +08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
CompileIssueType Compiler::getIssueTypeFromOutputLine(QString &line)
|
|
|
|
{
|
|
|
|
CompileIssueType result = CompileIssueType::Other;
|
|
|
|
line = line.trimmed();
|
|
|
|
int pos = line.indexOf(':');
|
|
|
|
if (pos>=0) {
|
|
|
|
QString s=line.mid(0,pos);
|
|
|
|
if (s == "error" || s == "fatal error") {
|
|
|
|
mErrorCount += 1;
|
|
|
|
line = tr("[Error] ")+line.mid(pos+1);
|
|
|
|
result = CompileIssueType::Error;
|
|
|
|
} else if (s == "warning") {
|
|
|
|
mWarningCount += 1;
|
|
|
|
line = tr("[Warning] ")+line.mid(pos+1);
|
|
|
|
result = CompileIssueType::Warning;
|
|
|
|
} else if (s == "info") {
|
|
|
|
mWarningCount += 1;
|
|
|
|
line = tr("[Info] ")+line.mid(pos+1);
|
|
|
|
result = CompileIssueType::Info;
|
|
|
|
} else if (s == "note") {
|
|
|
|
mWarningCount += 1;
|
|
|
|
line = tr("[Note] ")+line.mid(pos+1);
|
|
|
|
result = CompileIssueType::Note;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-13 07:49:36 +08:00
|
|
|
Settings::PCompilerSet Compiler::compilerSet()
|
|
|
|
{
|
2022-01-10 10:53:16 +08:00
|
|
|
if (mProject) {
|
|
|
|
int index = mProject->options().compilerSet;
|
|
|
|
Settings::PCompilerSet set = pSettings->compilerSets().getSet(index);
|
|
|
|
if (set)
|
|
|
|
return set;
|
|
|
|
}
|
2021-09-13 07:49:36 +08:00
|
|
|
return pSettings->compilerSets().defaultSet();
|
|
|
|
}
|
|
|
|
|
2021-04-24 15:57:45 +08:00
|
|
|
void Compiler::processOutput(QString &line)
|
|
|
|
{
|
2021-06-24 20:43:09 +08:00
|
|
|
if (line == COMPILE_PROCESS_END) {
|
|
|
|
if (mLastIssue) {
|
|
|
|
emit compileIssue(mLastIssue);
|
|
|
|
mLastIssue.reset();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2021-04-24 15:57:45 +08:00
|
|
|
QString inFilePrefix = QString("In file included from ");
|
|
|
|
QString fromPrefix = QString("from ");
|
|
|
|
PCompileIssue issue = std::make_shared<CompileIssue>();
|
|
|
|
issue->type = CompileIssueType::Other;
|
2021-06-24 16:05:19 +08:00
|
|
|
issue->endColumn = -1;
|
2021-04-24 15:57:45 +08:00
|
|
|
if (line.startsWith(inFilePrefix)) {
|
|
|
|
line.remove(0,inFilePrefix.length());
|
|
|
|
issue->filename = getFileNameFromOutputLine(line);
|
|
|
|
issue->line = getLineNumberFromOutputLine(line);
|
2021-05-27 01:05:49 +08:00
|
|
|
if (issue->line > 0)
|
|
|
|
issue->column = getColunmnFromOutputLine(line);
|
2021-04-24 15:57:45 +08:00
|
|
|
issue->type = getIssueTypeFromOutputLine(line);
|
|
|
|
issue->description = inFilePrefix + issue->filename;
|
|
|
|
emit compileIssue(issue);
|
|
|
|
return;
|
|
|
|
} else if(line.startsWith(fromPrefix)) {
|
|
|
|
line.remove(0,fromPrefix.length());
|
|
|
|
issue->filename = getFileNameFromOutputLine(line);
|
|
|
|
issue->line = getLineNumberFromOutputLine(line);
|
2021-05-27 01:05:49 +08:00
|
|
|
if (issue->line > 0)
|
|
|
|
issue->column = getColunmnFromOutputLine(line);
|
2021-04-24 15:57:45 +08:00
|
|
|
issue->type = getIssueTypeFromOutputLine(line);
|
|
|
|
issue->description = " from " + issue->filename;
|
|
|
|
emit compileIssue(issue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore code snippets that GCC produces
|
|
|
|
// they always start with a space
|
|
|
|
if (line.length()>0 && line[0] == ' ') {
|
2021-06-24 16:05:19 +08:00
|
|
|
if (!mLastIssue)
|
|
|
|
return;
|
|
|
|
QString s = line.trimmed();
|
|
|
|
if (s.startsWith('|') && s.indexOf('^')) {
|
|
|
|
int pos = 0;
|
|
|
|
while (pos < s.length()) {
|
|
|
|
if (s[pos]=='^')
|
|
|
|
break;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
if (pos<s.length()) {
|
|
|
|
int i=pos+1;
|
|
|
|
while (i<s.length()) {
|
|
|
|
if (s[i]!='~' && s[i]!='^')
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
mLastIssue->endColumn = mLastIssue->column+i-pos;
|
|
|
|
emit compileIssue(mLastIssue);
|
|
|
|
mLastIssue.reset();
|
|
|
|
}
|
|
|
|
}
|
2021-04-24 15:57:45 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-06-24 16:05:19 +08:00
|
|
|
|
|
|
|
if (mLastIssue) {
|
|
|
|
emit compileIssue(mLastIssue);
|
|
|
|
mLastIssue.reset();
|
|
|
|
}
|
|
|
|
|
2021-04-24 15:57:45 +08:00
|
|
|
// assume regular main.cpp:line:col: message
|
|
|
|
issue->filename = getFileNameFromOutputLine(line);
|
|
|
|
issue->line = getLineNumberFromOutputLine(line);
|
2021-06-24 16:05:19 +08:00
|
|
|
if (issue->line > 0) {
|
2021-05-27 01:05:49 +08:00
|
|
|
issue->column = getColunmnFromOutputLine(line);
|
2021-06-24 22:33:57 +08:00
|
|
|
issue->type = getIssueTypeFromOutputLine(line);
|
|
|
|
if (issue->column<=0 && issue->type == CompileIssueType::Other) {
|
2021-06-24 16:05:19 +08:00
|
|
|
issue->type = CompileIssueType::Error; //linkage error
|
2021-06-24 22:33:57 +08:00
|
|
|
mErrorCount += 1;
|
|
|
|
}
|
2021-06-24 16:05:19 +08:00
|
|
|
} else {
|
|
|
|
issue->column = -1;
|
|
|
|
issue->type = getIssueTypeFromOutputLine(line);
|
|
|
|
}
|
2021-04-24 15:57:45 +08:00
|
|
|
issue->description = line.trimmed();
|
2021-06-24 16:05:19 +08:00
|
|
|
if (issue->line<=0) {
|
|
|
|
emit compileIssue(issue);
|
|
|
|
} else
|
|
|
|
mLastIssue = issue;
|
2021-04-24 15:57:45 +08:00
|
|
|
}
|
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
void Compiler::stopCompile()
|
|
|
|
{
|
|
|
|
mStop = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Compiler::getCharsetArgument(const QByteArray& encoding)
|
|
|
|
{
|
|
|
|
QString result;
|
2021-10-04 00:18:16 +08:00
|
|
|
if (compilerSet()->autoAddCharsetParams() && encoding != ENCODING_ASCII
|
|
|
|
&& compilerSet()->compilerType()!="Clang") {
|
2021-04-20 22:24:33 +08:00
|
|
|
QString encodingName;
|
2022-01-24 11:23:30 +08:00
|
|
|
QString execEncodingName;
|
|
|
|
QString compilerSetExecCharset = compilerSet()->execCharset();
|
2021-09-28 17:17:33 +08:00
|
|
|
QString systemEncodingName=pCharsetInfoManager->getDefaultSystemEncoding();
|
2021-04-20 22:24:33 +08:00
|
|
|
if (encoding == ENCODING_SYSTEM_DEFAULT) {
|
|
|
|
encodingName = systemEncodingName;
|
|
|
|
} else if (encoding == ENCODING_UTF8_BOM) {
|
|
|
|
encodingName = "UTF-8";
|
|
|
|
} else {
|
|
|
|
encodingName = encoding;
|
|
|
|
}
|
2022-02-15 00:01:50 +08:00
|
|
|
if (compilerSetExecCharset == ENCODING_SYSTEM_DEFAULT || compilerSetExecCharset.isEmpty()) {
|
2022-01-24 11:23:30 +08:00
|
|
|
execEncodingName = systemEncodingName;
|
|
|
|
} else {
|
|
|
|
execEncodingName = compilerSetExecCharset;
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
result += QString(" -finput-charset=%1 -fexec-charset=%2")
|
2022-01-24 11:23:30 +08:00
|
|
|
.arg(encodingName, execEncodingName);
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Compiler::getCCompileArguments(bool checkSyntax)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
if (checkSyntax) {
|
|
|
|
result += " -fsyntax-only";
|
|
|
|
}
|
|
|
|
|
2021-09-13 10:48:44 +08:00
|
|
|
for (int i=0;i<compilerSet()->options().size();i++) {
|
|
|
|
PCompilerOption pOption = compilerSet()->options()[i];
|
|
|
|
// consider project specific options for the compiler, else global compiler options
|
|
|
|
if (
|
|
|
|
(mProject && (i < mProject->options().compilerOptions.length()))
|
|
|
|
|| (!mProject && (pOption->value > 0))) {
|
|
|
|
int value;
|
|
|
|
if (mProject) {
|
|
|
|
value = Settings::CompilerSet::charToValue(mProject->options().compilerOptions[i]);
|
|
|
|
} else {
|
|
|
|
value = pOption->value;
|
|
|
|
}
|
|
|
|
if (value > 0 && pOption->isC) {
|
2021-10-25 09:31:58 +08:00
|
|
|
if (checkSyntax && pOption->isLinker)
|
|
|
|
continue;
|
2021-09-13 10:48:44 +08:00
|
|
|
if (pOption->choices.isEmpty()) {
|
|
|
|
result += " " + pOption->setting;
|
|
|
|
} else if (value < pOption->choices.size()) {
|
|
|
|
QStringList nameValue=pOption->choices[value].split('=');
|
|
|
|
if (nameValue.count()==2) {
|
|
|
|
result += " " + pOption->setting + nameValue[1];
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compilerSet()->useCustomCompileParams() && !compilerSet()->customCompileParams().isEmpty()) {
|
2021-10-01 21:16:22 +08:00
|
|
|
result += " "+ parseMacros(compilerSet()->customCompileParams());
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-09-13 19:09:15 +08:00
|
|
|
|
|
|
|
if (mProject) {
|
|
|
|
QString s = mProject->options().compilerCmd;
|
|
|
|
if (!s.isEmpty()) {
|
|
|
|
s.replace("_@@_", " ");
|
2021-10-01 21:16:22 +08:00
|
|
|
result += " "+parseMacros(s);
|
2021-09-13 19:09:15 +08:00
|
|
|
}
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString Compiler::getCppCompileArguments(bool checkSyntax)
|
|
|
|
{
|
2021-09-13 10:48:44 +08:00
|
|
|
return getCCompileArguments(checkSyntax);
|
2021-04-20 22:24:33 +08:00
|
|
|
QString result;
|
|
|
|
if (checkSyntax) {
|
|
|
|
result += " -fsyntax-only";
|
|
|
|
}
|
|
|
|
|
2021-09-13 19:09:15 +08:00
|
|
|
for (int i=0;i<compilerSet()->options().size();i++) {
|
|
|
|
PCompilerOption pOption = compilerSet()->options()[i];
|
|
|
|
// consider project specific options for the compiler, else global compiler options
|
|
|
|
if (
|
|
|
|
(mProject && (i < mProject->options().compilerOptions.length()))
|
|
|
|
|| (!mProject && (pOption->value > 0))) {
|
|
|
|
int value;
|
|
|
|
if (mProject) {
|
|
|
|
value = Settings::CompilerSet::charToValue(mProject->options().compilerOptions[i]);
|
|
|
|
} else {
|
|
|
|
value = pOption->value;
|
|
|
|
}
|
|
|
|
if (value > 0 && pOption->isCpp) {
|
2021-10-25 09:31:58 +08:00
|
|
|
if (checkSyntax && pOption->isLinker)
|
|
|
|
continue;
|
2021-09-13 19:09:15 +08:00
|
|
|
if (pOption->choices.isEmpty()) {
|
|
|
|
result += " " + pOption->setting;
|
|
|
|
} else if (value < pOption->choices.size()) {
|
|
|
|
QStringList nameValue=pOption->choices[value].split('=');
|
|
|
|
if (nameValue.count()==2) {
|
|
|
|
result += " " + pOption->setting + nameValue[1];
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compilerSet()->useCustomCompileParams() && !compilerSet()->customCompileParams().isEmpty()) {
|
2021-10-01 21:16:22 +08:00
|
|
|
result += " "+ parseMacros(compilerSet()->customCompileParams());
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-09-13 19:09:15 +08:00
|
|
|
if (mProject) {
|
|
|
|
QString s = mProject->options().cppCompilerCmd;
|
|
|
|
if (!s.isEmpty()) {
|
|
|
|
s.replace("_@@_", " ");
|
2021-10-01 21:16:22 +08:00
|
|
|
result += " "+parseMacros(s);
|
2021-09-13 19:09:15 +08:00
|
|
|
}
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString Compiler::getCIncludeArguments()
|
|
|
|
{
|
|
|
|
QString result;
|
2021-08-29 10:14:07 +08:00
|
|
|
foreach (const QString& folder,compilerSet()->CIncludeDirs()) {
|
2021-04-20 22:24:33 +08:00
|
|
|
result += QString(" -I\"%1\"").arg(folder);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-12 22:45:00 +08:00
|
|
|
QString Compiler::getProjectIncludeArguments()
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
if (mProject) {
|
|
|
|
foreach (const QString& folder,mProject->options().includes) {
|
|
|
|
result += QString(" -I\"%1\"").arg(folder);
|
|
|
|
}
|
2021-09-13 22:45:50 +08:00
|
|
|
// result += QString(" -I\"%1\"").arg(extractFilePath(mProject->filename()));
|
2021-09-12 22:45:00 +08:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
QString Compiler::getCppIncludeArguments()
|
|
|
|
{
|
|
|
|
QString result;
|
2021-08-29 10:14:07 +08:00
|
|
|
foreach (const QString& folder,compilerSet()->CppIncludeDirs()) {
|
2021-04-20 22:24:33 +08:00
|
|
|
result += QString(" -I\"%1\"").arg(folder);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-04 14:06:48 +08:00
|
|
|
QString Compiler::getLibraryArguments(FileType fileType)
|
2021-04-20 22:24:33 +08:00
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
|
2021-09-13 19:09:15 +08:00
|
|
|
//Add libraries
|
2021-08-29 10:14:07 +08:00
|
|
|
foreach (const QString& folder, compilerSet()->libDirs()) {
|
2021-04-20 22:24:33 +08:00
|
|
|
result += QString(" -L\"%1\"").arg(folder);
|
|
|
|
}
|
|
|
|
|
2021-09-13 19:09:15 +08:00
|
|
|
//add libs added via project
|
|
|
|
if (mProject) {
|
|
|
|
foreach (const QString& folder, mProject->options().libs){
|
|
|
|
result += QString(" -L\"%1\"").arg(folder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-04 11:37:04 +08:00
|
|
|
//Add auto links
|
|
|
|
// is file and auto link enabled
|
2021-09-04 19:27:44 +08:00
|
|
|
if (pSettings->editor().enableAutolink() && (fileType == FileType::CSource ||
|
|
|
|
fileType == FileType::CppSource)){
|
2021-09-04 11:37:04 +08:00
|
|
|
Editor* editor = pMainWindow->editorList()->getEditor();
|
|
|
|
if (editor) {
|
|
|
|
PCppParser parser = editor->parser();
|
|
|
|
if (parser) {
|
|
|
|
int waitCount = 0;
|
|
|
|
//wait parsing ends, at most 1 second
|
|
|
|
while(parser->parsing()) {
|
|
|
|
if (waitCount>0)
|
|
|
|
break;
|
|
|
|
waitCount++;
|
|
|
|
QThread::msleep(100);
|
|
|
|
QApplication *app=dynamic_cast<QApplication*>(
|
|
|
|
QApplication::instance());
|
|
|
|
app->processEvents();
|
|
|
|
}
|
2021-09-04 14:06:48 +08:00
|
|
|
QSet<QString> parsedFiles;
|
|
|
|
result += parseFileIncludesForAutolink(
|
|
|
|
editor->filename(),
|
|
|
|
parsedFiles,
|
|
|
|
parser);
|
2021-09-04 11:37:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-09-13 19:09:15 +08:00
|
|
|
//add compiler set link options
|
|
|
|
//options like "-static" must be added after "-lxxx"
|
|
|
|
for (int i=0;i<compilerSet()->options().size();i++) {
|
|
|
|
PCompilerOption pOption = compilerSet()->options()[i];
|
|
|
|
// consider project specific options for the compiler, else global compiler options
|
|
|
|
if (
|
|
|
|
(mProject && (i < mProject->options().compilerOptions.length()))
|
|
|
|
|| (!mProject && (pOption->value > 0))) {
|
|
|
|
int value;
|
|
|
|
if (mProject) {
|
|
|
|
value = Settings::CompilerSet::charToValue(mProject->options().compilerOptions[i]);
|
|
|
|
} else {
|
|
|
|
value = pOption->value;
|
|
|
|
}
|
|
|
|
if (value > 0 && pOption->isLinker) {
|
|
|
|
if (pOption->choices.isEmpty()) {
|
|
|
|
result += " " + pOption->setting;
|
|
|
|
} else if (value < pOption->choices.size()) {
|
|
|
|
QStringList nameValue=pOption->choices[value].split('=');
|
|
|
|
if (nameValue.count()==2) {
|
|
|
|
result += " " + pOption->setting + nameValue[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-04 11:37:04 +08:00
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
// Add global compiler linker extras
|
|
|
|
if (compilerSet()->useCustomLinkParams() && !compilerSet()->customLinkParams().isEmpty()) {
|
2021-12-19 16:54:31 +08:00
|
|
|
result += " "+compilerSet()->customLinkParams();
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
|
2021-09-13 19:09:15 +08:00
|
|
|
if (mProject) {
|
|
|
|
if (mProject->options().type == ProjectType::GUI) {
|
|
|
|
result += " -mwindows";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mProject->options().linkerCmd.isEmpty()) {
|
2021-09-13 22:45:50 +08:00
|
|
|
QString s = mProject->options().linkerCmd;
|
|
|
|
if (!s.isEmpty()) {
|
|
|
|
s.replace("_@@_", " ");
|
|
|
|
result += " "+s;
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-09-13 19:09:15 +08:00
|
|
|
if (mProject->options().staticLink)
|
|
|
|
result += " -static";
|
|
|
|
} else if (compilerSet()->staticLink()) {
|
2021-09-02 21:01:23 +08:00
|
|
|
result += " -static";
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-09-04 11:37:04 +08:00
|
|
|
QString Compiler::parseFileIncludesForAutolink(
|
|
|
|
const QString &filename,
|
2021-10-25 12:33:02 +08:00
|
|
|
QSet<QString>& parsedFiles,
|
2021-09-04 11:37:04 +08:00
|
|
|
PCppParser& parser)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
if (parsedFiles.contains(filename))
|
|
|
|
return result;
|
|
|
|
parsedFiles.insert(filename);
|
2022-01-24 20:59:02 +08:00
|
|
|
PAutolink autolink = pAutolinkManager->getLink(filename);
|
2021-09-04 11:37:04 +08:00
|
|
|
if (autolink) {
|
|
|
|
result += ' '+autolink->linkOption;
|
|
|
|
}
|
|
|
|
QSet<QString> includedFiles = parser->getFileDirectIncludes(filename);
|
|
|
|
foreach (const QString& includeFilename, includedFiles) {
|
|
|
|
result += parseFileIncludesForAutolink(
|
|
|
|
includeFilename,
|
|
|
|
parsedFiles,
|
|
|
|
parser);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
void Compiler::runCommand(const QString &cmd, const QString &arguments, const QString &workingDir, const QString& inputText)
|
|
|
|
{
|
|
|
|
QProcess process;
|
|
|
|
mStop = false;
|
2021-06-21 11:21:26 +08:00
|
|
|
bool errorOccurred = false;
|
2021-04-20 22:24:33 +08:00
|
|
|
process.setProgram(cmd);
|
2021-09-13 22:45:50 +08:00
|
|
|
QString cmdDir = extractFileDir(cmd);
|
2021-12-16 17:56:42 +08:00
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
2021-09-13 22:45:50 +08:00
|
|
|
if (!cmdDir.isEmpty()) {
|
|
|
|
QString path = env.value("PATH");
|
2021-09-14 12:10:43 +08:00
|
|
|
if (path.isEmpty()) {
|
|
|
|
path = cmdDir;
|
|
|
|
} else {
|
|
|
|
path = cmdDir + PATH_SEPARATOR + path;
|
|
|
|
}
|
2021-09-13 22:45:50 +08:00
|
|
|
env.insert("PATH",path);
|
|
|
|
}
|
2021-12-16 17:56:42 +08:00
|
|
|
env.insert("LANG","en");
|
2022-02-11 14:04:18 +08:00
|
|
|
env.insert("LDFLAGS","-Wl,--stack,12582912");
|
|
|
|
env.insert("CFLAGS","");
|
|
|
|
env.insert("CXXFLAGS","");
|
2021-12-16 17:56:42 +08:00
|
|
|
process.setProcessEnvironment(env);
|
2022-01-04 16:50:54 +08:00
|
|
|
process.setArguments(splitProcessCommand(arguments));
|
2021-04-20 22:24:33 +08:00
|
|
|
process.setWorkingDirectory(workingDir);
|
|
|
|
|
2021-06-21 11:21:26 +08:00
|
|
|
process.connect(&process, &QProcess::errorOccurred,
|
|
|
|
[&](){
|
|
|
|
errorOccurred= true;
|
|
|
|
});
|
2021-04-20 22:24:33 +08:00
|
|
|
process.connect(&process, &QProcess::readyReadStandardError,[&process,this](){
|
2021-05-27 01:05:49 +08:00
|
|
|
this->error(QString::fromLocal8Bit( process.readAllStandardError()));
|
2021-04-20 22:24:33 +08:00
|
|
|
});
|
|
|
|
process.connect(&process, &QProcess::readyReadStandardOutput,[&process,this](){
|
2021-05-27 01:05:49 +08:00
|
|
|
this->log(QString::fromLocal8Bit( process.readAllStandardOutput()));
|
2021-04-20 22:24:33 +08:00
|
|
|
});
|
2021-08-29 10:14:07 +08:00
|
|
|
process.connect(&process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),[this](){
|
2021-06-24 20:43:09 +08:00
|
|
|
this->error(COMPILE_PROCESS_END);
|
|
|
|
});
|
2021-04-20 22:24:33 +08:00
|
|
|
process.start();
|
2021-06-24 20:43:09 +08:00
|
|
|
process.waitForStarted(5000);
|
2021-04-20 22:24:33 +08:00
|
|
|
if (!inputText.isEmpty())
|
2021-06-24 20:43:09 +08:00
|
|
|
process.write(inputText.toLocal8Bit());
|
2021-04-20 22:24:33 +08:00
|
|
|
process.closeWriteChannel();
|
|
|
|
while (true) {
|
|
|
|
process.waitForFinished(1000);
|
|
|
|
if (process.state()!=QProcess::Running) {
|
|
|
|
break;
|
|
|
|
}
|
2021-06-25 12:40:11 +08:00
|
|
|
if (mStop) {
|
|
|
|
process.terminate();
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-06-25 12:40:11 +08:00
|
|
|
if (errorOccurred)
|
|
|
|
break;
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
2021-06-21 11:21:26 +08:00
|
|
|
if (errorOccurred) {
|
|
|
|
switch (process.error()) {
|
|
|
|
case QProcess::FailedToStart:
|
2021-09-04 14:06:48 +08:00
|
|
|
throw CompileError(tr("The compiler process for '%1' failed to start.").arg(mFilename));
|
2021-06-21 11:21:26 +08:00
|
|
|
break;
|
|
|
|
case QProcess::Crashed:
|
2021-06-25 12:40:11 +08:00
|
|
|
if (!mStop)
|
|
|
|
throw CompileError(tr("The compiler process crashed after starting successfully."));
|
2021-06-21 11:21:26 +08:00
|
|
|
break;
|
|
|
|
case QProcess::Timedout:
|
|
|
|
throw CompileError(tr("The last waitFor...() function timed out."));
|
|
|
|
break;
|
|
|
|
case QProcess::WriteError:
|
|
|
|
throw CompileError(tr("An error occurred when attempting to write to the compiler process."));
|
|
|
|
break;
|
|
|
|
case QProcess::ReadError:
|
|
|
|
throw CompileError(tr("An error occurred when attempting to read from the compiler process."));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw CompileError(tr("An unknown error occurred."));
|
|
|
|
}
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|
|
|
|
|
2021-09-12 22:45:00 +08:00
|
|
|
const std::shared_ptr<Project> &Compiler::project() const
|
|
|
|
{
|
|
|
|
return mProject;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compiler::setProject(const std::shared_ptr<Project> &newProject)
|
|
|
|
{
|
|
|
|
mProject = newProject;
|
|
|
|
}
|
|
|
|
|
2021-06-25 12:40:11 +08:00
|
|
|
bool Compiler::isRebuild() const
|
|
|
|
{
|
|
|
|
return mRebuild;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compiler::setRebuild(bool isRebuild)
|
|
|
|
{
|
|
|
|
mRebuild = isRebuild;
|
|
|
|
}
|
|
|
|
|
2021-04-20 22:24:33 +08:00
|
|
|
void Compiler::log(const QString &msg)
|
|
|
|
{
|
|
|
|
emit compileOutput(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compiler::error(const QString &msg)
|
|
|
|
{
|
2021-06-24 20:43:09 +08:00
|
|
|
if (msg != COMPILE_PROCESS_END)
|
|
|
|
emit compileOutput(msg);
|
2021-04-24 15:57:45 +08:00
|
|
|
for (QString& s:msg.split("\n")) {
|
|
|
|
if (!s.isEmpty())
|
|
|
|
processOutput(s);
|
|
|
|
}
|
2021-04-20 22:24:33 +08:00
|
|
|
}
|