diff --git a/RedPandaIDE/compiler/compiler.cpp b/RedPandaIDE/compiler/compiler.cpp index 105aff64..e3123664 100644 --- a/RedPandaIDE/compiler/compiler.cpp +++ b/RedPandaIDE/compiler/compiler.cpp @@ -280,14 +280,27 @@ QString Compiler::getCCompileArguments(bool checkSyntax) result += " -fsyntax-only"; } - foreach (const PCompilerOption& pOption, compilerSet()->options()) { - if (pOption->value > 0 && pOption->isC) { - if (pOption->choices.isEmpty()) { - result += " " + pOption->setting; - } else if (pOption->value < pOption->choices.size()) { - QStringList nameValue=pOption->choices[pOption->value].split('='); - if (nameValue.count()==2) { - result += " " + pOption->setting + nameValue[1]; + for (int i=0;ioptions().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) { + 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]; + } } } } @@ -301,6 +314,7 @@ QString Compiler::getCCompileArguments(bool checkSyntax) QString Compiler::getCppCompileArguments(bool checkSyntax) { + return getCCompileArguments(checkSyntax); QString result; if (checkSyntax) { result += " -fsyntax-only"; diff --git a/RedPandaIDE/compiler/projectcompiler.cpp b/RedPandaIDE/compiler/projectcompiler.cpp index 380a81be..daea6d9d 100644 --- a/RedPandaIDE/compiler/projectcompiler.cpp +++ b/RedPandaIDE/compiler/projectcompiler.cpp @@ -1,5 +1,9 @@ #include "projectcompiler.h" #include "project.h" +#include "compilermanager.h" +#include "../systemconsts.h" + +#include ProjectCompiler::ProjectCompiler(std::shared_ptr project, bool silent, bool onlyCheckSyntax): Compiler("",silent,onlyCheckSyntax) @@ -9,9 +13,9 @@ ProjectCompiler::ProjectCompiler(std::shared_ptr project, bool silent, void ProjectCompiler::buildMakeFile() { - if (mProject->options().useCustomMakefile) - mMakefileName = mProject->options().customMakefile; - return; + //we are using custom make file, don't overwrite it + if (!mProject->options().customMakefile.isEmpty()) + return; switch(mProject->options().type) { case ProjectType::StaticLib: @@ -25,11 +29,188 @@ void ProjectCompiler::buildMakeFile() } } +void ProjectCompiler::createStandardMakeFile() +{ + QFile file(mProject->makeFileName()); + newMakeFile(file); + 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)"); + } + writeMakeObjFilesRules(file); +} + +void ProjectCompiler::newMakeFile(QFile& file) +{ + // Create OBJ output directory + if (!mProject->options().objectOutput.isEmpty()) { + QDir(mProject->directory()).mkpath(mProject->options().objectOutput); + } + + // 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 ProjectCompiler::writeMakeHeader(QFile &file) +{ + writeln(file,"# Project: " + mProject->name()); + writeln(file,QString("# Makefile created by Red Panda Dev-C++ ") + DEVCPP_VERSION); + 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) +{ + // Get list of object files + QString Objects; + QString LinkObjects; + + // Create a list of object files + for (int i=0;iunits().count();i++) { + PProjectUnit unit = mProject[i]; + 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) { + if (!mProject->options().objectOutput.isEmpty()) { + // ofile = C:\MyProgram\obj\main.o + QString ObjFile = includeTrailingPathDelimiter(mProject->options().objectOutput) + + extractFileName(unit->fileName()); + ObjFile = genMakePath1(extractRelativePath(mProject->directory(), changeFileExt(ObjFile, OBJ_EXT))); + Objects += ' ' + ObjFile; + + if (unit->link()) + LinkObjects += ' ' + ObjFile; + } else { + Objects += ' ' + genMakePath1(changeFileExt(RelativeName, OBJ_EXT)); + if (unit->link()) + LinkObjects = LinkObjects + ' ' + genMakePath1(changeFileExt(RelativeName, OBJ_EXT)); + } + } + } + + Objects = Objects.trimmed(); + LinkObjects = LinkObjects.trimmed(); + + // Get windres file + QString ObjResFile; + if (!mProject->options().privateResource.isEmpty()) { + if (!mProject->options().objectOutput.isEmpty()) { + ObjResFile = includeTrailingPathDelimiter(mProject->options().objectOutput) + + changeFileExt(mProject->options().privateResource, RES_EXT); + } else + ObjResFile = changeFileExt(mProject->options().privateResource, RES_EXT); + } + + // Mention progress in the logs + if (!ObjResFile.isEmpty()) { + log(tr("- Resource File: %1").arg(QDir(mProject->directory()).absoluteFilePath(ObjResFile))); + } + log(""); + + // Get list of applicable flags + QString cCompileArguments = getCCompileArguments(mOnlyCheckSyntax); + QString cppCompileArguments = getCppCompileArguments(mOnlyCheckSyntax); + QString libraryArguments = getLibraryArguments(); + QString cIncludeArguments = getCIncludeArguments(); + QString cppIncludeArguments = getCppIncludeArguments(); + QString projectIncludeArguments = getProjectIncludeArguments(); + + if (Pos(' -g3', fCompileParams) > 0) or (Pos('-g3', fCompileParams) = 1) then begin + Writeln(F, 'CPP = ' + fCompilerSet.gppName + ' -D__DEBUG__'); + Writeln(F, 'CC = ' + fCompilerSet.gccName + ' -D__DEBUG__'); + end else begin + Writeln(F, 'CPP = ' + fCompilerSet.gppName); + Writeln(F, 'CC = ' + fCompilerSet.gccName); + end; + Writeln(F, 'WINDRES = ' + fCompilerSet.windresName); + if (ObjResFile <> '') then begin + Writeln(F, 'RES = ' + GenMakePath1(ObjResFile)); + Writeln(F, 'OBJ = ' + Objects + ' $(RES)'); + Writeln(F, 'LINKOBJ = ' + LinkObjects + ' $(RES)'); + end else begin + Writeln(F, 'OBJ = ' + Objects); + Writeln(F, 'LINKOBJ = ' + LinkObjects); + end; + Writeln(F, 'LIBS = ' + StringReplace(fLibrariesParams, '\', '/', [rfReplaceAll])); + Writeln(F, 'INCS = ' + StringReplace(fIncludesParams, '\', '/', [rfReplaceAll])); + Writeln(F, 'CXXINCS = ' + StringReplace(fCppIncludesParams, '\', '/', [rfReplaceAll])); + Writeln(F, 'BIN = ' + GenMakePath1(ExtractRelativePath(Makefile, fProject.Executable))); + Writeln(F, 'CXXFLAGS = $(CXXINCS) ' + fCppCompileParams); + Writeln(F, 'ENCODINGS = -finput-charset=utf-8 -fexec-charset='+GetSystemCharsetName); + Writeln(F, 'CFLAGS = $(INCS) ' + fCompileParams); + // Writeln(F, 'RM = ' + CLEAN_PROGRAM + ' -f'); // TODO: use del or rm? + Writeln(F, 'RM = ' + CLEAN_PROGRAM + ' /f'); // TODO: use del or rm? + if fProject.Options.UsePrecompiledHeader then begin + Writeln(F, 'PCH_H = ' + fProject.Options.PrecompiledHeader ); + Writeln(F, 'PCH = ' + fProject.Options.PrecompiledHeader +'.gch' ); + end; + + // This needs to be put in before the clean command. + if fProject.Options.typ = dptDyn then begin + OutputFileDir := ExtractFilePath(Project.Executable); + LibOutputFile := OutputFileDir + 'lib' + ExtractFileName(Project.Executable); + if FileSamePath(LibOutputFile, Project.Directory) then + LibOutputFile := ExtractFileName(LibOutputFile) + else + LibOutputFile := ExtractRelativePath(Makefile, LibOutputFile); + + Writeln(F, 'DEF = ' + GenMakePath1(ChangeFileExt(LibOutputFile, DEF_EXT))); + Writeln(F, 'STATIC = ' + GenMakePath1(ChangeFileExt(LibOutputFile, LIB_EXT))); + end; + Writeln(F); +} + +void ProjectCompiler::writeln(QFile &file, const QString &s) +{ + if (!s.isEmpty()) + file.write(s.toLocal8Bit()); + file.write("\n"); +} + QString ProjectCompiler::pipedText() { return QString(); } +bool ProjectCompiler::prepareForRebuild() +{ + //we use make argument to clean + return true; +} + bool ProjectCompiler::prepareForCompile() { if (!mProject) @@ -43,6 +224,10 @@ bool ProjectCompiler::prepareForCompile() buildMakeFile(); - mCompiler = QString("%1 -f \"%2\" all").arg(compilerSet()->make(), - mMakefileName); + mCompiler = compilerSet()->make(); + if (mRebuild) { + mArguments = QString("-f \"%1\" clean all").arg(mProject->makeFileName()); + } else { + mArguments = QString("-f \"%1\" all").arg(mProject->makeFileName()); + } } diff --git a/RedPandaIDE/compiler/projectcompiler.h b/RedPandaIDE/compiler/projectcompiler.h index 70f240ef..94c88a19 100644 --- a/RedPandaIDE/compiler/projectcompiler.h +++ b/RedPandaIDE/compiler/projectcompiler.h @@ -13,13 +13,16 @@ public: private: void buildMakeFile(); + void createStandardMakeFile(); + void newMakeFile(QFile& file); + void writeMakeHeader(QFile& file); + void writeMakeDefines(QFile& file); + void writeln(QFile& file, const QString& s=""); // Compiler interface protected: bool prepareForCompile() override; QString pipedText() override; bool prepareForRebuild() override; -private: - QString mMakefileName; }; #endif // PROJECTCOMPILER_H diff --git a/RedPandaIDE/project.cpp b/RedPandaIDE/project.cpp index 0d44ef17..4d8a7c84 100644 --- a/RedPandaIDE/project.cpp +++ b/RedPandaIDE/project.cpp @@ -540,7 +540,7 @@ bool Project::saveUnits() return true; } -void Project::setCompilerOption(const QString &optionString, const QChar &value) +void Project::setCompilerOption(const QString &optionString, char value) { if (mOptions.compilerSet<0 || mOptions.compilerSet>=pSettings->compilerSets().size()) { return; @@ -607,7 +607,7 @@ void Project::saveOptions() ini.SetBoolValue("Project","IncludeVersionInfo", mOptions.includeVersionInfo); ini.SetBoolValue("Project","SupportXPThemes", mOptions.supportXPThemes); ini.SetLongValue("Project","CompilerSet", mOptions.compilerSet); - ini.SetValue("Project","CompilerSettings", toByteArray(mOptions.compilerOptions)); + ini.SetValue("Project","CompilerSettings", mOptions.compilerOptions); ini.SetBoolValue("Project","StaticLink", mOptions.staticLink); ini.SetBoolValue("Project","AddCharset", mOptions.addCharset); ini.SetValue("Project","Encoding",toByteArray(mOptions.encoding)); @@ -1103,7 +1103,7 @@ PFolderNode Project::folderNodeFromName(const QString &name) return mNode; } -QChar Project::getCompilerOption(const QString &optionString) +char Project::getCompilerOption(const QString &optionString) { // Does the option exist? Settings::PCompilerSet compilerSet = pSettings->compilerSets().getSet(mOptions.compilerSet); @@ -1241,7 +1241,7 @@ void Project::loadOptions(SimpleIni& ini) mOptions.compilerSet = pSettings->compilerSets().defaultIndex(); setModified(true); } - mOptions.compilerOptions = fromByteArray(ini.GetValue("Project", "CompilerSettings", "")); + mOptions.compilerOptions = ini.GetValue("Project", "CompilerSettings", ""); mOptions.staticLink = ini.GetBoolValue("Project", "StaticLink", true); mOptions.addCharset = ini.GetBoolValue("Project", "AddCharset", true); bool useUTF8 = ini.GetBoolValue("Project", "UseUTF8", false); diff --git a/RedPandaIDE/project.h b/RedPandaIDE/project.h index c6d34c06..a967c758 100644 --- a/RedPandaIDE/project.h +++ b/RedPandaIDE/project.h @@ -130,7 +130,7 @@ struct ProjectOptions{ bool includeVersionInfo; bool supportXPThemes; int compilerSet; - QString compilerOptions; + QByteArray compilerOptions; ProjectVersionInfo versionInfo; QString cmdLineArgs; bool staticLink; @@ -181,7 +181,7 @@ public: void doAutoOpen(); bool fileAlreadyExists(const QString& s); PFolderNode folderNodeFromName(const QString& name); - QChar getCompilerOption(const QString& optionString); + char getCompilerOption(const QString& optionString); QString getFolderPath(PFolderNode node); int getUnitFromString(const QString& s); void incrementBuildNumber(); @@ -206,7 +206,7 @@ public: void saveUnitAs(int i, const QString& sFileName); // save single [UnitX] void saveUnitLayout(Editor* e, int index); // save single [UnitX] cursor positions bool saveUnits(); - void setCompilerOption(const QString& optionString, const QChar& value); + void setCompilerOption(const QString& optionString, char value); void sortUnitsByPriority(); void sortUnitsByAlpha(); void updateFolders(); diff --git a/RedPandaIDE/settings.h b/RedPandaIDE/settings.h index 438079ea..f73e6551 100644 --- a/RedPandaIDE/settings.h +++ b/RedPandaIDE/settings.h @@ -871,9 +871,9 @@ public: bool staticLink() const; void setStaticLink(bool newStaticLink); - private: - int charToValue(char valueChar); + static int charToValue(char valueChar); + private: // Initialization void setExecutables(); void setUserInput(); diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 5b3cac52..fadd6fd5 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -22,6 +22,7 @@ #define RC_EXT "rc" #define RES_EXT "rc" #define H_EXT "h" +#define OBJ_EXT "o" #define DEV_INTERNAL_OPEN "$__DEV_INTERNAL_OPEN" #ifdef Q_OS_WIN