/*============================================================================
  CMake - Cross Platform Makefile Generator
  Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>

  Distributed under the OSI-approved BSD License (the "License");
  see accompanying file Copyright.txt for details.

  This software is distributed WITHOUT ANY WARRANTY; without even the
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the License for more information.
============================================================================*/
#include "cmGhsMultiTargetGenerator.h"

#include "cmGeneratedFileStream.h"
#include "cmGlobalGhsMultiGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
#include "cmSourceFile.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()
{
  cmDeleteAll(this->FolderBuildStreams);
}

std::string cmGhsMultiTargetGenerator::GetRelBuildFilePath(
  const cmGeneratorTarget* target)
{
  std::string output;
  char const* folderProp = target->GetProperty("FOLDER");
  output = NULL == folderProp ? "" : folderProp;
  cmSystemTools::ConvertToUnixSlashes(output);
  if (!output.empty()) {
    output += "/";
  }
  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)
{
  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());
    }
    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";
    }
    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;
    }
    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() == cmState::EXECUTABLE) {
      this->WriteTargetLinkLibraries(config, language);
    }
    this->WriteCustomCommands();

    std::map<const cmSourceFile*, std::string> objectNames =
      cmGhsMultiTargetGenerator::GetObjectNames(
        &objectSources, this->LocalGenerator, this->GeneratorTarget);

    this->WriteSources(objectSources, objectNames);
  }
}

bool cmGhsMultiTargetGenerator::IncludeThisTarget()
{
  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;
}

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;
}

GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const
{
  return cmGhsMultiTargetGenerator::GetGpjTag(this->GeneratorTarget);
}

GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag(
  const cmGeneratorTarget* target)
{
  GhsMultiGpj::Types output;
  if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(target)) {
    output = GhsMultiGpj::INTERGRITY_APPLICATION;
  } else if (target->GetType() == cmState::STATIC_LIBRARY) {
    output = GhsMultiGpj::LIBRARY;
  } else {
    output = GhsMultiGpj::PROGRAM;
  }
  return output;
}

cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
  const
{
  return static_cast<cmGlobalGhsMultiGenerator*>(
    this->LocalGenerator->GetGlobalGenerator());
}

void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string& config,
                                                   bool const notKernel)
{
  std::string outputDir(this->GetOutputDirectory(config));
  std::string outputFilename(this->GetOutputFilename(config));

  if (this->GeneratorTarget->GetType() == cmState::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() == cmState::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;
    }
  }
}

void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
                                                 const std::string& language,
                                                 bool const notKernel)
{
  std::map<std::string, std::string>::iterator i =
    this->FlagsByLanguage.find(language);
  if (i == this->FlagsByLanguage.end()) {
    std::string flags;
    const char* lang = language.c_str();

    if (notKernel) {
      this->LocalGenerator->AddLanguageFlags(flags, lang, config);
    } else {
      this->LocalGenerator->AddLanguageFlags(
        flags, lang + std::string("_GHS_KERNEL"), config);
    }
    this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang,
                                          config);
    this->LocalGenerator->AddVisibilityPresetFlags(
      flags, this->GeneratorTarget, lang);

    // Append old-style preprocessor definition flags.
    if (std::string(" ") != std::string(this->Makefile->GetDefineFlags())) {
      this->LocalGenerator->AppendFlags(flags,
                                        this->Makefile->GetDefineFlags());
    }

    // Add target-specific flags.
    this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang,
                                            config);

    std::map<std::string, std::string>::value_type entry(language, flags);
    i = this->FlagsByLanguage.insert(entry).first;
  }
}

std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
                                                  std::string const& config)
{
  std::map<std::string, std::string>::iterator i =
    this->DefinesByLanguage.find(language);
  if (i == this->DefinesByLanguage.end()) {
    std::set<std::string> defines;
    const char* lang = language.c_str();
    // Add the export symbol definition for shared library objects.
    if (const char* exportMacro = this->GeneratorTarget->GetExportMacro()) {
      this->LocalGenerator->AppendDefines(defines, exportMacro);
    }

    // Add preprocessor definitions for this target and configuration.
    this->LocalGenerator->AddCompileDefinitions(defines, this->GeneratorTarget,
                                                config, language);

    std::string definesString;
    this->LocalGenerator->JoinDefines(defines, definesString, lang);

    std::map<std::string, std::string>::value_type entry(language,
                                                         definesString);
    i = this->DefinesByLanguage.insert(entry).first;
  }
  return i->second;
}

void cmGhsMultiTargetGenerator::WriteCompilerFlags(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;
    }
  }
}

void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
  const std::string& config, const std::string& language)
{
  std::vector<std::string> compileDefinitions;
  this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
                                               language);
  for (std::vector<std::string>::const_iterator cdI =
         compileDefinitions.begin();
       cdI != compileDefinitions.end(); ++cdI) {
    *this->GetFolderBuildStreams() << "    -D" << (*cdI) << std::endl;
  }
}

void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config,
                                              const std::string& language)
{
  std::vector<std::string> includes;
  this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget,
                                              language, 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;
  }
}

void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries(
  std::string const& config, std::string const& language)
{
  // 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;
  }
  // 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;
  }

  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");
    this->LocalGenerator->GetTargetFlags(
      linkLibraries, flags, linkFlags, frameworkPath, linkPath,
      this->GeneratorTarget, useWatcomQuote);
    linkFlags = cmSystemTools::TrimWhitespace(linkFlags);

    if (!linkPath.empty()) {
      linkPath = " " + linkPath.substr(0U, linkPath.size() - 1U);
      *this->GetFolderBuildStreams() << linkPath;
    }

    if (!linkFlags.empty()) {
      *this->GetFolderBuildStreams() << "    " << linkFlags << std::endl;
    }
  }
}

