- enhancement: Support SDCC Project.

This commit is contained in:
Roy Qu 2023-08-17 19:24:49 +08:00
parent dd5640d334
commit 6b2a800d37
24 changed files with 624 additions and 83 deletions

View File

@ -33,6 +33,7 @@ Red Panda C++ Version 2.24
- fix: Can't suggest header filename starting with numbers. - fix: Can't suggest header filename starting with numbers.
- enhancement: Better layout for compiler options page. - enhancement: Better layout for compiler options page.
- enhancement: False branches are displayed as comments. - enhancement: False branches are displayed as comments.
- enhancement: Support SDCC Project.
Red Panda C++ Version 2.23 Red Panda C++ Version 2.23

View File

@ -397,10 +397,12 @@ ENABLE_SDCC {
DEFINES += ENABLE_SDCC DEFINES += ENABLE_SDCC
SOURCES += \ SOURCES += \
compiler/sdccfilecompiler.cpp compiler/sdccfilecompiler.cpp \
compiler/sdccprojectcompiler.cpp
HEADERS += \ HEADERS += \
compiler/sdccfilecompiler.h compiler/sdccfilecompiler.h \
compiler/sdccprojectcompiler.h
} }

View File

@ -16,8 +16,10 @@
*/ */
#include "compilermanager.h" #include "compilermanager.h"
#include "filecompiler.h" #include "filecompiler.h"
#include "../project.h"
#ifdef ENABLE_SDCC #ifdef ENABLE_SDCC
#include "sdccfilecompiler.h" #include "sdccfilecompiler.h"
#include "sdccprojectcompiler.h"
#endif #endif
#include "stdincompiler.h" #include "stdincompiler.h"
#include "../mainwindow.h" #include "../mainwindow.h"
@ -126,7 +128,7 @@ void CompilerManager::compileProject(std::shared_ptr<Project> project, bool rebu
mCompileErrorCount = 0; mCompileErrorCount = 0;
mCompileIssueCount = 0; mCompileIssueCount = 0;
//deleted when thread finished //deleted when thread finished
mCompiler = new ProjectCompiler(project,false); mCompiler = createProjectCompiler(project);
mCompiler->setRebuild(rebuild); mCompiler->setRebuild(rebuild);
connect(mCompiler, &Compiler::finished, mCompiler, &QObject::deleteLater); connect(mCompiler, &Compiler::finished, mCompiler, &QObject::deleteLater);
connect(mCompiler, &Compiler::compileFinished, this, &CompilerManager::onCompileFinished); connect(mCompiler, &Compiler::compileFinished, this, &CompilerManager::onCompileFinished);
@ -158,7 +160,7 @@ void CompilerManager::cleanProject(std::shared_ptr<Project> project)
mCompileErrorCount = 0; mCompileErrorCount = 0;
mCompileIssueCount = 0; mCompileIssueCount = 0;
//deleted when thread finished //deleted when thread finished
ProjectCompiler* compiler = new ProjectCompiler(project,false); ProjectCompiler* compiler = createProjectCompiler(project);
compiler->setOnlyClean(true); compiler->setOnlyClean(true);
mCompiler = compiler; mCompiler = compiler;
mCompiler->setRebuild(false); mCompiler->setRebuild(false);
@ -189,10 +191,10 @@ void CompilerManager::buildProjectMakefile(std::shared_ptr<Project> project)
if (mCompiler!=nullptr) { if (mCompiler!=nullptr) {
return; return;
} }
ProjectCompiler compiler(project,false); ProjectCompiler* pCompiler=createProjectCompiler(project);
compiler.buildMakeFile(); pCompiler->buildMakeFile();
delete pCompiler;
} }
} }
void CompilerManager::checkSyntax(const QString &filename, const QByteArray& encoding, const QString &content, std::shared_ptr<Project> project) void CompilerManager::checkSyntax(const QString &filename, const QByteArray& encoding, const QString &content, std::shared_ptr<Project> project)
@ -461,6 +463,14 @@ void CompilerManager::onSyntaxCheckIssue(PCompileIssue issue)
mSyntaxCheckIssueCount++; mSyntaxCheckIssueCount++;
} }
ProjectCompiler *CompilerManager::createProjectCompiler(std::shared_ptr<Project> project)
{
if (project->options().type==ProjectType::MicroController)
return new SDCCProjectCompiler(project);
else
return new ProjectCompiler(project);
}
int CompilerManager::syntaxCheckIssueCount() const int CompilerManager::syntaxCheckIssueCount() const
{ {
return mSyntaxCheckIssueCount; return mSyntaxCheckIssueCount;

View File

@ -25,6 +25,7 @@
class Runner; class Runner;
class Project; class Project;
class Compiler; class Compiler;
class ProjectCompiler;
struct OJProblem; struct OJProblem;
using POJProblem = std::shared_ptr<OJProblem>; using POJProblem = std::shared_ptr<OJProblem>;
struct OJProblemCase; struct OJProblemCase;
@ -85,7 +86,8 @@ private slots:
void onCompileIssue(PCompileIssue issue); void onCompileIssue(PCompileIssue issue);
void onSyntaxCheckFinished(QString filename); void onSyntaxCheckFinished(QString filename);
void onSyntaxCheckIssue(PCompileIssue issue); void onSyntaxCheckIssue(PCompileIssue issue);
private:
ProjectCompiler* createProjectCompiler(std::shared_ptr<Project> project);
private: private:
Compiler* mCompiler; Compiler* mCompiler;
int mCompileErrorCount; int mCompileErrorCount;

View File

@ -23,8 +23,8 @@
#include <QDir> #include <QDir>
ProjectCompiler::ProjectCompiler(std::shared_ptr<Project> project, bool onlyCheckSyntax): ProjectCompiler::ProjectCompiler(std::shared_ptr<Project> project):
Compiler("",onlyCheckSyntax), Compiler("",false),
mOnlyClean(false) mOnlyClean(false)
{ {
setProject(project); setProject(project);
@ -66,10 +66,8 @@ void ProjectCompiler::createStaticMakeFile()
QFile file(mProject->makeFileName()); QFile file(mProject->makeFileName());
newMakeFile(file); newMakeFile(file);
writeln(file,"$(BIN): $(LINKOBJ)"); writeln(file,"$(BIN): $(LINKOBJ)");
if (!mOnlyCheckSyntax) { writeln(file,"\tar r $(BIN) $(LINKOBJ)");
writeln(file,"\tar r $(BIN) $(LINKOBJ)"); writeln(file,"\tranlib $(BIN)");
writeln(file,"\tranlib $(BIN)");
}
writeMakeObjFilesRules(file); writeMakeObjFilesRules(file);
} }
@ -78,12 +76,10 @@ void ProjectCompiler::createDynamicMakeFile()
QFile file(mProject->makeFileName()); QFile file(mProject->makeFileName());
newMakeFile(file); newMakeFile(file);
writeln(file,"$(BIN): $(LINKOBJ)"); writeln(file,"$(BIN): $(LINKOBJ)");
if (!mOnlyCheckSyntax) { if (mProject->options().isCpp) {
if (mProject->options().isCpp) { writeln(file, "\t$(CPP) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)");
writeln(file, "\t$(CPP) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)"); } else {
} else { writeln(file, "\t$(CC) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)");
writeln(file, "\t$(CC) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)");
}
} }
writeMakeObjFilesRules(file); writeMakeObjFilesRules(file);
} }
@ -136,11 +132,6 @@ void ProjectCompiler::writeMakeHeader(QFile &file)
writeln(file,"# Project: " + mProject->name()); writeln(file,"# Project: " + mProject->name());
writeln(file,QString("# Makefile created by Red Panda C++ ") + REDPANDA_CPP_VERSION); writeln(file,QString("# Makefile created by Red Panda C++ ") + REDPANDA_CPP_VERSION);
writeln(file); writeln(file);
if (mOnlyCheckSyntax) {
writeln(file,"# This Makefile is written for syntax check!");
writeln(file,"# Regenerate it if you want to use this Makefile to build.");
writeln(file);
}
} }
void ProjectCompiler::writeMakeDefines(QFile &file) void ProjectCompiler::writeMakeDefines(QFile &file)
@ -221,8 +212,8 @@ void ProjectCompiler::writeMakeDefines(QFile &file)
log(""); log("");
// Get list of applicable flags // Get list of applicable flags
QString cCompileArguments = getCCompileArguments(mOnlyCheckSyntax); QString cCompileArguments = getCCompileArguments(false);
QString cppCompileArguments = getCppCompileArguments(mOnlyCheckSyntax); QString cppCompileArguments = getCppCompileArguments(false);
QString libraryArguments = getLibraryArguments(FileType::Project); QString libraryArguments = getLibraryArguments(FileType::Project);
QString cIncludeArguments = getCIncludeArguments() + " " + getProjectIncludeArguments(); QString cIncludeArguments = getCIncludeArguments() + " " + getProjectIncludeArguments();
QString cppIncludeArguments = getCppIncludeArguments() + " " +getProjectIncludeArguments(); QString cppIncludeArguments = getCppIncludeArguments() + " " +getProjectIncludeArguments();
@ -240,7 +231,7 @@ void ProjectCompiler::writeMakeDefines(QFile &file)
#endif #endif
if (!objResFile.isEmpty()) { if (!objResFile.isEmpty()) {
writeln(file,"RES = " + objResFile2); writeln(file,"RES = " + objResFile2);
writeln(file,"OBJ = " + Objects + " $(RES)"); writeln(file,"OBJ = " + Objects);
writeln(file,"LINKOBJ = " + LinkObjects + " " + objResFile); writeln(file,"LINKOBJ = " + LinkObjects + " " + objResFile);
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
writeln(file,"CLEANOBJ = " + cleanObjects + writeln(file,"CLEANOBJ = " + cleanObjects +
@ -314,10 +305,7 @@ void ProjectCompiler::writeMakeDefines(QFile &file)
void ProjectCompiler::writeMakeTarget(QFile &file) void ProjectCompiler::writeMakeTarget(QFile &file)
{ {
if (mOnlyCheckSyntax) writeln(file, ".PHONY: all all-before all-after clean clean-custom");
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);
writeln(file, "all: all-before $(BIN) all-after"); writeln(file, "all: all-before $(BIN) all-after");
writeln(file); writeln(file);
@ -468,21 +456,12 @@ void ProjectCompiler::writeMakeObjFilesRules(QFile &file)
} }
if (fileType==FileType::CSource || fileType==FileType::CppSource) { if (fileType==FileType::CSource || fileType==FileType::CppSource) {
if (mOnlyCheckSyntax) { if (unit->compileCpp())
if (unit->compileCpp()) writeln(file, "\t$(CPP) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CXXFLAGS) " + encodingStr);
writeln(file, "\t$(CPP) -c " + genMakePath1(shortFileName) + " $(CXXFLAGS) " + encodingStr); else
else
writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " $(CFLAGS) " + encodingStr);
} else {
if (unit->compileCpp())
writeln(file, "\t$(CPP) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CXXFLAGS) " + encodingStr);
else
writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CFLAGS) " + encodingStr);
}
} else if (fileType==FileType::GAS) {
if (!mOnlyCheckSyntax) {
writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CFLAGS) " + encodingStr); writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CFLAGS) " + encodingStr);
} } else if (fileType==FileType::GAS) {
writeln(file, "\t$(CC) -c " + genMakePath1(shortFileName) + " -o " + objFileName2 + " $(CFLAGS) " + encodingStr);
} }
} }
} }
@ -499,17 +478,15 @@ void ProjectCompiler::writeMakeObjFilesRules(QFile &file)
QString resFiles; QString resFiles;
// Concatenate all resource filenames (not created when syntax checking) // Concatenate all resource filenames (not created when syntax checking)
if (!mOnlyCheckSyntax) { foreach(const PProjectUnit& unit, mProject->unitList()) {
foreach(const PProjectUnit& unit, mProject->unitList()) { if (getFileType(unit->fileName())!=FileType::WindowsResourceSource)
if (getFileType(unit->fileName())!=FileType::WindowsResourceSource) continue;
continue; if (fileExists(unit->fileName())) {
if (fileExists(unit->fileName())) { QString ResFile = extractRelativePath(mProject->makeFileName(), unit->fileName());
QString ResFile = extractRelativePath(mProject->makeFileName(), unit->fileName()); resFiles = resFiles + genMakePath2(ResFile) + ' ';
resFiles = resFiles + genMakePath2(ResFile) + ' ';
}
} }
resFiles = resFiles.trimmed();
} }
resFiles = resFiles.trimmed();
// Determine resource output file // Determine resource output file
QString fullName; QString fullName;
@ -530,16 +507,10 @@ void ProjectCompiler::writeMakeObjFilesRules(QFile &file)
if (mProject->getCompileOption(CC_CMD_OPT_POINTER_SIZE)=="32") if (mProject->getCompileOption(CC_CMD_OPT_POINTER_SIZE)=="32")
windresArgs = " -F pe-i386"; windresArgs = " -F pe-i386";
if (mOnlyCheckSyntax) { writeln(file);
writeln(file); writeln(file, objFileName2 + ": " + privResName2 + ' ' + resFiles);
writeln(file, objFileName2 + ':'); writeln(file, "\t$(WINDRES) -i " + privResName + windresArgs + " --input-format=rc -o " + objFileName + " -O coff $(WINDRESFLAGS)"
writeln(file, "\t$(WINDRES) -i " + privResName + windresArgs + " --input-format=rc -o nul -O coff $(WINDRESFLAGS)" + ResIncludes); + ResIncludes);
} else {
writeln(file);
writeln(file, objFileName2 + ": " + privResName2 + ' ' + resFiles);
writeln(file, "\t$(WINDRES) -i " + privResName + windresArgs + " --input-format=rc -o " + objFileName + " -O coff $(WINDRESFLAGS)"
+ ResIncludes);
}
writeln(file); writeln(file);
} }
#endif #endif

