Browse Source

Merge topic 'ghs_predefined_targets'

399e73b89a GHS: release note
829e946c69 GHS: Update tests for updated binary layout
93c1acd8ff GHS: List predefined targets before user targets in GUI
bdb213819c GHS: Do not include WindowsPaths
b3e9c72901 GHS: use INSTALL target
a645287784 GHS: update build command
724b5491ef GHS: Rearrange project files in binary directory
edff0f6a1d GHS: Use Custom Target for ALL_BUILD
...

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !7079
Brad King 3 years ago
parent
commit
7e642a6fa0

+ 6 - 0
Help/release/dev/ghs_predefined_targets.rst

@@ -0,0 +1,6 @@
+ghs_predefined_targets
+----------------------
+
+* A new predefined target `RERUN_CMAKE` is added for
+  :generator:`Green Hills MULTI` generator to easily rerun
+  CMake if any CMake files were updated.

+ 0 - 2
Modules/Platform/GHS-MULTI.cmake

@@ -13,5 +13,3 @@ set(GHSMULTI 1)
 
 set(CMAKE_FIND_LIBRARY_PREFIXES "")
 set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
-
-include(Platform/WindowsPaths)

+ 22 - 14
Source/cmGhsMultiTargetGenerator.cxx

@@ -107,12 +107,6 @@ void cmGhsMultiTargetGenerator::Generate()
       return;
   }
 
-  // Tell the global generator the name of the project file
-  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
-                                             this->Name);
-  this->GeneratorTarget->Target->SetProperty(
-    "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
-
   this->GenerateTarget();
 }
 
@@ -121,7 +115,14 @@ void cmGhsMultiTargetGenerator::GenerateTarget()
   // Open the target file in copy-if-different mode.
   std::string fproj =
     cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
-             this->Name, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
+             this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget),
+             '/', this->Name, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
+
+  // Tell the global generator the name of the project file
+  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME", fproj);
+  this->GeneratorTarget->Target->SetProperty(
+    "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
+
   cmGeneratedFileStream fout(fproj);
   fout.SetCopyIfDifferent(true);
 
@@ -155,10 +156,16 @@ void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
 {
   std::string outpath;
 
+  /* Determine paths from the target project file to where the output artifacts
+   * need to be located.
+   */
   if (this->TagType != GhsMultiGpj::SUBPROJECT) {
     // set target binary file destination
-    outpath = this->GeneratorTarget->GetDirectory(config);
-    outpath = this->LocalGenerator->MaybeRelativeToCurBinDir(outpath);
+    std::string binpath = cmStrCat(
+      this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+      this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget));
+    outpath = cmSystemTools::RelativePath(
+      binpath, this->GeneratorTarget->GetDirectory(config));
     /* clang-format off */
     fout << "    :binDirRelative=\"" << outpath << "\"\n"
             "    -o \"" << this->TargetNameReal << "\"\n";
@@ -166,7 +173,7 @@ void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
   }
 
   // set target object file destination
-  outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+  outpath = ".";
   fout << "    :outputDirRelative=\"" << outpath << "\"\n";
 }
 
@@ -576,11 +583,12 @@ void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
       // Open the filestream in copy-if-different mode.
       std::string gname = sg;
       cmsys::SystemTools::ReplaceString(gname, "\\", "_");
-      std::string lpath = cmStrCat(
-        this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
-        gname, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
+      std::string lpath =
+        cmStrCat(gname, cmGlobalGhsMultiGenerator::FILE_EXTENSION);
       std::string fpath = cmStrCat(
-        this->LocalGenerator->GetCurrentBinaryDirectory(), '/', lpath);
+        this->LocalGenerator->GetCurrentBinaryDirectory(), '/',
+        this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/',
+        lpath);
       cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath);
       f->SetCopyIfDifferent(true);
       gfiles.push_back(f);

+ 232 - 120
Source/cmGlobalGhsMultiGenerator.cxx

@@ -2,14 +2,19 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGlobalGhsMultiGenerator.h"
 
+#include <algorithm>
+#include <functional>
 #include <map>