void cmGhsMultiTargetGenerator::WriteCustomCommands()
{
  WriteCustomCommandsHelper(this->GeneratorTarget->GetPreBuildCommands(),
                            cmTarget::PRE_BUILD);
  WriteCustomCommandsHelper(this->GeneratorTarget->GetPostBuildCommands(),
                            cmTarget::POST_BUILD);
}

void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
  std::vector<cmCustomCommand> const& commandsSet,
  cmTarget::CustomCommandType const commandType)
{
  for (std::vector<cmCustomCommand>::const_iterator commandsSetI =
         commandsSet.begin();
       commandsSetI != commandsSet.end(); ++commandsSetI) {
    cmCustomCommandLines const& commands = commandsSetI->GetCommandLines();
    for (cmCustomCommandLines::const_iterator commandI = commands.begin();
         commandI != commands.end(); ++commandI) {
      switch (commandType) {
        case cmTarget::PRE_BUILD:
          *this->GetFolderBuildStreams() << "    :preexecShellSafe=";
          break;
        case cmTarget::POST_BUILD:
          *this->GetFolderBuildStreams() << "    :postexecShellSafe=";
          break;
        default:
          assert("Only pre and post are supported");
      }
      cmCustomCommandLine const& command = *commandI;
      for (cmCustomCommandLine::const_iterator commandLineI = command.begin();
           commandLineI != command.end(); ++commandLineI) {
        std::string subCommandE =
          this->LocalGenerator->EscapeForShell(*commandLineI, true);
        if (!command.empty()) {
          *this->GetFolderBuildStreams()
            << (command.begin() == commandLineI ? "'" : " ");
          // Need to double escape backslashes
          cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
        }
        *this->GetFolderBuildStreams() << subCommandE;
      }
      if (!command.empty()) {
        *this->GetFolderBuildStreams() << "'" << std::endl;
      }
    }
  }
}

std::map<const cmSourceFile*, std::string>
cmGhsMultiTargetGenerator::GetObjectNames(
  std::vector<cmSourceFile*>* const objectSources,
  cmLocalGhsMultiGenerator* const localGhsMultiGenerator,
  cmGeneratorTarget* const generatorTarget)
{
  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());
    }
  }

  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)
{
  for (std::vector<cmSourceFile*>::const_iterator si = objectSources.begin();
       si != objectSources.end(); ++si) {
    std::vector<cmSourceGroup> sourceGroups(this->Makefile->GetSourceGroups());
    char const* sourceFullPath = (*si)->GetFullPath().c_str();
    cmSourceGroup* sourceGroup =
      this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups);
    std::string sgPath(sourceGroup->GetFullName());
    cmSystemTools::ConvertToUnixSlashes(sgPath);
    cmGlobalGhsMultiGenerator::AddFilesUpToPath(
      this->GetFolderBuildStreams(), &this->FolderBuildStreams,
      this->LocalGenerator->GetBinaryDirectory(), sgPath,
      GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath);

    std::string fullSourcePath((*si)->GetFullPath());
    if ((*si)->GetExtension() == "int" || (*si)->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;
    }

    if ("ld" != (*si)->GetExtension() && "int" != (*si)->GetExtension() &&
        "bsp" != (*si)->GetExtension()) {
      this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], (*si));
      if (objectNames.end() != objectNames.find(*si)) {
        *this->FolderBuildStreams[sgPath]
          << "    -o \"" << objectNames.find(*si)->second << "\"" << std::endl;
      }

      this->WriteObjectDir(this->FolderBuildStreams[sgPath],
                           this->AbsBuildFilePath + sgPath);
    }
  }
}

void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
  cmGeneratedFileStream* fileStream, 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;
    }
  }
}

void cmGhsMultiTargetGenerator::WriteObjectDir(
  cmGeneratedFileStream* fileStream, std::string const& dir)
{
  std::string workingDir(dir);
  cmSystemTools::ConvertToUnixSlashes(workingDir);
  if (!workingDir.empty()) {
    workingDir += "/";
  }
  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;
  }

  std::string configCapped(cmSystemTools::UpperCase(config));
  const char* runtimeOutputSProp = this->GeneratorTarget->GetProperty(
    "RUNTIME_OUTPUT_DIRECTORY_" + configCapped);
  if (NULL != runtimeOutputSProp) {
    outputDir = runtimeOutputSProp;
  }
  cmSystemTools::ConvertToUnixSlashes(outputDir);

  if (!outputDir.empty()) {
    outputDir += "/";
  }

  return outputDir;
}

std::string cmGhsMultiTargetGenerator::GetOutputFilename(
  const std::string& config) const
{
  std::string outputFilename(this->GeneratorTarget->GetName());

  const char* outputNameProp =
    this->GeneratorTarget->GetProperty("OUTPUT_NAME");
  if (NULL != outputNameProp) {
    outputFilename = outputNameProp;
  }

  std::string configCapped(cmSystemTools::UpperCase(config));
  const char* outputNameSProp =
    this->GeneratorTarget->GetProperty(configCapped + "_OUTPUT_NAME");
  if (NULL != outputNameSProp) {
    outputFilename = outputNameSProp;
  }

  return outputFilename;
}

std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory(
  cmLocalGhsMultiGenerator const* localGhsMultiGenerator,
  cmGeneratorTarget* const generatorTarget, cmSourceFile* const 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());
  char const* const sourceFullPath = sourceFile->GetFullPath().c_str();
  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;
}

bool cmGhsMultiTargetGenerator::IsNotKernel(std::string const& config,
                                            const std::string& language)
{
  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;
}

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;
    }
  }
  return output;
}

bool cmGhsMultiTargetGenerator::DetermineIfDynamicDownload(
  std::string const& config, const std::string& language)
{
  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;
    }
  }
  return output;
}
