| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 | /*=========================================================================  Program:   CMake - Cross-Platform Makefile Generator  Module:    $RCSfile$  Language:  C++  Date:      $Date$  Version:   $Revision$  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.  Copyright (c) 2004 Alexander Neundorf [email protected], All rights reserved.  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.     This software is distributed WITHOUT ANY WARRANTY; without even      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      PURPOSE.  See the above copyright notices for more information.=========================================================================*/#include "cmGlobalKdevelopGenerator.h"#include "cmGlobalUnixMakefileGenerator3.h"#include "cmLocalUnixMakefileGenerator3.h"#include "cmMakefile.h"#include "cmake.h"#include "cmSourceFile.h"#include "cmGeneratedFileStream.h"#include "cmSystemTools.h"#include <cmsys/SystemTools.hxx>#include <cmsys/Directory.hxx>//----------------------------------------------------------------------------void cmGlobalKdevelopGenerator::GetDocumentation(cmDocumentationEntry& entry, const char*) const{  entry.Name = this->GetName();  entry.Brief = "Generates KDevelop 3 project files.";  entry.Full =    "Project files for KDevelop 3 will be created in the top directory "    "and in every subdirectory which features a CMakeLists.txt file "    "containing a PROJECT() call. "    "If you change the settings using KDevelop cmake will try its best "    "to keep your changes when regenerating the project files. "    "Additionally a hierarchy of UNIX makefiles is generated into the "    "build tree.  Any "    "standard UNIX-style make program can build the project through the "    "default make target.  A \"make install\" target is also provided.";}cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator():cmExternalMakefileProjectGenerator(){  this->SupportedGlobalGenerators.push_back("Unix Makefiles");}void cmGlobalKdevelopGenerator::SetGlobalGenerator(                                                  cmGlobalGenerator* generator){  cmExternalMakefileProjectGenerator::SetGlobalGenerator(generator);  cmGlobalUnixMakefileGenerator3* mf = (cmGlobalUnixMakefileGenerator3*)                                                                     generator;  mf->SetToolSupportsColor(false);  mf->SetForceVerboseMakefiles(true);}void cmGlobalKdevelopGenerator::Generate(){  // for each sub project in the project create   // a kdevelop project  for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator        it = this->GlobalGenerator->GetProjectMap().begin();       it!= this->GlobalGenerator->GetProjectMap().end();       ++it)    {    cmMakefile* mf = it->second[0]->GetMakefile();    std::string outputDir=mf->GetStartOutputDirectory();    std::string projectDir=mf->GetHomeDirectory();    std::string projectName=mf->GetProjectName();    std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");    std::string fileToOpen;    const std::vector<cmLocalGenerator*>& lgs= it->second;    // create the project.kdevelop.filelist file    if(!this->CreateFilelistFile(lgs, outputDir, projectDir,                                 projectName, cmakeFilePattern, fileToOpen))      {      cmSystemTools::Error("Can not create filelist file");      return;      }    //try to find the name of an executable so we have something to    //run from kdevelop for now just pick the first executable found    std::string executable;    for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin();         lg!=lgs.end(); lg++)      {      cmMakefile* makefile=(*lg)->GetMakefile();      cmTargets& targets=makefile->GetTargets();      for (cmTargets::iterator ti = targets.begin();           ti != targets.end(); ti++)        {        if (ti->second.GetType()==cmTarget::EXECUTABLE)          {          executable = ti->second.GetProperty("LOCATION");          break;          }        }      if (!executable.empty())        {        break;        }      }          // now create a project file    this->CreateProjectFile(outputDir, projectDir, projectName,                            executable, cmakeFilePattern, fileToOpen);    }}bool cmGlobalKdevelopGenerator::CreateFilelistFile(const std::vector<cmLocalGenerator*>& lgs,                     const std::string& outputDir,                      const std::string& projectDirIn,                     const std::string& projectname,                     std::string& cmakeFilePattern,                     std::string& fileToOpen){  std::string projectDir = projectDirIn + "/";  std::string filename = outputDir+ "/" + projectname +".kdevelop.filelist";  std::set<cmStdString> files;  std::string tmp;  for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin();        it!=lgs.end(); it++)    {    cmMakefile* makefile=(*it)->GetMakefile();    const std::vector<std::string>& listFiles=makefile->GetListFiles();    for (std::vector<std::string>::const_iterator lt=listFiles.begin();          lt!=listFiles.end(); lt++)      {      tmp=*lt;      cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");      // make sure the file is part of this source tree      if ((tmp[0]!='/') &&           (strstr(tmp.c_str(),                   cmake::GetCMakeFilesDirectoryPostSlash())==0))        {        files.insert(tmp);        tmp=cmSystemTools::GetFilenameName(tmp);        //add all files which dont match the default         // */CMakeLists.txt;*cmake; to the file pattern        if ((tmp!="CMakeLists.txt")            && (strstr(tmp.c_str(), ".cmake")==0))          {          cmakeFilePattern+=tmp+";";          }        }      }      //get all sources    cmTargets& targets=makefile->GetTargets();    for (cmTargets::iterator ti = targets.begin();         ti != targets.end(); ti++)      {      const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();      for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();           si!=sources.end(); si++)        {        tmp=(*si)->GetFullPath();        std::string headerBasename=cmSystemTools::GetFilenamePath(tmp);        headerBasename+="/";        headerBasename+=cmSystemTools::GetFilenameWithoutExtension(tmp);        cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");        if ((tmp[0]!='/')  &&             (strstr(tmp.c_str(),                   cmake::GetCMakeFilesDirectoryPostSlash())==0) &&           (cmSystemTools::GetFilenameExtension(tmp)!=".moc"))          {          files.insert(tmp);          // check if there's a matching header around          for(std::vector<std::string>::const_iterator                ext = makefile->GetHeaderExtensions().begin();              ext !=  makefile->GetHeaderExtensions().end(); ++ext)            {            std::string hname=headerBasename;            hname += ".";            hname += *ext;            if(cmSystemTools::FileExists(hname.c_str()))              {              cmSystemTools::ReplaceString(hname, projectDir.c_str(), "");              files.insert(hname);              break;              }            }          }        }      for (std::vector<std::string>::const_iterator lt=listFiles.begin();           lt!=listFiles.end(); lt++)        {        tmp=*lt;        cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");        if ((tmp[0]!='/') &&             (strstr(tmp.c_str(),                     cmake::GetCMakeFilesDirectoryPostSlash())==0))          {          files.insert(tmp.c_str());          }        }      }    }  //check if the output file already exists and read it  //insert all files which exist into the set of files  std::ifstream oldFilelist(filename.c_str());  if (oldFilelist)    {    while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))      {      if (tmp[0]=='/')        {        continue;        }      std::string completePath=projectDir+tmp;      if (cmSystemTools::FileExists(completePath.c_str()))        {        files.insert(tmp);        }      }    oldFilelist.close();    }  //now write the new filename  cmGeneratedFileStream fout(filename.c_str());  if(!fout)    {    return false;    }     fileToOpen="";  for (std::set<cmStdString>::const_iterator it=files.begin();        it!=files.end(); it++)    {    // get the full path to the file    tmp=cmSystemTools::CollapseFullPath(it->c_str(), projectDir.c_str());    // just select the first source file    if (fileToOpen.empty())    {       std::string ext = cmSystemTools::GetFilenameExtension(tmp);       if ((ext==".c") || (ext==".cc") || (ext==".cpp")  || (ext==".cxx")           || (ext==".C") || (ext==".h") || (ext==".hpp"))       {       fileToOpen=tmp;       }    }    // make it relative to the project dir    cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");    // only put relative paths    if (tmp.size() && tmp[0] != '/')      {      fout << tmp.c_str() <<"\n";      }    }  return true;}/* create the project file, if it already exists, merge it with theexisting one, otherwise create a new one */void cmGlobalKdevelopGenerator::CreateProjectFile(const std::string& outputDir,                    const std::string& projectDir,                    const std::string& projectname,                     const std::string& executable,                    const std::string& cmakeFilePattern,                    const std::string& fileToOpen){  this->Blacklist.clear();  std::string filename=outputDir+"/";  filename+=projectname+".kdevelop";  std::string sessionFilename=outputDir+"/";  sessionFilename+=projectname+".kdevses";  if (cmSystemTools::FileExists(filename.c_str()))    {    this->MergeProjectFiles(outputDir, projectDir, filename,                             executable, cmakeFilePattern,                             fileToOpen, sessionFilename);    }  else    {    // add all subdirectories to the kdevelop blacklist    // so they are not monitored for added or removed files    // since this is basically handled by adding files to the cmake files    cmsys::Directory d;    if (d.Load(projectDir.c_str()))      {      size_t numf = d.GetNumberOfFiles();      for (unsigned int i = 0; i < numf; i++)        {        std::string nextFile = d.GetFile(i);        if ((nextFile!=".") && (nextFile!=".."))          {          std::string tmp = projectDir;          tmp += "/";          tmp += nextFile;          if (cmSystemTools::FileIsDirectory(tmp.c_str()))            {            this->Blacklist.push_back(nextFile);            }          }        }      }    this->CreateNewProjectFile(outputDir, projectDir, filename,                               executable, cmakeFilePattern,                                fileToOpen, sessionFilename);    }}void cmGlobalKdevelopGenerator::MergeProjectFiles(const std::string& outputDir,                     const std::string& projectDir,                     const std::string& filename,                     const std::string& executable,                     const std::string& cmakeFilePattern,                    const std::string& fileToOpen,                    const std::string& sessionFilename){  std::ifstream oldProjectFile(filename.c_str());  if (!oldProjectFile)    {    this->CreateNewProjectFile(outputDir, projectDir, filename,                                executable, cmakeFilePattern,                                fileToOpen, sessionFilename);    return;    }  /* Read the existing project file (line by line), copy all lines    into the new project file, except the ones which can be reliably    set from contents of the CMakeLists.txt */  std::string tmp;  std::vector<std::string> lines;  while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))    {    lines.push_back(tmp);    }  oldProjectFile.close();  cmGeneratedFileStream fout(filename.c_str());  if(!fout)    {    return;    }  for (std::vector<std::string>::const_iterator it=lines.begin();        it!=lines.end(); it++)    {    const char* line=(*it).c_str();    // skip these tags as they are always replaced    if ((strstr(line, "<projectdirectory>")!=0)        || (strstr(line, "<projectmanagement>")!=0)        || (strstr(line, "<absoluteprojectpath>")!=0)        || (strstr(line, "<filelistdirectory>")!=0)        || (strstr(line, "<buildtool>")!=0)        || (strstr(line, "<builddir>")!=0))      {      continue;      }    // output the line from the file if it is not one of the above tags    fout<<*it<<"\n";    // if this is the <general> tag output the stuff that goes in the    // general tag    if (strstr(line, "<general>"))      {      fout<< "  <projectmanagement>KDevCustomProject</projectmanagement>\n";      fout<< "  <projectdirectory>" <<projectDir.c_str()           << "</projectdirectory>\n";   //this one is important      fout<<"  <absoluteprojectpath>true</absoluteprojectpath>\n";      //and this one      }    // inside kdevcustomproject the <filelistdirectory> must be put    if (strstr(line, "<kdevcustomproject>"))      {      fout<<"    <filelistdirectory>"<<outputDir.c_str()          <<"</filelistdirectory>\n";      }    // buildtool and builddir go inside <build>    if (strstr(line, "<build>"))      {      fout<<"      <buildtool>make</buildtool>\n";      fout<<"      <builddir>"<<outputDir.c_str()<<"</builddir>\n";      }    }}void cmGlobalKdevelopGenerator::CreateNewProjectFile(const std::string& outputDir,                       const std::string& projectDir,                       const std::string& filename,                       const std::string& executable,                       const std::string& cmakeFilePattern,                       const std::string& fileToOpen,                       const std::string& sessionFilename){  cmGeneratedFileStream fout(filename.c_str());  if(!fout)    {    return;    }  // check for a version control system  bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());  bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());  bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C")                           || this->GlobalGenerator->GetLanguageEnabled("CXX"));  bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");  std::string primaryLanguage = "C++";  if (enableFortran && !enableCxx)    {    primaryLanguage="Fortran77";    }  fout<<"<?xml version = '1.0'?>\n"        "<kdevelop>\n"        "  <general>\n"        "  <author></author>\n"        "  <email></email>\n"        "  <version>$VERSION$</version>\n"        "  <projectmanagement>KDevCustomProject</projectmanagement>\n"        "  <primarylanguage>" << primaryLanguage << "</primarylanguage>\n"        "  <ignoreparts/>\n"        "  <projectdirectory>" << projectDir.c_str() <<         "</projectdirectory>\n";   //this one is important  fout<<"  <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one  // setup additional languages  fout<<"  <secondaryLanguages>\n";  if (enableFortran && enableCxx)    {    fout<<"     <language>Fortran</language>\n";    }  if (enableCxx)    {    fout<<"     <language>C</language>\n";    }  fout<<"  </secondaryLanguages>\n";  if (hasSvn)    {    fout << "  <versioncontrol>kdevsubversion</versioncontrol>\n";    }  else if (hasCvs)    {    fout << "  <versioncontrol>kdevcvsservice</versioncontrol>\n";    }  fout<<"  </general>\n"        "  <kdevcustomproject>\n"        "    <filelistdirectory>" << outputDir.c_str() <<        "</filelistdirectory>\n"        "    <run>\n"        "      <mainprogram>" << executable.c_str() << "</mainprogram>\n"        "      <directoryradio>custom</directoryradio>\n"        "      <customdirectory>"<<outputDir.c_str()<<"</customdirectory>\n"        "      <programargs></programargs>\n"        "      <terminal>false</terminal>\n"        "      <autocompile>true</autocompile>\n"        "      <envvars/>\n"        "    </run>\n"        "    <build>\n"        "      <buildtool>make</buildtool>\n"; //this one is important  fout<<"      <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one  fout<<"    </build>\n"        "    <make>\n"        "      <abortonerror>false</abortonerror>\n"        "      <numberofjobs>1</numberofjobs>\n"        "      <dontact>false</dontact>\n"        "      <makebin></makebin>\n"        "      <selectedenvironment>default</selectedenvironment>\n"        "      <environments>\n"        "        <default/>\n"        "      </environments>\n"        "    </make>\n";  fout<<"    <blacklist>\n";  for(std::vector<std::string>::const_iterator dirIt=this->Blacklist.begin();      dirIt != this->Blacklist.end();      ++dirIt)    {    fout<<"      <path>" << dirIt->c_str() << "</path>\n";    }  fout<<"    </blacklist>\n";  fout<<"  </kdevcustomproject>\n"        "  <kdevfilecreate>\n"        "    <filetypes/>\n"        "    <useglobaltypes>\n"        "      <type ext=\"ui\" />\n"        "      <type ext=\"cpp\" />\n"        "      <type ext=\"h\" />\n"        "    </useglobaltypes>\n"        "  </kdevfilecreate>\n"        "  <kdevdoctreeview>\n"        "    <projectdoc>\n"        "      <userdocDir>html/</userdocDir>\n"        "      <apidocDir>html/</apidocDir>\n"        "    </projectdoc>\n"        "    <ignoreqt_xml/>\n"        "    <ignoredoxygen/>\n"        "    <ignorekdocs/>\n"        "    <ignoretocs/>\n"        "    <ignoredevhelp/>\n"        "  </kdevdoctreeview>\n";  if (enableCxx)    {    fout<<"  <cppsupportpart>\n"          "    <filetemplates>\n"          "      <interfacesuffix>.h</interfacesuffix>\n"          "      <implementationsuffix>.cpp</implementationsuffix>\n"          "    </filetemplates>\n"          "  </cppsupportpart>\n"          "  <kdevcppsupport>\n"          "    <codecompletion>\n"          "      <includeGlobalFunctions>true</includeGlobalFunctions>\n"          "      <includeTypes>true</includeTypes>\n"          "      <includeEnums>true</includeEnums>\n"          "      <includeTypedefs>false</includeTypedefs>\n"          "      <automaticCodeCompletion>true</automaticCodeCompletion>\n"          "      <automaticArgumentsHint>true</automaticArgumentsHint>\n"          "      <automaticHeaderCompletion>true</automaticHeaderCompletion>\n"          "      <codeCompletionDelay>250</codeCompletionDelay>\n"          "      <argumentsHintDelay>400</argumentsHintDelay>\n"          "      <headerCompletionDelay>250</headerCompletionDelay>\n"          "    </codecompletion>\n"          "    <references/>\n"          "  </kdevcppsupport>\n";    }  if (enableFortran)    {    fout<<"  <kdevfortransupport>\n"          "    <ftnchek>\n"          "      <division>false</division>\n"          "      <extern>false</extern>\n"          "      <declare>false</declare>\n"          "      <pure>false</pure>\n"          "      <argumentsall>false</argumentsall>\n"          "      <commonall>false</commonall>\n"          "      <truncationall>false</truncationall>\n"          "      <usageall>false</usageall>\n"          "      <f77all>false</f77all>\n"          "      <portabilityall>false</portabilityall>\n"          "      <argumentsonly/>\n"          "      <commononly/>\n"          "      <truncationonly/>\n"          "      <usageonly/>\n"          "      <f77only/>\n"          "      <portabilityonly/>\n"          "    </ftnchek>\n"          "  </kdevfortransupport>\n";    }  // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()  // command  fout<<"  <kdevfileview>\n"        "    <groups>\n"        "      <group pattern=\"" << cmakeFilePattern.c_str() <<        "\" name=\"CMake\" />\n";  if (enableCxx)    {    fout<<"      <group pattern=\"*.h;*.hxx;*.hpp\" name=\"Header\" />\n"          "      <group pattern=\"*.c\" name=\"C Sources\" />\n"          "      <group pattern=\"*.cpp;*.C;*.cxx;*.cc\" name=\"C++ Sources\""          "/>\n";    }  if (enableFortran)    {    fout<<"      <group pattern=\"*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;"          "*.F95\" name=\"Fortran Sources\" />\n";    }  fout<<"      <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n"        "      <hidenonprojectfiles>true</hidenonprojectfiles>\n"        "    </groups>\n"        "    <tree>\n"        "      <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n"        "      <hidenonprojectfiles>true</hidenonprojectfiles>\n"        "    </tree>\n"        "  </kdevfileview>\n"        "</kdevelop>\n";  if (sessionFilename.empty())    {    return;    }  // and a session file, so that kdevelop opens a file if it opens the  // project the first time  cmGeneratedFileStream devses(sessionFilename.c_str());  if(!devses)    {    return;    }  devses<<"<?xml version = '1.0' encoding = \'UTF-8\'?>\n"          "<!DOCTYPE KDevPrjSession>\n"          "<KDevPrjSession>\n"          " <DocsAndViews NumberOfDocuments=\"1\" >\n"          "  <Doc0 NumberOfViews=\"1\" URL=\"file://" << fileToOpen.c_str() <<          "\" >\n"          "   <View0 line=\"0\" Type=\"Source\" />\n"          "  </Doc0>\n"          " </DocsAndViews>\n"          "</KDevPrjSession>\n";}
 |