-#include <ostream>
+#include <sstream>
 #include <utility>
 
 #include <cm/memory>
 #include <cm/string>
 #include <cmext/algorithm>
+#include <cmext/memory>
 
+#include "cmCustomCommand.h"
+#include "cmCustomCommandLines.h"
 #include "cmDocumentationEntry.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
@@ -18,10 +23,13 @@
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
 #include "cmMessageType.h"
+#include "cmPolicies.h"
+#include "cmSourceFile.h"
 #include "cmState.h"
 #include "cmStateTypes.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
+#include "cmTarget.h"
 #include "cmValue.h"
 #include "cmVersion.h"
 #include "cmake.h"
@@ -32,6 +40,8 @@ const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild";
 #elif defined(_WIN32)
 const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe";
 #endif
+const char* cmGlobalGhsMultiGenerator::CHECK_BUILD_SYSTEM_TARGET =
+  "RERUN_CMAKE";
 
 cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
   : cmGlobalGenerator(cm)
@@ -279,7 +289,7 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
 {
   this->WriteFileHeader(fout);
   this->WriteMacros(fout, root);
-  this->WriteHighLevelDirectives(root, fout);
+  this->WriteHighLevelDirectives(fout, root);
   GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
 
   fout << "# Top Level Project File\n";
@@ -308,9 +318,13 @@ void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout,
 }
 
 void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
-                                                 std::string& all_target)
+                                                 bool filterPredefined)
 {
-  fout << "CMakeFiles/" << all_target << " [Project]\n";
+  std::set<std::string> predefinedTargets;
+  predefinedTargets.insert(this->GetInstallTargetName());
+  predefinedTargets.insert(this->GetAllTargetName());
+  predefinedTargets.insert(std::string(CHECK_BUILD_SYSTEM_TARGET));
+
   // All known targets
   for (cmGeneratorTarget const* target : this->ProjectTargets) {
     if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
@@ -320,8 +334,13 @@ void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout,
          target->GetName() != this->GetInstallTargetName())) {
       continue;
     }
-    fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION
-         << " [Project]\n";
+    /* Check if the current target is a predefined CMake target */
+    bool predefinedTarget =
+      predefinedTargets.find(target->GetName()) != predefinedTargets.end();
+    if ((filterPredefined && predefinedTarget) ||
+        (!filterPredefined && !predefinedTarget)) {
+      fout << target->GetName() + ".tgt" + FILE_EXTENSION << " [Project]\n";
+    }
   }
 }
 
@@ -329,36 +348,22 @@ void cmGlobalGhsMultiGenerator::WriteProjectLine(
   std::ostream& fout, cmGeneratorTarget const* target,
   std::string& rootBinaryDir)
 {
-  cmValue projName = target->GetProperty("GENERATOR_FILE_NAME");
+  cmValue projFile = target->GetProperty("GENERATOR_FILE_NAME");
   cmValue projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
-  if (projName && projType) {
-    cmLocalGenerator* lg = target->GetLocalGenerator();
-    std::string dir = lg->GetCurrentBinaryDirectory();
-    dir = cmSystemTools::ForceToRelativePath(rootBinaryDir, dir);
-    if (dir == ".") {
-      dir.clear();
-    } else {
-      if (dir.back() != '/') {
-        dir += "/";
-      }
-    }
+  /* If either value is not valid then this particular target is an
+   * unsupported target type and should be skipped.
+   */
+  if (projFile && projType) {
+    std::string path = cmSystemTools::RelativePath(rootBinaryDir, projFile);
 
-    std::string projFile = dir + *projName + FILE_EXTENSION;
-    fout << projFile;
+    fout << path;
     fout << ' ' << *projType << '\n';
-  } else {
-    /* Should never happen */
-    std::string message =
-      "The project file for target [" + target->GetName() + "] is missing.\n";
-    cmSystemTools::Error(message);
-    fout << "{comment} " << target->GetName() << " [missing project file]\n";
   }
 }
 
 void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
 {
-  std::string rootBinaryDir =
-    cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeFiles");
+  std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
 
   // All known targets
   for (cmGeneratorTarget const* target : this->ProjectTargets) {
@@ -391,62 +396,6 @@ void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root)
   }
 }
 
