123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- /*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2004-2009 Kitware, Inc.
- Copyright 2004 Alexander Neundorf ([email protected])
- 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 "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>
- #include <cmsys/FStream.hxx>
- //----------------------------------------------------------------------------
- void cmGlobalKdevelopGenerator
- ::GetDocumentation(cmDocumentationEntry& entry, const char*) const
- {
- entry.Name = this->GetName();
- entry.Brief = "Generates KDevelop 3 project files.";
- }
- cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
- :cmExternalMakefileProjectGenerator()
- {
- this->SupportedGlobalGenerators.push_back("Unix Makefiles");
- #ifdef CMAKE_USE_NINJA
- this->SupportedGlobalGenerators.push_back("Ninja");
- #endif
- }
- void cmGlobalKdevelopGenerator::Generate()
- {
- // for each sub project in the project create
- // a kdevelop project
- for (std::map<std::string, 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.GetLocation(0);
- 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<std::string> 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++)
- {
- std::vector<cmSourceFile*> sources;
- ti->second.GetSourceFiles(sources);
- 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
- cmsys::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<std::string>::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 the
- existing 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 which are cmake build directories to the
- // kdevelop blacklist so they are not monitored for added or removed files
- // since this is 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()))
- {
- tmp += "/CMakeCache.txt";
- if ((nextFile == "CMakeFiles")
- || (cmSystemTools::FileExists(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)
- {
- cmsys::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>" << this->GlobalGenerator->GetLocalGenerators()[0]->
- GetMakefile()->GetRequiredDefinition("CMAKE_MAKE_PROGRAM")
- << " </makebin>\n"
- " <selectedenvironment>default</selectedenvironment>\n"
- " <environments>\n"
- " <default>\n"
- " <envvar value=\"1\" name=\"VERBOSE\" />\n"
- " <envvar value=\"1\" name=\"CMAKE_NO_VERBOSE\" />\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";
- }
|