diff options
Diffstat (limited to 'Source')
26 files changed, 1063 insertions, 979 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index dd9eccd..62f5f70 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 13) -set(CMake_VERSION_PATCH 20190117) +set(CMake_VERSION_PATCH 20190121) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index 8867323..320647a 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -1039,6 +1039,11 @@ void cmCTestMultiProcessHandler::PrintOutputAsJson() testRun.SetTestProperties(&p); testRun.ComputeArguments(); + // Skip tests not available in this configuration. + if (p.Args.size() >= 2 && p.Args[1] == "NOT_AVAILABLE") { + continue; + } + Json::Value testInfo = DumpCTestInfo(testRun, p, backtraceGraph); tests.append(testInfo); } diff --git a/Source/CTest/cmCTestSubmitCommand.cxx b/Source/CTest/cmCTestSubmitCommand.cxx index 76a1830..00c0610 100644 --- a/Source/CTest/cmCTestSubmitCommand.cxx +++ b/Source/CTest/cmCTestSubmitCommand.cxx @@ -15,36 +15,28 @@ class cmExecutionStatus; cmCTestGenericHandler* cmCTestSubmitCommand::InitializeHandler() { - const char* ctestDropMethod = - this->Makefile->GetDefinition("CTEST_DROP_METHOD"); - const char* ctestDropSite = this->Makefile->GetDefinition("CTEST_DROP_SITE"); - const char* ctestDropLocation = - this->Makefile->GetDefinition("CTEST_DROP_LOCATION"); - if (!ctestDropMethod) { - ctestDropMethod = "http"; - } + const char* submitURL = !this->SubmitURL.empty() + ? this->SubmitURL.c_str() + : this->Makefile->GetDefinition("CTEST_SUBMIT_URL"); - if (!ctestDropSite) { - // error: CDash requires CTEST_DROP_SITE definition - // in CTestConfig.cmake - } - if (!ctestDropLocation) { - // error: CDash requires CTEST_DROP_LOCATION definition - // in CTestConfig.cmake + if (submitURL) { + this->CTest->SetCTestConfiguration("SubmitURL", submitURL, this->Quiet); + } else { + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "DropMethod", "CTEST_DROP_METHOD", this->Quiet); + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet); + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD", + this->Quiet); + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "DropSite", "CTEST_DROP_SITE", this->Quiet); + this->CTest->SetCTestConfigurationFromCMakeVariable( + this->Makefile, "DropLocation", "CTEST_DROP_LOCATION", this->Quiet); } - this->CTest->SetCTestConfiguration("DropMethod", ctestDropMethod, - this->Quiet); - this->CTest->SetCTestConfiguration("DropSite", ctestDropSite, this->Quiet); - this->CTest->SetCTestConfiguration("DropLocation", ctestDropLocation, - this->Quiet); this->CTest->SetCTestConfigurationFromCMakeVariable( this->Makefile, "CurlOptions", "CTEST_CURL_OPTIONS", this->Quiet); - this->CTest->SetCTestConfigurationFromCMakeVariable( - this->Makefile, "DropSiteUser", "CTEST_DROP_SITE_USER", this->Quiet); - this->CTest->SetCTestConfigurationFromCMakeVariable( - this->Makefile, "DropSitePassword", "CTEST_DROP_SITE_PASSWORD", - this->Quiet); const char* notesFilesVariable = this->Makefile->GetDefinition("CTEST_NOTES_FILES"); @@ -184,6 +176,11 @@ bool cmCTestSubmitCommand::CheckArgumentKeyword(std::string const& arg) return true; } + if (arg == "SUBMIT_URL") { + this->ArgumentDoing = ArgumentDoingSubmitURL; + return true; + } + if (arg == "INTERNAL_TEST_CHECKSUM") { this->InternalTest = true; return true; @@ -249,6 +246,12 @@ bool cmCTestSubmitCommand::CheckArgumentValue(std::string const& arg) return true; } + if (this->ArgumentDoing == ArgumentDoingSubmitURL) { + this->ArgumentDoing = ArgumentDoingNone; + this->SubmitURL = arg; + return true; + } + // Look for other arguments. return this->Superclass::CheckArgumentValue(arg); } diff --git a/Source/CTest/cmCTestSubmitCommand.h b/Source/CTest/cmCTestSubmitCommand.h index c4b84ce..0caccd6 100644 --- a/Source/CTest/cmCTestSubmitCommand.h +++ b/Source/CTest/cmCTestSubmitCommand.h @@ -71,6 +71,7 @@ protected: ArgumentDoingCDashUpload, ArgumentDoingCDashUploadType, ArgumentDoingHttpHeader, + ArgumentDoingSubmitURL, ArgumentDoingLast2 }; @@ -85,6 +86,7 @@ protected: std::string CDashUploadFile; std::string CDashUploadType; std::vector<std::string> HttpHeaders; + std::string SubmitURL; }; #endif diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 8ba3774..5213bd3 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -162,7 +162,6 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP( /* In windows, this will init the winsock stuff */ ::curl_global_init(CURL_GLOBAL_ALL); - std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod")); std::string curlopt(this->CTest->GetCTestConfiguration("CurlOptions")); std::vector<std::string> args; cmSystemTools::ExpandListArgument(curlopt, args); @@ -495,27 +494,6 @@ void cmCTestSubmitHandler::ParseResponse( } } -void cmCTestSubmitHandler::ConstructCDashURL(std::string& dropMethod, - std::string& url) -{ - dropMethod = this->CTest->GetCTestConfiguration("DropMethod"); - url = dropMethod; - url += "://"; - if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) { - url += this->CTest->GetCTestConfiguration("DropSiteUser"); - cmCTestOptionalLog( - this->CTest, HANDLER_OUTPUT, - this->CTest->GetCTestConfiguration("DropSiteUser").c_str(), this->Quiet); - if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) { - url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword"); - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******", this->Quiet); - } - url += "@"; - } - url += this->CTest->GetCTestConfiguration("DropSite") + - this->CTest->GetCTestConfiguration("DropLocation"); -} - int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, std::string const& typeString) { @@ -536,16 +514,15 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file, curl.SetCurlOptions(args); curl.SetTimeOutSeconds(SUBMIT_TIMEOUT_IN_SECONDS_DEFAULT); curl.SetHttpHeaders(this->HttpHeaders); - std::string dropMethod; - std::string url; - this->ConstructCDashURL(dropMethod, url); + std::string url = this->CTest->GetSubmitURL(); std::string fields; std::string::size_type pos = url.find('?'); if (pos != std::string::npos) { fields = url.substr(pos + 1); url = url.substr(0, pos); } - if (!(dropMethod == "http" || dropMethod == "https")) { + if (!cmHasLiteralPrefix(url, "http://") && + !cmHasLiteralPrefix(url, "https://")) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Only http and https are supported for CDASH_UPLOAD\n"); return -1; @@ -872,10 +849,7 @@ int cmCTestSubmitHandler::ProcessHandler() cnt++; } } - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - "Submit files (using " - << this->CTest->GetCTestConfiguration("DropMethod") - << ")" << std::endl, + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "Submit files\n", this->Quiet); const char* specificTrack = this->CTest->GetSpecificTrack(); if (specificTrack) { @@ -885,72 +859,32 @@ int cmCTestSubmitHandler::ProcessHandler() } this->SetLogFile(&ofs); - std::string dropMethod(this->CTest->GetCTestConfiguration("DropMethod")); - - if (dropMethod.empty()) { - dropMethod = "http"; + std::string url = this->CTest->GetSubmitURL(); + cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, + " SubmitURL: " << url << '\n', this->Quiet); + if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" + + this->CTest->GetCurrentTag(), + files, prefix, url)) { + cmCTestLog(this->CTest, ERROR_MESSAGE, + " Problems when submitting via HTTP\n"); + ofs << " Problems when submitting via HTTP\n"; + return -1; } - - if (dropMethod == "http" || dropMethod == "https") { - std::string url = dropMethod; - url += "://"; - ofs << "Using drop method: " << dropMethod << std::endl; - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - " Using HTTP submit method" << std::endl - << " Drop site:" << url, - this->Quiet); - if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) { - url += this->CTest->GetCTestConfiguration("DropSiteUser"); - cmCTestOptionalLog( - this->CTest, HANDLER_OUTPUT, - this->CTest->GetCTestConfiguration("DropSiteUser").c_str(), - this->Quiet); - if (!this->CTest->GetCTestConfiguration("DropSitePassword").empty()) { - url += ":" + this->CTest->GetCTestConfiguration("DropSitePassword"); - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, ":******", - this->Quiet); - } - url += "@"; - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "@", this->Quiet); - } - url += this->CTest->GetCTestConfiguration("DropSite") + - this->CTest->GetCTestConfiguration("DropLocation"); + if (this->HasErrors) { + cmCTestLog(this->CTest, HANDLER_OUTPUT, + " Errors occurred during submission.\n"); + ofs << " Errors occurred during submission.\n"; + } else { cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - this->CTest->GetCTestConfiguration("DropSite") - << this->CTest->GetCTestConfiguration("DropLocation") + " Submission successful" + << (this->HasWarnings ? ", with warnings." : "") << std::endl, this->Quiet); - if (!this->SubmitUsingHTTP(buildDirectory + "/Testing/" + - this->CTest->GetCurrentTag(), - files, prefix, url)) { - cmCTestLog(this->CTest, ERROR_MESSAGE, - " Problems when submitting via HTTP" << std::endl); - ofs << " Problems when submitting via HTTP" << std::endl; - return -1; - } - if (this->HasErrors) { - cmCTestLog(this->CTest, HANDLER_OUTPUT, - " Errors occurred during " - "submission." - << std::endl); - ofs << " Errors occurred during submission. " << std::endl; - } else { - cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, - " Submission successful" - << (this->HasWarnings ? ", with warnings." : "") - << std::endl, - this->Quiet); - ofs << " Submission successful" - << (this->HasWarnings ? ", with warnings." : "") << std::endl; - } - - return 0; + ofs << " Submission successful" + << (this->HasWarnings ? ", with warnings." : "") << std::endl; } - cmCTestLog(this->CTest, ERROR_MESSAGE, - " Unknown submission method: \"" << dropMethod << "\"" - << std::endl); - return -1; + return 0; } std::string cmCTestSubmitHandler::GetSubmitResultsPrefix() diff --git a/Source/CTest/cmCTestSubmitHandler.h b/Source/CTest/cmCTestSubmitHandler.h index 393e826..58f4f97 100644 --- a/Source/CTest/cmCTestSubmitHandler.h +++ b/Source/CTest/cmCTestSubmitHandler.h @@ -48,8 +48,6 @@ public: this->HttpHeaders = v; } - void ConstructCDashURL(std::string& dropMethod, std::string& url); - private: void SetLogFile(std::ostream* ost) { this->LogFile = ost; } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index aa24ace..7966a0d 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1944,6 +1944,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, this->Quiet = true; this->OutputAsJson = true; this->OutputAsJsonVersion = 1; + } else if (format != "human") { + errormsg = "'--show-only=' given unknown value '" + format + "'"; + return false; } } @@ -2626,6 +2629,32 @@ void cmCTest::SetCTestConfiguration(const char* name, const char* value, this->CTestConfiguration[name] = value; } +std::string cmCTest::GetSubmitURL() +{ + std::string url = this->GetCTestConfiguration("SubmitURL"); + if (url.empty()) { + std::string method = this->GetCTestConfiguration("DropMethod"); + std::string user = this->GetCTestConfiguration("DropSiteUser"); + std::string password = this->GetCTestConfiguration("DropSitePassword"); + std::string site = this->GetCTestConfiguration("DropSite"); + std::string location = this->GetCTestConfiguration("DropLocation"); + + url = method.empty() ? "http" : method; + url += "://"; + if (!user.empty()) { + url += user; + if (!password.empty()) { + url += ':'; + url += password; + } + url += '@'; + } + url += site; + url += location; + } + return url; +} + std::string cmCTest::GetCurrentTag() { return this->CurrentTag; diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 2b40ca3..a82f400 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -176,6 +176,8 @@ public: bool suppress = false); void EmptyCTestConfiguration(); + std::string GetSubmitURL(); + /** * constructor and destructor */ diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index c4e83df..fcb27b4 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -57,6 +57,12 @@ static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES = "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES"; static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED"; +/* GHS Multi platform variables */ +static std::set<std::string> ghs_platform_vars{ + "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT", + "GHS_OS_ROOT", "GHS_OS_DIR", "GHS_BSP_NAME" +}; + static void writeProperty(FILE* fout, std::string const& targetName, std::string const& prop, std::string const& value) { @@ -869,6 +875,16 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, projectName = "CMAKE_TRY_COMPILE"; } + if (this->Makefile->GetState()->UseGhsMultiIDE()) { + // Forward the GHS variables to the inner project cache. + for (std::string const& var : ghs_platform_vars) { + if (const char* val = this->Makefile->GetDefinition(var)) { + std::string flag = "-D" + var + "=" + val; + cmakeFlags.push_back(std::move(flag)); + } + } + } + bool erroroc = cmSystemTools::GetErrorOccuredFlag(); cmSystemTools::ResetErrorOccuredFlag(); std::string output; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index db2fde8..999af54 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -185,6 +185,9 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args, if (subCommand == "READ_SYMLINK") { return this->HandleReadSymlinkCommand(args); } + if (subCommand == "CREATE_LINK") { + return this->HandleCreateLinkCommand(args); + } std::string e = "does not recognize sub-command " + subCommand; this->SetError(e); @@ -3670,3 +3673,119 @@ bool cmFileCommand::HandleReadSymlinkCommand( return true; } + +bool cmFileCommand::HandleCreateLinkCommand( + std::vector<std::string> const& args) +{ + if (args.size() < 3) { + this->SetError("CREATE_LINK must be called with at least two additional " + "arguments"); + return false; + } + + cmCommandArgumentsHelper argHelper; + cmCommandArgumentGroup group; + + cmCAString linkArg(&argHelper, "CREATE_LINK"); + cmCAString fileArg(&argHelper, nullptr); + cmCAString newFileArg(&argHelper, nullptr); + + cmCAString resultArg(&argHelper, "RESULT", &group); + cmCAEnabler copyOnErrorArg(&argHelper, "COPY_ON_ERROR", &group); + cmCAEnabler symbolicArg(&argHelper, "SYMBOLIC", &group); + + linkArg.Follows(nullptr); + fileArg.Follows(&linkArg); + newFileArg.Follows(&fileArg); + group.Follows(&newFileArg); + + std::vector<std::string> unconsumedArgs; + argHelper.Parse(&args, &unconsumedArgs); + + if (!unconsumedArgs.empty()) { + this->SetError("unknown argument: \"" + unconsumedArgs.front() + '\"'); + return false; + } + + std::string fileName = fileArg.GetString(); + std::string newFileName = newFileArg.GetString(); + + // Output variable for storing the result. + const std::string& resultVar = resultArg.GetString(); + + // The system error message generated in the operation. + std::string result; + + // Check if the paths are distinct. + if (fileName == newFileName) { + result = "CREATE_LINK cannot use same file and newfile"; + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + return true; + } + this->SetError(result); + return false; + } + + // Hard link requires original file to exist. + if (!symbolicArg.IsEnabled() && !cmSystemTools::FileExists(fileName)) { + result = "Cannot hard link \'" + fileName + "\' as it does not exist."; + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + return true; + } + this->SetError(result); + return false; + } + + // Check if the new file already exists and remove it. + if ((cmSystemTools::FileExists(newFileName) || + cmSystemTools::FileIsSymlink(newFileName)) && + !cmSystemTools::RemoveFile(newFileName)) { + std::ostringstream e; + e << "Failed to create link '" << newFileName + << "' because existing path cannot be removed: " + << cmSystemTools::GetLastSystemError() << "\n"; + + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, e.str().c_str()); + return true; + } + this->SetError(e.str()); + return false; + } + + // Whether the operation completed successfully. + bool completed = false; + + // Check if the command requires a symbolic link. + if (symbolicArg.IsEnabled()) { + completed = cmSystemTools::CreateSymlink(fileName, newFileName, &result); + } else { + completed = cmSystemTools::CreateLink(fileName, newFileName, &result); + } + + // Check if copy-on-error is enabled in the arguments. + if (!completed && copyOnErrorArg.IsEnabled()) { + completed = + cmSystemTools::cmCopyFile(fileName.c_str(), newFileName.c_str()); + if (!completed) { + result = "Copy failed: " + cmSystemTools::GetLastSystemError(); + } + } + + // Check if the operation was successful. + if (completed) { + result = "0"; + } else if (resultVar.empty()) { + // The operation failed and the result is not reported in a variable. + this->SetError(result); + return false; + } + + if (!resultVar.empty()) { + this->Makefile->AddDefinition(resultVar, result.c_str()); + } + + return true; +} diff --git a/Source/cmFileCommand.h b/Source/cmFileCommand.h index fe05c98..12c5115 100644 --- a/Source/cmFileCommand.h +++ b/Source/cmFileCommand.h @@ -61,6 +61,7 @@ protected: bool HandleLockCommand(std::vector<std::string> const& args); bool HandleSizeCommand(std::vector<std::string> const& args); bool HandleReadSymlinkCommand(std::vector<std::string> const& args); + bool HandleCreateLinkCommand(std::vector<std::string> const& args); private: void AddEvaluationFile(const std::string& inputName, diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 26f8f87..9ae1cb9 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -95,6 +95,7 @@ cmFindPackageCommand::cmFindPackageCommand() this->UseLib32Paths = false; this->UseLib64Paths = false; this->UseLibx32Paths = false; + this->UseRealPath = false; this->PolicyScope = true; this->VersionMajor = 0; this->VersionMinor = 0; @@ -195,6 +196,11 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, this->NoSystemRegistry = true; } + // Check whether we should resolve symlinks when finding packages + if (this->Makefile->IsOn("CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS")) { + this->UseRealPath = true; + } + // Check if Sorting should be enabled if (const char* so = this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) { @@ -1502,6 +1508,10 @@ bool cmFindPackageCommand::FindConfigFile(std::string const& dir, fprintf(stderr, "Checking file [%s]\n", file.c_str()); } if (cmSystemTools::FileExists(file, true) && this->CheckVersion(file)) { + // Allow resolving symlinks when the config file is found through a link + if (this->UseRealPath) { + file = cmSystemTools::GetRealPath(file); + } return true; } } diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 05bad49..83d8431 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -178,6 +178,7 @@ private: bool UseLib32Paths; bool UseLib64Paths; bool UseLibx32Paths; + bool UseRealPath; bool PolicyScope; std::string LibraryArchitecture; std::vector<std::string> Names; diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx index f58cfc1..c1f0742 100644 --- a/Source/cmGhsMultiGpj.cxx +++ b/Source/cmGhsMultiGpj.cxx @@ -4,31 +4,34 @@ #include "cmGeneratedFileStream.h" -void GhsMultiGpj::WriteGpjTag(Types const gpjType, - cmGeneratedFileStream* const filestream) +static const char* GHS_TAG[] = { "[INTEGRITY Application]", + "[Library]", + "[Project]", + "[Program]", + "[Reference]", + "[Subproject]" }; + +const char* GhsMultiGpj::GetGpjTag(Types const gpjType) { char const* tag; switch (gpjType) { case INTERGRITY_APPLICATION: - tag = "INTEGRITY Application"; - break; case LIBRARY: - tag = "Library"; - break; case PROJECT: - tag = "Project"; - break; case PROGRAM: - tag = "Program"; - break; case REFERENCE: - tag = "Reference"; - break; case SUBPROJECT: - tag = "Subproject"; + tag = GHS_TAG[gpjType]; break; default: tag = ""; } - *filestream << "[" << tag << "]" << std::endl; + return tag; +} + +void GhsMultiGpj::WriteGpjTag(Types const gpjType, std::ostream& fout) +{ + char const* tag; + tag = GhsMultiGpj::GetGpjTag(gpjType); + fout << tag << std::endl; } diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h index b1eead1..6d59225 100644 --- a/Source/cmGhsMultiGpj.h +++ b/Source/cmGhsMultiGpj.h @@ -4,6 +4,7 @@ #define cmGhsMultiGpj_h #include "cmConfigure.h" // IWYU pragma: keep +#include <iosfwd> class cmGeneratedFileStream; @@ -20,8 +21,9 @@ public: SUBPROJECT }; - static void WriteGpjTag(Types const gpjType, - cmGeneratedFileStream* filestream); + static void WriteGpjTag(Types const gpjType, std::ostream& fout); + + static const char* GetGpjTag(Types const gpjType); }; #endif // ! cmGhsMultiGpjType_h diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 1a25633..19605e4 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGhsMultiTargetGenerator.h" +#include "cmComputeLinkInformation.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGhsMultiGenerator.h" @@ -9,177 +10,128 @@ #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" #include "cmSourceFile.h" +#include "cmSourceGroup.h" #include "cmTarget.h" -#include <assert.h> - -std::string const cmGhsMultiTargetGenerator::DDOption("-dynamic"); cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target) : GeneratorTarget(target) , LocalGenerator( static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator())) , Makefile(target->Target->GetMakefile()) - , TargetGroup(DetermineIfTargetGroup(target)) - , DynamicDownload(false) -{ - this->RelBuildFilePath = this->GetRelBuildFilePath(target); - - this->RelOutputFileName = this->RelBuildFilePath + target->GetName() + ".a"; - - this->RelBuildFileName = this->RelBuildFilePath; - this->RelBuildFileName += this->GetBuildFileName(target); - - std::string absPathToRoot = this->GetAbsPathToRoot(target); - absPathToRoot = this->AddSlashIfNeededToPath(absPathToRoot); - this->AbsBuildFilePath = absPathToRoot + this->RelBuildFilePath; - this->AbsBuildFileName = absPathToRoot + this->RelBuildFileName; - this->AbsOutputFileName = absPathToRoot + this->RelOutputFileName; -} - -cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() + , Name(target->GetName()) { - cmDeleteAll(this->FolderBuildStreams); -} - -std::string cmGhsMultiTargetGenerator::GetRelBuildFilePath( - const cmGeneratorTarget* target) -{ - std::string output = target->GetEffectiveFolderName(); - cmSystemTools::ConvertToUnixSlashes(output); - if (!output.empty()) { - output += "/"; + // Store the configuration name that is being used + if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) { + // Use the build type given by the user. + this->ConfigName = config; + } else { + // No configuration type given. + this->ConfigName.clear(); } - output += target->GetName() + "/"; - return output; -} - -std::string cmGhsMultiTargetGenerator::GetAbsPathToRoot( - const cmGeneratorTarget* target) -{ - return target->GetLocalGenerator()->GetBinaryDirectory(); } -std::string cmGhsMultiTargetGenerator::GetAbsBuildFilePath( - const cmGeneratorTarget* target) -{ - std::string output; - output = cmGhsMultiTargetGenerator::GetAbsPathToRoot(target); - output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output); - output += cmGhsMultiTargetGenerator::GetRelBuildFilePath(target); - return output; -} - -std::string cmGhsMultiTargetGenerator::GetRelBuildFileName( - const cmGeneratorTarget* target) -{ - std::string output; - output = cmGhsMultiTargetGenerator::GetRelBuildFilePath(target); - output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output); - output += cmGhsMultiTargetGenerator::GetBuildFileName(target); - return output; -} - -std::string cmGhsMultiTargetGenerator::GetBuildFileName( - const cmGeneratorTarget* target) -{ - std::string output; - output = target->GetName(); - output += cmGlobalGhsMultiGenerator::FILE_EXTENSION; - return output; -} - -std::string cmGhsMultiTargetGenerator::AddSlashIfNeededToPath( - std::string const& input) +cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() { - std::string output(input); - if (!cmHasLiteralSuffix(output, "/")) { - output += "/"; - } - return output; } void cmGhsMultiTargetGenerator::Generate() { - std::vector<cmSourceFile*> objectSources = this->GetSources(); - if (!objectSources.empty() && this->IncludeThisTarget()) { - if (!cmSystemTools::FileExists(this->AbsBuildFilePath.c_str())) { - cmSystemTools::MakeDirectory(this->AbsBuildFilePath.c_str()); + // Determine type of target for this project + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::EXECUTABLE: { + // Get the name of the executable to generate. + std::string targetName; + std::string targetNameImport; + std::string targetNamePDB; + this->GeneratorTarget->GetExecutableNames( + targetName, this->TargetNameReal, targetNameImport, targetNamePDB, + this->ConfigName); + if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) { + this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION; + } else { + this->TagType = GhsMultiGpj::PROGRAM; + } + break; + } + case cmStateEnums::STATIC_LIBRARY: { + std::string targetName; + std::string targetNameSO; + std::string targetNameImport; + std::string targetNamePDB; + this->GeneratorTarget->GetLibraryNames( + targetName, targetNameSO, this->TargetNameReal, targetNameImport, + targetNamePDB, this->ConfigName); + this->TagType = GhsMultiGpj::LIBRARY; + break; + } + case cmStateEnums::SHARED_LIBRARY: { + std::string msg = "add_library(<name> SHARED ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg.c_str()); + return; } - cmGlobalGhsMultiGenerator::Open(std::string(""), this->AbsBuildFileName, - &this->FolderBuildStreams); - cmGlobalGhsMultiGenerator::OpenBuildFileStream( - this->GetFolderBuildStreams()); - std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - if (0 == config.length()) { - config = "RELEASE"; + case cmStateEnums::OBJECT_LIBRARY: { + std::string targetName; + std::string targetNameSO; + std::string targetNameImport; + std::string targetNamePDB; + this->GeneratorTarget->GetLibraryNames( + targetName, targetNameSO, this->TargetNameReal, targetNameImport, + targetNamePDB, this->ConfigName); + this->TagType = GhsMultiGpj::SUBPROJECT; + break; } - const std::string language( - this->GeneratorTarget->GetLinkerLanguage(config)); - config = cmSystemTools::UpperCase(config); - this->DynamicDownload = this->DetermineIfDynamicDownload(config, language); - if (this->DynamicDownload) { - *this->GetFolderBuildStreams() - << "#component integrity_dynamic_download" << std::endl; + case cmStateEnums::MODULE_LIBRARY: { + std::string msg = "add_library(<name> MODULE ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg.c_str()); + return; } - GhsMultiGpj::WriteGpjTag(this->GetGpjTag(), this->GetFolderBuildStreams()); - cmGlobalGhsMultiGenerator::WriteDisclaimer(this->GetFolderBuildStreams()); - - bool const notKernel = this->IsNotKernel(config, language); - this->WriteTypeSpecifics(config, notKernel); - this->SetCompilerFlags(config, language, notKernel); - this->WriteCompilerFlags(config, language); - this->WriteCompilerDefinitions(config, language); - this->WriteIncludes(config, language); - if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { - this->WriteTargetLinkLibraries(config, language); + case cmStateEnums::UTILITY: { + std::string msg = "add_custom_target(<name> ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg.c_str()); + return; } - this->WriteCustomCommands(); + default: + return; + } - std::map<const cmSourceFile*, std::string> objectNames = - cmGhsMultiTargetGenerator::GetObjectNames( - &objectSources, this->LocalGenerator, this->GeneratorTarget); + // Tell the global generator the name of the project file + this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", + this->Name.c_str()); + this->GeneratorTarget->Target->SetProperty( + "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType)); - this->WriteSources(objectSources, objectNames); - } + this->GenerateTarget(); } -bool cmGhsMultiTargetGenerator::IncludeThisTarget() +void cmGhsMultiTargetGenerator::GenerateTarget() { - bool output = true; - char const* excludeFromAll = - this->GeneratorTarget->GetProperty("EXCLUDE_FROM_ALL"); - if (NULL != excludeFromAll && '1' == excludeFromAll[0] && - '\0' == excludeFromAll[1]) { - output = false; - } - return output; -} + // Open the filestream in copy-if-different mode. + std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory(); + fname += "/"; + fname += this->Name; + fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION; + cmGeneratedFileStream fout(fname.c_str()); + fout.SetCopyIfDifferent(true); -std::vector<cmSourceFile*> cmGhsMultiTargetGenerator::GetSources() const -{ - std::vector<cmSourceFile*> output; - std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); - this->GeneratorTarget->GetSourceFiles(output, config); - return output; -} + this->GetGlobalGenerator()->WriteFileHeader(fout); + GhsMultiGpj::WriteGpjTag(this->TagType, fout); -GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const -{ - return cmGhsMultiTargetGenerator::GetGpjTag(this->GeneratorTarget); -} + const std::string language( + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName)); -GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag( - const cmGeneratorTarget* target) -{ - GhsMultiGpj::Types output; - if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(target)) { - output = GhsMultiGpj::INTERGRITY_APPLICATION; - } else if (target->GetType() == cmStateEnums::STATIC_LIBRARY) { - output = GhsMultiGpj::LIBRARY; - } else { - output = GhsMultiGpj::PROGRAM; - } - return output; + this->WriteTargetSpecifics(fout, this->ConfigName); + this->SetCompilerFlags(this->ConfigName, language); + this->WriteCompilerFlags(fout, this->ConfigName, language); + this->WriteCompilerDefinitions(fout, this->ConfigName, language); + this->WriteIncludes(fout, this->ConfigName, language); + this->WriteTargetLinkLine(fout, this->ConfigName); + this->WriteCustomCommands(fout); + this->WriteSources(fout); + this->WriteReferences(fout); + fout.Close(); } cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator() @@ -189,41 +141,27 @@ cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator() this->LocalGenerator->GetGlobalGenerator()); } -void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string& config, - bool const notKernel) +void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout, + const std::string& config) { - std::string outputDir(this->GetOutputDirectory(config)); - std::string outputFilename(this->GetOutputFilename(config)); - - if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { - std::string const& static_library_suffix = - this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"); - *this->GetFolderBuildStreams() - << " -o \"" << outputDir << outputFilename << static_library_suffix - << "\"" << std::endl; - } else if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) { - if (notKernel && !this->IsTargetGroup()) { - *this->GetFolderBuildStreams() << " -relprog" << std::endl; - } - if (this->IsTargetGroup()) { - *this->GetFolderBuildStreams() - << " -o \"" << outputDir << outputFilename << ".elf\"" << std::endl; - *this->GetFolderBuildStreams() - << " :extraOutputFile=\"" << outputDir << outputFilename - << ".elf.ael\"" << std::endl; - } else { - std::string const executable_suffix = - this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX"); - *this->GetFolderBuildStreams() - << " -o \"" << outputDir << outputFilename << executable_suffix - << "\"" << std::endl; - } + std::string outpath; + std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + + if (this->TagType != GhsMultiGpj::SUBPROJECT) { + // set target binary file destination + outpath = this->GeneratorTarget->GetDirectory(config); + outpath = this->LocalGenerator->ConvertToRelativePath(rootpath, outpath); + fout << " :binDirRelative=\"" << outpath << "\"" << std::endl; + fout << " -o \"" << this->TargetNameReal << "\"" << std::endl; } + + // set target object file destination + outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); + fout << " :outputDirRelative=\"" << outpath << "\"" << std::endl; } void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, - const std::string& language, - bool const notKernel) + const std::string& language) { std::map<std::string, std::string>::iterator i = this->FlagsByLanguage.find(language); @@ -231,14 +169,9 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, std::string flags; const char* lang = language.c_str(); - if (notKernel) { - this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, - lang, config); - } else { - this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, - lang + std::string("_GHS_KERNEL"), - config); - } + this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang, + config); + this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang, config); this->LocalGenerator->AddVisibilityPresetFlags( @@ -281,21 +214,25 @@ std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language, return i->second; } -void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::string const&, +void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout, + std::string const&, const std::string& language) { std::map<std::string, std::string>::iterator flagsByLangI = this->FlagsByLanguage.find(language); if (flagsByLangI != this->FlagsByLanguage.end()) { if (!flagsByLangI->second.empty()) { - *this->GetFolderBuildStreams() - << " " << flagsByLangI->second << std::endl; + std::vector<std::string> ghsCompFlags = + cmSystemTools::ParseArguments(flagsByLangI->second.c_str()); + for (auto& f : ghsCompFlags) { + fout << " " << f << std::endl; + } } } } void cmGhsMultiTargetGenerator::WriteCompilerDefinitions( - const std::string& config, const std::string& language) + std::ostream& fout, const std::string& config, const std::string& language) { std::vector<std::string> compileDefinitions; this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config, @@ -303,11 +240,12 @@ void cmGhsMultiTargetGenerator::WriteCompilerDefinitions( for (std::vector<std::string>::const_iterator cdI = compileDefinitions.begin(); cdI != compileDefinitions.end(); ++cdI) { - *this->GetFolderBuildStreams() << " -D" << (*cdI) << std::endl; + fout << " -D" << (*cdI) << std::endl; } } -void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config, +void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout, + const std::string& config, const std::string& language) { std::vector<std::string> includes; @@ -316,80 +254,73 @@ void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config, for (std::vector<std::string>::const_iterator includes_i = includes.begin(); includes_i != includes.end(); ++includes_i) { - *this->GetFolderBuildStreams() - << " -I\"" << *includes_i << "\"" << std::endl; + fout << " -I\"" << *includes_i << "\"" << std::endl; } } -void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries( - std::string const& config, std::string const& language) +void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, + std::string const& config) { - // library directories - cmTargetDependSet tds = - this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget); - for (cmTargetDependSet::iterator tdsI = tds.begin(); tdsI != tds.end(); - ++tdsI) { - const cmGeneratorTarget* tg = *tdsI; - *this->GetFolderBuildStreams() - << " -L\"" << GetAbsBuildFilePath(tg) << "\"" << std::endl; + if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) { + return; } - // library targets - cmTarget::LinkLibraryVectorType llv = - this->GeneratorTarget->Target->GetOriginalLinkLibraries(); - for (cmTarget::LinkLibraryVectorType::const_iterator llvI = llv.begin(); - llvI != llv.end(); ++llvI) { - std::string libName = llvI->first; - // if it is a user defined target get the full path to the lib - cmTarget* tg(GetGlobalGenerator()->FindTarget(libName)); - if (NULL != tg) { - libName = tg->GetName() + ".a"; - } - *this->GetFolderBuildStreams() - << " -l\"" << libName << "\"" << std::endl; + + std::string linkLibraries; + std::string flags; + std::string linkFlags; + std::string frameworkPath; + std::string linkPath; + + std::unique_ptr<cmLinkLineComputer> linkLineComputer( + this->GetGlobalGenerator()->CreateLinkLineComputer( + this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory())); + + this->LocalGenerator->GetTargetFlags( + linkLineComputer.get(), config, linkLibraries, flags, linkFlags, + frameworkPath, linkPath, this->GeneratorTarget); + + // write out link options + std::vector<std::string> lopts = + cmSystemTools::ParseArguments(linkFlags.c_str()); + for (auto& l : lopts) { + fout << " " << l << std::endl; } - if (!this->TargetGroup) { - std::string linkLibraries; - std::string flags; - std::string linkFlags; - std::string frameworkPath; - std::string linkPath; - std::string createRule = - this->GeneratorTarget->GetCreateRuleVariable(language, config); - bool useWatcomQuote = - this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE"); - std::unique_ptr<cmLinkLineComputer> linkLineComputer( - this->GetGlobalGenerator()->CreateLinkLineComputer( - this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); - linkLineComputer->SetUseWatcomQuote(useWatcomQuote); - - this->LocalGenerator->GetTargetFlags( - linkLineComputer.get(), config, linkLibraries, flags, linkFlags, - frameworkPath, linkPath, this->GeneratorTarget); - linkFlags = cmSystemTools::TrimWhitespace(linkFlags); - - if (!linkPath.empty()) { - linkPath = " " + linkPath.substr(0U, linkPath.size() - 1U); - *this->GetFolderBuildStreams() << linkPath; - } + // write out link search paths + // must be quoted for paths that contain spaces + std::vector<std::string> lpath = + cmSystemTools::ParseArguments(linkPath.c_str()); + for (auto& l : lpath) { + fout << " -L\"" << l << "\"" << std::endl; + } + + // write out link libs + // must be quoted for filepaths that contains spaces + std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory(); - if (!linkFlags.empty()) { - *this->GetFolderBuildStreams() << " " << linkFlags << std::endl; + std::vector<std::string> llibs = + cmSystemTools::ParseArguments(linkLibraries.c_str()); + for (auto& l : llibs) { + if (l.compare(0, 2, "-l") == 0) { + fout << " \"" << l << "\"" << std::endl; + } else { + std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l); + fout << " -l\"" << rl << "\"" << std::endl; } } } -void cmGhsMultiTargetGenerator::WriteCustomCommands() +void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout) { - WriteCustomCommandsHelper(this->GeneratorTarget->GetPreBuildCommands(), + WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(), cmTarget::PRE_BUILD); - WriteCustomCommandsHelper(this->GeneratorTarget->GetPostBuildCommands(), - cmTarget::POST_BUILD); + WriteCustomCommandsHelper( + fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD); } void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( - std::vector<cmCustomCommand> const& commandsSet, + std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet, cmTarget::CustomCommandType const commandType) { for (std::vector<cmCustomCommand>::const_iterator commandsSetI = @@ -400,10 +331,10 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( commandI != commands.end(); ++commandI) { switch (commandType) { case cmTarget::PRE_BUILD: - *this->GetFolderBuildStreams() << " :preexecShellSafe="; + fout << " :preexecShellSafe="; break; case cmTarget::POST_BUILD: - *this->GetFolderBuildStreams() << " :postexecShellSafe="; + fout << " :postexecShellSafe="; break; default: assert("Only pre and post are supported"); @@ -414,242 +345,237 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( std::string subCommandE = this->LocalGenerator->EscapeForShell(*commandLineI, true); if (!command.empty()) { - *this->GetFolderBuildStreams() - << (command.begin() == commandLineI ? "'" : " "); + fout << (command.begin() == commandLineI ? "'" : " "); // Need to double escape backslashes cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\"); } - *this->GetFolderBuildStreams() << subCommandE; + fout << subCommandE; } if (!command.empty()) { - *this->GetFolderBuildStreams() << "'" << std::endl; + fout << "'" << std::endl; } } } } -std::map<const cmSourceFile*, std::string> -cmGhsMultiTargetGenerator::GetObjectNames( - std::vector<cmSourceFile*>* const objectSources, - cmLocalGhsMultiGenerator* const localGhsMultiGenerator, - cmGeneratorTarget* const generatorTarget) +void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout, + const cmSourceFile* sf, + std::string propName, + std::string propFlag) { - std::map<std::string, std::vector<cmSourceFile*>> filenameToSource; - std::map<cmSourceFile*, std::string> sourceToFilename; - for (std::vector<cmSourceFile*>::const_iterator sf = objectSources->begin(); - sf != objectSources->end(); ++sf) { - const std::string filename = - cmSystemTools::GetFilenameName((*sf)->GetFullPath()); - const std::string lower_filename = cmSystemTools::LowerCase(filename); - filenameToSource[lower_filename].push_back(*sf); - sourceToFilename[*sf] = lower_filename; - } - - std::vector<cmSourceFile*> duplicateSources; - for (std::map<std::string, std::vector<cmSourceFile*>>::const_iterator - msvSourceI = filenameToSource.begin(); - msvSourceI != filenameToSource.end(); ++msvSourceI) { - if (msvSourceI->second.size() > 1) { - duplicateSources.insert(duplicateSources.end(), - msvSourceI->second.begin(), - msvSourceI->second.end()); + const char* prop = sf->GetProperty(propName); + if (prop) { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(prop, list); + for (auto& p : list) { + fout << " " << propFlag << p << std::endl; } } - - std::map<const cmSourceFile*, std::string> objectNamesCorrected; - - for (std::vector<cmSourceFile*>::const_iterator sf = - duplicateSources.begin(); - sf != duplicateSources.end(); ++sf) { - std::string const longestObjectDirectory( - cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory( - localGhsMultiGenerator, generatorTarget, *sf)); - std::string objFilenameName = - localGhsMultiGenerator->GetObjectFileNameWithoutTarget( - **sf, longestObjectDirectory); - cmsys::SystemTools::ReplaceString(objFilenameName, "/", "_"); - objectNamesCorrected[*sf] = objFilenameName; - } - - return objectNamesCorrected; } -void cmGhsMultiTargetGenerator::WriteSources( - std::vector<cmSourceFile*> const& objectSources, - std::map<const cmSourceFile*, std::string> const& objectNames) +void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) { - for (const cmSourceFile* sf : objectSources) { - std::vector<cmSourceGroup> sourceGroups(this->Makefile->GetSourceGroups()); - std::string const& sourceFullPath = sf->GetFullPath(); - cmSourceGroup* sourceGroup = - this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups); - std::string sgPath = sourceGroup->GetFullName(); - cmSystemTools::ConvertToUnixSlashes(sgPath); - cmGlobalGhsMultiGenerator::AddFilesUpToPath( - this->GetFolderBuildStreams(), &this->FolderBuildStreams, - this->LocalGenerator->GetBinaryDirectory().c_str(), sgPath, - GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath); - - std::string fullSourcePath(sf->GetFullPath()); - if (sf->GetExtension() == "int" || sf->GetExtension() == "bsp") { - *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl; - } else { - // WORKAROUND: GHS MULTI needs the path to use backslashes without quotes - // to open files in search as of version 6.1.6 - cmsys::SystemTools::ReplaceString(fullSourcePath, "/", "\\"); - *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl; - } + /* vector of all sources for this target */ + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName); - if ("ld" != sf->GetExtension() && "int" != sf->GetExtension() && - "bsp" != sf->GetExtension()) { - this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], sf); - if (objectNames.end() != objectNames.find(sf)) { - *this->FolderBuildStreams[sgPath] - << " -o \"" << objectNames.find(sf)->second << "\"" << std::endl; - } + /* vector of all groups defined for this target + * -- but the vector is not expanded with sub groups or in any useful order + */ + std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); - this->WriteObjectDir(this->FolderBuildStreams[sgPath], - this->AbsBuildFilePath + sgPath); - } + /* for each source file assign it to its group */ + std::map<std::string, std::vector<cmSourceFile*>> groupFiles; + std::set<std::string> groupNames; + for (auto& sf : sources) { + cmSourceGroup* sourceGroup = + this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups); + std::string gn = sourceGroup->GetFullName(); + groupFiles[gn].push_back(sf); + groupNames.insert(gn); } -} -void cmGhsMultiTargetGenerator::WriteObjectLangOverride( - cmGeneratedFileStream* fileStream, const cmSourceFile* sourceFile) -{ - const char* rawLangProp = sourceFile->GetProperty("LANGUAGE"); - if (NULL != rawLangProp) { - std::string sourceLangProp(rawLangProp); - std::string extension(sourceFile->GetExtension()); - if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) { - *fileStream << " -dotciscxx" << std::endl; + /* list of known groups and the order they are displayed in a project file */ + const std::vector<std::string> standardGroups = { + "Header Files", "Source Files", "CMake Rules", + "Object Files", "Object Libraries", "Resources" + }; + + /* list of groups in the order they are displayed in a project file*/ + std::vector<std::string> groupFilesList(groupFiles.size()); + + /* put the groups in the order they should be listed + * - standard groups first, and then everything else + * in the order used by std::map. + */ + int i = 0; + for (const std::string& gn : standardGroups) { + auto n = groupNames.find(gn); + if (n != groupNames.end()) { + groupFilesList[i] = *n; + i += 1; + groupNames.erase(gn); } } -} -void cmGhsMultiTargetGenerator::WriteObjectDir( - cmGeneratedFileStream* fileStream, std::string const& dir) -{ - std::string workingDir(dir); - cmSystemTools::ConvertToUnixSlashes(workingDir); - if (!workingDir.empty()) { - workingDir += "/"; + { /* catch-all group - is last item */ + std::string gn = ""; + auto n = groupNames.find(gn); + if (n != groupNames.end()) { + groupFilesList.back() = *n; + groupNames.erase(gn); + } } - workingDir += "Objs"; - *fileStream << " -object_dir=\"" << workingDir << "\"" << std::endl; -} -std::string cmGhsMultiTargetGenerator::GetOutputDirectory( - const std::string& config) const -{ - std::string outputDir(AbsBuildFilePath); - - const char* runtimeOutputProp = - this->GeneratorTarget->GetProperty("RUNTIME_OUTPUT_DIRECTORY"); - if (NULL != runtimeOutputProp) { - outputDir = runtimeOutputProp; + for (auto& n : groupNames) { + groupFilesList[i] = n; + i += 1; } - std::string configCapped(cmSystemTools::UpperCase(config)); - const char* runtimeOutputSProp = this->GeneratorTarget->GetProperty( - "RUNTIME_OUTPUT_DIRECTORY_" + configCapped); - if (NULL != runtimeOutputSProp) { - outputDir = runtimeOutputSProp; + /* sort the files within each group */ + for (auto& n : groupFilesList) { + std::sort(groupFiles[n].begin(), groupFiles[n].end(), + [](cmSourceFile* l, cmSourceFile* r) { + return l->GetFullPath() < r->GetFullPath(); + }); } - cmSystemTools::ConvertToUnixSlashes(outputDir); - if (!outputDir.empty()) { - outputDir += "/"; - } + /* list of open project files */ + std::vector<cmGeneratedFileStream*> gfiles; + + /* write files into the proper project file + * -- groups go into main project file + * unless FOLDER property or variable is set. + */ + for (auto& sg : groupFilesList) { + std::ostream* fout; + bool useProjectFile = + cmSystemTools::IsOn( + this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) || + cmSystemTools::IsOn( + this->Makefile->GetDefinition("GHS_NO_SOURCE_GROUP_FILE")); + if (useProjectFile || sg.empty()) { + fout = &fout_proj; + } else { + // Open the filestream in copy-if-different mode. + std::string gname = sg; + cmsys::SystemTools::ReplaceString(gname, "\\", "_"); + std::string lpath = + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); + lpath += "/"; + lpath += gname; + lpath += cmGlobalGhsMultiGenerator::FILE_EXTENSION; + std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + fpath += "/"; + fpath += lpath; + cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str()); + f->SetCopyIfDifferent(true); + gfiles.push_back(f); + fout = f; + this->GetGlobalGenerator()->WriteFileHeader(*f); + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f); + fout_proj << lpath << " "; + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj); + } - return outputDir; -} + if (useProjectFile) { + if (sg.empty()) { + *fout << "{comment} Others" << std::endl; + } else { + *fout << "{comment} " << sg << std::endl; + } + } -std::string cmGhsMultiTargetGenerator::GetOutputFilename( - const std::string& config) const -{ - std::string outputFilename(this->GeneratorTarget->GetName()); + /* output rule for each source file */ + for (const cmSourceFile* si : groupFiles[sg]) { - const char* outputNameProp = - this->GeneratorTarget->GetProperty("OUTPUT_NAME"); - if (NULL != outputNameProp) { - outputFilename = outputNameProp; - } + // Convert filename to native system + // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on + // windows when opening some files from the search window. + std::string fname(si->GetFullPath()); + cmSystemTools::ConvertToOutputSlashes(fname); + *fout << fname << std::endl; + + if ("ld" != si->GetExtension() && "int" != si->GetExtension() && + "bsp" != si->GetExtension()) { + this->WriteObjectLangOverride(*fout, si); + } + + this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I"); + this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D"); + this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", ""); - std::string configCapped(cmSystemTools::UpperCase(config)); - const char* outputNameSProp = - this->GeneratorTarget->GetProperty(configCapped + "_OUTPUT_NAME"); - if (NULL != outputNameSProp) { - outputFilename = outputNameSProp; + /* to avoid clutter in the gui only print out the objectName if it has + * been renamed */ + std::string objectName = this->GeneratorTarget->GetObjectName(si); + if (!objectName.empty() && + this->GeneratorTarget->HasExplicitObjectName(si)) { + *fout << " -o " << objectName << std::endl; + } + } } - return outputFilename; + for (cmGeneratedFileStream* f : gfiles) { + f->Close(); + } } -std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory( - cmLocalGhsMultiGenerator const* localGhsMultiGenerator, - cmGeneratorTarget* const generatorTarget, cmSourceFile* const sourceFile) +void cmGhsMultiTargetGenerator::WriteObjectLangOverride( + std::ostream& fout, const cmSourceFile* sourceFile) { - std::string dir_max; - dir_max += - localGhsMultiGenerator->GetMakefile()->GetCurrentBinaryDirectory(); - dir_max += "/"; - dir_max += generatorTarget->Target->GetName(); - dir_max += "/"; - std::vector<cmSourceGroup> sourceGroups( - localGhsMultiGenerator->GetMakefile()->GetSourceGroups()); - std::string const& sourceFullPath = sourceFile->GetFullPath(); - cmSourceGroup* sourceGroup = - localGhsMultiGenerator->GetMakefile()->FindSourceGroup(sourceFullPath, - sourceGroups); - std::string const& sgPath = sourceGroup->GetFullName(); - dir_max += sgPath; - dir_max += "/Objs/libs/"; - dir_max += generatorTarget->Target->GetName(); - dir_max += "/"; - return dir_max; + const char* rawLangProp = sourceFile->GetProperty("LANGUAGE"); + if (NULL != rawLangProp) { + std::string sourceLangProp(rawLangProp); + std::string extension(sourceFile->GetExtension()); + if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) { + fout << " -dotciscxx" << std::endl; + } + } } -bool cmGhsMultiTargetGenerator::IsNotKernel(std::string const& config, - const std::string& language) +void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout) { - bool output; - std::vector<std::string> options; - this->GeneratorTarget->GetCompileOptions(options, config, language); - output = - options.end() == std::find(options.begin(), options.end(), "-kernel"); - return output; -} + // This only applies to INTEGRITY Applications + if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) { + return; + } -bool cmGhsMultiTargetGenerator::DetermineIfTargetGroup( - const cmGeneratorTarget* target) -{ - bool output = false; - std::vector<cmSourceFile*> sources; - std::string config = - target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); - target->GetSourceFiles(sources, config); - for (std::vector<cmSourceFile*>::const_iterator sources_i = sources.begin(); - sources.end() != sources_i; ++sources_i) { - if ("int" == (*sources_i)->GetExtension()) { - output = true; - } + // Get the targets that this one depends upon + cmTargetDependSet unordered = + this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget); + cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered, + this->Name); + for (auto& t : ordered) { + std::string tname = t->GetName(); + std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory(); + std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + std::string outpath = + this->LocalGenerator->ConvertToRelativePath(rootpath, tpath) + "/" + + tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION; + + fout << outpath; + fout << " "; + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout); + + // Tell the global generator that a refernce project needs to be created + t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON"); } - return output; } -bool cmGhsMultiTargetGenerator::DetermineIfDynamicDownload( - std::string const& config, const std::string& language) +bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void) { - std::vector<std::string> options; - bool output = false; - this->GeneratorTarget->GetCompileOptions(options, config, language); - for (std::vector<std::string>::const_iterator options_i = options.begin(); - options_i != options.end(); ++options_i) { - std::string option = *options_i; - if (this->DDOption == option) { - output = true; + const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app"); + if (p) { + return cmSystemTools::IsOn( + this->GeneratorTarget->GetProperty("ghs_integrity_app")); + } else { + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName); + for (auto& sf : sources) { + if ("int" == sf->GetExtension()) { + return true; + } } + return false; } - return output; } diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h index e936b08..a241cc6 100644 --- a/Source/cmGhsMultiTargetGenerator.h +++ b/Source/cmGhsMultiTargetGenerator.h @@ -24,97 +24,49 @@ public: virtual void Generate(); - bool IncludeThisTarget(); - std::vector<cmSourceFile*> GetSources() const; - GhsMultiGpj::Types GetGpjTag() const; - static GhsMultiGpj::Types GetGpjTag(const cmGeneratorTarget* target); - const char* GetAbsBuildFilePath() const - { - return this->AbsBuildFilePath.c_str(); - } - const char* GetRelBuildFileName() const - { - return this->RelBuildFileName.c_str(); - } - const char* GetAbsBuildFileName() const - { - return this->AbsBuildFileName.c_str(); - } - const char* GetAbsOutputFileName() const - { - return this->AbsOutputFileName.c_str(); - } - - static std::string GetRelBuildFilePath(const cmGeneratorTarget* target); - static std::string GetAbsPathToRoot(const cmGeneratorTarget* target); - static std::string GetAbsBuildFilePath(const cmGeneratorTarget* target); - static std::string GetRelBuildFileName(const cmGeneratorTarget* target); - static std::string GetBuildFileName(const cmGeneratorTarget* target); - static std::string AddSlashIfNeededToPath(std::string const& input); - private: cmGlobalGhsMultiGenerator* GetGlobalGenerator() const; - cmGeneratedFileStream* GetFolderBuildStreams() - { - return this->FolderBuildStreams[""]; - }; - bool IsTargetGroup() const { return this->TargetGroup; } - - void WriteTypeSpecifics(const std::string& config, bool notKernel); - void WriteCompilerFlags(const std::string& config, + + void GenerateTarget(); + + void WriteTargetSpecifics(std::ostream& fout, const std::string& config); + + void WriteCompilerFlags(std::ostream& fout, const std::string& config, const std::string& language); - void WriteCompilerDefinitions(const std::string& config, + void WriteCompilerDefinitions(std::ostream& fout, const std::string& config, const std::string& language); - void SetCompilerFlags(std::string const& config, const std::string& language, - bool const notKernel); + void SetCompilerFlags(std::string const& config, + const std::string& language); + std::string GetDefines(const std::string& langugae, std::string const& config); - void WriteIncludes(const std::string& config, const std::string& language); - void WriteTargetLinkLibraries(std::string const& config, - std::string const& language); - void WriteCustomCommands(); + void WriteIncludes(std::ostream& fout, const std::string& config, + const std::string& language); + void WriteTargetLinkLine(std::ostream& fout, std::string const& config); + void WriteCustomCommands(std::ostream& fout); void WriteCustomCommandsHelper( - std::vector<cmCustomCommand> const& commandsSet, + std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet, cmTarget::CustomCommandType commandType); - void WriteSources( - std::vector<cmSourceFile*> const& objectSources, - std::map<const cmSourceFile*, std::string> const& objectNames); - static std::map<const cmSourceFile*, std::string> GetObjectNames( - std::vector<cmSourceFile*>* objectSources, - cmLocalGhsMultiGenerator* localGhsMultiGenerator, - cmGeneratorTarget* generatorTarget); - static void WriteObjectLangOverride(cmGeneratedFileStream* fileStream, + void WriteSources(std::ostream& fout_proj); + void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf, + std::string propName, std::string propFlag); + void WriteReferences(std::ostream& fout); + static void WriteObjectLangOverride(std::ostream& fout, const cmSourceFile* sourceFile); - static void WriteObjectDir(cmGeneratedFileStream* fileStream, - std::string const& dir); - std::string GetOutputDirectory(const std::string& config) const; - std::string GetOutputFilename(const std::string& config) const; - static std::string ComputeLongestObjectDirectory( - cmLocalGhsMultiGenerator const* localGhsMultiGenerator, - cmGeneratorTarget* generatorTarget, cmSourceFile* const sourceFile); - - bool IsNotKernel(std::string const& config, const std::string& language); - static bool DetermineIfTargetGroup(const cmGeneratorTarget* target); - bool DetermineIfDynamicDownload(std::string const& config, - const std::string& language); + bool DetermineIfIntegrityApp(void); cmGeneratorTarget* GeneratorTarget; cmLocalGhsMultiGenerator* LocalGenerator; cmMakefile* Makefile; - std::string AbsBuildFilePath; - std::string RelBuildFilePath; - std::string AbsBuildFileName; - std::string RelBuildFileName; - std::string RelOutputFileName; - std::string AbsOutputFileName; - std::map<std::string, cmGeneratedFileStream*> FolderBuildStreams; - bool TargetGroup; - bool DynamicDownload; - static std::string const DDOption; std::map<std::string, std::string> FlagsByLanguage; std::map<std::string, std::string> DefinesByLanguage; + + std::string TargetNameReal; + GhsMultiGpj::Types TagType; + std::string const Name; + std::string ConfigName; /* CMAKE_BUILD_TYPE */ }; #endif // ! cmGhsMultiTargetGenerator_h diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ccb3aa4..039f881 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -302,7 +302,8 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const for (cmGeneratorTarget* target : targets) { if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET || target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY || - target->GetType() == cmStateEnums::TargetType::UTILITY) { + target->GetType() == cmStateEnums::TargetType::UTILITY || + cmSystemTools::IsOn(target->GetProperty("ghs_integrity_app"))) { continue; } diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 831c4a9..557efec 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -11,6 +11,7 @@ #include "cmGhsMultiTargetGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" +#include "cmState.h" #include "cmVersion.h" #include "cmake.h" @@ -20,13 +21,12 @@ const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs"; cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm) : cmGlobalGenerator(cm) - , OSDirRelative(false) { + cm->GetState()->SetGhsMultiIDE(true); } cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() { - cmDeleteAll(TargetFolderBuildStreams); } cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator( @@ -42,46 +42,59 @@ void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) "Generates Green Hills MULTI files (experimental, work-in-progress)."; } +void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( + cmGeneratorTarget* gt) const +{ + // Compute full path to object file directory for this target. + std::string dir; + dir += gt->LocalGenerator->GetCurrentBinaryDirectory(); + dir += "/"; + dir += gt->LocalGenerator->GetTargetDirectory(gt); + dir += "/"; + gt->ObjectDirectory = dir; +} + bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, cmMakefile* mf) { - std::string tsp; /* toolset path */ - std::string tsn = ts; /* toolset name */ + std::string tsp; /* toolset path */ - GetToolset(mf, tsp, tsn); + this->GetToolset(mf, tsp, ts); /* no toolset was found */ - if (tsn.empty()) { + if (tsp.empty()) { return false; } else if (ts.empty()) { std::string message; message = "Green Hills MULTI: -T <toolset> not specified; defaulting to \""; - message += tsn; + message += tsp; message += "\""; cmSystemTools::Message(message.c_str()); - /* store the toolset for later use + /* store the full toolset for later use * -- already done if -T<toolset> was specified */ - mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsn.c_str(), - "Name of generator toolset.", + mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp.c_str(), + "Location of generator toolset.", cmStateEnums::INTERNAL); } /* set the build tool to use */ + std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") + + DEFAULT_BUILD_PROGRAM); const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM"); - std::string gbuild(tsp + "/" + tsn + "/" + DEFAULT_BUILD_PROGRAM); /* check if the toolset changed from last generate */ if (prevTool != NULL && (gbuild != prevTool)) { - std::string message = "generator toolset: "; + std::string message = "toolset build tool: "; message += gbuild; - message += "\nDoes not match the toolset used previously: "; + message += "\nDoes not match the previously used build tool: "; message += prevTool; message += "\nEither remove the CMakeCache.txt file and CMakeFiles " "directory or choose a different binary directory."; cmSystemTools::Error(message.c_str()); + return false; } else { /* store the toolset that is being used for this build */ mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(), @@ -89,25 +102,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, true); } - mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsn.c_str()); - - // FIXME: compiler detection not implemented - // gbuild uses the primaryTarget setting in the top-level project - // file to determine which compiler to use. Because compiler - // detection is not implemented these variables must be - // set to skip past these tests. However cmake will verify that - // the executable pointed to by CMAKE_<LANG>_COMPILER exists. - // To pass this additional check gbuild is used as a place holder for the - // actual compiler. - mf->AddDefinition("CMAKE_C_COMPILER", gbuild.c_str()); - mf->AddDefinition("CMAKE_C_COMPILER_ID_RUN", "TRUE"); - mf->AddDefinition("CMAKE_C_COMPILER_ID", "GHS"); - mf->AddDefinition("CMAKE_C_COMPILER_FORCED", "TRUE"); - - mf->AddDefinition("CMAKE_CXX_COMPILER", gbuild.c_str()); - mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE"); - mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHS"); - mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE"); + mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str()); return true; } @@ -130,6 +125,8 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM"); if (tgtPlatform == nullptr) { + cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not " + "specified; defaulting to \"integrity\""); tgtPlatform = "integrity"; } @@ -160,11 +157,11 @@ bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/) } void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, - std::string& ts) + const std::string& ts) { const char* ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT"); - if (!ghsRoot) { + if (!ghsRoot || ghsRoot[0] == '\0') { ghsRoot = DEFAULT_TOOLSET_ROOT; } tsd = ghsRoot; @@ -173,129 +170,208 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, std::vector<std::string> output; // Use latest? version + if (tsd.back() != '/') { + tsd += "/"; + } cmSystemTools::Glob(tsd, "comp_[^;]+", output); if (output.empty()) { - cmSystemTools::Error("GHS toolset not found in ", tsd.c_str()); - ts = ""; + std::string msg = + "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + tsd + "\"."; + cmSystemTools::Error(msg.c_str()); + tsd = ""; } else { - ts = output.back(); + tsd += output.back(); } } else { - std::string tryPath = tsd + std::string("/") + ts; + std::string tryPath; + /* CollapseCombinedPath will check if ts is an absolute path */ + tryPath = cmSystemTools::CollapseCombinedPath(tsd, ts); if (!cmSystemTools::FileExists(tryPath)) { - cmSystemTools::Error("GHS toolset \"", ts.c_str(), "\" not found in ", - tsd.c_str()); - ts = ""; + std::string msg = "GHS toolset \"" + tryPath + "\" not found."; + cmSystemTools::Error(msg.c_str()); + tsd = ""; + } else { + tsd = tryPath; } } } -void cmGlobalGhsMultiGenerator::OpenBuildFileStream( - std::string const& filepath, cmGeneratedFileStream** filestream) +void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout) { - // Get a stream where to generate things. - if (NULL == *filestream) { - *filestream = new cmGeneratedFileStream(filepath.c_str()); - if (NULL != *filestream) { - OpenBuildFileStream(*filestream); - } - } + fout << "#!gbuild" << std::endl; + fout << "#" << std::endl + << "# CMAKE generated file: DO NOT EDIT!" << std::endl + << "# Generated by \"" << this->GetActualName() << "\"" + << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "." + << cmVersion::GetMinorVersion() << std::endl + << "#" << std::endl + << std::endl; } -void cmGlobalGhsMultiGenerator::OpenBuildFileStream( - cmGeneratedFileStream* filestream) +void cmGlobalGhsMultiGenerator::WriteTopLevelProject( + std::ostream& fout, cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators) { - *filestream << "#!gbuild" << std::endl; -} + WriteFileHeader(fout); -void cmGlobalGhsMultiGenerator::OpenBuildFileStream() -{ - // Compute GHS MULTI's build file path. - std::string buildFilePath = - this->GetCMakeInstance()->GetHomeOutputDirectory(); - buildFilePath += "/"; - buildFilePath += "default"; - buildFilePath += FILE_EXTENSION; - - this->Open(std::string(""), buildFilePath, &this->TargetFolderBuildStreams); - OpenBuildFileStream(GetBuildFileStream()); - - char const* osDir = - this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR"); - if (NULL == osDir) { - osDir = ""; - cmSystemTools::Error("GHS_OS_DIR cache variable must be set"); - } else { - this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR"); - } - std::string fOSDir(this->trimQuotes(osDir)); - std::replace(fOSDir.begin(), fOSDir.end(), '\\', '/'); - if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0])) { - this->OSDirRelative = false; - } else { - this->OSDirRelative = true; + this->WriteMacros(fout); + this->WriteHighLevelDirectives(fout); + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout); + + fout << "# Top Level Project File" << std::endl; + + // Specify BSP option if supplied by user + // -- not all platforms require this entry in the project file + // integrity platforms require this field; use default if needed + std::string platform; + if (const char* p = + this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) { + platform = p; } std::string bspName; - char const* bspCache = - this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME"); - if (bspCache) { + if (char const* bspCache = + this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) { bspName = bspCache; this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME"); + } else { + bspName = "IGNORE"; } - if (bspName.empty() || bspName.compare("IGNORE") == 0) { + + if (platform.find("integrity") != std::string::npos && + cmSystemTools::IsOff(bspName.c_str())) { const char* a = this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM"); bspName = "sim"; bspName += (a ? a : ""); } - this->WriteMacros(); - this->WriteHighLevelDirectives(); + if (!cmSystemTools::IsOff(bspName.c_str())) { + fout << " -bsp " << bspName << std::endl; + } + + // Specify OS DIR if supplied by user + // -- not all platforms require this entry in the project file + std::string osDir; + std::string osDirOption; + if (char const* osDirCache = + this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) { + osDir = osDirCache; + } + + if (char const* osDirOptionCache = + this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) { + osDirOption = osDirOptionCache; + } - GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream()); - this->WriteDisclaimer(this->GetBuildFileStream()); - *this->GetBuildFileStream() << "# Top Level Project File" << std::endl; - *this->GetBuildFileStream() << " -bsp " << bspName << std::endl; + if (!cmSystemTools::IsOff(osDir.c_str()) || + platform.find("integrity") != std::string::npos) { + std::replace(osDir.begin(), osDir.end(), '\\', '/'); + fout << " " << osDirOption << "\"" << osDir << "\"" << std::endl; + } - this->WriteCompilerOptions(fOSDir); + WriteSubProjects(fout, root, generators); } -void cmGlobalGhsMultiGenerator::CloseBuildFileStream( - cmGeneratedFileStream** filestream) +void cmGlobalGhsMultiGenerator::WriteSubProjects( + std::ostream& fout, cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators) { - if (filestream) { - delete *filestream; - *filestream = NULL; - } else { - cmSystemTools::Error("Build file stream was not open."); + // Collect all targets under this root generator and the transitive + // closure of their dependencies. + TargetDependSet projectTargets; + TargetDependSet originalTargets; + this->GetTargetSets(projectTargets, originalTargets, root, generators); + OrderedTargetDependSet orderedProjectTargets(projectTargets, ""); + + // write out all the sub-projects + std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); + for (cmGeneratorTarget const* target : orderedProjectTargets) { + if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + continue; + } + + const char* projName = target->GetProperty("GENERATOR_FILE_NAME"); + const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT"); + if (projName && projType) { + cmLocalGenerator* lg = target->GetLocalGenerator(); + std::string dir = lg->GetCurrentBinaryDirectory(); + dir = root->ConvertToRelativePath(rootBinaryDir, dir.c_str()); + if (dir == ".") { + dir.clear(); + } else { + if (dir.back() != '/') { + dir += "/"; + } + } + + if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) { + fout << "{comment} "; + } + std::string projFile = dir + projName + FILE_EXTENSION; + fout << projFile; + fout << " " << projType << std::endl; + + if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) { + // create reference project + std::string fname = dir; + fname += target->GetName(); + fname += "REF"; + fname += FILE_EXTENSION; + + cmGeneratedFileStream fref(fname.c_str()); + fref.SetCopyIfDifferent(true); + + this->WriteFileHeader(fref); + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref); + fref << " :reference=" << projFile << std::endl; + + fref.Close(); + } + } } } void cmGlobalGhsMultiGenerator::Generate() { + // first do the superclass method this->cmGlobalGenerator::Generate(); - if (!this->LocalGenerators.empty()) { - this->OpenBuildFileStream(); + // output top-level projects + for (auto& it : this->ProjectMap) { + this->OutputTopLevelProject(it.second[0], it.second); + } +} - // Build all the folder build files - for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { - cmLocalGhsMultiGenerator* lg = - static_cast<cmLocalGhsMultiGenerator*>(this->LocalGenerators[i]); - const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets(); - this->UpdateBuildFiles(tgts); - } +void cmGlobalGhsMultiGenerator::OutputTopLevelProject( + cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) +{ + if (generators.empty()) { + return; } - cmDeleteAll(TargetFolderBuildStreams); - this->TargetFolderBuildStreams.clear(); + /* Name top-level projects as filename.top.gpj to avoid name clashes + * with target projects. This avoid the issue where the project has + * the same name as the executable target. + */ + std::string fname = root->GetCurrentBinaryDirectory(); + fname += "/"; + fname += root->GetProjectName(); + fname += ".top"; + fname += FILE_EXTENSION; + + cmGeneratedFileStream fout(fname.c_str()); + fout.SetCopyIfDifferent(true); + + this->WriteTopLevelProject(fout, root, generators); + + fout.Close(); } void cmGlobalGhsMultiGenerator::GenerateBuildCommand( std::vector<std::string>& makeCommand, const std::string& makeProgram, - const std::string& /*projectName*/, const std::string& /*projectDir*/, + const std::string& projectName, const std::string& projectDir, const std::string& targetName, const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions) { @@ -313,16 +389,34 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand( makeCommand.insert(makeCommand.end(), makeOptions.begin(), makeOptions.end()); + + /* determine which top-project file to use */ + std::string proj = projectName + ".top" + FILE_EXTENSION; + std::vector<std::string> files; + cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files); + if (!files.empty()) { + auto p = std::find(files.begin(), files.end(), proj); + if (p == files.end()) { + proj = files.at(0); + } + } + + makeCommand.push_back("-top"); + makeCommand.push_back(proj); if (!targetName.empty()) { if (targetName == "clean") { makeCommand.push_back("-clean"); } else { - makeCommand.push_back(targetName); + if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) { + makeCommand.push_back(targetName); + } else { + makeCommand.push_back(targetName + ".gpj"); + } } } } -void cmGlobalGhsMultiGenerator::WriteMacros() +void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout) { char const* ghsGpjMacros = this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS"); @@ -332,12 +426,12 @@ void cmGlobalGhsMultiGenerator::WriteMacros() for (std::vector<std::string>::const_iterator expandedListI = expandedList.begin(); expandedListI != expandedList.end(); ++expandedListI) { - *this->GetBuildFileStream() << "macro " << *expandedListI << std::endl; + fout << "macro " << *expandedListI << std::endl; } } } -void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives() +void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout) { /* set primary target */ std::string tgt; @@ -357,183 +451,46 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives() tgt += ".tgt"; } - *this->GetBuildFileStream() << "primaryTarget=" << tgt << std::endl; + fout << "primaryTarget=" << tgt << std::endl; char const* const customization = this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION"); if (NULL != customization && strlen(customization) > 0) { - *this->GetBuildFileStream() - << "customization=" << trimQuotes(customization) << std::endl; + fout << "customization=" << trimQuotes(customization) << std::endl; this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION"); } } -void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const& fOSDir) -{ - *this->GetBuildFileStream() - << " -os_dir=\"" << fOSDir << "\"" << std::endl; -} - -void cmGlobalGhsMultiGenerator::WriteDisclaimer(std::ostream* os) -{ - (*os) << "#" << std::endl - << "# CMAKE generated file: DO NOT EDIT!" << std::endl - << "# Generated by \"" << GetActualName() << "\"" - << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "." - << cmVersion::GetMinorVersion() << std::endl - << "#" << std::endl; -} - -void cmGlobalGhsMultiGenerator::AddFilesUpToPath( - cmGeneratedFileStream* mainBuildFile, - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - char const* homeOutputDirectory, std::string const& path, - GhsMultiGpj::Types projType, std::string const& relPath) +std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str) { - std::string workingPath(path); - cmSystemTools::ConvertToUnixSlashes(workingPath); - std::vector<std::string> splitPath = cmSystemTools::SplitString(workingPath); - std::string workingRelPath(relPath); - cmSystemTools::ConvertToUnixSlashes(workingRelPath); - if (!workingRelPath.empty()) { - workingRelPath += "/"; - } - std::string pathUpTo; - for (std::vector<std::string>::const_iterator splitPathI = splitPath.begin(); - splitPath.end() != splitPathI; ++splitPathI) { - pathUpTo += *splitPathI; - if (targetFolderBuildStreams->end() == - targetFolderBuildStreams->find(pathUpTo)) { - AddFilesUpToPathNewBuildFile( - mainBuildFile, targetFolderBuildStreams, homeOutputDirectory, pathUpTo, - splitPath.begin() == splitPathI, workingRelPath, projType); + std::string result; + result.reserve(str.size()); + for (const char* ch = str.c_str(); *ch != '\0'; ++ch) { + if (*ch != '"') { + result += *ch; } - AddFilesUpToPathAppendNextFile(targetFolderBuildStreams, pathUpTo, - splitPathI, splitPath.end(), projType); - pathUpTo += "/"; - } -} - -void cmGlobalGhsMultiGenerator::Open( - std::string const& mapKeyName, std::string const& fileName, - std::map<std::string, cmGeneratedFileStream*>* fileMap) -{ - if (fileMap->end() == fileMap->find(fileName)) { - cmGeneratedFileStream* temp(new cmGeneratedFileStream); - temp->open(fileName.c_str()); - (*fileMap)[mapKeyName] = temp; - } -} - -void cmGlobalGhsMultiGenerator::AddFilesUpToPathNewBuildFile( - cmGeneratedFileStream* mainBuildFile, - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - char const* homeOutputDirectory, std::string const& pathUpTo, - bool const isFirst, std::string const& relPath, - GhsMultiGpj::Types const projType) -{ - // create folders up to file path - std::string absPath = std::string(homeOutputDirectory) + "/" + relPath; - std::string newPath = absPath + pathUpTo; - if (!cmSystemTools::FileExists(newPath.c_str())) { - cmSystemTools::MakeDirectory(newPath.c_str()); - } - - // Write out to filename for first time - std::string relFilename(GetFileNameFromPath(pathUpTo)); - std::string absFilename = absPath + relFilename; - Open(pathUpTo, absFilename, targetFolderBuildStreams); - OpenBuildFileStream((*targetFolderBuildStreams)[pathUpTo]); - GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]); - WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo]); - - // Add to main build file - if (isFirst) { - *mainBuildFile << relFilename << " "; - GhsMultiGpj::WriteGpjTag(projType, mainBuildFile); - } -} - -void cmGlobalGhsMultiGenerator::AddFilesUpToPathAppendNextFile( - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - std::string const& pathUpTo, - std::vector<std::string>::const_iterator splitPathI, - std::vector<std::string>::const_iterator end, - GhsMultiGpj::Types const projType) -{ - std::vector<std::string>::const_iterator splitPathNextI = splitPathI + 1; - if (end != splitPathNextI && - targetFolderBuildStreams->end() == - targetFolderBuildStreams->find(pathUpTo + "/" + *splitPathNextI)) { - std::string nextFilename(*splitPathNextI); - nextFilename = GetFileNameFromPath(nextFilename); - *(*targetFolderBuildStreams)[pathUpTo] << nextFilename << " "; - GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]); } + return result; } -std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath( - std::string const& path) +bool cmGlobalGhsMultiGenerator::TargetCompare::operator()( + cmGeneratorTarget const* l, cmGeneratorTarget const* r) const { - std::string output(path); - if (!path.empty()) { - cmSystemTools::ConvertToUnixSlashes(output); - std::vector<std::string> splitPath = cmSystemTools::SplitString(output); - output += "/" + splitPath.back() + FILE_EXTENSION; + // Make sure a given named target is ordered first, + // e.g. to set ALL_BUILD as the default active project. + // When the empty string is named this is a no-op. + if (r->GetName() == this->First) { + return false; } - return output; -} - -void cmGlobalGhsMultiGenerator::UpdateBuildFiles( - const std::vector<cmGeneratorTarget*>& tgts) -{ - for (std::vector<cmGeneratorTarget*>::const_iterator tgtsI = tgts.begin(); - tgtsI != tgts.end(); ++tgtsI) { - const cmGeneratorTarget* tgt = *tgtsI; - if (IsTgtForBuild(tgt)) { - std::string folderName = tgt->GetEffectiveFolderName(); - if (this->TargetFolderBuildStreams.end() == - this->TargetFolderBuildStreams.find(folderName)) { - this->AddFilesUpToPath( - GetBuildFileStream(), &this->TargetFolderBuildStreams, - this->GetCMakeInstance()->GetHomeOutputDirectory().c_str(), - folderName, GhsMultiGpj::PROJECT); - } - std::vector<std::string> splitPath = cmSystemTools::SplitString( - cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt)); - std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" + - splitPath.back()); - *this->TargetFolderBuildStreams[folderName] << foldNameRelBuildFile - << " "; - GhsMultiGpj::WriteGpjTag(cmGhsMultiTargetGenerator::GetGpjTag(tgt), - this->TargetFolderBuildStreams[folderName]); - } + if (l->GetName() == this->First) { + return true; } + return l->GetName() < r->GetName(); } -bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmGeneratorTarget* tgt) +cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet( + TargetDependSet const& targets, std::string const& first) + : derived(TargetCompare(first)) { - const std::string config = - tgt->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); - std::vector<cmSourceFile*> tgtSources; - tgt->GetSourceFiles(tgtSources, config); - bool tgtInBuild = true; - char const* excludeFromAll = tgt->GetProperty("EXCLUDE_FROM_ALL"); - if (NULL != excludeFromAll && '1' == excludeFromAll[0] && - '\0' == excludeFromAll[1]) { - tgtInBuild = false; - } - return !tgtSources.empty() && tgtInBuild; -} - -std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str) -{ - std::string result; - result.reserve(str.size()); - for (const char* ch = str.c_str(); *ch != '\0'; ++ch) { - if (*ch != '"') { - result += *ch; - } - } - return result; + this->insert(targets.begin(), targets.end()); } diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index a5aff73..9332567 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -13,7 +13,7 @@ class cmGeneratedFileStream; class cmGlobalGhsMultiGenerator : public cmGlobalGenerator { public: - /// The default name of GHS MULTI's build file. Typically: monolith.gpj. + // The default filename extension of GHS MULTI's build files. static const char* FILE_EXTENSION; cmGlobalGhsMultiGenerator(cmake* cm); @@ -63,29 +63,28 @@ public: */ bool FindMakeProgram(cmMakefile* mf) override; - cmGeneratedFileStream* GetBuildFileStream() - { - return this->TargetFolderBuildStreams[""]; - } + void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override; - static void OpenBuildFileStream(std::string const& filepath, - cmGeneratedFileStream** filestream); - static void OpenBuildFileStream(cmGeneratedFileStream* filestream); - static void CloseBuildFileStream(cmGeneratedFileStream** filestream); - /// Write the common disclaimer text at the top of each build file. - static void WriteDisclaimer(std::ostream* os); - std::vector<std::string> GetLibDirs() { return this->LibDirs; } - - static void AddFilesUpToPath( - cmGeneratedFileStream* mainBuildFile, - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - char const* homeOutputDirectory, std::string const& path, - GhsMultiGpj::Types projType, std::string const& relPath = ""); - static void Open(std::string const& mapKeyName, std::string const& fileName, - std::map<std::string, cmGeneratedFileStream*>* fileMap); - - static std::string trimQuotes(std::string const& str); - inline bool IsOSDirRelative() { return this->OSDirRelative; } + // Write the common disclaimer text at the top of each build file. + void WriteFileHeader(std::ostream& fout); + + // Target dependency sorting + class TargetSet : public std::set<cmGeneratorTarget const*> + { + }; + class TargetCompare + { + std::string First; + + public: + TargetCompare(std::string const& first) + : First(first) + { + } + bool operator()(cmGeneratorTarget const* l, + cmGeneratorTarget const* r) const; + }; + class OrderedTargetDependSet; protected: void Generate() override; @@ -100,35 +99,35 @@ protected: std::vector<std::string>()) override; private: - void GetToolset(cmMakefile* mf, std::string& tsd, std::string& ts); - void OpenBuildFileStream(); - - void WriteMacros(); - void WriteHighLevelDirectives(); - void WriteCompilerOptions(std::string const& fOSDir); - - static void AddFilesUpToPathNewBuildFile( - cmGeneratedFileStream* mainBuildFile, - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - char const* homeOutputDirectory, std::string const& pathUpTo, bool isFirst, - std::string const& relPath, GhsMultiGpj::Types projType); - static void AddFilesUpToPathAppendNextFile( - std::map<std::string, cmGeneratedFileStream*>* targetFolderBuildStreams, - std::string const& pathUpTo, - std::vector<std::string>::const_iterator splitPathI, - std::vector<std::string>::const_iterator end, GhsMultiGpj::Types projType); - static std::string GetFileNameFromPath(std::string const& path); - void UpdateBuildFiles(const std::vector<cmGeneratorTarget*>& tgts); - bool IsTgtForBuild(const cmGeneratorTarget* tgt); - - std::vector<cmGeneratedFileStream*> TargetSubProjects; - std::map<std::string, cmGeneratedFileStream*> TargetFolderBuildStreams; - - std::vector<std::string> LibDirs; - - bool OSDirRelative; + void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts); + + /* top-level project */ + void OutputTopLevelProject(cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators); + void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators); + void WriteMacros(std::ostream& fout); + void WriteHighLevelDirectives(std::ostream& fout); + void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root, + std::vector<cmLocalGenerator*>& generators); + + std::string trimQuotes(std::string const& str); + static const char* DEFAULT_BUILD_PROGRAM; static const char* DEFAULT_TOOLSET_ROOT; }; +class cmGlobalGhsMultiGenerator::OrderedTargetDependSet + : public std::multiset<cmTargetDepend, + cmGlobalGhsMultiGenerator::TargetCompare> +{ + typedef std::multiset<cmTargetDepend, + cmGlobalGhsMultiGenerator::TargetCompare> + derived; + +public: + typedef cmGlobalGenerator::TargetDependSet TargetDependSet; + OrderedTargetDependSet(TargetDependSet const&, std::string const& first); +}; + #endif diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx index ab6774e..125e8b5 100644 --- a/Source/cmLocalGhsMultiGenerator.cxx +++ b/Source/cmLocalGhsMultiGenerator.cxx @@ -7,6 +7,7 @@ #include "cmGhsMultiTargetGenerator.h" #include "cmGlobalGhsMultiGenerator.h" #include "cmMakefile.h" +#include "cmSourceFile.h" cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg, cmMakefile* mf) @@ -18,16 +19,82 @@ cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator() { } +std::string cmLocalGhsMultiGenerator::GetTargetDirectory( + cmGeneratorTarget const* target) const +{ + std::string dir; + dir += target->GetName(); + dir += ".dir"; + return dir; +} + +void cmLocalGhsMultiGenerator::GenerateTargetsDepthFirst( + cmGeneratorTarget* target, std::vector<cmGeneratorTarget*>& remaining) +{ + if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + return; + } + // Find this target in the list of remaining targets. + auto it = std::find(remaining.begin(), remaining.end(), target); + if (it == remaining.end()) { + // This target was already handled. + return; + } + // Remove this target from the list of remaining targets because + // we are handling it now. + *it = nullptr; + + cmGhsMultiTargetGenerator tg(target); + tg.Generate(); +} + void cmLocalGhsMultiGenerator::Generate() { - const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets(); + std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets(); + for (auto& t : remaining) { + if (t) { + GenerateTargetsDepthFirst(t, remaining); + } + } +} + +void cmLocalGhsMultiGenerator::ComputeObjectFilenames( + std::map<cmSourceFile const*, std::string>& mapping, + cmGeneratorTarget const* gt) +{ + std::string dir_max; + dir_max += this->GetCurrentBinaryDirectory(); + dir_max += "/"; + dir_max += this->GetTargetDirectory(gt); + dir_max += "/"; + + // Count the number of object files with each name. Note that + // filesystem may not be case sensitive. + std::map<std::string, int> counts; + + for (auto const& si : mapping) { + cmSourceFile const* sf = si.first; + std::string objectNameLower = cmSystemTools::LowerCase( + cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())); + objectNameLower += this->GlobalGenerator->GetLanguageOutputExtension(*sf); + counts[objectNameLower] += 1; + } + + // For all source files producing duplicate names we need unique + // object name computation. + for (auto& si : mapping) { + cmSourceFile const* sf = si.first; + std::string objectName = + cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()); + objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf); - for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin(); - l != tgts.end(); ++l) { - if ((*l)->GetType() == cmStateEnums::INTERFACE_LIBRARY) { - continue; + if (counts[cmSystemTools::LowerCase(objectName)] > 1) { + const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf); + bool keptSourceExtension; + objectName = this->GetObjectFileNameWithoutTarget(*sf, dir_max, + &keptSourceExtension); + cmsys::SystemTools::ReplaceString(objectName, "/", "_"); } - cmGhsMultiTargetGenerator tg(*l); - tg.Generate(); + si.second = objectName; } } diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h index aa842d7..d5bec42 100644 --- a/Source/cmLocalGhsMultiGenerator.h +++ b/Source/cmLocalGhsMultiGenerator.h @@ -24,6 +24,17 @@ public: * Generate the makefile for this directory. */ virtual void Generate(); + + std::string GetTargetDirectory( + cmGeneratorTarget const* target) const override; + + void ComputeObjectFilenames( + std::map<cmSourceFile const*, std::string>& mapping, + cmGeneratorTarget const* gt = nullptr) override; + +private: + void GenerateTargetsDepthFirst(cmGeneratorTarget* target, + std::vector<cmGeneratorTarget*>& remaining); }; #endif diff --git a/Source/cmState.cxx b/Source/cmState.cxx index cf170b0..d4d3df5 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -596,6 +596,16 @@ bool cmState::UseWindowsVSIDE() const return this->WindowsVSIDE; } +void cmState::SetGhsMultiIDE(bool ghsMultiIDE) +{ + this->GhsMultiIDE = ghsMultiIDE; +} + +bool cmState::UseGhsMultiIDE() const +{ + return this->GhsMultiIDE; +} + void cmState::SetWatcomWMake(bool watcomWMake) { this->WatcomWMake = watcomWMake; diff --git a/Source/cmState.h b/Source/cmState.h index dfd6d2c..e447485 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -164,6 +164,8 @@ public: bool UseWindowsShell() const; void SetWindowsVSIDE(bool windowsVSIDE); bool UseWindowsVSIDE() const; + void SetGhsMultiIDE(bool ghsMultiIDE); + bool UseGhsMultiIDE() const; void SetWatcomWMake(bool watcomWMake); bool UseWatcomWMake() const; void SetMinGWMake(bool minGWMake); @@ -222,6 +224,7 @@ private: bool IsGeneratorMultiConfig = false; bool WindowsShell = false; bool WindowsVSIDE = false; + bool GhsMultiIDE = false; bool WatcomWMake = false; bool MinGWMake = false; bool NMake = false; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index aa85c4a..71a9cb4 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -3114,7 +3114,8 @@ std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes) } bool cmSystemTools::CreateSymlink(const std::string& origName, - const std::string& newName) + const std::string& newName, + std::string* errorMessage) { uv_fs_t req; int flags = 0; @@ -3128,7 +3129,32 @@ bool cmSystemTools::CreateSymlink(const std::string& origName, if (err) { std::string e = "failed to create symbolic link '" + newName + "': " + uv_strerror(err); - cmSystemTools::Error(e.c_str()); + if (errorMessage) { + *errorMessage = std::move(e); + } else { + cmSystemTools::Error(e.c_str()); + } + return false; + } + + return true; +} + +bool cmSystemTools::CreateLink(const std::string& origName, + const std::string& newName, + std::string* errorMessage) +{ + uv_fs_t req; + int err = + uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr); + if (err) { + std::string e = + "failed to create link '" + newName + "': " + uv_strerror(err); + if (errorMessage) { + *errorMessage = std::move(e); + } else { + cmSystemTools::Error(e.c_str()); + } return false; } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index c0999e7..489811d 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -528,7 +528,14 @@ public: /** Create a symbolic link if the platform supports it. Returns whether creation succeeded. */ static bool CreateSymlink(const std::string& origName, - const std::string& newName); + const std::string& newName, + std::string* errorMessage = nullptr); + + /** Create a hard link if the platform supports it. Returns whether + creation succeeded. */ + static bool CreateLink(const std::string& origName, + const std::string& newName, + std::string* errorMessage = nullptr); private: static bool s_ForceUnixPaths; |