| 1 | /* |
| 2 | * Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com) |
| 3 | * |
| 4 | * This program is free software: you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License as published by |
| 6 | * the Free Software Foundation, either version 3 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 16 | */ |
| 17 | #include "projectcompiler.h" |
| 18 | #include "../project.h" |
| 19 | #include "compilermanager.h" |
| 20 | #include "../systemconsts.h" |
| 21 | #include "qt_utils/charsetinfo.h" |
| 22 | #include "../editor.h" |
| 23 | |
| 24 | #include <QDir> |
| 25 | |
| 26 | ProjectCompiler::ProjectCompiler(std::shared_ptr<Project> project, bool silent, bool onlyCheckSyntax): |
| 27 | Compiler("" ,silent,onlyCheckSyntax), |
| 28 | mOnlyClean(false) |
| 29 | { |
| 30 | setProject(project); |
| 31 | } |
| 32 | |
| 33 | void ProjectCompiler::buildMakeFile() |
| 34 | { |
| 35 | //we are using custom make file, don't overwrite it |
| 36 | if (!mProject->options().customMakefile.isEmpty()) |
| 37 | return; |
| 38 | |
| 39 | switch(mProject->options().type) { |
| 40 | case ProjectType::StaticLib: |
| 41 | createStaticMakeFile(); |
| 42 | break; |
| 43 | case ProjectType::DynamicLib: |
| 44 | createDynamicMakeFile(); |
| 45 | break; |
| 46 | default: |
| 47 | createStandardMakeFile(); |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | void ProjectCompiler::createStandardMakeFile() |
| 52 | { |
| 53 | QFile file(mProject->makeFileName()); |
| 54 | newMakeFile(file); |
| 55 | file.write("$(BIN): $(OBJ)\n" ); |
| 56 | if (!mOnlyCheckSyntax) { |
| 57 | if (mProject->options().isCpp) { |
| 58 | writeln(file,"\t$(CPP) $(LINKOBJ) -o $(BIN) $(LIBS)" ); |
| 59 | } else |
| 60 | writeln(file,"\t$(CC) $(LINKOBJ) -o $(BIN) $(LIBS)" ); |
| 61 | } |
| 62 | writeMakeObjFilesRules(file); |
| 63 | } |
| 64 | |
| 65 | void ProjectCompiler::createStaticMakeFile() |
| 66 | { |
| 67 | QFile file(mProject->makeFileName()); |
| 68 | newMakeFile(file); |
| 69 | writeln(file,"$(BIN): $(LINKOBJ)" ); |
| 70 | if (!mOnlyCheckSyntax) { |
| 71 | writeln(file,"\tar r $(BIN) $(LINKOBJ)" ); |
| 72 | writeln(file,"\tranlib $(BIN)" ); |
| 73 | } |
| 74 | writeMakeObjFilesRules(file); |
| 75 | } |
| 76 | |
| 77 | void ProjectCompiler::createDynamicMakeFile() |
| 78 | { |
| 79 | QFile file(mProject->makeFileName()); |
| 80 | newMakeFile(file); |
| 81 | writeln(file,"$(BIN): $(LINKOBJ)" ); |
| 82 | if (!mOnlyCheckSyntax) { |
| 83 | if (mProject->options().isCpp) { |
| 84 | file.write("\t$(CPP) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)" ); |
| 85 | } else { |
| 86 | file.write("\t$(CC) -mdll $(LINKOBJ) -o $(BIN) $(LIBS) -Wl,--output-def,$(DEF),--out-implib,$(STATIC)" ); |
| 87 | } |
| 88 | } |
| 89 | writeMakeObjFilesRules(file); |
| 90 | } |
| 91 | |
| 92 | void ProjectCompiler::newMakeFile(QFile& file) |
| 93 | { |
| 94 | // Create OBJ output directory |
| 95 | if (!mProject->options().objectOutput.isEmpty()) { |
| 96 | QDir(mProject->directory()).mkpath(mProject->options().objectOutput); |
| 97 | } |
| 98 | |
| 99 | // Write more information to the log file than before |
| 100 | log(tr("Building makefile..." )); |
| 101 | log("--------" ); |
| 102 | log(tr("- Filename: %1" ).arg(mProject->makeFileName())); |
| 103 | |
| 104 | // Create the actual file |
| 105 | if (!file.open(QFile::WriteOnly | QFile::Truncate)) |
| 106 | throw CompileError(tr("Can't open '%1' for write!" ).arg(mProject->makeFileName())); |
| 107 | |
| 108 | // Write header |
| 109 | writeMakeHeader(file); |
| 110 | |
| 111 | // Writes definition list |
| 112 | writeMakeDefines(file); |
| 113 | |
| 114 | // Write PHONY and all targets |
| 115 | writeMakeTarget(file); |
| 116 | |
| 117 | // Write list of includes |
| 118 | writeMakeIncludes(file); |
| 119 | |
| 120 | // Write clean command |
| 121 | writeMakeClean(file); |
| 122 | } |
| 123 | |
| 124 | void ProjectCompiler::(QFile &file) |
| 125 | { |
| 126 | writeln(file,"# Project: " + mProject->name()); |
| 127 | writeln(file,QString("# Makefile created by Red Panda C++ " ) + REDPANDA_CPP_VERSION); |
| 128 | writeln(file); |
| 129 | if (mOnlyCheckSyntax) { |
| 130 | writeln(file,"# This Makefile is written for syntax check!" ); |
| 131 | writeln(file,"# Regenerate it if you want to use this Makefile to build." ); |
| 132 | writeln(file); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | void ProjectCompiler::writeMakeDefines(QFile &file) |
| 137 | { |
| 138 | // Get list of object files |
| 139 | QString Objects; |
| 140 | QString LinkObjects; |
| 141 | QString cleanObjects; |
| 142 | |
| 143 | // Create a list of object files |
| 144 | for (int i=0;i<mProject->units().count();i++) { |
| 145 | PProjectUnit unit = mProject->units()[i]; |
| 146 | if (!unit->compile() && !unit->link()) |
| 147 | continue; |
| 148 | |
| 149 | // Only process source files |
| 150 | QString RelativeName = extractRelativePath(mProject->directory(), unit->fileName()); |
| 151 | FileType fileType = getFileType(RelativeName); |
| 152 | if (fileType == FileType::CSource || fileType == FileType::CppSource) { |
| 153 | if (!mProject->options().objectOutput.isEmpty()) { |
| 154 | // ofile = C:\MyProgram\obj\main.o |
| 155 | QString fullObjFile = includeTrailingPathDelimiter(mProject->options().objectOutput) |
| 156 | + extractFileName(unit->fileName()); |
| 157 | QString relativeObjFile = extractRelativePath(mProject->directory(), changeFileExt(fullObjFile, OBJ_EXT)); |
| 158 | QString ObjFile = genMakePath2(relativeObjFile); |
| 159 | Objects += ' ' + ObjFile; |
| 160 | #ifdef Q_OS_WIN |
| 161 | cleanObjects += ' ' + genMakePath1(relativeObjFile).replace("/" ,QDir::separator()); |
| 162 | #else |
| 163 | cleanObjects += ' ' + genMakePath1(relativeObjFile); |
| 164 | #endif |
| 165 | if (unit->link()) { |
| 166 | LinkObjects += ' ' + genMakePath1(relativeObjFile); |
| 167 | } |
| 168 | } else { |
| 169 | Objects += ' ' + genMakePath2(changeFileExt(RelativeName, OBJ_EXT)); |
| 170 | #ifdef Q_OS_WIN |
| 171 | cleanObjects += ' ' + genMakePath1(changeFileExt(RelativeName, OBJ_EXT)).replace("/" ,QDir::separator()); |
| 172 | #else |
| 173 | cleanObjects += ' ' + genMakePath1(changeFileExt(RelativeName, OBJ_EXT)); |
| 174 | #endif |
| 175 | if (unit->link()) |
| 176 | LinkObjects = LinkObjects + ' ' + genMakePath1(changeFileExt(RelativeName, OBJ_EXT)); |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | Objects = Objects.trimmed(); |
| 182 | LinkObjects = LinkObjects.trimmed(); |
| 183 | |
| 184 | // Get windres file |
| 185 | QString ObjResFile; |
| 186 | #ifdef Q_OS_WIN |
| 187 | if (!mProject->options().privateResource.isEmpty()) { |
| 188 | if (!mProject->options().objectOutput.isEmpty()) { |
| 189 | ObjResFile = includeTrailingPathDelimiter(mProject->options().objectOutput) + |
| 190 | changeFileExt(mProject->options().privateResource, RES_EXT); |
| 191 | } else |
| 192 | ObjResFile = changeFileExt(mProject->options().privateResource, RES_EXT); |
| 193 | } |
| 194 | #endif |
| 195 | |
| 196 | // Mention progress in the logs |
| 197 | if (!ObjResFile.isEmpty()) { |
| 198 | log(tr("- Resource File: %1" ).arg(QDir(mProject->directory()).absoluteFilePath(ObjResFile))); |
| 199 | } |
| 200 | log("" ); |
| 201 | |
| 202 | // Get list of applicable flags |
| 203 | QString cCompileArguments = getCCompileArguments(mOnlyCheckSyntax); |
| 204 | QString cppCompileArguments = getCppCompileArguments(mOnlyCheckSyntax); |
| 205 | QString libraryArguments = getLibraryArguments(FileType::Project); |
| 206 | QString cIncludeArguments = getCIncludeArguments() + " " + getProjectIncludeArguments(); |
| 207 | QString cppIncludeArguments = getCppIncludeArguments() + " " +getProjectIncludeArguments(); |
| 208 | |
| 209 | if (cCompileArguments.indexOf(" -g3" )>=0 |
| 210 | || cCompileArguments.startsWith("-g3" )) { |
| 211 | cCompileArguments += " -D__DEBUG__" ; |
| 212 | cppCompileArguments+= " -D__DEBUG__" ; |
| 213 | } |
| 214 | writeln(file,"CPP = " + extractFileName(compilerSet()->cppCompiler())); |
| 215 | writeln(file,"CC = " + extractFileName(compilerSet()->CCompiler())); |
| 216 | #ifdef Q_OS_WIN |
| 217 | writeln(file,"WINDRES = " + extractFileName(compilerSet()->resourceCompiler())); |
| 218 | #endif |
| 219 | if (!ObjResFile.isEmpty()) { |
| 220 | writeln(file,"RES = " + genMakePath1(ObjResFile)); |
| 221 | writeln(file,"OBJ = " + Objects + " $(RES)" ); |
| 222 | writeln(file,"LINKOBJ = " + LinkObjects + " $(RES)" ); |
| 223 | #ifdef Q_OS_WIN |
| 224 | writeln(file,"CLEANOBJ = " + cleanObjects + |
| 225 | " " + genMakePath1(ObjResFile).replace("/" ,QDir::separator()) |
| 226 | + " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable())).replace("/" ,QDir::separator()) ); |
| 227 | #else |
| 228 | writeln(file,"CLEANOBJ = " + cleanObjects + |
| 229 | " " + genMakePath1(ObjResFile) |
| 230 | + " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable()))); |
| 231 | #endif |
| 232 | } else { |
| 233 | writeln(file,"OBJ = " + Objects); |
| 234 | writeln(file,"LINKOBJ = " + LinkObjects); |
| 235 | #ifdef Q_OS_WIN |
| 236 | writeln(file,"CLEANOBJ = " + cleanObjects + |
| 237 | + " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable())).replace("/" ,QDir::separator()) ); |
| 238 | #else |
| 239 | writeln(file,"CLEANOBJ = " + cleanObjects + |
| 240 | + " " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable()))); |
| 241 | #endif |
| 242 | }; |
| 243 | libraryArguments.replace('\\', '/'); |
| 244 | writeln(file,"LIBS = " + libraryArguments); |
| 245 | cIncludeArguments.replace('\\', '/'); |
| 246 | writeln(file,"INCS = " + cIncludeArguments); |
| 247 | cppIncludeArguments.replace('\\', '/'); |
| 248 | writeln(file,"CXXINCS = " + cppIncludeArguments); |
| 249 | writeln(file,"BIN = " + genMakePath1(extractRelativePath(mProject->makeFileName(), mProject->executable()))); |
| 250 | cppCompileArguments.replace('\\', '/'); |
| 251 | writeln(file,"CXXFLAGS = $(CXXINCS) " + cppCompileArguments); |
| 252 | //writeln(file,"ENCODINGS = -finput-charset=utf-8 -fexec-charset='+GetSystemCharsetName); |
| 253 | cCompileArguments.replace('\\', '/'); |
| 254 | writeln(file,"CFLAGS = $(INCS) " + cCompileArguments); |
| 255 | writeln(file, QString("RM = " ) + CLEAN_PROGRAM ); |
| 256 | if (mProject->options().usePrecompiledHeader){ |
| 257 | writeln(file,"PCH_H = " + mProject->options().precompiledHeader ); |
| 258 | writeln(file,"PCH = " + changeFileExt(mProject->options().precompiledHeader, GCH_EXT)); |
| 259 | } |
| 260 | |
| 261 | |
| 262 | // This needs to be put in before the clean command. |
| 263 | if (mProject->options().type == ProjectType::DynamicLib) { |
| 264 | QString OutputFileDir = extractFilePath(mProject->executable()); |
| 265 | QString libOutputFile = includeTrailingPathDelimiter(OutputFileDir) + "lib" + extractFileName(mProject->executable()); |
| 266 | if (QFileInfo(libOutputFile).absoluteFilePath() |
| 267 | == mProject->directory()) |
| 268 | libOutputFile = extractFileName(libOutputFile); |
| 269 | else |
| 270 | libOutputFile = extractRelativePath(mProject->makeFileName(), libOutputFile); |
| 271 | writeln(file,"DEF = " + genMakePath1(changeFileExt(libOutputFile, DEF_EXT))); |
| 272 | writeln(file,"STATIC = " + genMakePath1(changeFileExt(libOutputFile, LIB_EXT))); |
| 273 | #ifdef Q_OS_WIN |
| 274 | writeln(file,"CLEAN_DEF = " + genMakePath1(changeFileExt(libOutputFile, DEF_EXT)).replace("/" ,QDir::separator())); |
| 275 | writeln(file,"CLEAN_STATIC = " + genMakePath1(changeFileExt(libOutputFile, LIB_EXT)).replace("/" ,QDir::separator())); |
| 276 | #else |
| 277 | writeln(file,"CLEAN_DEF = " + genMakePath1(changeFileExt(libOutputFile, DEF_EXT))); |
| 278 | writeln(file,"CLEAN_STATIC = " + genMakePath1(changeFileExt(libOutputFile, LIB_EXT))); |
| 279 | #endif |
| 280 | } |
| 281 | writeln(file); |
| 282 | } |
| 283 | |
| 284 | void ProjectCompiler::writeMakeTarget(QFile &file) |
| 285 | { |
| 286 | if (mOnlyCheckSyntax) |
| 287 | writeln(file, ".PHONY: all all-before all-after clean clean-custom $(OBJ) $(BIN)" ); |
| 288 | else |
| 289 | writeln(file, ".PHONY: all all-before all-after clean clean-custom" ); |
| 290 | writeln(file); |
| 291 | writeln(file, "all: all-before $(BIN) all-after" ); |
| 292 | writeln(file); |
| 293 | if (mProject->options().usePrecompiledHeader) { |
| 294 | writeln(file, "$(PCH) : $(PCH_H)" ); |
| 295 | writeln(file, " $(CPP) -x c++-header \"$(PCH_H)\" -o \"$(PCH)\" $(CXXFLAGS)" ); |
| 296 | writeln(file); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | void ProjectCompiler::writeMakeIncludes(QFile &file) |
| 301 | { |
| 302 | foreach(const QString& s, mProject->options().makeIncludes) { |
| 303 | writeln(file, "include " + genMakePath1(s)); |
| 304 | } |
| 305 | if (!mProject->options().makeIncludes.isEmpty()) { |
| 306 | writeln(file); |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | void ProjectCompiler::writeMakeClean(QFile &file) |
| 311 | { |
| 312 | writeln(file, "clean: clean-custom" ); |
| 313 | if (mProject->options().type == ProjectType::DynamicLib) |
| 314 | writeln(file, QString("\t${RM} $(CLEANOBJ) $(CLEAN_DEF) $(CLEAN_STATIC) > %1 2>&1" ).arg(NULL_FILE)); |
| 315 | else |
| 316 | writeln(file, QString("\t${RM} $(CLEANOBJ) > %1 2>&1" ).arg(NULL_FILE)); |
| 317 | writeln(file); |
| 318 | } |
| 319 | |
| 320 | void ProjectCompiler::writeMakeObjFilesRules(QFile &file) |
| 321 | { |
| 322 | PCppParser parser = mProject->cppParser(); |
| 323 | QString precompileStr; |
| 324 | if (mProject->options().usePrecompiledHeader) |
| 325 | precompileStr = " $(PCH) " ; |
| 326 | |
| 327 | for (int i = 0;i<mProject->units().count();i++) { |
| 328 | PProjectUnit unit = mProject->units()[i]; |
| 329 | FileType fileType = getFileType(unit->fileName()); |
| 330 | // Only process source files |
| 331 | if (fileType!=FileType::CSource && fileType!=FileType::CppSource) |
| 332 | continue; |
| 333 | |
| 334 | QString shortFileName = extractRelativePath(mProject->makeFileName(),unit->fileName()); |
| 335 | |
| 336 | writeln(file); |
| 337 | QString objStr=genMakePath2(shortFileName); |
| 338 | // if we have scanned it, use scanned info |
| 339 | if (parser && parser->scannedFiles().contains(unit->fileName())) { |
| 340 | QSet<QString> fileIncludes = parser->getFileIncludes(unit->fileName()); |
| 341 | foreach (const QString& , fileIncludes) { |
| 342 | if (headerName == unit->fileName()) |
| 343 | continue; |
| 344 | if (!parser->isSystemHeaderFile(headerName) |
| 345 | && ! parser->isProjectHeaderFile(headerName)) { |
| 346 | for (int j = 0;j<mProject->units().count();j++) { |
| 347 | PProjectUnit unit2 = mProject->units()[j]; |
| 348 | if (unit2->fileName()==headerName) { |
| 349 | objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),headerName)); |
| 350 | break; |
| 351 | } |
| 352 | } |
| 353 | } |
| 354 | } |
| 355 | } else { |
| 356 | foreach (const PProjectUnit& u, mProject->units()) { |
| 357 | FileType fileType = getFileType(u->fileName()); |
| 358 | if (fileType == FileType::CHeader || fileType==FileType::CppHeader) |
| 359 | objStr = objStr + ' ' + genMakePath2(extractRelativePath(mProject->makeFileName(),u->fileName())); |
| 360 | } |
| 361 | } |
| 362 | QString ObjFileName; |
| 363 | QString ObjFileName2; |
| 364 | if (!mProject->options().objectOutput.isEmpty()) { |
| 365 | ObjFileName = includeTrailingPathDelimiter(mProject->options().objectOutput) + |
| 366 | extractFileName(unit->fileName()); |
| 367 | ObjFileName = genMakePath2(extractRelativePath(mProject->makeFileName(), changeFileExt(ObjFileName, OBJ_EXT))); |
| 368 | ObjFileName2 = genMakePath1(extractRelativePath(mProject->makeFileName(), changeFileExt(ObjFileName, OBJ_EXT))); |
| 369 | // if (!extractFileDir(ObjFileName).isEmpty()) { |
| 370 | // objStr = genMakePath2(includeTrailingPathDelimiter(extractFileDir(ObjFileName))) + objStr; |
| 371 | // } |
| 372 | } else { |
| 373 | ObjFileName = genMakePath2(changeFileExt(shortFileName, OBJ_EXT)); |
| 374 | ObjFileName2 = genMakePath1(changeFileExt(shortFileName, OBJ_EXT)); |
| 375 | } |
| 376 | |
| 377 | objStr = ObjFileName + ": " +objStr+precompileStr; |
| 378 | |
| 379 | writeln(file,objStr); |
| 380 | |
| 381 | // Write custom build command |
| 382 | if (unit->overrideBuildCmd() && !unit->buildCmd().isEmpty()) { |
| 383 | QString BuildCmd = unit->buildCmd(); |
| 384 | BuildCmd.replace("<CRTAB>" , "\n\t" ); |
| 385 | writeln(file, '\t' + BuildCmd); |
| 386 | // Or roll our own |
| 387 | } else { |
| 388 | QString encodingStr; |
| 389 | if (compilerSet()->compilerType() != COMPILER_CLANG && mProject->options().addCharset) { |
| 390 | QByteArray defaultSystemEncoding=pCharsetInfoManager->getDefaultSystemEncoding(); |
| 391 | QByteArray encoding = mProject->options().execEncoding; |
| 392 | QByteArray targetEncoding; |
| 393 | QByteArray sourceEncoding; |
| 394 | if ( encoding == ENCODING_SYSTEM_DEFAULT || encoding.isEmpty()) { |
| 395 | targetEncoding = defaultSystemEncoding; |
| 396 | } else if (encoding == ENCODING_UTF8_BOM) { |
| 397 | targetEncoding = "UTF-8" ; |
| 398 | } else { |
| 399 | targetEncoding = encoding; |
| 400 | } |
| 401 | |
| 402 | if (unit->encoding() == ENCODING_AUTO_DETECT) { |
| 403 | Editor* editor = mProject->unitEditor(unit); |
| 404 | if (editor && editor->fileEncoding()!=ENCODING_ASCII |
| 405 | && editor->fileEncoding()!=targetEncoding) { |
| 406 | sourceEncoding = editor->fileEncoding(); |
| 407 | } else { |
| 408 | sourceEncoding = targetEncoding; |
| 409 | } |
| 410 | } else if (unit->encoding()==ENCODING_SYSTEM_DEFAULT) { |
| 411 | sourceEncoding = defaultSystemEncoding; |
| 412 | } else if (unit->encoding()!=ENCODING_ASCII && !unit->encoding().isEmpty() |
| 413 | && unit->encoding()!=targetEncoding) { |
| 414 | sourceEncoding = unit->encoding(); |
| 415 | } |
| 416 | |
| 417 | if (sourceEncoding!=targetEncoding) { |
| 418 | encodingStr = QString(" -finput-charset=%1 -fexec-charset=%2" ) |
| 419 | .arg(QString(sourceEncoding), |
| 420 | QString(targetEncoding)); |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | if (mOnlyCheckSyntax) { |
| 425 | if (unit->compileCpp()) |
| 426 | writeln(file, "\t$(CPP) -c " + genMakePath1(unit->fileName()) + " $(CXXFLAGS) " + encodingStr); |
| 427 | else |
| 428 | writeln(file, "\t(CC) -c " + genMakePath1(unit->fileName()) + " $(CFLAGS) " + encodingStr); |
| 429 | } else { |
| 430 | if (unit->compileCpp()) |
| 431 | writeln(file, "\t$(CPP) -c " + genMakePath1(unit->fileName()) + " -o " + ObjFileName2 + " $(CXXFLAGS) " + encodingStr); |
| 432 | else |
| 433 | writeln(file, "\t$(CC) -c " + genMakePath1(unit->fileName()) + " -o " + ObjFileName2 + " $(CFLAGS) " + encodingStr); |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | #ifdef Q_OS_WIN |
| 439 | if (!mProject->options().privateResource.isEmpty()) { |
| 440 | |
| 441 | // Concatenate all resource include directories |
| 442 | QString ResIncludes(" " ); |
| 443 | for (int i=0;i<mProject->options().resourceIncludes.count();i++) { |
| 444 | QString filename = mProject->options().resourceIncludes[i]; |
| 445 | if (!filename.isEmpty()) |
| 446 | ResIncludes = ResIncludes + " --include-dir " + genMakePath1(filename); |
| 447 | } |
| 448 | |
| 449 | QString ResFiles; |
| 450 | // Concatenate all resource filenames (not created when syntax checking) |
| 451 | if (!mOnlyCheckSyntax) { |
| 452 | foreach(const PProjectUnit& unit, mProject->units()) { |
| 453 | if (getFileType(unit->fileName())!=FileType::WindowsResourceSource) |
| 454 | continue; |
| 455 | if (fileExists(unit->fileName())) { |
| 456 | QString ResFile = extractRelativePath(mProject->makeFileName(), unit->fileName()); |
| 457 | ResFiles = ResFiles + genMakePath2(ResFile) + ' '; |
| 458 | } |
| 459 | } |
| 460 | ResFiles = ResFiles.trimmed(); |
| 461 | } |
| 462 | |
| 463 | // Determine resource output file |
| 464 | QString ObjFileName; |
| 465 | if (!mProject->options().objectOutput.isEmpty()) { |
| 466 | ObjFileName = includeTrailingPathDelimiter(mProject->options().objectOutput) + |
| 467 | changeFileExt(mProject->options().privateResource, RES_EXT); |
| 468 | } else { |
| 469 | ObjFileName = changeFileExt(mProject->options().privateResource, RES_EXT); |
| 470 | } |
| 471 | ObjFileName = genMakePath1(extractRelativePath(mProject->filename(), ObjFileName)); |
| 472 | QString PrivResName = genMakePath1(extractRelativePath(mProject->filename(), mProject->options().privateResource)); |
| 473 | |
| 474 | // Build final cmd |
| 475 | QString WindresArgs; |
| 476 | if (getCCompileArguments(mOnlyCheckSyntax).contains("-m32" )) |
| 477 | WindresArgs = " -F pe-i386" ; |
| 478 | |
| 479 | if (mOnlyCheckSyntax) { |
| 480 | writeln(file); |
| 481 | writeln(file, ObjFileName + ':'); |
| 482 | writeln(file, "\t$(WINDRES) -i " + PrivResName + WindresArgs + " --input-format=rc -o nul -O coff" + ResIncludes); |
| 483 | } else { |
| 484 | writeln(file); |
| 485 | writeln(file, ObjFileName + ": " + PrivResName + ' ' + ResFiles); |
| 486 | writeln(file, "\t$(WINDRES) -i " + PrivResName + WindresArgs + " --input-format=rc -o " + ObjFileName + " -O coff" |
| 487 | + ResIncludes); |
| 488 | } |
| 489 | writeln(file); |
| 490 | } |
| 491 | #endif |
| 492 | } |
| 493 | |
| 494 | void ProjectCompiler::writeln(QFile &file, const QString &s) |
| 495 | { |
| 496 | if (!s.isEmpty()) |
| 497 | file.write(s.toLocal8Bit()); |
| 498 | file.write("\n" ); |
| 499 | } |
| 500 | |
| 501 | bool ProjectCompiler::onlyClean() const |
| 502 | { |
| 503 | return mOnlyClean; |
| 504 | } |
| 505 | |
| 506 | void ProjectCompiler::setOnlyClean(bool newOnlyClean) |
| 507 | { |
| 508 | mOnlyClean = newOnlyClean; |
| 509 | } |
| 510 | |
| 511 | bool ProjectCompiler::prepareForRebuild() |
| 512 | { |
| 513 | //we use make argument to clean |
| 514 | return true; |
| 515 | } |
| 516 | |
| 517 | bool ProjectCompiler::prepareForCompile() |
| 518 | { |
| 519 | if (!mProject) |
| 520 | return false; |
| 521 | //initProgressForm(); |
| 522 | log(tr("Compiling project changes..." )); |
| 523 | log("--------" ); |
| 524 | log(tr("- Project Filename: %1" ).arg(mProject->filename())); |
| 525 | log(tr("- Compiler Set Name: %1" ).arg(compilerSet()->name())); |
| 526 | log("" ); |
| 527 | |
| 528 | buildMakeFile(); |
| 529 | |
| 530 | mCompiler = compilerSet()->make(); |
| 531 | if (mOnlyClean) { |
| 532 | mArguments = QString("-f \"%1\" clean" ).arg(extractRelativePath( |
| 533 | mProject->directory(), |
| 534 | mProject->makeFileName())); |
| 535 | } else if (mRebuild) { |
| 536 | mArguments = QString("-f \"%1\" clean all" ).arg(extractRelativePath( |
| 537 | mProject->directory(), |
| 538 | mProject->makeFileName())); |
| 539 | } else { |
| 540 | mArguments = QString("-f \"%1\" all" ).arg(extractRelativePath( |
| 541 | mProject->directory(), |
| 542 | mProject->makeFileName())); |
| 543 | } |
| 544 | mDirectory = mProject->directory(); |
| 545 | |
| 546 | log(tr("Processing makefile:" )); |
| 547 | log("--------" ); |
| 548 | log(tr("- makefile processer: %1" ).arg(mCompiler)); |
| 549 | log(tr("- Command: %1 %2" ).arg(extractFileName(mCompiler)).arg(mArguments)); |
| 550 | log("" ); |
| 551 | |
| 552 | return true; |
| 553 | } |
| 554 | |