-void cmGlobalGhsMultiGenerator::WriteAllTarget(
-  cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators,
-  std::string& all_target)
-{
-  this->ProjectTargets.clear();
-
-  // create target build file
-  all_target = root->GetProjectName() + "." + this->GetAllTargetName() +
-    ".tgt" + FILE_EXTENSION;
-  std::string fname =
-    root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target;
-  cmGeneratedFileStream fbld(fname);
-  fbld.SetCopyIfDifferent(true);
-  this->WriteFileHeader(fbld);
-  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld);
-
-  // 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 sortedProjectTargets(projectTargets, "");
-  std::vector<cmGeneratorTarget const*> defaultTargets;
-  for (cmGeneratorTarget const* t : sortedProjectTargets) {
-    /* save list of all targets in sorted order */
-    this->ProjectTargets.push_back(t);
-  }
-  for (cmGeneratorTarget const* t : sortedProjectTargets) {
-    if (!t->IsInBuildSystem()) {
-      continue;
-    }
-    if (!this->IsExcluded(t->GetLocalGenerator(), t)) {
-      defaultTargets.push_back(t);
-    }
-  }
-  std::vector<cmGeneratorTarget const*> build;
-  if (this->ComputeTargetBuildOrder(defaultTargets, build)) {
-    std::string message = "The inter-target dependency graph for project [" +
-      root->GetProjectName() + "] had a cycle.\n";
-    cmSystemTools::Error(message);
-  } else {
-    // determine the targets for ALL target
-    std::string rootBinaryDir =
-      cmStrCat(root->GetCurrentBinaryDirectory(), "/CMakeFiles");
-    for (cmGeneratorTarget const* target : build) {
-      if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY ||
-          target->GetType() == cmStateEnums::MODULE_LIBRARY ||
-          target->GetType() == cmStateEnums::SHARED_LIBRARY) {
-        continue;
-      }
-      this->WriteProjectLine(fbld, target, rootBinaryDir);
-    }
-  }
-  fbld.Close();
-}
-
 void cmGlobalGhsMultiGenerator::Generate()
 {
   std::string fname;
@@ -476,18 +425,36 @@ void cmGlobalGhsMultiGenerator::Generate()
   this->WriteFileHeader(ftarget);
   this->WriteCustomTargetBOD(ftarget);
   ftarget.Close();
+
+  // create the stamp file when running CMake
+  if (!this->StampFile.empty()) {
+    cmGeneratedFileStream fstamp(this->StampFile);
+    fstamp.SetCopyIfDifferent(false);
+    fstamp.Close();
+  }
 }
 
 void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
   cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
 {
   std::string fname;
-  std::string all_target;
 
   if (generators.empty()) {
     return;
   }
 
+  // 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 sortedProjectTargets(projectTargets, "");
+  this->ProjectTargets.clear();
+  for (cmGeneratorTarget const* t : sortedProjectTargets) {
+    /* save list of all targets in sorted order */
+    this->ProjectTargets.push_back(t);
+  }
+
   /* 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.
@@ -498,11 +465,9 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
   cmGeneratedFileStream top(fname);
   top.SetCopyIfDifferent(true);
   this->WriteTopLevelProject(top, root);
-
-  this->WriteAllTarget(root, generators, all_target);
   this->WriteTargets(root);
-
-  this->WriteSubProjects(top, all_target);
+  this->WriteSubProjects(top, true);
+  this->WriteSubProjects(top, false);
   top.Close();
 }
 
@@ -510,59 +475,62 @@ std::vector<cmGlobalGenerator::GeneratedMakeCommand>
 cmGlobalGhsMultiGenerator::GenerateBuildCommand(
   const std::string& makeProgram, const std::string& projectName,
   const std::string& projectDir, std::vector<std::string> const& targetNames,
-  const std::string& /*config*/, int jobs, bool /*verbose*/,
+  const std::string& /*config*/, int jobs, bool verbose,
   const cmBuildOptions& /*buildOptions*/,
   std::vector<std::string> const& makeOptions)
 {
-  GeneratedMakeCommand makeCommand = {};
-  std::string gbuild;
-  if (cmValue gbuildCached =
-        this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) {
-    gbuild = *gbuildCached;
-  }
-  makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild));
+  GeneratedMakeCommand makeCommand;
+
+  makeCommand.Add(this->SelectMakeProgram(makeProgram));
 
   if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) {
-    makeCommand.Add("-parallel");
-    if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
-      makeCommand.Add(std::to_string(jobs));
+    if (jobs == cmake::DEFAULT_BUILD_PARALLEL_LEVEL) {
+      makeCommand.Add("-parallel");
+    } else {
+      makeCommand.Add(std::string("-parallel=") + std::to_string(jobs));
     }
   }
 
