1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalKdevelopGenerator.cxx,v $
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"
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.";
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 "
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
59 for (std::map
<cmStdString
, std::vector
<cmLocalGenerator
*> >::const_iterator
60 it
= this->GlobalGenerator
->GetProjectMap().begin();
61 it
!= this->GlobalGenerator
->GetProjectMap().end();
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");
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();
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");
95 if (!executable
.empty())
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
;
121 for (std::vector
<cmLocalGenerator
*>::const_iterator it
=lgs
.begin();
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
++)
130 cmSystemTools::ReplaceString(tmp
, projectDir
.c_str(), "");
131 // make sure the file is part of this source tree
134 cmake::GetCMakeFilesDirectoryPostSlash())==0))
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
+";";
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
);
160 headerBasename
+=cmSystemTools::GetFilenameWithoutExtension(tmp
);
162 cmSystemTools::ReplaceString(tmp
, projectDir
.c_str(), "");
166 cmake::GetCMakeFilesDirectoryPostSlash())==0) &&
167 (cmSystemTools::GetFilenameExtension(tmp
)!=".moc"))
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
;
179 if(cmSystemTools::FileExists(hname
.c_str()))
181 cmSystemTools::ReplaceString(hname
, projectDir
.c_str(), "");
188 for (std::vector
<std::string
>::const_iterator lt
=listFiles
.begin();
189 lt
!=listFiles
.end(); lt
++)
192 cmSystemTools::ReplaceString(tmp
, projectDir
.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());
208 while (cmSystemTools::GetLineFromStream(oldFilelist
, tmp
))
214 std::string completePath
=projectDir
+tmp
;
215 if (cmSystemTools::FileExists(completePath
.c_str()))
223 //now write the new filename
224 cmGeneratedFileStream
fout(filename
.c_str());
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"))
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";
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
);
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
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
;
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());
324 this->CreateNewProjectFile(outputDir
, projectDir
, filename
,
325 executable
, cmakeFilePattern
,
326 fileToOpen
, sessionFilename
);
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 */
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());
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))
362 // output the line from the file if it is not one of the above tags
364 // if this is the <general> tag output the stuff that goes in the
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";
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());
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"
420 " <author></author>\n"
422 " <version>$VERSION$</version>\n"
423 " <projectmanagement>KDevCustomProject</projectmanagement>\n"
424 " <primarylanguage>" << primaryLanguage
<< "</primarylanguage>\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";
438 fout
<<" <language>C</language>\n";
440 fout
<<" </secondaryLanguages>\n";
444 fout
<< " <versioncontrol>kdevsubversion</versioncontrol>\n";
448 fout
<< " <versioncontrol>kdevcvsservice</versioncontrol>\n";
451 fout
<<" </general>\n"
452 " <kdevcustomproject>\n"
453 " <filelistdirectory>" << outputDir
.c_str() <<
454 "</filelistdirectory>\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"
465 " <buildtool>make</buildtool>\n"; //this one is important
466 fout
<<" <builddir>"<<outputDir
.c_str()<<"</builddir>\n"; //and this one
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"
481 fout
<<" <blacklist>\n";
482 for(std::vector
<std::string
>::const_iterator dirIt
=this->Blacklist
.begin();
483 dirIt
!= this->Blacklist
.end();
486 fout
<<" <path>" << dirIt
->c_str() << "</path>\n";
488 fout
<<" </blacklist>\n";
490 fout
<<" </kdevcustomproject>\n"
491 " <kdevfilecreate>\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"
501 " <userdocDir>html/</userdocDir>\n"
502 " <apidocDir>html/</apidocDir>\n"
505 " <ignoredoxygen/>\n"
508 " <ignoredevhelp/>\n"
509 " </kdevdoctreeview>\n";
513 fout
<<" <cppsupportpart>\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"
533 " </kdevcppsupport>\n";
538 fout
<<" <kdevfortransupport>\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"
552 " <truncationonly/>\n"
555 " <portabilityonly/>\n"
557 " </kdevfortransupport>\n";
560 // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
562 fout
<<" <kdevfileview>\n"
564 " <group pattern=\"" << cmakeFilePattern
.c_str() <<
565 "\" name=\"CMake\" />\n";
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\""
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"
585 " <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n"
586 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
591 if (sessionFilename
.empty())
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());
603 devses
<<"<?xml version = '1.0' encoding = \'UTF-8\'?>\n"
604 "<!DOCTYPE KDevPrjSession>\n"
606 " <DocsAndViews NumberOfDocuments=\"1\" >\n"
607 " <Doc0 NumberOfViews=\"1\" URL=\"file://" << fileToOpen
.c_str() <<
609 " <View0 line=\"0\" Type=\"Source\" />\n"
612 "</KDevPrjSession>\n";