View File

@ -26,10 +26,10 @@ class ProjectCompiler : public Compiler
{ {
Q_OBJECT Q_OBJECT
public: public:
ProjectCompiler(std::shared_ptr<Project> project, bool onlyCheckSyntax); ProjectCompiler(std::shared_ptr<Project> project);
ProjectCompiler(const ProjectCompiler&)=delete; ProjectCompiler(const ProjectCompiler&)=delete;
ProjectCompiler& operator=(const ProjectCompiler&)=delete; ProjectCompiler& operator=(const ProjectCompiler&)=delete;
void buildMakeFile(); virtual void buildMakeFile();
bool onlyClean() const; bool onlyClean() const;
void setOnlyClean(bool newOnlyClean); void setOnlyClean(bool newOnlyClean);

View File

@ -0,0 +1,362 @@
/*
* 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/>.
*/
#include "sdccprojectcompiler.h"
#include "../project.h"
#include "compilermanager.h"
#include "../systemconsts.h"
#include <QDir>
SDCCProjectCompiler::SDCCProjectCompiler(std::shared_ptr<Project> project):
ProjectCompiler(project)
{
}
void SDCCProjectCompiler::buildMakeFile()
{
//we are using custom make file, don't overwrite it
if (mProject->options().useCustomMakefile && !mProject->options().customMakefile.isEmpty())
return;
createStandardMakeFile();
}
void SDCCProjectCompiler::createStandardMakeFile()
{
QFile file(mProject->makeFileName());
newMakeFile(file);
QString suffix = compilerSet()->executableSuffix();
if (suffix == SDCC_IHX_SUFFIX) {
writeln(file,"$(BIN): $(OBJ)");
writeln(file,"\t$(CC) $(LIBS) -o $(BIN) $(LINKOBJ)");
} else {
writeln(file,"$(IHX): $(OBJ)\n");
writeln(file,"\t$(CC) $(LIBS) -o $(IHX) $(LINKOBJ)");
if (suffix == SDCC_HEX_SUFFIX) {
writeln(file,"$(BIN): $(IHX)");
writeln(file,"\t$(PACKIHX) $(IHX) > $(BIN)");
} else {
writeln(file,"$(BIN): $(IHX)");
writeln(file,"\t$(MAKEBIN) $(IHX) $(BIN)");
}
}
writeMakeObjFilesRules(file);
}
void SDCCProjectCompiler::newMakeFile(QFile& file)
{
// Create OBJ output directory
if (!mProject->options().objectOutput.isEmpty()) {
QDir(mProject->directory()).mkpath(mProject->options().objectOutput);
}
// Create executable output directory
if (!mProject->options().exeOutput.isEmpty()) {
QDir(mProject->directory()).mkpath(mProject->options().exeOutput);
}
// Write more information to the log file than before
log(tr("Building makefile..."));
log("--------");
log(tr("- Filename: %1").arg(mProject->makeFileName()));
// Create the actual file
if (!file.open(QFile::WriteOnly | QFile::Truncate))
throw CompileError(tr("Can't open '%1' for write!").arg(mProject->makeFileName()));
// Write header
writeMakeHeader(file);
// Writes definition list
writeMakeDefines(file);
// Write PHONY and all targets
writeMakeTarget(file);
// Write list of includes
writeMakeIncludes(file);
// Write clean command
writeMakeClean(file);
}
void SDCCProjectCompiler::writeMakeHeader(QFile &file)
{
writeln(file,"# Project: " + mProject->name());
writeln(file,QString("# Makefile created by Red Panda C++ ") + REDPANDA_CPP_VERSION);
writeln(file);
}
void SDCCProjectCompiler::writeMakeDefines(QFile &file)
{
// Get list of object files
QString Objects;
QString LinkObjects;
QString cleanObjects;
// Create a list of object files
foreach(const PProjectUnit &unit, mProject->unitList()) {
if (!unit->compile() && !unit->link())
continue;
// Only process source files
QString RelativeName = extractRelativePath(mProject->directory(), unit->fileName());
FileType fileType = getFileType(RelativeName);
if (fileType == FileType::CSource || fileType == FileType::CppSource
|| fileType==FileType::GAS) {
if (!mProject->options().objectOutput.isEmpty()) {
// ofile = C:\MyProgram\obj\main.o
QString fullObjFile = includeTrailingPathDelimiter(mProject->options().objectOutput)
+ extractFileName(unit->fileName());
QString relativeObjFile = extractRelativePath(mProject->directory(), changeFileExt(fullObjFile, SDCC_REL_SUFFIX));
QString objFile = genMakePath2(relativeObjFile);
Objects += ' ' + objFile;
#ifdef Q_OS_WIN
cleanObjects += ' ' + genMakePath1(relativeObjFile).replace("/",QDir::separator());
#else
cleanObjects += ' ' + genMakePath1(relativeObjFile);
#endif
if (unit->link()) {
LinkObjects += ' ' + genMakePath1(relativeObjFile);
}
} else {
Objects += ' ' + genMakePath2(changeFileExt(RelativeName, SDCC_REL_SUFFIX));
#ifdef Q_OS_WIN
cleanObjects += ' ' + genMakePath1(changeFileExt(RelativeName, SDCC_REL_SUFFIX)).replace("/",QDir::separator());
#else
cleanObjects += ' ' + genMakePath1(changeFileExt(RelativeName, SDCC_REL_SUFFIX));
#endif
if (unit->link())
LinkObjects = LinkObjects + ' ' + genMakePath1(changeFileExt(RelativeName, SDCC_REL_SUFFIX));
}
}
}
Objects = Objects.trimmed();
LinkObjects = LinkObjects.trimmed();
// Get list of applicable flags
QString cCompileArguments = getCCompileArguments(mOnlyCheckSyntax);
QString libraryArguments = getLibraryArguments(FileType::Project);
QString cIncludeArguments = getCIncludeArguments() + " " + getProjectIncludeArguments();
if (cCompileArguments.indexOf(" -g3")>=0
|| cCompileArguments.startsWith("-g3")) {
cCompileArguments += " -D__DEBUG__";
}
writeln(file,"CC = " + extractFileName(compilerSet()->CCompiler()));
writeln(file,QString("PACKIHX = ") + PACKIHX_PROGRAM);
writeln(file,QString("MAKEBIN = ") + MAKEBIN_PROGRAM);
writeln(file,"OBJ = " + Objects);
writeln(file,"LINKOBJ = " + LinkObjects);
#ifdef Q_OS_WIN
writeln(file,"CLEANOBJ = " + cleanObjects +
+ " " + genMakePath1(extractRelativePath(mProject->makeFileName(), changeFileExt(mProject->executable(),SDCC_IHX_SUFFIX))).replace("/",QDir::separator())
+ " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable())).replace("/",QDir::separator()) );
#else
writeln(file,"CLEANOBJ = " + cleanObjects +
+ " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable())));
#endif
libraryArguments.replace('\\', '/');
writeln(file,"LIBS = " + libraryArguments);
cIncludeArguments.replace('\\', '/');
writeln(file,"INCS = " + cIncludeArguments);
writeln(file,"IHX = " + genMakePath1(extractRelativePath(mProject->makeFileName(), changeFileExt(mProject->executable(), SDCC_IHX_SUFFIX))));
writeln(file,"BIN = " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable())));
//writeln(file,"ENCODINGS = -finput-charset=utf-8 -fexec-charset='+GetSystemCharsetName);
cCompileArguments.replace('\\', '/');
writeln(file,"CFLAGS = $(INCS) " + cCompileArguments);
writeln(file, QString("RM = ") + CLEAN_PROGRAM );
writeln(file);
}
void SDCCProjectCompiler::writeMakeTarget(QFile &file)
{
writeln(file, ".PHONY: all all-before all-after clean clean-custom");
writeln(file);
writeln(file, "all: all-before $(BIN) all-after");
writeln(file);
}
void SDCCProjectCompiler::writeMakeIncludes(QFile &file)
{
foreach(const QString& s, mProject->options().makeIncludes) {
writeln(file, "include " + genMakePath1(s));
}
if (!mProject->options().makeIncludes.isEmpty()) {
writeln(file);
}
}
void SDCCProjectCompiler::writeMakeClean(QFile &file)
{
writeln(file, "clean: clean-custom");
QString target="$(CLEANOBJ)";
writeln(file, QString("\t-$(RM) %1 > %2 2>&1").arg(target,NULL_FILE));
writeln(file);
}
void SDCCProjectCompiler::writeMakeObjFilesRules(QFile &file)
{
PCppParser parser = mProject->cppParser();
QString precompileStr;
QList<PProjectUnit> projectUnits=mProject->unitList();
foreach(const PProjectUnit &unit, projectUnits) {
if (!unit->compile())
continue;
FileType fileType = getFileType(unit->fileName());
// Only process source files
if (fileType!=FileType::CSource && fileType!=FileType::CppSource
&& fileType!=FileType::GAS)
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 PProjectUnit &unit2, projectUnits) {
if (unit2==unit)
continue;
if (fileIncludes.contains(unit2->fileName())) {
objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),unit2->fileName()));
}
}
} else {
foreach(const PProjectUnit &unit2, projectUnits) {
FileType fileType = getFileType(unit2->fileName());
if (fileType == FileType::CHeader || fileType==FileType::CppHeader)
objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),unit2->fileName()));
}
}
QString objFileName;
QString objFileName2;
if (!mProject->options().objectOutput.isEmpty()) {
QString fullObjname = includeTrailingPathDelimiter(mProject->options().objectOutput) +
extractFileName(unit->fileName());
objFileName = genMakePath2(extractRelativePath(mProject->makeFileName(), changeFileExt(fullObjname, SDCC_REL_SUFFIX)));
objFileName2 = genMakePath1(extractRelativePath(mProject->makeFileName(), changeFileExt(fullObjname, SDCC_REL_SUFFIX)));
// if (!extractFileDir(ObjFileName).isEmpty()) {
// objStr = genMakePath2(includeTrailingPathDelimiter(extractFileDir(ObjFileName))) + objStr;
// }
} else {
objFileName = genMakePath2(changeFileExt(shortFileName, SDCC_REL_SUFFIX));
objFileName2 = genMakePath1(changeFileExt(shortFileName, SDCC_REL_SUFFIX));
}
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 {
if (fileType==FileType::CSource) {
writeln(file, "\t$(CC) $(CFLAGS) -c " + genMakePath1(shortFileName));
}
}
}
}
void SDCCProjectCompiler::writeln(QFile &file, const QString &s)
{
if (!s.isEmpty())
file.write(s.toLocal8Bit());
file.write("\n");
}
bool SDCCProjectCompiler::prepareForRebuild()
{
//we use make argument to clean
return true;
}
bool SDCCProjectCompiler::prepareForCompile()
{
if (!mProject)
return false;
//initProgressForm();
log(tr("Compiling project changes..."));
log("--------");
log(tr("- Project Filename: %1").arg(mProject->filename()));
log(tr("- Compiler Set Name: %1").arg(compilerSet()->name()));
log("");
buildMakeFile();
mCompiler = compilerSet()->make();
if (!fileExists(mCompiler)) {
throw CompileError(
tr("Make program '%1' doesn't exists!").arg(mCompiler)
+"<br />"
+tr("Please check the \"program\" page of compiler settings."));
}
QString parallelParam;
if (mProject->options().allowParallelBuilding) {
if (mProject->options().parellelBuildingJobs==0) {
parallelParam = " --jobs";
} else {
parallelParam = QString(" -j%1").arg(mProject->options().parellelBuildingJobs);
}
}
if (onlyClean()) {
mArguments = QString(" %1 -f \"%2\" clean").arg(parallelParam,
extractRelativePath(
mProject->directory(),
mProject->makeFileName()));
} else if (mRebuild) {
mArguments = QString(" -f \"%1\" clean").arg(extractRelativePath(
mProject->directory(),
mProject->makeFileName()));
mExtraCompilersList.append(mCompiler);
mExtraOutputFilesList.append("");
mExtraArgumentsList.append(QString(" %1 -f \"%2\" all").arg(parallelParam,
extractRelativePath(
mProject->directory(),
mProject->makeFileName())));
} else {
mArguments = QString(" %1 -f \"%2\" all").arg(parallelParam,
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(extractFileName(mCompiler)).arg(mArguments));
log("");
return true;
}

View File

@ -0,0 +1,50 @@
/*
* 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/>.
*/
#ifndef SDCCPROJECTCOMPILER_H
#define SDCCPROJECTCOMPILER_H
#include "projectcompiler.h"
#include <QObject>
#include <QFile>
class Project;
class SDCCProjectCompiler : public ProjectCompiler
{
Q_OBJECT
public:
SDCCProjectCompiler(std::shared_ptr<Project> project);
SDCCProjectCompiler(const SDCCProjectCompiler&)=delete;
SDCCProjectCompiler& operator=(const SDCCProjectCompiler&)=delete;
void buildMakeFile();
private:
void createStandardMakeFile();
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:
bool prepareForCompile() override;
bool prepareForRebuild() override;
};
#endif // PROJECTCOMPILER_H

View File

@ -855,6 +855,9 @@ QString CppParser::getHeaderFileName(const QString &relativeTo, const QString &h
bool CppParser::isLineVisible(const QString &fileName, int line) bool CppParser::isLineVisible(const QString &fileName, int line)
{ {
QMutexLocker locker(&mMutex); QMutexLocker locker(&mMutex);
if (mParsing) {
return true;
}
PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName); PFileIncludes fileIncludes = mPreprocessor.includesList().value(fileName);
if (!fileIncludes) if (!fileIncludes)
return true; return true;

View File

@ -130,6 +130,14 @@ QString Project::executable() const
exeFileName = mOptions.overridenOutput; exeFileName = mOptions.overridenOutput;
} else { } else {
switch(mOptions.type) { switch(mOptions.type) {
case ProjectType::MicroController: {
Settings::PCompilerSet pSet=pSettings->compilerSets().getSet(mOptions.compilerSet);
if (pSet)
exeFileName = changeFileExt(extractFileName(mFilename),pSet->executableSuffix());
else
exeFileName = changeFileExt(extractFileName(mFilename),SDCC_HEX_SUFFIX);
}
break;
case ProjectType::StaticLib: case ProjectType::StaticLib:
exeFileName = changeFileExt(extractFileName(mFilename),STATIC_LIB_EXT); exeFileName = changeFileExt(extractFileName(mFilename),STATIC_LIB_EXT);
if (!exeFileName.startsWith("lib")) if (!exeFileName.startsWith("lib"))

View File

@ -35,7 +35,8 @@ enum class ProjectType {
GUI=0, GUI=0,
Console=1, Console=1,
StaticLib=2, StaticLib=2,
DynamicLib=3 DynamicLib=3,
MicroController=4
}; };
struct ProjectVersionInfo{ struct ProjectVersionInfo{

View File

@ -2456,7 +2456,34 @@ void Settings::CompilerSet::setExecutables()
mDebugServer = findProgramInBinDirs(GDB_SERVER_PROGRAM); mDebugServer = findProgramInBinDirs(GDB_SERVER_PROGRAM);
} }
mMake = findProgramInBinDirs(MAKE_PROGRAM); mMake = findProgramInBinDirs(MAKE_PROGRAM);
#ifdef Q_OS_WIN
mResourceCompiler = findProgramInBinDirs(WINDRES_PROGRAM); mResourceCompiler = findProgramInBinDirs(WINDRES_PROGRAM);
if (mMake.isEmpty()) {
mMake = findProgramInBinDirs(MAKE2_PROGRAM);
}
if (mMake.isEmpty()) {
QSet<QString> searched;
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
QString path = env.value("PATH");
QStringList pathList = path.split(PATH_SEPARATOR);
QString folder;
for (int i=pathList.count()-1;i>=0;i--) {
folder = pathList[i];
if (searched.contains(folder))
continue;
searched.insert(folder);
QDir dir(folder);
if (dir.exists(MAKE_PROGRAM)) {
mMake = dir.absoluteFilePath(MAKE_PROGRAM);
break;
} else if (dir.exists(MAKE2_PROGRAM)) {
mMake = dir.absoluteFilePath(MAKE2_PROGRAM);
break;
}
}
}
#endif
} }
void Settings::CompilerSet::setDirectories(const QString& binDir) void Settings::CompilerSet::setDirectories(const QString& binDir)

View File

@ -127,12 +127,34 @@ void ProjectCompilerWidget::on_cbCompilerSet_currentIndexChanged(int index)
if (!mInitialized || index==project->options().compilerSet) { if (!mInitialized || index==project->options().compilerSet) {
return; return;
} }
Settings::PCompilerSet pSet=pSettings->compilerSets().getSet(index);
if (pSet) {
if (project->options().type==ProjectType::MicroController) {
if (pSet->compilerType()!=CompilerType::SDCC) {
QMessageBox::information(this,
tr("Wrong Compiler Type"),
tr("Compiler %1 can't compile a microcontroller project.").arg(pSet->name())
);
ui->cbCompilerSet->setCurrentIndex(project->options().compilerSet);
return;
}
} else {
if (pSet->compilerType()==CompilerType::SDCC) {
QMessageBox::information(this,
tr("Wrong Compiler Type"),
tr("Compiler %1 can only compile microcontroller project.").arg(pSet->name())
);
ui->cbCompilerSet->setCurrentIndex(project->options().compilerSet);
return;
}
}
}
if (QMessageBox::warning( if (QMessageBox::warning(
this, this,
MainWindow::tr("Change Project Compiler Set"), tr("Change Project Compiler Set"),
MainWindow::tr("Change the project's compiler set will lose all custom compiler set options.") tr("Change the project's compiler set will lose all custom compiler set options.")
+"<br />" +"<br />"
+ MainWindow::tr("Do you really want to do that?"), + tr("Do you really want to do that?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) != QMessageBox::Yes) { QMessageBox::No) != QMessageBox::Yes) {
ui->cbCompilerSet->setCurrentIndex(project->options().compilerSet); ui->cbCompilerSet->setCurrentIndex(project->options().compilerSet);

View File

@ -53,6 +53,14 @@ void ProjectGeneralWidget::doLoad()
std::shared_ptr<Project> project = pMainWindow->project(); std::shared_ptr<Project> project = pMainWindow->project();
if (!project) if (!project)
return; return;
bool isMicroControllerProject=(project->options().type==ProjectType::MicroController);
ui->grpType->setVisible(!isMicroControllerProject);
ui->grpIcon->setVisible(!isMicroControllerProject);
ui->lblEncoding->setVisible(!isMicroControllerProject);
ui->panelEncoding->setVisible(!isMicroControllerProject);
ui->txtName->setText(project->name()); ui->txtName->setText(project->name());
ui->txtFileName->setText(project->filename()); ui->txtFileName->setText(project->filename());
ui->txtOutputFile->setText(project->executable()); ui->txtOutputFile->setText(project->executable());

View File

@ -60,7 +60,7 @@
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="lblEncoding">
<property name="text"> <property name="text">
<string>Default encoding:</string> <string>Default encoding:</string>
</property> </property>
@ -70,7 +70,7 @@
<widget class="QWidget" name="widget_2" native="true"> <widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="grpIcon">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -172,7 +172,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox"> <widget class="QGroupBox" name="grpType">
<property name="title"> <property name="title">
<string>Type</string> <string>Type</string>
</property> </property>
@ -279,7 +279,7 @@
</spacer> </spacer>
</item> </item>
<item row="4" column="1"> <item row="4" column="1">
<widget class="QWidget" name="widget_3" native="true"> <widget class="QWidget" name="panelEncoding" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>

View File

@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "../mainwindow.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include "ui_settingsdialog.h" #include "ui_settingsdialog.h"
#include "settingswidget.h" #include "settingswidget.h"
@ -40,7 +41,6 @@
#include "debuggeneralwidget.h" #include "debuggeneralwidget.h"
#include "formattergeneralwidget.h" #include "formattergeneralwidget.h"
#include "languageasmgenerationwidget.h" #include "languageasmgenerationwidget.h"
#include "languagecformatwidget.h"
#include "projectgeneralwidget.h" #include "projectgeneralwidget.h"
#include "projectfileswidget.h" #include "projectfileswidget.h"
#include "projectcompilerwidget.h" #include "projectcompilerwidget.h"
@ -252,6 +252,13 @@ PSettingsDialog SettingsDialog::projectOptionDialog()
{ {
PSettingsDialog dialog = std::make_shared<SettingsDialog>(); PSettingsDialog dialog = std::make_shared<SettingsDialog>();
bool isMicroControllerProject=false;
std::shared_ptr<Project> project = pMainWindow->project();
if (project)
isMicroControllerProject=(project->options().type==ProjectType::MicroController);
dialog->setWindowTitle(tr("Project Options")); dialog->setWindowTitle(tr("Project Options"));
SettingsWidget* widget = new ProjectGeneralWidget(tr("General"),tr("Project")); SettingsWidget* widget = new ProjectGeneralWidget(tr("General"),tr("Project"));
@ -269,8 +276,10 @@ PSettingsDialog SettingsDialog::projectOptionDialog()
widget = new ProjectDirectoriesWidget(tr("Directories"),tr("Project")); widget = new ProjectDirectoriesWidget(tr("Directories"),tr("Project"));
dialog->addWidget(widget); dialog->addWidget(widget);
widget = new ProjectPreCompileWidget(tr("Precompiled Header"),tr("Project")); if (!isMicroControllerProject) {
dialog->addWidget(widget); widget = new ProjectPreCompileWidget(tr("Precompiled Header"),tr("Project"));
dialog->addWidget(widget);
}
widget = new ProjectMakefileWidget(tr("Makefile"),tr("Project")); widget = new ProjectMakefileWidget(tr("Makefile"),tr("Project"));
dialog->addWidget(widget); dialog->addWidget(widget);
@ -278,12 +287,16 @@ PSettingsDialog SettingsDialog::projectOptionDialog()
widget = new ProjectOutputWidget(tr("Output"),tr("Project")); widget = new ProjectOutputWidget(tr("Output"),tr("Project"));
dialog->addWidget(widget); dialog->addWidget(widget);
widget = new ProjectDLLHostWidget(tr("DLL host"),tr("Project")); if (!isMicroControllerProject) {
dialog->addWidget(widget); widget = new ProjectDLLHostWidget(tr("DLL host"),tr("Project"));
dialog->addWidget(widget);
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
widget = new ProjectVersionInfoWidget(tr("Version info"),tr("Project")); if (!isMicroControllerProject) {
dialog->addWidget(widget); widget = new ProjectVersionInfoWidget(tr("Version info"),tr("Project"));
dialog->addWidget(widget);
}
#endif #endif
dialog->selectFirstWidget(); dialog->selectFirstWidget();

View File

@ -40,6 +40,7 @@
#define SDCC_PROGRAM "sdcc.exe" #define SDCC_PROGRAM "sdcc.exe"
#define PACKIHX_PROGRAM "packihx.exe" #define PACKIHX_PROGRAM "packihx.exe"
#define MAKEBIN_PROGRAM "makebin.exe" #define MAKEBIN_PROGRAM "makebin.exe"
#define MAKE2_PROGRAM "make.exe"
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
#define CONSOLE_PAUSER "consolepauser" #define CONSOLE_PAUSER "consolepauser"
#define ASSEMBLER "nasm" #define ASSEMBLER "nasm"

View File

@ -121,7 +121,17 @@ void NewProjectDialog::addTemplate(const QString &filename)
return; return;
PProjectTemplate t = std::make_shared<ProjectTemplate>(); PProjectTemplate t = std::make_shared<ProjectTemplate>();
t->readTemplateFile(filename); t->readTemplateFile(filename);
mTemplates.append(t); Settings::PCompilerSet pSet=pSettings->compilerSets().defaultSet();
if (pSet) {
if (pSet->compilerType()==CompilerType::SDCC) {
if (t->options().type==ProjectType::MicroController)
mTemplates.append(t);
} else {
if (t->options().type!=ProjectType::MicroController)
mTemplates.append(t);
}
} else
mTemplates.append(t);
} }
void NewProjectDialog::readTemplateDirs() void NewProjectDialog::readTemplateDirs()

View File

@ -0,0 +1,18 @@
[Template]
ver=2
Name=MCS51
Name[zh_CN]=MCS51
Icon=microcontroller.ico
Description=A simple MCS51 program
Description[zh_CN]=MCS51单片机程序
Category=SDCC
Category[zh_CN]=SDCC
[Unit0]
CName=main.c
C=main.c
[Project]
UnitCount=1
Type=4
IsCpp=0

View File

@ -0,0 +1,7 @@
#include <8051.h>
void main(void) {
for(;;) {
P1--;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -0,0 +1,18 @@
[Template]
ver=2
Name=MCS51
Name[zh_CN]=MCS51
Icon=microcontroller.ico
Description=A simple MCS51 program
Description[zh_CN]=MCS51单片机程序
Category=SDCC
Category[zh_CN]=SDCC
[Unit0]
CName=main.c
C=main.c
[Project]
UnitCount=1
Type=4
IsCpp=0

View File

@ -0,0 +1,7 @@
#include <8051.h>
void main(void) {
for(;;) {
P1--;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB