work save: compile & run project

This commit is contained in:
royqh1979@gmail.com 2021-09-13 22:45:50 +08:00
parent c72afb3558
commit 6335991ccf
17 changed files with 321 additions and 30 deletions

View File

@ -46,7 +46,7 @@ void Compiler::run()
mWarningCount = 0;
QElapsedTimer timer;
timer.start();
runCommand(mCompiler, mArguments, QFileInfo(mCompiler).absolutePath(), pipedText());
runCommand(mCompiler, mArguments, mDirectory, pipedText());
log("");
log(tr("Compile Result:"));
log("------------------");
@ -382,7 +382,7 @@ QString Compiler::getProjectIncludeArguments()
foreach (const QString& folder,mProject->options().includes) {
result += QString(" -I\"%1\"").arg(folder);
}
result += QString(" -I\"%1\"").arg(extractFilePath(mProject->filename()));
// result += QString(" -I\"%1\"").arg(extractFilePath(mProject->filename()));
}
return result;
}
@ -479,9 +479,12 @@ QString Compiler::getLibraryArguments(FileType fileType)
}
if (!mProject->options().linkerCmd.isEmpty()) {
result += " " + mProject->options().linkerCmd;
QString s = mProject->options().linkerCmd;
if (!s.isEmpty()) {
s.replace("_@@_", " ");
result += " "+s;
}
}
if (mProject->options().staticLink)
result += " -static";
} else if (compilerSet()->staticLink()) {
@ -520,6 +523,14 @@ void Compiler::runCommand(const QString &cmd, const QString &arguments, const Q
mStop = false;
bool errorOccurred = false;
process.setProgram(cmd);
QString cmdDir = extractFileDir(cmd);
if (!cmdDir.isEmpty()) {
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH");
path = cmdDir + ';' + path;
env.insert("PATH",path);
process.setProcessEnvironment(env);
}
process.setArguments(QProcess::splitCommand(arguments));
process.setWorkingDirectory(workingDir);

View File

@ -73,6 +73,7 @@ protected:
int mWarningCount;
PCompileIssue mLastIssue;
QString mFilename;
QString mDirectory;
bool mRebuild;
std::shared_ptr<Project> mProject;

View File

@ -7,6 +7,7 @@
#include "utils.h"
#include "../settings.h"
#include <QMessageBox>
#include "projectcompiler.h"
CompilerManager::CompilerManager(QObject *parent) : QObject(parent)
{
@ -61,6 +62,32 @@ void CompilerManager::compile(const QString& filename, const QByteArray& encodin
}
}
void CompilerManager::compileProject(std::shared_ptr<Project> project, bool rebuild, bool silent,bool onlyCheckSyntax)
{
if (!pSettings->compilerSets().defaultSet()) {
QMessageBox::critical(pMainWindow,
tr("No compiler set"),
tr("No compiler set is configured.")+tr("Can't start debugging."));
return;
}
{
QMutexLocker locker(&mCompileMutex);
if (mCompiler!=nullptr) {
return;
}
mCompileErrorCount = 0;
mCompiler = new ProjectCompiler(project,silent,onlyCheckSyntax);
mCompiler->setRebuild(rebuild);
connect(mCompiler, &Compiler::compileFinished, this ,&CompilerManager::onCompileFinished);
connect(mCompiler, &Compiler::compileIssue, this, &CompilerManager::onCompileIssue);
connect(mCompiler, &Compiler::compileFinished, pMainWindow, &MainWindow::onCompileFinished);
connect(mCompiler, &Compiler::compileOutput, pMainWindow, &MainWindow::onCompileLog);
connect(mCompiler, &Compiler::compileIssue, pMainWindow, &MainWindow::onCompileIssue);
connect(mCompiler, &Compiler::compileErrorOccured, pMainWindow, &MainWindow::onCompileErrorOccured);
mCompiler->start();
}
}
void CompilerManager::checkSyntax(const QString &filename, const QString &content, bool isAscii, std::shared_ptr<Project> project)
{
if (!pSettings->compilerSets().defaultSet()) {

View File

@ -20,7 +20,7 @@ public:
bool running();
void compile(const QString& filename, const QByteArray& encoding, bool rebuild, bool silent=false,bool onlyCheckSyntax=false);
void compileProject(std::shared_ptr<Project> project);
void compileProject(std::shared_ptr<Project> project, bool rebuild, bool silent=false,bool onlyCheckSyntax=false);
void checkSyntax(const QString&filename, const QString& content, bool isAscii, std::shared_ptr<Project> project);
void run(const QString& filename, const QString& arguments, const QString& workDir);
void stopRun();

View File

@ -69,6 +69,7 @@ bool FileCompiler::prepareForCompile()
log("------------------");
log(tr("%1 Compiler: %2").arg(strFileType).arg(mCompiler));
log(tr("Command: %1 %2").arg(QFileInfo(mCompiler).fileName()).arg(mArguments));
mDirectory = extractFileDir(mFilename);
return true;
}

View File

@ -1,7 +1,9 @@
#include "projectcompiler.h"
#include "project.h"
#include "../project.h"
#include "compilermanager.h"
#include "../systemconsts.h"
#include "../platform.h"
#include "../editor.h"
#include <QDir>
@ -36,7 +38,6 @@ void ProjectCompiler::createStandardMakeFile()
file.write("$(BIN): $(OBJ)\n");
if (!mOnlyCheckSyntax) {
if (mProject->options().useGPP) {
writeln(file,"$(BIN): $(OBJ)");
writeln(file,"\t$(CPP) $(LINKOBJ) -o \"$(BIN)\" $(LIBS)");
} else
writeln(file,"\t$(CC) $(LINKOBJ) -o \"$(BIN)\" $(LIBS)");
@ -44,6 +45,33 @@ void ProjectCompiler::createStandardMakeFile()
writeMakeObjFilesRules(file);
}
void ProjectCompiler::createStaticMakeFile()
{
QFile file(mProject->makeFileName());
newMakeFile(file);
file.write("$(BIN): $(LINKOBJ)");
if (!mOnlyCheckSyntax) {
writeln(file,"\tar r $(BIN) $(LINKOBJ)");
writeln(file,"\tranlib $(BIN)");
}
writeMakeObjFilesRules(file);
}
void ProjectCompiler::createDynamicMakeFile()
{
QFile file(mProject->makeFileName());
newMakeFile(file);
file.write("$(BIN): $(LINKOBJ)");
if (!mOnlyCheckSyntax) {
if (mProject->options().useGPP) {
file.write("\t$(CPP) -mdll $(LINKOBJ) -o \"$(BIN)\" $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)");
} else {
file.write("\t$(CC) -mdll $(LINKOBJ) -o \"$(BIN)\" $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)");
}
}
writeMakeObjFilesRules(file);
}
void ProjectCompiler::newMakeFile(QFile& file)
{
// Create OBJ output directory
@ -58,7 +86,7 @@ void ProjectCompiler::newMakeFile(QFile& file)
// Create the actual file
if (!file.open(QFile::WriteOnly | QFile::Truncate))
throw CompileError(tr("Can't open '%1' for write!").arg(mProject->makeFileName());
throw CompileError(tr("Can't open '%1' for write!").arg(mProject->makeFileName()));
// Write header
writeMakeHeader(file);
@ -152,9 +180,9 @@ void ProjectCompiler::writeMakeDefines(QFile &file)
cCompileArguments += " -D__DEBUG__";
cppCompileArguments+= " -D__DEBUG__";
}
writeln(file,"CPP = " + compilerSet()->cppCompiler());
writeln(file,"CC = " + compilerSet()->CCompiler());
writeln(file,"WINDRES = " + compilerSet()->resourceCompiler());
writeln(file,"CPP = " + extractFileName(compilerSet()->cppCompiler()));
writeln(file,"CC = " + extractFileName(compilerSet()->CCompiler()));
writeln(file,"WINDRES = " + extractFileName(compilerSet()->resourceCompiler()));
if (!ObjResFile.isEmpty()) {
writeln(file,"RES = " + genMakePath1(ObjResFile));
writeln(file,"OBJ = " + Objects + " $(RES)");
@ -198,6 +226,181 @@ void ProjectCompiler::writeMakeDefines(QFile &file)
writeln(file);
}
void ProjectCompiler::writeMakeTarget(QFile &file)
{
if (mOnlyCheckSyntax)
writeln(file, ".PHONY: all all-before all-after clean clean-custom $(OBJ) $(BIN)");
else
writeln(file, ".PHONY: all all-before all-after clean clean-custom");
writeln(file);
writeln(file, "all: all-before $(BIN) all-after");
writeln(file);
if (mProject->options().usePrecompiledHeader) {
writeln(file, "$(PCH) : $(PCH_H)");
writeln(file, " $(CPP) -x c++-header \"$(PCH_H)\" -o \"$(PCH)\" $(CXXFLAGS)");
writeln(file);
}
}
void ProjectCompiler::writeMakeIncludes(QFile &file)
{
foreach(const QString& s, mProject->options().makeIncludes) {
writeln(file, "include " + genMakePath1(s));
}
if (!mProject->options().makeIncludes.isEmpty()) {
writeln(file);
}
}
void ProjectCompiler::writeMakeClean(QFile &file)
{
writeln(file, "clean: clean-custom");
if (mProject->options().type == ProjectType::DynamicLib)
writeln(file, "\t${RM} $(OBJ) $(BIN) $(DEF) $(STATIC)");
else
writeln(file, "\t${RM} $(OBJ) $(BIN)");
writeln(file);
}
void ProjectCompiler::writeMakeObjFilesRules(QFile &file)
{
PCppParser parser = mProject->cppParser();
QString precompileStr;
if (mProject->options().usePrecompiledHeader)
precompileStr = " $(PCH) ";
for (int i = 0;i<mProject->units().count();i++) {
PProjectUnit unit = mProject->units()[i];
FileType fileType = getFileType(unit->fileName());
// Only process source files
if (fileType!=FileType::CSource && fileType!=FileType::CppSource)
continue;
QString shortFileName = extractRelativePath(mProject->makeFileName(),unit->fileName());
writeln(file);
QString objStr=genMakePath2(shortFileName);
// if we have scanned it, use scanned info
if (parser && parser->scannedFiles().contains(unit->fileName())) {
QSet<QString> fileIncludes = parser->getFileIncludes(unit->fileName());
foreach (const QString& headerName, fileIncludes) {
if (headerName == unit->fileName())
continue;
if (!parser->isSystemHeaderFile(headerName)
&& ! parser->isProjectHeaderFile(headerName)) {
objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),headerName));
}
}
} else {
foreach (const PProjectUnit& u, mProject->units()) {
FileType fileType = getFileType(u->fileName());
if (fileType == FileType::CHeader || fileType==FileType::CppHeader)
objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),u->fileName()));
}
}
QString ObjFileName;
if (!mProject->options().objectOutput.isEmpty()) {
ObjFileName = includeTrailingPathDelimiter(mProject->options().objectOutput) +
extractFileName(unit->fileName());
ObjFileName = genMakePath1(extractRelativePath(mProject->makeFileName(), changeFileExt(ObjFileName, OBJ_EXT)));
if (!extractFileDir(ObjFileName).isEmpty()) {
objStr = genMakePath2(includeTrailingPathDelimiter(extractFileDir(ObjFileName))) + objStr;
}
} else {
ObjFileName = genMakePath1(changeFileExt(shortFileName, OBJ_EXT));
}
objStr = ObjFileName + ": "+objStr+precompileStr;
writeln(file,objStr);
// Write custom build command
if (unit->overrideBuildCmd() && !unit->buildCmd().isEmpty()) {
QString BuildCmd = unit->buildCmd();
BuildCmd.replace("<CRTAB>", "\n\t");
writeln(file, '\t' + BuildCmd);
// Or roll our own
} else {
QString encodingStr;
if (mProject->options().addCharset) {
if (unit->encoding() == ENCODING_AUTO_DETECT) {
if (unit->editor())
encodingStr = QString(" -finput-charset=%1 -fexec-charset=%2")
.arg(unit->editor()->fileEncoding(),getDefaultSystemEncoding());
} else {
encodingStr = QString(" -finput-charset=%1 -fexec-charset=%2")
.arg(unit->encoding(),getDefaultSystemEncoding());
}
}
if (mOnlyCheckSyntax) {
if (unit->compileCpp())
writeln(file, "\t$(CPP) -c " + genMakePath1(shortFileName) + " $(CXXFLAGS) " + encodingStr);
else
writeln(file, "\t(CC) -c " + genMakePath1(shortFileName) + " $(CFLAGS) " + encodingStr);
} else {
if (unit->compileCpp())
writeln(file, "\t$(CPP) -c " + genMakePath1(shortFileName) + " -o " + ObjFileName + " $(CXXFLAGS) " + encodingStr);
else
writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " -o " + ObjFileName + " $(CFLAGS) " + encodingStr);
}
}
}
if (!mProject->options().privateResource.isEmpty()) {
// Concatenate all resource include directories
QString ResIncludes(" ");
for (int i=0;i<mProject->options().resourceIncludes.count();i++) {
QString filename = mProject->options().resourceIncludes[i];
if (!filename.isEmpty())
ResIncludes = ResIncludes + " --include-dir " + genMakePath1(filename);
}
QString ResFiles;
// Concatenate all resource filenames (not created when syntax checking)
if (!mOnlyCheckSyntax) {
foreach(const PProjectUnit& unit, mProject->units()) {
if (getFileType(unit->fileName())!=FileType::WindowsResourceSource)
continue;
if (QFile(unit->fileName()).exists()) {
QString ResFile = extractRelativePath(mProject->makeFileName(), unit->fileName());
ResFiles = ResFiles + genMakePath2(ResFile) + ' ';
}
}
ResFiles = ResFiles.trimmed();
}
// Determine resource output file
QString ObjFileName;
if (!mProject->options().objectOutput.isEmpty()) {
ObjFileName = includeTrailingPathDelimiter(mProject->options().objectOutput) +
changeFileExt(mProject->options().privateResource, RES_EXT);
} else {
ObjFileName = changeFileExt(mProject->options().privateResource, RES_EXT);
}
ObjFileName = genMakePath1(extractRelativePath(mProject->filename(), ObjFileName));
QString PrivResName = genMakePath1(extractRelativePath(mProject->filename(), mProject->options().privateResource));
// Build final cmd
QString WindresArgs;
if (getCCompileArguments(mOnlyCheckSyntax).contains("-m32"))
WindresArgs = " -F pe-i386";
if (mOnlyCheckSyntax) {
writeln(file);
writeln(file, ObjFileName + ':');
writeln(file, "\t$(WINDRES) -i " + PrivResName + WindresArgs + " --input-format=rc -o nul -O coff" + ResIncludes);
} else {
writeln(file);
writeln(file, ObjFileName + ": " + PrivResName + ' ' + ResFiles);
writeln(file, "\t$(WINDRES) -i " + PrivResName + WindresArgs + " --input-format=rc -o " + ObjFileName + " -O coff"
+ ResIncludes);
}
writeln(file);
}
}
void ProjectCompiler::writeln(QFile &file, const QString &s)
{
if (!s.isEmpty())
@ -231,8 +434,21 @@ bool ProjectCompiler::prepareForCompile()
mCompiler = compilerSet()->make();
if (mRebuild) {
mArguments = QString("-f \"%1\" clean all").arg(mProject->makeFileName());
mArguments = QString("-f \"%1\" clean all").arg(extractRelativePath(
mProject->directory(),
mProject->makeFileName()));
} else {
mArguments = QString("-f \"%1\" all").arg(mProject->makeFileName());
mArguments = QString("-f \"%1\" all").arg(extractRelativePath(
mProject->directory(),
mProject->makeFileName()));
}
mDirectory = mProject->directory();
log(tr("Processing makefile:"));
log("--------");
log(tr("- makefile processer: %1").arg(mCompiler));
log(tr("- Command: %1 %2").arg(mCompiler).arg(mArguments));
log("");
return true;
}