-  makeCommand.Add(makeOptions.begin(), makeOptions.end());
-
-  /* determine which top-project file to use */
+  /* determine the top-project file in the project directory */
   std::string proj = projectName + ".top" + FILE_EXTENSION;
   std::vector<std::string> files;
   cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
   if (!files.empty()) {
-    /* if multiple top-projects are found in build directory
-     * then prefer projectName top-project.
-     */
-    if (!cm::contains(files, proj)) {
-      proj = files.at(0);
-    }
+    /* use the real top-level project in the directory */
+    proj = files.at(0);
   }
-
   makeCommand.Add("-top", proj);
+
+  /* determine targets to build */
+  bool build_all = false;
   if (!targetNames.empty()) {
-    if (cm::contains(targetNames, "clean")) {
-      makeCommand.Add("-clean");
-    } else {
-      for (const auto& tname : targetNames) {
-        if (!tname.empty()) {
+    for (const auto& tname : targetNames) {
+      if (!tname.empty()) {
+        if (tname == "clean") {
+          makeCommand.Add("-clean");
+        } else {
           makeCommand.Add(tname + ".tgt.gpj");
         }
+      } else {
+        build_all = true;
       }
     }
   } else {
+    build_all = true;
+  }
+
+  if (build_all) {
     /* transform name to default build */;
-    std::string all = proj;
-    all.replace(all.end() - 7, all.end(),
-                std::string(this->GetAllTargetName()) + ".tgt.gpj");
+    std::string all = std::string(this->GetAllTargetName()) + ".tgt.gpj";
     makeCommand.Add(all);
   }
-  return { makeCommand };
+
+  if (verbose) {
+    makeCommand.Add("-commands");
+  }
+  makeCommand.Add(makeOptions.begin(), makeOptions.end());
+
+  return { std::move(makeCommand) };
 }
 
 void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
@@ -579,7 +547,7 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout,
 }
 
 void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(
-  cmLocalGenerator* root, std::ostream& fout)
+  std::ostream& fout, cmLocalGenerator* root)
 {
   /* put primary target and customization files into project file */
   cmValue const tgt = root->GetMakefile()->GetDefinition("GHS_PRIMARY_TARGET");
@@ -681,3 +649,147 @@ bool cmGlobalGhsMultiGenerator::VisitTarget(
   /* already complete */
   return false;
 }
+
+bool cmGlobalGhsMultiGenerator::AddCheckTarget()
+{
+  // Skip the target if no regeneration is to be done.
+  if (this->GlobalSettingIsOn("CMAKE_SUPPRESS_REGENERATION")) {
+    return false;
+  }
+
+  // Get the generators.
+  std::vector<std::unique_ptr<cmLocalGenerator>> const& generators =
+    this->LocalGenerators;
+  auto& lg =
+    cm::static_reference_cast<cmLocalGhsMultiGenerator>(generators[0]);
+
+  // The name of the output file for the custom command.
+  this->StampFile = lg.GetBinaryDirectory() + std::string("/CMakeFiles/") +
+    CHECK_BUILD_SYSTEM_TARGET;
+
+  // Add a custom rule to re-run CMake if any input files changed.
+  {
+    // Collect the input files used to generate all targets in this
+    // project.
+    std::vector<std::string> listFiles;
+    for (const auto& gen : generators) {
+      cm::append(listFiles, gen->GetMakefile()->GetListFiles());
+    }
+
+    // Add the cache file.
+    listFiles.push_back(cmStrCat(
+      this->GetCMakeInstance()->GetHomeOutputDirectory(), "/CMakeCache.txt"));
+
+    // Print not implemented warning.
+    if (this->GetCMakeInstance()->DoWriteGlobVerifyTarget()) {
+      std::ostringstream msg;
+      msg << "Any pre-check scripts, such as those generated for file(GLOB "
+             "CONFIGURE_DEPENDS), will not be run by gbuild.";
+      this->GetCMakeInstance()->IssueMessage(MessageType::AUTHOR_WARNING,
+                                             msg.str());
+    }
+
+    // Sort the list of input files and remove duplicates.
+    std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>());
+    auto newEnd = std::unique(listFiles.begin(), listFiles.end());
+    listFiles.erase(newEnd, listFiles.end());
+
+    // Create a rule to re-run CMake and create output file.
+    std::string argS = cmStrCat("-S", lg.GetSourceDirectory());
+    std::string argB = cmStrCat("-B", lg.GetBinaryDirectory());
+    cmCustomCommandLines commandLines = cmMakeSingleCommandLine(
+      { cmSystemTools::GetCMakeCommand(), argS, argB });
+
+    /* Create the target(Exclude from ALL_BUILD).
+     *
+     * The build tool, currently, does not support rereading the project files
+     * if they get updated. So do not run this target as part of ALL_BUILD.
+     */
+    auto cc = cm::make_unique<cmCustomCommand>();
+    cmTarget* tgt =
+      lg.AddUtilityCommand(CHECK_BUILD_SYSTEM_TARGET, true, std::move(cc));
+    auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg);
+    auto* gt = ptr.get();
+    lg.AddGeneratorTarget(std::move(ptr));
+
+    // Add the rule.
+    cc = cm::make_unique<cmCustomCommand>();
+    cc->SetOutputs(this->StampFile);
+    cc->SetDepends(listFiles);
+    cc->SetCommandLines(commandLines);
+    cc->SetComment("Checking Build System");
+    cc->SetCMP0116Status(cmPolicies::NEW);
+    cc->SetEscapeOldStyle(false);
+    cc->SetStdPipesUTF8(true);
+
+    if (cmSourceFile* file =
+          lg.AddCustomCommandToOutput(std::move(cc), true)) {
+      gt->AddSource(file->ResolveFullPath());
+    } else {
+      cmSystemTools::Error("Error adding rule for " + this->StampFile);
+    }
+    // Organize in the "predefined targets" folder:
+    if (this->UseFolderProperty()) {
+      tgt->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+    }
+  }
+
+  return true;
+}
+
+void cmGlobalGhsMultiGenerator::AddAllTarget()
+{
+  // Add a special target that depends on ALL projects for easy build
+  // of one configuration only.
+  for (auto const& it : this->ProjectMap) {
+    std::vector<cmLocalGenerator*> const& gen = it.second;
+    // add the ALL_BUILD to the first local generator of each project
+    if (!gen.empty()) {
+      // Use no actual command lines so that the target itself is not
+      // considered always out of date.
+      auto cc = cm::make_unique<cmCustomCommand>();
+      cc->SetCMP0116Status(cmPolicies::NEW);
+      cc->SetEscapeOldStyle(false);
+      cc->SetComment("Build all projects");
+      cmTarget* allBuild = gen[0]->AddUtilityCommand(this->GetAllTargetName(),
+                                                     true, std::move(cc));
+
+      gen[0]->AddGeneratorTarget(
+        cm::make_unique<cmGeneratorTarget>(allBuild, gen[0]));
+
+      // Organize in the "predefined targets" folder:
+      if (this->UseFolderProperty()) {
+        allBuild->SetProperty("FOLDER", this->GetPredefinedTargetsFolder());
+      }
+
+      // Now make all targets depend on the ALL_BUILD target
+      for (cmLocalGenerator const* i : gen) {
+        for (const auto& tgt : i->GetGeneratorTargets()) {
+          // Skip global or imported targets
+          if (tgt->GetType() == cmStateEnums::GLOBAL_TARGET ||
+              tgt->IsImported()) {
+            continue;
+          }
+          // Skip Exclude From All Targets
+          if (!this->IsExcluded(gen[0], tgt.get())) {
+            allBuild->AddUtility(tgt->GetName(), false);
+          }
+        }
+      }
+    }
+  }
+}
+
+void cmGlobalGhsMultiGenerator::AddExtraIDETargets()
+{
+  // Add a special target that depends on ALL projects.
+  this->AddAllTarget();
+
+  /* Add Custom Target to check if CMake needs to be rerun.
+   *
+   * The build tool, currently, does not support rereading the project files
+   * if they get updated.  So do not make the other targets dependent on this
+   * check.
+   */
+  this->AddCheckTarget();
+}

