Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmGlobalKdevelopGenerator.cxx
blob7e045caa2590a52f744b2e83685d30b02b1ad39d
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalKdevelopGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2007/10/22 17:28:49 $
7 Version: $Revision: 1.29 $
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");
56 void cmGlobalKdevelopGenerator::SetGlobalGenerator(
57 cmGlobalGenerator* generator)
59 cmExternalMakefileProjectGenerator::SetGlobalGenerator(generator);
60 cmGlobalUnixMakefileGenerator3* mf = (cmGlobalUnixMakefileGenerator3*)
61 generator;
62 mf->SetToolSupportsColor(false);
63 mf->SetForceVerboseMakefiles(true);
66 void cmGlobalKdevelopGenerator::Generate()
68 // for each sub project in the project create
69 // a kdevelop project
70 for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
71 it = this->GlobalGenerator->GetProjectMap().begin();
72 it!= this->GlobalGenerator->GetProjectMap().end();
73 ++it)
75 cmMakefile* mf = it->second[0]->GetMakefile();
76 std::string outputDir=mf->GetStartOutputDirectory();
77 std::string projectDir=mf->GetHomeDirectory();
78 std::string projectName=mf->GetProjectName();
79 std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
80 std::string fileToOpen;
81 const std::vector<cmLocalGenerator*>& lgs= it->second;
82 // create the project.kdevelop.filelist file
83 if(!this->CreateFilelistFile(lgs, outputDir, projectDir,
84 projectName, cmakeFilePattern, fileToOpen))
86 cmSystemTools::Error("Can not create filelist file");
87 return;
89 //try to find the name of an executable so we have something to
90 //run from kdevelop for now just pick the first executable found
91 std::string executable;
92 for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin();
93 lg!=lgs.end(); lg++)
95 cmMakefile* makefile=(*lg)->GetMakefile();
96 cmTargets& targets=makefile->GetTargets();
97 for (cmTargets::iterator ti = targets.begin();
98 ti != targets.end(); ti++)
100 if (ti->second.GetType()==cmTarget::EXECUTABLE)
102 executable = ti->second.GetProperty("LOCATION");
103 break;
106 if (!executable.empty())
108 break;
112 // now create a project file
113 this->CreateProjectFile(outputDir, projectDir, projectName,
114 executable, cmakeFilePattern, fileToOpen);
118 bool cmGlobalKdevelopGenerator
119 ::CreateFilelistFile(const std::vector<cmLocalGenerator*>& lgs,
120 const std::string& outputDir,
121 const std::string& projectDirIn,
122 const std::string& projectname,
123 std::string& cmakeFilePattern,
124 std::string& fileToOpen)
126 std::string projectDir = projectDirIn + "/";
127 std::string filename = outputDir+ "/" + projectname +".kdevelop.filelist";
129 std::set<cmStdString> files;
130 std::string tmp;
132 for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin();
133 it!=lgs.end(); it++)
135 cmMakefile* makefile=(*it)->GetMakefile();
136 const std::vector<std::string>& listFiles=makefile->GetListFiles();
137 for (std::vector<std::string>::const_iterator lt=listFiles.begin();
138 lt!=listFiles.end(); lt++)
140 tmp=*lt;
141 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
142 // make sure the file is part of this source tree
143 if ((tmp[0]!='/') &&
144 (strstr(tmp.c_str(),
145 cmake::GetCMakeFilesDirectoryPostSlash())==0))
147 files.insert(tmp);
148 tmp=cmSystemTools::GetFilenameName(tmp);
149 //add all files which dont match the default
150 // */CMakeLists.txt;*cmake; to the file pattern
151 if ((tmp!="CMakeLists.txt")
152 && (strstr(tmp.c_str(), ".cmake")==0))
154 cmakeFilePattern+=tmp+";";
159 //get all sources
160 cmTargets& targets=makefile->GetTargets();
161 for (cmTargets::iterator ti = targets.begin();
162 ti != targets.end(); ti++)
164 const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();
165 for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
166 si!=sources.end(); si++)
168 tmp=(*si)->GetFullPath();
169 std::string headerBasename=cmSystemTools::GetFilenamePath(tmp);
170 headerBasename+="/";
171 headerBasename+=cmSystemTools::GetFilenameWithoutExtension(tmp);
173 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
175 if ((tmp[0]!='/') &&
176 (strstr(tmp.c_str(),
177 cmake::GetCMakeFilesDirectoryPostSlash())==0) &&
178 (cmSystemTools::GetFilenameExtension(tmp)!=".moc"))
180 files.insert(tmp);
182 // check if there's a matching header around
183 for(std::vector<std::string>::const_iterator
184 ext = makefile->GetHeaderExtensions().begin();
185 ext != makefile->GetHeaderExtensions().end(); ++ext)
187 std::string hname=headerBasename;
188 hname += ".";
189 hname += *ext;
190 if(cmSystemTools::FileExists(hname.c_str()))
192 cmSystemTools::ReplaceString(hname, projectDir.c_str(), "");
193 files.insert(hname);
194 break;
199 for (std::vector<std::string>::const_iterator lt=listFiles.begin();
200 lt!=listFiles.end(); lt++)
202 tmp=*lt;
203 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
204 if ((tmp[0]!='/') &&
205 (strstr(tmp.c_str(),
206 cmake::GetCMakeFilesDirectoryPostSlash())==0))
208 files.insert(tmp.c_str());
214 //check if the output file already exists and read it
215 //insert all files which exist into the set of files
216 std::ifstream oldFilelist(filename.c_str());
217 if (oldFilelist)
219 while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))
221 if (tmp[0]=='/')
223 continue;
225 std::string completePath=projectDir+tmp;
226 if (cmSystemTools::FileExists(completePath.c_str()))
228 files.insert(tmp);
231 oldFilelist.close();
234 //now write the new filename
235 cmGeneratedFileStream fout(filename.c_str());
236 if(!fout)
238 return false;
241 fileToOpen="";
242 for (std::set<cmStdString>::const_iterator it=files.begin();
243 it!=files.end(); it++)
245 // get the full path to the file
246 tmp=cmSystemTools::CollapseFullPath(it->c_str(), projectDir.c_str());
247 // just select the first source file
248 if (fileToOpen.empty())
250 std::string ext = cmSystemTools::GetFilenameExtension(tmp);
251 if ((ext==".c") || (ext==".cc") || (ext==".cpp") || (ext==".cxx")
252 || (ext==".C") || (ext==".h") || (ext==".hpp"))
254 fileToOpen=tmp;
257 // make it relative to the project dir
258 cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
259 // only put relative paths
260 if (tmp.size() && tmp[0] != '/')
262 fout << tmp.c_str() <<"\n";
265 return true;
269 /* create the project file, if it already exists, merge it with the
270 existing one, otherwise create a new one */
271 void cmGlobalKdevelopGenerator
272 ::CreateProjectFile(const std::string& outputDir,
273 const std::string& projectDir,
274 const std::string& projectname,
275 const std::string& executable,
276 const std::string& cmakeFilePattern,
277 const std::string& fileToOpen)
279 this->Blacklist.clear();
281 std::string filename=outputDir+"/";
282 filename+=projectname+".kdevelop";
283 std::string sessionFilename=outputDir+"/";
284 sessionFilename+=projectname+".kdevses";
286 if (cmSystemTools::FileExists(filename.c_str()))
288 this->MergeProjectFiles(outputDir, projectDir, filename,
289 executable, cmakeFilePattern,
290 fileToOpen, sessionFilename);
292 else
294 // add all subdirectories to the kdevelop blacklist
295 // so they are not monitored for added or removed files
296 // since this is basically handled by adding files to the cmake files
297 cmsys::Directory d;
298 if (d.Load(projectDir.c_str()))
300 size_t numf = d.GetNumberOfFiles();
301 for (unsigned int i = 0; i < numf; i++)
303 std::string nextFile = d.GetFile(i);
304 if ((nextFile!=".") && (nextFile!=".."))
306 std::string tmp = projectDir;
307 tmp += "/";
308 tmp += nextFile;
309 if (cmSystemTools::FileIsDirectory(tmp.c_str()))
311 this->Blacklist.push_back(nextFile);
316 this->CreateNewProjectFile(outputDir, projectDir, filename,
317 executable, cmakeFilePattern,
318 fileToOpen, sessionFilename);
323 void cmGlobalKdevelopGenerator
324 ::MergeProjectFiles(const std::string& outputDir,
325 const std::string& projectDir,
326 const std::string& filename,
327 const std::string& executable,
328 const std::string& cmakeFilePattern,
329 const std::string& fileToOpen,
330 const std::string& sessionFilename)
332 std::ifstream oldProjectFile(filename.c_str());
333 if (!oldProjectFile)
335 this->CreateNewProjectFile(outputDir, projectDir, filename,
336 executable, cmakeFilePattern,
337 fileToOpen, sessionFilename);
338 return;
341 /* Read the existing project file (line by line), copy all lines
342 into the new project file, except the ones which can be reliably
343 set from contents of the CMakeLists.txt */
344 std::string tmp;
345 std::vector<std::string> lines;
346 while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
348 lines.push_back(tmp);
350 oldProjectFile.close();
352 cmGeneratedFileStream fout(filename.c_str());
353 if(!fout)
355 return;
358 for (std::vector<std::string>::const_iterator it=lines.begin();
359 it!=lines.end(); it++)
361 const char* line=(*it).c_str();
362 // skip these tags as they are always replaced
363 if ((strstr(line, "<projectdirectory>")!=0)
364 || (strstr(line, "<projectmanagement>")!=0)
365 || (strstr(line, "<absoluteprojectpath>")!=0)
366 || (strstr(line, "<filelistdirectory>")!=0)
367 || (strstr(line, "<buildtool>")!=0)
368 || (strstr(line, "<builddir>")!=0))
370 continue;
373 // output the line from the file if it is not one of the above tags
374 fout<<*it<<"\n";
375 // if this is the <general> tag output the stuff that goes in the
376 // general tag
377 if (strstr(line, "<general>"))
379 fout<< " <projectmanagement>KDevCustomProject</projectmanagement>\n";
380 fout<< " <projectdirectory>" <<projectDir.c_str()
381 << "</projectdirectory>\n"; //this one is important
382 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n";
383 //and this one
385 // inside kdevcustomproject the <filelistdirectory> must be put
386 if (strstr(line, "<kdevcustomproject>"))
388 fout<<" <filelistdirectory>"<<outputDir.c_str()
389 <<"</filelistdirectory>\n";
391 // buildtool and builddir go inside <build>
392 if (strstr(line, "<build>"))
394 fout<<" <buildtool>make</buildtool>\n";
395 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n";
400 void cmGlobalKdevelopGenerator
401 ::CreateNewProjectFile(const std::string& outputDir,
402 const std::string& projectDir,
403 const std::string& filename,
404 const std::string& executable,
405 const std::string& cmakeFilePattern,
406 const std::string& fileToOpen,
407 const std::string& sessionFilename)
409 cmGeneratedFileStream fout(filename.c_str());
410 if(!fout)
412 return;
415 // check for a version control system
416 bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());
417 bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());
419 bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C")
420 || this->GlobalGenerator->GetLanguageEnabled("CXX"));
421 bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");
422 std::string primaryLanguage = "C++";
423 if (enableFortran && !enableCxx)
425 primaryLanguage="Fortran77";
428 fout<<"<?xml version = '1.0'?>\n"
429 "<kdevelop>\n"
430 " <general>\n"
431 " <author></author>\n"
432 " <email></email>\n"
433 " <version>$VERSION$</version>\n"
434 " <projectmanagement>KDevCustomProject</projectmanagement>\n"
435 " <primarylanguage>" << primaryLanguage << "</primarylanguage>\n"
436 " <ignoreparts/>\n"
437 " <projectdirectory>" << projectDir.c_str() <<
438 "</projectdirectory>\n"; //this one is important
439 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
441 // setup additional languages
442 fout<<" <secondaryLanguages>\n";
443 if (enableFortran && enableCxx)
445 fout<<" <language>Fortran</language>\n";
447 if (enableCxx)
449 fout<<" <language>C</language>\n";
451 fout<<" </secondaryLanguages>\n";
453 if (hasSvn)
455 fout << " <versioncontrol>kdevsubversion</versioncontrol>\n";
457 else if (hasCvs)
459 fout << " <versioncontrol>kdevcvsservice</versioncontrol>\n";
462 fout<<" </general>\n"
463 " <kdevcustomproject>\n"
464 " <filelistdirectory>" << outputDir.c_str() <<
465 "</filelistdirectory>\n"
466 " <run>\n"
467 " <mainprogram>" << executable.c_str() << "</mainprogram>\n"
468 " <directoryradio>custom</directoryradio>\n"
469 " <customdirectory>"<<outputDir.c_str()<<"</customdirectory>\n"
470 " <programargs></programargs>\n"
471 " <terminal>false</terminal>\n"
472 " <autocompile>true</autocompile>\n"
473 " <envvars/>\n"
474 " </run>\n"
475 " <build>\n"
476 " <buildtool>make</buildtool>\n"; //this one is important
477 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
478 fout<<" </build>\n"
479 " <make>\n"
480 " <abortonerror>false</abortonerror>\n"
481 " <numberofjobs>1</numberofjobs>\n"
482 " <dontact>false</dontact>\n"
483 " <makebin></makebin>\n"
484 " <selectedenvironment>default</selectedenvironment>\n"
485 " <environments>\n"
486 " <default/>\n"
487 " </environments>\n"
488 " </make>\n";
490 fout<<" <blacklist>\n";
491 for(std::vector<std::string>::const_iterator dirIt=this->Blacklist.begin();
492 dirIt != this->Blacklist.end();
493 ++dirIt)
495 fout<<" <path>" << dirIt->c_str() << "</path>\n";
497 fout<<" </blacklist>\n";
499 fout<<" </kdevcustomproject>\n"
500 " <kdevfilecreate>\n"
501 " <filetypes/>\n"
502 " <useglobaltypes>\n"
503 " <type ext=\"ui\" />\n"
504 " <type ext=\"cpp\" />\n"
505 " <type ext=\"h\" />\n"
506 " </useglobaltypes>\n"
507 " </kdevfilecreate>\n"
508 " <kdevdoctreeview>\n"
509 " <projectdoc>\n"
510 " <userdocDir>html/</userdocDir>\n"
511 " <apidocDir>html/</apidocDir>\n"
512 " </projectdoc>\n"
513 " <ignoreqt_xml/>\n"
514 " <ignoredoxygen/>\n"
515 " <ignorekdocs/>\n"
516 " <ignoretocs/>\n"
517 " <ignoredevhelp/>\n"
518 " </kdevdoctreeview>\n";
520 if (enableCxx)
522 fout<<" <cppsupportpart>\n"
523 " <filetemplates>\n"
524 " <interfacesuffix>.h</interfacesuffix>\n"
525 " <implementationsuffix>.cpp</implementationsuffix>\n"
526 " </filetemplates>\n"
527 " </cppsupportpart>\n"
528 " <kdevcppsupport>\n"
529 " <codecompletion>\n"
530 " <includeGlobalFunctions>true</includeGlobalFunctions>\n"
531 " <includeTypes>true</includeTypes>\n"
532 " <includeEnums>true</includeEnums>\n"
533 " <includeTypedefs>false</includeTypedefs>\n"
534 " <automaticCodeCompletion>true</automaticCodeCompletion>\n"
535 " <automaticArgumentsHint>true</automaticArgumentsHint>\n"
536 " <automaticHeaderCompletion>true</automaticHeaderCompletion>\n"
537 " <codeCompletionDelay>250</codeCompletionDelay>\n"
538 " <argumentsHintDelay>400</argumentsHintDelay>\n"
539 " <headerCompletionDelay>250</headerCompletionDelay>\n"
540 " </codecompletion>\n"
541 " <references/>\n"
542 " </kdevcppsupport>\n";
545 if (enableFortran)
547 fout<<" <kdevfortransupport>\n"
548 " <ftnchek>\n"
549 " <division>false</division>\n"
550 " <extern>false</extern>\n"
551 " <declare>false</declare>\n"
552 " <pure>false</pure>\n"
553 " <argumentsall>false</argumentsall>\n"
554 " <commonall>false</commonall>\n"
555 " <truncationall>false</truncationall>\n"
556 " <usageall>false</usageall>\n"
557 " <f77all>false</f77all>\n"
558 " <portabilityall>false</portabilityall>\n"
559 " <argumentsonly/>\n"
560 " <commononly/>\n"
561 " <truncationonly/>\n"
562 " <usageonly/>\n"
563 " <f77only/>\n"
564 " <portabilityonly/>\n"
565 " </ftnchek>\n"
566 " </kdevfortransupport>\n";
569 // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
570 // command
571 fout<<" <kdevfileview>\n"
572 " <groups>\n"
573 " <group pattern=\"" << cmakeFilePattern.c_str() <<
574 "\" name=\"CMake\" />\n";
576 if (enableCxx)
578 fout<<" <group pattern=\"*.h;*.hxx;*.hpp\" name=\"Header\" />\n"
579 " <group pattern=\"*.c\" name=\"C Sources\" />\n"
580 " <group pattern=\"*.cpp;*.C;*.cxx;*.cc\" name=\"C++ Sources\""
581 "/>\n";
584 if (enableFortran)
586 fout<<" <group pattern=\"*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;"
587 "*.F95\" name=\"Fortran Sources\" />\n";
590 fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n"
591 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
592 " </groups>\n"
593 " <tree>\n"
594 " <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n"
595 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
596 " </tree>\n"
597 " </kdevfileview>\n"
598 "</kdevelop>\n";
600 if (sessionFilename.empty())
602 return;
605 // and a session file, so that kdevelop opens a file if it opens the
606 // project the first time
607 cmGeneratedFileStream devses(sessionFilename.c_str());
608 if(!devses)
610 return;
612 devses<<"<?xml version = '1.0' encoding = \'UTF-8\'?>\n"
613 "<!DOCTYPE KDevPrjSession>\n"
614 "<KDevPrjSession>\n"
615 " <DocsAndViews NumberOfDocuments=\"1\" >\n"
616 " <Doc0 NumberOfViews=\"1\" URL=\"file://" << fileToOpen.c_str() <<
617 "\" >\n"
618 " <View0 line=\"0\" Type=\"Source\" />\n"
619 " </Doc0>\n"
620 " </DocsAndViews>\n"
621 "</KDevPrjSession>\n";