View File

@ -14,10 +14,15 @@ public:
private:
void buildMakeFile();
void createStandardMakeFile();
void createStaticMakeFile();
void createDynamicMakeFile();
void newMakeFile(QFile& file);
void writeMakeHeader(QFile& file);
void writeMakeDefines(QFile& file);
void writeMakeTarget(QFile& file);
void writeMakeIncludes(QFile& file);
void writeMakeClean(QFile& file);
void writeMakeObjFilesRules(QFile& file);
void writeln(QFile& file, const QString& s="");
// Compiler interface
protected:

View File

@ -57,6 +57,7 @@ bool StdinCompiler::prepareForCompile()
log("------------------");
log(tr("%1 Compiler: %2").arg(strFileType).arg(mCompiler));
log(tr("Command: %1 %2").arg(QFileInfo(mCompiler).fileName()).arg(mArguments));
mDirectory = extractFileDir(mFilename);
return true;
}

View File

@ -62,6 +62,7 @@ Editor::Editor(QWidget *parent, const QString& filename,
mParentPageControl(parentPageControl),
mInProject(inProject),
mIsNew(isNew),
mSyntaxIssues(),
mSyntaxErrorColor(QColorConstants::Red),
mSyntaxWarningColor("orange"),
mLineCount(0),

View File

@ -785,21 +785,27 @@ bool MainWindow::compile(bool rebuild)
if (target == CompileTarget::Project) {
if (!mProject->saveUnits())
return false;
updateAppTitle();
// Check if saves have been succesful
for (int i=0; i<mEditorList->pageCount();i++) {
Editor * e= (*(mEditorList))[i];
if (e->inProject() && e->modified())
return false;
}
ui->tableIssues->clearIssues();
// Increment build number automagically
if (mProject->options().versionInfo.autoIncBuildNr) {
mProject->incrementBuildNumber();
}
mProject->buildPrivateResource();
mCompilerManager->compileProject(mProject);
if (mCompileSuccessionTask) {
mCompileSuccessionTask->filename = mProject->executable();
}
updateCompileActions();
openCloseBottomPanel(true);
ui->tabMessages->setCurrentWidget(ui->tabCompilerOutput);
mCompilerManager->compileProject(mProject,rebuild);
updateAppTitle();
} else {
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
@ -814,8 +820,8 @@ bool MainWindow::compile(bool rebuild)
updateCompileActions();
openCloseBottomPanel(true);
ui->tabMessages->setCurrentWidget(ui->tabCompilerOutput);
updateAppTitle();
mCompilerManager->compile(editor->filename(),editor->fileEncoding(),rebuild);
updateAppTitle();
return true;
}
}
@ -878,14 +884,19 @@ void MainWindow::runExecutable(const QString &exeName,const QString &filename)
void MainWindow::runExecutable()
{
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
if (editor->modified()) {
if (!editor->save(false,false))
return;
CompileTarget target =getCompileTarget();
if (target == CompileTarget::Project) {
runExecutable(mProject->executable(),mProject->filename());
} else {
Editor * editor = mEditorList->getEditor();
if (editor != NULL ) {
if (editor->modified()) {
if (!editor->save(false,false))
return;
}
QString exeName= getCompiledExecutableName(editor->filename());
runExecutable(exeName,editor->filename());
}
QString exeName= getCompiledExecutableName(editor->filename());
runExecutable(exeName,editor->filename());
}
}

View File

@ -825,6 +825,11 @@ void CppParser::unFreeze()
mLockCount--;
}
QSet<QString> CppParser::scannedFiles()
{
return mPreprocessor.scannedFiles();
}
QString CppParser::getScopePrefix(const PStatement& statement){
switch (statement->classScope) {
case StatementClassScope::scsPublic:

View File

@ -77,6 +77,7 @@ public:
bool parsing() const;
void reset();
void unFreeze(); // UnFree/UnLock (reparse while searching)
QSet<QString> scannedFiles();

View File

@ -5,6 +5,7 @@
#include <QFileInfo>
#include <QDebug>
#include <QGlobalStatic>
#include "../utils.h"
QStringList CppDirectives;
QStringList JavadocTags;
@ -368,9 +369,11 @@ bool isSystemHeaderFile(const QString &fileName, const QSet<QString> &includePat
QFileInfo info(fileName);
if (info.exists()) { // full file name
QDir dir = info.dir();
QString absPath = dir.absolutePath();
if (includePaths.contains(absPath))
return true;
QString absPath = excludeTrailingPathDelimiter(dir.absolutePath());
foreach (const QString& incPath, includePaths) {
if (absPath.startsWith(incPath))
return true;
}
}
} else {
//check if it's in the include dir

View File

@ -12,7 +12,7 @@
#define MAKE_PROGRAM "mingw32-make.exe"
#define WINDRES_PROGRAM "windres.exe"
#define GPROF_PROGRAM "gprof.exe"
#define CLEAN_PROGRAM "del /q"
#define CLEAN_PROGRAM "del /q /f"
#define CPP_PROGRAM "cpp.exe"
#else
#error "Only support windows now!"

View File

@ -647,7 +647,8 @@ QString genMakePath(const QString &fileName, bool escapeSpaces, bool encloseInQu
result.replace(' ',"\\ ");
}
if (encloseInQuotes)
result = '"'+result+'"';
if (result.contains(' '))
result = '"'+result+'"';
return result;
}
@ -697,3 +698,8 @@ bool isReadOnly(const QString &filename)
{
return QFile(filename).isWritable();
}
QString extractFileDir(const QString &fileName)
{
return extractFilePath(fileName);
}

View File

@ -164,6 +164,7 @@ bool findComplement(const QString& s,
void logToFile(const QString& s, const QString& filename, bool append=true);
QString extractFileName(const QString& fileName);
QString extractFileDir(const QString& fileName);
QString extractFilePath(const QString& filePath);
QString extractAbsoluteFilePath(const QString& filePath);
QString getSizeString(int size);

View File

@ -98,7 +98,8 @@ void IssuesModel::clearIssues()
}
foreach (const QString& filename, issueFiles) {
Editor *e=pMainWindow->editorList()->getOpenedEditorByFilename(filename);
e->clearSyntaxIssues();
if (e)
e->clearSyntaxIssues();
}
}