ENH: make sure CTEST_CURL_OPTIONS work from script mode
[cmake.git] / Source / cmGlobalKdevelopGenerator.cxx
blob5eedd13add4cfe1a8f66a82bf7bba91fd8864819
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGlobalKdevelopGenerator.cxx,v $
5 Language: C++
6 Date: $Date: 2008-08-16 20:58:20 $
7 Version: $Revision: 1.33 $
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 which are cmake build directories to the
284 // kdevelop blacklist so they are not monitored for added or removed files
285 // since this is 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 tmp += "/CMakeCache.txt";
301 if ((nextFile == "CMakeFiles")
302 || (cmSystemTools::FileExists(tmp.c_str())))
304 this->Blacklist.push_back(nextFile);
310 this->CreateNewProjectFile(outputDir, projectDir, filename,
311 executable, cmakeFilePattern,
312 fileToOpen, sessionFilename);
317 void cmGlobalKdevelopGenerator
318 ::MergeProjectFiles(const std::string& outputDir,
319 const std::string& projectDir,
320 const std::string& filename,
321 const std::string& executable,
322 const std::string& cmakeFilePattern,
323 const std::string& fileToOpen,
324 const std::string& sessionFilename)
326 std::ifstream oldProjectFile(filename.c_str());
327 if (!oldProjectFile)
329 this->CreateNewProjectFile(outputDir, projectDir, filename,
330 executable, cmakeFilePattern,
331 fileToOpen, sessionFilename);
332 return;
335 /* Read the existing project file (line by line), copy all lines
336 into the new project file, except the ones which can be reliably
337 set from contents of the CMakeLists.txt */
338 std::string tmp;
339 std::vector<std::string> lines;
340 while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
342 lines.push_back(tmp);
344 oldProjectFile.close();
346 cmGeneratedFileStream fout(filename.c_str());
347 if(!fout)
349 return;
352 for (std::vector<std::string>::const_iterator it=lines.begin();
353 it!=lines.end(); it++)
355 const char* line=(*it).c_str();
356 // skip these tags as they are always replaced
357 if ((strstr(line, "<projectdirectory>")!=0)
358 || (strstr(line, "<projectmanagement>")!=0)
359 || (strstr(line, "<absoluteprojectpath>")!=0)
360 || (strstr(line, "<filelistdirectory>")!=0)
361 || (strstr(line, "<buildtool>")!=0)
362 || (strstr(line, "<builddir>")!=0))
364 continue;
367 // output the line from the file if it is not one of the above tags
368 fout<<*it<<"\n";
369 // if this is the <general> tag output the stuff that goes in the
370 // general tag
371 if (strstr(line, "<general>"))
373 fout<< " <projectmanagement>KDevCustomProject</projectmanagement>\n";
374 fout<< " <projectdirectory>" <<projectDir.c_str()
375 << "</projectdirectory>\n"; //this one is important
376 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n";
377 //and this one
379 // inside kdevcustomproject the <filelistdirectory> must be put
380 if (strstr(line, "<kdevcustomproject>"))
382 fout<<" <filelistdirectory>"<<outputDir.c_str()
383 <<"</filelistdirectory>\n";
385 // buildtool and builddir go inside <build>
386 if (strstr(line, "<build>"))
388 fout<<" <buildtool>make</buildtool>\n";
389 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n";
394 void cmGlobalKdevelopGenerator
395 ::CreateNewProjectFile(const std::string& outputDir,
396 const std::string& projectDir,
397 const std::string& filename,
398 const std::string& executable,
399 const std::string& cmakeFilePattern,
400 const std::string& fileToOpen,
401 const std::string& sessionFilename)
403 cmGeneratedFileStream fout(filename.c_str());
404 if(!fout)
406 return;
409 // check for a version control system
410 bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());
411 bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());
413 bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C")
414 || this->GlobalGenerator->GetLanguageEnabled("CXX"));
415 bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");
416 std::string primaryLanguage = "C++";
417 if (enableFortran && !enableCxx)
419 primaryLanguage="Fortran77";
422 fout<<"<?xml version = '1.0'?>\n"
423 "<kdevelop>\n"
424 " <general>\n"
425 " <author></author>\n"
426 " <email></email>\n"
427 " <version>$VERSION$</version>\n"
428 " <projectmanagement>KDevCustomProject</projectmanagement>\n"
429 " <primarylanguage>" << primaryLanguage << "</primarylanguage>\n"
430 " <ignoreparts/>\n"
431 " <projectdirectory>" << projectDir.c_str() <<
432 "</projectdirectory>\n"; //this one is important
433 fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
435 // setup additional languages
436 fout<<" <secondaryLanguages>\n";
437 if (enableFortran && enableCxx)
439 fout<<" <language>Fortran</language>\n";
441 if (enableCxx)
443 fout<<" <language>C</language>\n";
445 fout<<" </secondaryLanguages>\n";
447 if (hasSvn)
449 fout << " <versioncontrol>kdevsubversion</versioncontrol>\n";
451 else if (hasCvs)
453 fout << " <versioncontrol>kdevcvsservice</versioncontrol>\n";
456 fout<<" </general>\n"
457 " <kdevcustomproject>\n"
458 " <filelistdirectory>" << outputDir.c_str() <<
459 "</filelistdirectory>\n"
460 " <run>\n"
461 " <mainprogram>" << executable.c_str() << "</mainprogram>\n"
462 " <directoryradio>custom</directoryradio>\n"
463 " <customdirectory>"<<outputDir.c_str()<<"</customdirectory>\n"
464 " <programargs></programargs>\n"
465 " <terminal>false</terminal>\n"
466 " <autocompile>true</autocompile>\n"
467 " <envvars/>\n"
468 " </run>\n"
469 " <build>\n"
470 " <buildtool>make</buildtool>\n"; //this one is important
471 fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
472 fout<<" </build>\n"
473 " <make>\n"
474 " <abortonerror>false</abortonerror>\n"
475 " <numberofjobs>1</numberofjobs>\n"
476 " <dontact>false</dontact>\n"
477 " <makebin>" << this->GlobalGenerator->GetLocalGenerators()[0]->
478 GetMakefile()->GetRequiredDefinition("CMAKE_BUILD_TOOL")
479 << " </makebin>\n"
480 " <selectedenvironment>default</selectedenvironment>\n"
481 " <environments>\n"
482 " <default>\n"
483 " <envvar value=\"1\" name=\"VERBOSE\" />\n"
484 " </default>\n"
485 " </environments>\n"
486 " </make>\n";
488 fout<<" <blacklist>\n";
489 for(std::vector<std::string>::const_iterator dirIt=this->Blacklist.begin();
490 dirIt != this->Blacklist.end();
491 ++dirIt)
493 fout<<" <path>" << dirIt->c_str() << "</path>\n";
495 fout<<" </blacklist>\n";
497 fout<<" </kdevcustomproject>\n"
498 " <kdevfilecreate>\n"
499 " <filetypes/>\n"
500 " <useglobaltypes>\n"
501 " <type ext=\"ui\" />\n"
502 " <type ext=\"cpp\" />\n"
503 " <type ext=\"h\" />\n"
504 " </useglobaltypes>\n"
505 " </kdevfilecreate>\n"
506 " <kdevdoctreeview>\n"
507 " <projectdoc>\n"
508 " <userdocDir>html/</userdocDir>\n"
509 " <apidocDir>html/</apidocDir>\n"
510 " </projectdoc>\n"
511 " <ignoreqt_xml/>\n"
512 " <ignoredoxygen/>\n"
513 " <ignorekdocs/>\n"
514 " <ignoretocs/>\n"
515 " <ignoredevhelp/>\n"
516 " </kdevdoctreeview>\n";
518 if (enableCxx)
520 fout<<" <cppsupportpart>\n"
521 " <filetemplates>\n"
522 " <interfacesuffix>.h</interfacesuffix>\n"
523 " <implementationsuffix>.cpp</implementationsuffix>\n"
524 " </filetemplates>\n"
525 " </cppsupportpart>\n"
526 " <kdevcppsupport>\n"
527 " <codecompletion>\n"
528 " <includeGlobalFunctions>true</includeGlobalFunctions>\n"
529 " <includeTypes>true</includeTypes>\n"
530 " <includeEnums>true</includeEnums>\n"
531 " <includeTypedefs>false</includeTypedefs>\n"
532 " <automaticCodeCompletion>true</automaticCodeCompletion>\n"
533 " <automaticArgumentsHint>true</automaticArgumentsHint>\n"
534 " <automaticHeaderCompletion>true</automaticHeaderCompletion>\n"
535 " <codeCompletionDelay>250</codeCompletionDelay>\n"
536 " <argumentsHintDelay>400</argumentsHintDelay>\n"
537 " <headerCompletionDelay>250</headerCompletionDelay>\n"
538 " </codecompletion>\n"
539 " <references/>\n"
540 " </kdevcppsupport>\n";
543 if (enableFortran)
545 fout<<" <kdevfortransupport>\n"
546 " <ftnchek>\n"
547 " <division>false</division>\n"
548 " <extern>false</extern>\n"
549 " <declare>false</declare>\n"
550 " <pure>false</pure>\n"
551 " <argumentsall>false</argumentsall>\n"
552 " <commonall>false</commonall>\n"
553 " <truncationall>false</truncationall>\n"
554 " <usageall>false</usageall>\n"
555 " <f77all>false</f77all>\n"
556 " <portabilityall>false</portabilityall>\n"
557 " <argumentsonly/>\n"
558 " <commononly/>\n"
559 " <truncationonly/>\n"
560 " <usageonly/>\n"
561 " <f77only/>\n"
562 " <portabilityonly/>\n"
563 " </ftnchek>\n"
564 " </kdevfortransupport>\n";
567 // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
568 // command
569 fout<<" <kdevfileview>\n"
570 " <groups>\n"
571 " <group pattern=\"" << cmakeFilePattern.c_str() <<
572 "\" name=\"CMake\" />\n";
574 if (enableCxx)
576 fout<<" <group pattern=\"*.h;*.hxx;*.hpp\" name=\"Header\" />\n"
577 " <group pattern=\"*.c\" name=\"C Sources\" />\n"
578 " <group pattern=\"*.cpp;*.C;*.cxx;*.cc\" name=\"C++ Sources\""
579 "/>\n";
582 if (enableFortran)
584 fout<<" <group pattern=\"*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;"
585 "*.F95\" name=\"Fortran Sources\" />\n";
588 fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n"
589 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
590 " </groups>\n"
591 " <tree>\n"
592 " <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n"
593 " <hidenonprojectfiles>true</hidenonprojectfiles>\n"
594 " </tree>\n"
595 " </kdevfileview>\n"
596 "</kdevelop>\n";
598 if (sessionFilename.empty())
600 return;
603 // and a session file, so that kdevelop opens a file if it opens the
604 // project the first time
605 cmGeneratedFileStream devses(sessionFilename.c_str());
606 if(!devses)
608 return;
610 devses<<"<?xml version = '1.0' encoding = \'UTF-8\'?>\n"
611 "<!DOCTYPE KDevPrjSession>\n"
612 "<KDevPrjSession>\n"
613 " <DocsAndViews NumberOfDocuments=\"1\" >\n"
614 " <Doc0 NumberOfViews=\"1\" URL=\"file://" << fileToOpen.c_str() <<
615 "\" >\n"
616 " <View0 line=\"0\" Type=\"Source\" />\n"
617 " </Doc0>\n"
618 " </DocsAndViews>\n"
619 "</KDevPrjSession>\n";