+ 7 - 7
Source/cmGlobalGhsMultiGenerator.h

@@ -81,8 +81,6 @@ public:
   // Write the common disclaimer text at the top of each build file.
   void WriteFileHeader(std::ostream& fout);
 
-  const char* GetInstallTargetName() const override { return "install"; }
-
 protected:
   void Generate() override;
   std::vector<GeneratedMakeCommand> GenerateBuildCommand(
@@ -92,6 +90,7 @@ protected:
     const cmBuildOptions& buildOptions = cmBuildOptions(),
     std::vector<std::string> const& makeOptions =
       std::vector<std::string>()) override;
+  void AddExtraIDETargets() override;
 
 private:
   void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
@@ -101,20 +100,21 @@ private:
                              std::vector<cmLocalGenerator*>& generators);
   void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root);
   void WriteMacros(std::ostream& fout, cmLocalGenerator* root);
-  void WriteHighLevelDirectives(cmLocalGenerator* root, std::ostream& fout);
-  void WriteSubProjects(std::ostream& fout, std::string& all_target);
+  void WriteHighLevelDirectives(std::ostream& fout, cmLocalGenerator* root);
+  void WriteSubProjects(std::ostream& fout, bool filterPredefined);
   void WriteTargets(cmLocalGenerator* root);
   void WriteProjectLine(std::ostream& fout, cmGeneratorTarget const* target,
                         std::string& rootBinaryDir);
   void WriteCustomRuleBOD(std::ostream& fout);
   void WriteCustomTargetBOD(std::ostream& fout);
