Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmGlobalKdevelopGenerator.cxx
blob15516c0964cdb51af8c99c686c7341ab075d3b4f
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalKdevelopGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008-03-27 21:40:43 $
7 Version: $Revision: 1.31 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 Copyright (c) 2004 Alexander Neundorf neundorf@kde.org, All rights reserved.
11 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
13 This software is distributed WITHOUT ANY WARRANTY; without even
14 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 PURPOSE. See the above copyright notices for more information.
17 =========================================================================*/
19 #include "cmGlobalKdevelopGenerator.h"
20 #include "cmGlobalUnixMakefileGenerator3.h"
21 #include "cmLocalUnixMakefileGenerator3.h"
22 #include "cmMakefile.h"
23 #include "cmake.h"
24 #include "cmSourceFile.h"
25 #include "cmGeneratedFileStream.h"
26 #include "cmSystemTools.h"
28 #include <cmsys/SystemTools.hxx>
29 #include <cmsys/Directory.hxx>
31 //----------------------------------------------------------------------------
32 void cmGlobalKdevelopGenerator
33 ::GetDocumentation(cmDocumentationEntry& entry, const char*) const
35 entry.Name = this->GetName();
36 entry.Brief = "Generates KDevelop 3 project files.";
37 entry.Full =
38 "Project files for KDevelop 3 will be created in the top directory "
39 "and in every subdirectory which features a CMakeLists.txt file "
40 "containing a PROJECT() call. "
41 "If you change the settings using KDevelop cmake will try its best "
42 "to keep your changes when regenerating the project files. "
43 "Additionally a hierarchy of UNIX makefiles is generated into the "
44 "build tree. Any "
45 "standard UNIX-style make program can build the project through the "
46 "default make target. A \"make install\" target is also provided.";
49 cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
50 :cmExternalMakefileProjectGenerator()
52 this->SupportedGlobalGenerators.push_back("Unix Makefiles");
55 void cmGlobalKdevelopGenerator::Generate()
57 // for each sub project in the project create
58 // a kdevelop project
59 for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
60 it = this->GlobalGenerator->GetProjectMap().begin();
61 it!= this->GlobalGenerator->GetProjectMap().end();
62 ++it)
64 cmMakefile* mf = it->second[0]->GetMakefile();
65 std::string outputDir=mf->GetStartOutputDirectory();
66 std::string projectDir=mf->GetHomeDirectory();
67 std::string projectName=mf->GetProjectName();
68 std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
69 std::string fileToOpen;
70 const std::vector<cmLocalGenerator*>& lgs= it->second;
71 // create the project.kdevelop.filelist file
72 if(!this->CreateFilelistFile(lgs, outputDir, projectDir,
73 projectName, cmakeFilePattern, fileToOpen))
75 cmSystemTools::Error("Can not create filelist file");
76 return;
78 //try to find the name of an executable so we have something to
79 //run from kdevelop for now just pick the first executable found
80 std::string executable;
81 for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin();
82 lg!=lgs.end(); lg++)
84 cmMakefile* makefile=(*lg)->GetMakefile();
85 cmTargets& targets=makefile->GetTargets();
86 for (cmTargets::iterator ti = targets.begin();
87 ti != targets.end(); ti++)
89 if (ti->second.GetType()==cmTarget::EXECUTABLE)
91 executable = ti->second.GetProperty("LOCATION");
92 break;
95 if (!executable.empty())
97 break;
101 // now create a project file
102 this->CreateProjectFile(outputDir, projectDir, projectName,
103 executable, cmakeFilePattern, fileToOpen);
107 bool cmGlobalKdevelopGenerator
108 ::CreateFilelistFile(const std::vector<cmLocalGenerator*>& lgs,
109 const std::string& outputDir,
110 const std::string& projectDirIn,
111 const std::string& projectname,
112 std::string& cmakeFilePattern,
113 std::string& fileToOpen)
115 std::string projectDir = projectDirIn + "/";
116 std::string filename = outputDir+ "/" + projectname +".kdevelop.filelist";
118 std::set<cmStdString> files;
119 std::string tmp;
121 for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin();
122 it!=lgs.end(); it++)
124 cmMakefile* makefile=(*it)->GetMakefile();
125 const std::vector<std::string>& listFiles=makefile->GetListFiles();
126 for (std::vector<std::string>::const_iterator lt=listFiles.begin();
127 lt!=listFiles.end(); lt++)
129 tmp=*lt;
130 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
131 // make sure the file is part of this source tree
132 if ((tmp[0]!='/') &&
133 (strstr(tmp.c_str(),
134 cmake::GetCMakeFilesDirectoryPostSlash())==0))
136 files.insert(tmp);
137 tmp=cmSystemTools::GetFilenameName(tmp);
138 //add all files which dont match the default
139 // */CMakeLists.txt;*cmake; to the file pattern
140 if ((tmp!="CMakeLists.txt")
141 && (strstr(tmp.c_str(), ".cmake")==0))
143 cmakeFilePattern+=tmp+";";
148 //get all sources
149 cmTargets& targets=makefile->GetTargets();
150 for (cmTargets::iterator ti = targets.begin();
151 ti != targets.end(); ti++)
153 const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();
154 for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
155 si!=sources.end(); si++)
157 tmp=(*si)->GetFullPath();
158 std::string headerBasename=cmSystemTools::GetFilenamePath(tmp);
159 headerBasename+="/";
160 headerBasename+=cmSystemTools::GetFilenameWithoutExtension(tmp);
162 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
164 if ((tmp[0]!='/') &&
165 (strstr(tmp.c_str(),
166 cmake::GetCMakeFilesDirectoryPostSlash())==0) &&
167 (cmSystemTools::GetFilenameExtension(tmp)!=".moc"))
169 files.insert(tmp);
171 // check if there's a matching header around
172 for(std::vector<std::string>::const_iterator
173 ext = makefile->GetHeaderExtensions().begin();
174 ext != makefile->GetHeaderExtensions().end(); ++ext)
176 std::string hname=headerBasename;
177 hname += ".";
178 hname += *ext;
179 if(cmSystemTools::FileExists(hname.c_str()))
181 cmSystemTools::ReplaceString(hname, projectDir.c_str(), "");
182 files.insert(hname);
183 break;
188 for (std::vector<std::string>::const_iterator lt=listFiles.begin();
189 lt!=listFiles.end(); lt++)
191 tmp=*lt;
192 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
193 if ((tmp[0]!='/') &&
194 (strstr(tmp.c_str(),
195 cmake::GetCMakeFilesDirectoryPostSlash())==0))
197 files.insert(tmp.c_str());
203 //check if the output file already exists and read it
204 //insert all files which exist into the set of files
205 std::ifstream oldFilelist(filename.c_str());
206 if (oldFilelist)
208 while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))
210 if (tmp[0]=='/')
212 continue;
214 std::string completePath=projectDir+tmp;
215 if (cmSystemTools::FileExists(completePath.c_str()))
217 files.insert(tmp);
220 oldFilelist.close();
223 //now write the new filename
224 cmGeneratedFileStream fout(filename.c_str());
225 if(!fout)
227 return false;
230 fileToOpen="";
231 for (std::set<cmStdString>::const_iterator it=files.begin();
232 it!=files.end(); it++)
234 // get the full path to the file
235 tmp=cmSystemTools::CollapseFullPath(it->c_str(), projectDir.c_str());
236 // just select the first source file
237 if (fileToOpen.empty())
239 std::string ext = cmSystemTools::GetFilenameExtension(tmp);
240 if ((ext==".c") || (ext==".cc") || (ext==".cpp") || (ext==".cxx")
241 || (ext==".C") || (ext==".h") || (ext==".hpp"))
243 fileToOpen=tmp;
246 // make it relative to the project dir
247 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
248 // only put relative paths
249 if (tmp.size() && tmp[0] != '/')
251 fout << tmp.c_str() <<"\n";
254 return true;
258 /* create the project file, if it already exists, merge it with the
259 existing one, otherwise create a new one */
260 void cmGlobalKdevelopGenerator
261 ::CreateProjectFile(const std::string& outputDir,
262 const std::string& projectDir,
263 const std::string& projectname,
264 const std::string& executable,
265 const std::string& cmakeFilePattern,
266 const std::string& fileToOpen)
268 this->Blacklist.clear();
270 std::string filename=outputDir+"/";
271 filename+=projectname+".kdevelop";
272 std::string sessionFilename=outputDir+"/";
273 sessionFilename+=projectname+".kdevses";
275 if (cmSystemTools::FileExists(filename.c_str()))
277 this->MergeProjectFiles(outputDir, projectDir, filename,
278 executable, cmakeFilePattern,
279 fileToOpen, sessionFilename);
281 else
283 // add all subdirectories to the kdevelop blacklist
284 // so they are not monitored for added or removed files
285 // since this is basically handled by adding files to the cmake files
286 cmsys::Directory d;
287 if (d.Load(projectDir.c_str()))
289 size_t numf = d.GetNumberOfFiles();
290 for (unsigned int i = 0; i < numf; i++)
292 std::string nextFile = d.GetFile(i);
293 if ((nextFile!=".") && (nextFile!=".."))
295 std::string tmp = projectDir;
296 tmp += "/";
297 tmp += nextFile;
298 if (cmSystemTools::FileIsDirectory(tmp.c_str()))
300 this->Blacklist.push_back(nextFile);
305 this->CreateNewProjectFile(outputDir, projectDir, filename,
306 executable, cmakeFilePattern,
307 fileToOpen, sessionFilename);
312 void cmGlobalKdevelopGenerator
313 ::MergeProjectFiles(const std::string& outputDir,
314 const std::string& projectDir,
315 const std::string& filename,
316 const std::string& executable,
317 const std::string& cmakeFilePattern,
318 const std::string& fileToOpen,
319 const std::string& sessionFilename)
321 std::ifstream oldProjectFile(filename.c_str());
322 if (!oldProjectFile)
324 this->CreateNewProjectFile(outputDir, projectDir, filename,
325 executable, cmakeFilePattern,
326 fileToOpen, sessionFilename);
327 return;
330 /* Read the existing project file (line by line), copy all lines
331 into the new project file, except the ones which can be reliably
332 set from contents of the CMakeLists.txt */
333 std::string tmp;
334 std::vector<std::string> lines;
335 while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
337 lines.push_back(tmp);
339 oldProjectFile.close();
341 cmGeneratedFileStream fout(filename.c_str());
342 if(!fout)
344 return;
347 for (std::vector<std::string>::const_iterator it=lines.begin();
348 it!=lines.end(); it++)
350 const char* line=(*it).c_str();
351 // skip these tags as they are always replaced
352 if ((strstr(line, "<projectdirectory>")!=0)
353 || (strstr(line, "<projectmanagement>")!=0)
354 || (strstr(line, "<absoluteprojectpath>")!=0)
355 || (strstr(line, "<filelistdirectory>")!=0)
356 || (strstr(line, "<buildtool>")!=0)
357 || (strstr(line, "<builddir>")!=0))
359 continue;
362 // output the line from the file if it is not one of the above tags
363 fout<<*it<<"\n";
364 // if this is the <general> tag output the stuff that goes in the
365 // general tag
366 if (strstr(line, "<general>"))
368 fout<< " <projectmanagement>KDevCustomProject</projectmanagement>\n";
369 fout<< " <projectdirectory>" <<projectDir.c_str()
370 << "</projectdirectory>\n"; //this one is important
371 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n";
372 //and this one
374 // inside kdevcustomproject the <filelistdirectory> must be put
375 if (strstr(line, "<kdevcustomproject>"))
377 fout<<" <filelistdirectory>"<<outputDir.c_str()
378 <<"</filelistdirectory>\n";
380 // buildtool and builddir go inside <build>
381 if (strstr(line, "<build>"))
383 fout<<" <buildtool>make</buildtool>\n";
384 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n";
389 void cmGlobalKdevelopGenerator
390 ::CreateNewProjectFile(const std::string& outputDir,
391 const std::string& projectDir,
392 const std::string& filename,
393 const std::string& executable,
394 const std::string& cmakeFilePattern,
395 const std::string& fileToOpen,
396 const std::string& sessionFilename)
398 cmGeneratedFileStream fout(filename.c_str());
399 if(!fout)
401 return;
404 // check for a version control system
405 bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());
406 bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());
408 bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C")
409 || this->GlobalGenerator->GetLanguageEnabled("CXX"));
410 bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");
411 std::string primaryLanguage = "C++";
412 if (enableFortran && !enableCxx)
414 primaryLanguage="Fortran77";
417 fout<<"<?xml version = '1.0'?>\n"
418 "<kdevelop>\n"
419 " <general>\n"
420 " <author></author>\n"
421 " <email></email>\n"
422 " <version>$VERSION$</version>\n"
423 " <projectmanagement>KDevCustomProject</projectmanagement>\n"
424 " <primarylanguage>" << primaryLanguage << "</primarylanguage>\n"
425 " <ignoreparts/>\n"
426 " <projectdirectory>" << projectDir.c_str() <<
427 "</projectdirectory>\n"; //this one is important
428 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
430 // setup additional languages
431 fout<<" <secondaryLanguages>\n";
432 if (enableFortran && enableCxx)
434 fout<<" <language>Fortran</language>\n";
436 if (enableCxx)
438 fout<<" <language>C</language>\n";
440 fout<<" </secondaryLanguages>\n";
442 if (hasSvn)
444 fout << " <versioncontrol>kdevsubversion</versioncontrol>\n";
446 else if (hasCvs)
448 fout << " <versioncontrol>kdevcvsservice</versioncontrol>\n";
451 fout<<" </general>\n"
452 " <kdevcustomproject>\n"
453 " <filelistdirectory>" << outputDir.c_str() <<
454 "</filelistdirectory>\n"
455 " <run>\n"
456 " <mainprogram>" << executable.c_str() << "</mainprogram>\n"
457 " <directoryradio>custom</directoryradio>\n"
458 " <customdirectory>"<<outputDir.c_str()<<"</customdirectory>\n"
459 " <programargs></programargs>\n"
460 " <terminal>false</terminal>\n"
461 " <autocompile>true</autocompile>\n"
462 " <envvars/>\n"
463 " </run>\n"
464 " <build>\n"
465 " <buildtool>make</buildtool>\n"; //this one is important
466 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
467 fout<<" </build>\n"
468 " <make>\n"
469 " <abortonerror>false</abortonerror>\n"
470 " <numberofjobs>1</numberofjobs>\n"
471 " <dontact>false</dontact>\n"
472 " <makebin>" << this->GlobalGenerator->GetLocalGenerators()[0]->
473 GetMakefile()->GetRequiredDefinition("CMAKE_BUILD_TOOL")
474 << " VERBOSE=1 </makebin>\n"
475 " <selectedenvironment>default</selectedenvironment>\n"
476 " <environments>\n"
477 " <default/>\n"
478 " </environments>\n"
479 " </make>\n";
481 fout<<" <blacklist>\n";
482 for(std::vector<std::string>::const_iterator dirIt=this->Blacklist.begin();
483 dirIt != this->Blacklist.end();
484 ++dirIt)
486 fout<<" <path>" << dirIt->c_str() << "</path>\n";
488 fout<<" </blacklist>\n";
490 fout<<" </kdevcustomproject>\n"
491 " <kdevfilecreate>\n"
492 " <filetypes/>\n"
493 " <useglobaltypes>\n"
494 " <type ext=\"ui\" />\n"
495 " <type ext=\"cpp\" />\n"
496 " <type ext=\"h\" />\n"
497 " </useglobaltypes>\n"
498 " </kdevfilecreate>\n"
499 " <kdevdoctreeview>\n"
500 " <projectdoc>\n"
501 " <userdocDir>html/</userdocDir>\n"
502 " <apidocDir>html/</apidocDir>\n"
503 " </projectdoc>\n"
504 " <ignoreqt_xml/>\n"
505 " <ignoredoxygen/>\n"
506 " <ignorekdocs/>\n"
507 " <ignoretocs/>\n"
508 " <ignoredevhelp/>\n"
509 " </kdevdoctreeview>\n";
511 if (enableCxx)
513 fout<<" <cppsupportpart>\n"
514 " <filetemplates>\n"
515 " <interfacesuffix>.h</interfacesuffix>\n"
516 " <implementationsuffix>.cpp</implementationsuffix>\n"
517 " </filetemplates>\n"
518 " </cppsupportpart>\n"
519 " <kdevcppsupport>\n"
520 " <codecompletion>\n"
521 " <includeGlobalFunctions>true</includeGlobalFunctions>\n"
522 " <includeTypes>true</includeTypes>\n"
523 " <includeEnums>true</includeEnums>\n"
524 " <includeTypedefs>false</includeTypedefs>\n"
525 " <automaticCodeCompletion>true</automaticCodeCompletion>\n"
526 " <automaticArgumentsHint>true</automaticArgumentsHint>\n"
527 " <automaticHeaderCompletion>true</automaticHeaderCompletion>\n"
528 " <codeCompletionDelay>250</codeCompletionDelay>\n"
529 " <argumentsHintDelay>400</argumentsHintDelay>\n"
530 " <headerCompletionDelay>250</headerCompletionDelay>\n"
531 " </codecompletion>\n"
532 " <references/>\n"
533 " </kdevcppsupport>\n";
536 if (enableFortran)
538 fout<<" <kdevfortransupport>\n"
539 " <ftnchek>\n"
540 " <division>false</division>\n"
541 " <extern>false</extern>\n"
542 " <declare>false</declare>\n"
543 " <pure>false</pure>\n"
544 " <argumentsall>false</argumentsall>\n"
545 " <commonall>false</commonall>\n"
546 " <truncationall>false</truncationall>\n"
547 " <usageall>false</usageall>\n"
548 " <f77all>false</f77all>\n"
549 " <portabilityall>false</portabilityall>\n"
550 " <argumentsonly/>\n"
551 " <commononly/>\n"
552 " <truncationonly/>\n"
553 " <usageonly/>\n"
554 " <f77only/>\n"
555 " <portabilityonly/>\n"
556 " </ftnchek>\n"
557 " </kdevfortransupport>\n";
560 // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
561 // command
562 fout<<" <kdevfileview>\n"
563 " <groups>\n"
564 " <group pattern=\"" << cmakeFilePattern.c_str() <<
565 "\" name=\"CMake\" />\n";
567 if (enableCxx)
569 fout<<" <group pattern=\"*.h;*.hxx;*.hpp\" name=\"Header\" />\n"
570 " <group pattern=\"*.c\" name=\"C Sources\" />\n"
571 " <group pattern=\"*.cpp;*.C;*.cxx;*.cc\" name=\"C++ Sources\""
572 "/>\n";
575 if (enableFortran)
577 fout<<" <group pattern=\"*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;"
578 "*.F95\" name=\"Fortran Sources\" />\n";
581 fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n"
582 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
583 " </groups>\n"
584 " <tree>\n"
585 " <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n"
586 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
587 " </tree>\n"
588 " </kdevfileview>\n"
589 "</kdevelop>\n";
591 if (sessionFilename.empty())
593 return;
596 // and a session file, so that kdevelop opens a file if it opens the
597 // project the first time
598 cmGeneratedFileStream devses(sessionFilename.c_str());
599 if(!devses)
601 return;
603 devses<<"<?xml version = '1.0' encoding = \'UTF-8\'?>\n"
604 "<!DOCTYPE KDevPrjSession>\n"
605 "<KDevPrjSession>\n"
606 " <DocsAndViews NumberOfDocuments=\"1\" >\n"
607 " <Doc0 NumberOfViews=\"1\" URL=\"file://" << fileToOpen.c_str() <<
608 "\" >\n"
609 " <View0 line=\"0\" Type=\"Source\" />\n"
610 " </Doc0>\n"
611 " </DocsAndViews>\n"
612 "</KDevPrjSession>\n";