-  void WriteAllTarget(cmLocalGenerator* root,
-                      std::vector<cmLocalGenerator*>& generators,
-                      std::string& all_target);
+  bool AddCheckTarget();
+  void AddAllTarget();
 
+  std::string StampFile;
   static std::string TrimQuotes(std::string str);
 
   static const char* DEFAULT_BUILD_PROGRAM;
+  static const char* CHECK_BUILD_SYSTEM_TARGET;
 
   bool ComputeTargetBuildOrder(cmGeneratorTarget const* tgt,
                                std::vector<cmGeneratorTarget const*>& build);

+ 1 - 1
Tests/CMakeLists.txt

@@ -2319,7 +2319,7 @@ if(BUILD_TESTING)
     endmacro()
     macro(add_test_GhsMulti_rename_install test_name)
       add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
-        "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target install)
+        "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} --build . --target INSTALL)
     endmacro()
     #unset ghs config variables
     unset(ghs_config_name)

+ 5 - 10
Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt

@@ -27,8 +27,7 @@ try_compile(RESULT
 message("Output from build:\n${OUTPUT}")
 if (RUN_TEST STREQUAL "RELEASE_FLAGS")
   find_file (fileName test_none.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/build
-    ${CMAKE_CURRENT_BINARY_DIR}/build/test_none
+    ${CMAKE_CURRENT_BINARY_DIR}/build/test_none.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -40,8 +39,7 @@ if (RUN_TEST STREQUAL "RELEASE_FLAGS")
 else()
   unset(fileName CACHE)
   find_file (fileName K1.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/build
-    ${CMAKE_CURRENT_BINARY_DIR}/build/K1
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K1.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -53,8 +51,7 @@ else()
 
   unset(fileName CACHE)
   find_file (fileName K2.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/build
-    ${CMAKE_CURRENT_BINARY_DIR}/build/K2
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K2.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -66,8 +63,7 @@ else()
 
   unset(fileName CACHE)
   find_file (fileName K3.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/build
-    ${CMAKE_CURRENT_BINARY_DIR}/build/K3
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K3.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -79,8 +75,7 @@ else()
 
   unset(fileName CACHE)
   find_file (fileName K4.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/build
-    ${CMAKE_CURRENT_BINARY_DIR}/build/K4
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K4.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)

+ 2 - 0
Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt

@@ -14,4 +14,6 @@ set_target_properties( lib1 PROPERTIES EXCLUDE_FROM_ALL yes )
 
 add_library(lib2 EXCLUDE_FROM_ALL lib1.c)
 
+add_library(lib3 lib1.c)
+
 add_executable(exe1 exe1.c)

+ 53 - 51
Tests/GhsMulti/GhsMultiExclude/verify.cmake

@@ -1,54 +1,56 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-#test project was generated
-unset(fileName CACHE)
-find_file (fileName lib1.gpj
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib1
-  )
-
-if (fileName)
-  message("Found target lib1: ${fileName}")
-else()
-  message(SEND_ERROR "Could not find target lib1: ${fileName}")
-endif()
-
-#test project was built
-unset(fileName CACHE)
-find_file (fileName lib1.a
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib1
-  )
-
-if (fileName)
-  message(SEND_ERROR "Found target lib1: ${fileName}")
-else()
-  message("Could not find target lib1: ${fileName}")
-endif()
-
-#test project was generated
-unset(fileName CACHE)
-find_file (fileName lib2.gpj
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib2
-  )
-
-if (fileName)
-  message("Found target lib2 ${fileName}")
-else()
-  message(SEND_ERROR "Could not find target lib2: ${fileName}")
-endif()
-
-#test project was built
-unset(fileName CACHE)
-find_file (fileName lib2.a
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib2
-  )
-
-if (fileName)
-  message(SEND_ERROR "Found target lib2: ${fileName}")
-else()
-  message("Could not find target lib2: ${fileName}")
-endif()
+function(verify_skipped_tgt name)
+  unset(fileName CACHE)
+  find_file (fileName ${name}.tgt.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+
+  if (fileName)
+    message("Found target ${name}: ${fileName}")
+  else()
+    message(SEND_ERROR "Could not find target ${name}: ${fileName}")
+  endif()
+
+  #test project was built
+  unset(fileName CACHE)
+  find_file (fileName lib${name}.a
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+
+  if (fileName)
+    message(SEND_ERROR "Found target ${name}: ${fileName}")
+  else()
+    message("Could not find target ${name}: ${fileName}")
+  endif()
+endfunction()
+
+function(locate_tgt name)
+  unset(fileName CACHE)
+  find_file (fileName ${name}.tgt.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+
+  if (fileName)
+    message("Found target ${name}: ${fileName}")
+  else()
+    message(SEND_ERROR "Could not find target ${name}: ${fileName}")
+  endif()
+
+  #test project was built
+  unset(fileName CACHE)
+  find_file (fileName lib${name}.a
+    ${CMAKE_CURRENT_BINARY_DIR}
+    )
+
+  if (fileName)
+    message( "Found target ${name}: ${fileName}")
+  else()
+    message(SEND_ERROR "Could not find target ${name}: ${fileName}")
+  endif()
+endfunction()
+
+verify_skipped_tgt(lib1)
+verify_skipped_tgt(lib2)
+locate_tgt(lib3)

+ 9 - 6
Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt

@@ -38,8 +38,7 @@ if (RUN_TEST STREQUAL "NO_FLAGS")
 else()
   unset(fileName CACHE)
   find_file(fileName exe1.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build/exe1
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/exe1.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -54,13 +53,14 @@ else()
     string(FIND "${fileText}" "${opt}" opt_found)
     if ( opt_found EQUAL -1 )
       message(SEND_ERROR "Could not find: ${opt}")
+    else()
+      message("located: ${opt}")
     endif()
   endforeach()
 
   unset(fileName CACHE)
   find_file (fileName lib1.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib1
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib1.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -71,13 +71,14 @@ else()
     string(FIND "${fileText}" "${opt}" opt_found)
     if (opt_found EQUAL -1)
       message(SEND_ERROR "Could not find: ${opt}")
+    else()
+      message("located: ${opt}")
     endif()
   endforeach()
 
   unset(fileName CACHE)
   find_file (fileName lib2.gpj
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build
-    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib2
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib2.dir
     )
   message("Parsing project file: ${fileName}")
   file(STRINGS ${fileName} fileText)
@@ -87,6 +88,8 @@ else()
     string(FIND "${fileText}" "${opt}" opt_found)
     if ( opt_found EQUAL -1 )
       message(SEND_ERROR "Could not find: ${opt}")
+    else()
+      message("located: ${opt}")
     endif()
   endforeach()
 endif()

+ 35 - 55
Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake

@@ -1,58 +1,38 @@
 # Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 # file Copyright.txt or https://cmake.org/licensing for details.
 
-#test project was generated
-unset(fileName CACHE)
-find_file(fileName lib3.gpj
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib3
-  ${CMAKE_CURRENT_BINARY_DIR}/examples
-  )
-
-if (fileName)
-  message("Found target lib3: ${fileName}")
-else()
-  message(SEND_ERROR "Could not find target lib3: ${fileName}")
-endif()
-
-#test project was generated
-unset(fileName CACHE)
-find_file (fileName exe3.gpj
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/exe3
-  ${CMAKE_CURRENT_BINARY_DIR}/examples
-  )
-
-if (fileName)
-  message("Found target exe3: ${fileName}")
-else()
-  message(SEND_ERROR "Could not find target exe3: ${fileName}")
-endif()
-
-#test project was not built
-unset(fileName CACHE)
-find_file (fileName lib3.a
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/lib3
-  ${CMAKE_CURRENT_BINARY_DIR}/examples
-  )
-
-if (fileName)
-  message(SEND_ERROR "Found target lib3: ${fileName}")
-else()
-  message("Could not find target lib3: ${fileName}")
-endif()
-
-unset(fileName CACHE)
-find_file (fileName NAMES exe3.as exe3
-  HINTS
-  ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_CURRENT_BINARY_DIR}/exe3
-  ${CMAKE_CURRENT_BINARY_DIR}/examples
-  )
-
-if (fileName)
-  message(SEND_ERROR "Found target exe3: ${fileName}")
-else()
-  message("Could not find target exe3: ${fileName}")
-endif()
+function(verify_project_top name)
+  unset(fileName CACHE)
+  find_file (fileName ${name}.top.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_CURRENT_BINARY_DIR}/sub
+    ${CMAKE_CURRENT_BINARY_DIR}/examples
+    )
+
+  if (fileName)
+    message("Found target ${name}: ${fileName}")
+  else()
+    message(SEND_ERROR "Could not find project ${name}: ${fileName}")
+  endif()
+endfunction()
+
+function(verify_exe_built name)
+  unset(fileName CACHE)
+  find_file (fileName ${name}
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${CMAKE_CURRENT_BINARY_DIR}/sub
+    )
+
+  if (fileName)
+    message("Found target ${name}: ${fileName}")
+  else()
+    message(SEND_ERROR "Could not find project ${name}: ${fileName}")
+  endif()
+endfunction()
+
+#test project top files were generated
+verify_project_top(test)
+verify_project_top(test2)
+verify_project_top(test3)
+verify_exe_built(exe1)
+verify_exe_built(exe2)