/*========================================================================= Program: CMake - Cross-Platform Makefile Generator Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. Copyright (c) 2004 Alexander Neundorf, neundorf@kde.org. All rights reserved. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmGlobalGenerator.h" #include "cmLocalKdevelopGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" #include "cmSourceFile.h" #include "cmMakeDepend.h" #include "cmCacheManager.h" #include "cmGeneratedFileStream.h" #include "cmake.h" #include // Ideas for moving this stuff into the global generator // Right now in your local generator you read and write a file to build // up a list of all files in the project. // Basically, there does not need to be a local kdevlop generator at all, // it can just use the unix makefile one. Then in the global generators // Generate method you do something like this: // unsigned int i; // for(i = 0; i < m_LocalGenerators.size(); ++i) // { // // Get list of targets and sources from local generator i // // add them to a file map like you do now in the local generator // } // // now write out the Project.filelist file and Project.kdevlop files // It should most likely do the same thing as the visual studio generators and // write out all the sub-projects as well. And also honor the exclude from above // option. // I guess at the end of the day it should do something like this: // TopProject.kdevelop // TopProject.kdevelop.filelist // SubProject/SubProject.kdevelop // SubProject/SubProject.kdevelop.filelist // if SubProject was in a SUBDIR(EXCLUDE_FROM_ALL SubProject) // then its files should not be in TopProject.filelist. // If you look at these functions you can see how the visual studio // cmGlobalVisualStudio7Generator::Generate() // generate the project // void cmGlobalVisualStudio7Generator::CollectSubprojects() // create a map of project names to local // // generators // void cmGlobalVisualStudio7Generator::OutputSLNFile(cmLocalGenerator* root, // std::vector& generators) // // output a project for each project and sub project cmLocalKdevelopGenerator::cmLocalKdevelopGenerator() :cmLocalUnixMakefileGenerator() { } cmLocalKdevelopGenerator::~cmLocalKdevelopGenerator() { } void cmLocalKdevelopGenerator::Generate(bool fromTheTop) { cmLocalUnixMakefileGenerator::Generate(fromTheTop); if ( m_GlobalGenerator->GetCMakeInstance()->GetLocal() ) { return; } // Does this local generator contain a PROJECT command // if so, then generate a kdevelop project for it if (strcmp(m_Makefile->GetDefinition("PROJECT_BINARY_DIR"), m_Makefile->GetStartOutputDirectory())==0) { std::string outputDir=m_Makefile->GetStartOutputDirectory(); std::string projectDir=m_Makefile->GetHomeDirectory(); std::string projectName=m_Makefile->GetProjectName(); std::string cmakeFilePattern("CMakeLists.txt;*.cmake;"); if (!this->CreateFilelistFile(outputDir, projectDir, projectName, cmakeFilePattern)) { 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; cmTargets& targets=m_Makefile->GetTargets(); for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++) { if (ti->second.GetType()==cmTarget::EXECUTABLE) { executable=ti->first; break; } } this->CreateProjectFile(outputDir, projectDir, projectName, executable, cmakeFilePattern); } } /* create the project file, if it already exists, merge it with the existing one, otherwise create a new one */ void cmLocalKdevelopGenerator::CreateProjectFile(const std::string& outputDir, const std::string& projectDir, const std::string& projectname, const std::string& executable, const std::string& cmakeFilePattern) { std::string filename=outputDir+"/"; filename+=projectname+".kdevelop"; if (cmSystemTools::FileExists(filename.c_str())) { this->MergeProjectFiles(outputDir, projectDir, filename, executable, cmakeFilePattern); } else { this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern); } } void cmLocalKdevelopGenerator::MergeProjectFiles(const std::string& outputDir, const std::string& projectDir, const std::string& filename, const std::string& executable, const std::string& cmakeFilePattern) { std::ifstream oldProjectFile(filename.c_str()); if (!oldProjectFile) { this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern); 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 lines; while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp)) { lines.push_back(tmp); } oldProjectFile.close(); cmGeneratedFileStream fout(filename.c_str()); if(!fout) { return; } for (std::vector::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, "")!=0) || (strstr(line, "")!=0) || (strstr(line, "")!=0) || (strstr(line, "")!=0) || (strstr(line, "")!=0) || (strstr(line, "")!=0)) { continue; } // output the line from the file if it is not one of the above tags fout<<*it<<"\n"; // if this is the tag output the stuff that goes in the general tag if (strstr(line, "")) { fout<<" KDevCustomProject\n"; fout<<" "<\n"; //this one is important fout<<" true\n"; //and this one } // inside kdevcustomproject the must be put if (strstr(line, "")) { fout<<" "<\n"; } // buildtool and builddir go inside if (strstr(line, "")) { fout<<" make\n"; //this one is important fout<<" "<\n"; //and this one } } } void cmLocalKdevelopGenerator::CreateNewProjectFile(const std::string& outputDir, const std::string& projectDir, const std::string& filename, const std::string& executable, const std::string& cmakeFilePattern) { cmGeneratedFileStream fout(filename.c_str()); if(!fout) { return; } fout<<"\n"; fout<<"\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" $VERSION$\n"; fout<<" KDevCustomProject\n"; fout<<" C++\n"; fout<<" \n"; fout<<" "<\n"; //this one is important fout<<" true\n"; //and this one fout<<" \n"; fout<<" C\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" "<\n"; fout<<" \n"; fout<<" "<\n"; fout<<" custom\n"; fout<<" /\n"; fout<<" \n"; fout<<" false\n"; fout<<" true\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" make\n"; //this one is important fout<<" "<\n"; //and this one fout<<" \n"; fout<<" \n"; fout<<" false\n"; fout<<" 1\n"; fout<<" false\n"; fout<<" \n"; fout<<" default\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" html/\n"; fout<<" html/\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" .h\n"; fout<<" .cpp\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" true\n"; fout<<" true\n"; fout<<" true\n"; fout<<" false\n"; fout<<" true\n"; fout<<" true\n"; fout<<" true\n"; fout<<" 250\n"; fout<<" 400\n"; fout<<" 250\n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" \n"; fout<<" true\n"; fout<<" \n"; fout<<" \n"; fout<<" *.o,*.lo,CVS,*~,cmake*\n"; fout<<" true\n"; fout<<" \n"; fout<<" \n"; fout<<"\n"; } bool cmLocalKdevelopGenerator::CreateFilelistFile(const std::string& outputDir, const std::string& _projectDir, const std::string& projectname, std::string& cmakeFilePattern) { std::string projectDir=_projectDir+"/"; std::string filename=outputDir+"/"+projectname+".kdevelop.filelist"; std::set files; std::string tmp; // loop over all local generators in the entire project // This should be moved into the global generator // FIXME std::vector lgs; m_GlobalGenerator->GetLocalGenerators(lgs); for (std::vector::const_iterator it=lgs.begin(); it!=lgs.end(); it++) { cmMakefile* makefile=(*it)->GetMakefile(); // if the makefile GetStartOutputDirectory is not a substring of the outputDir // then skip it if (strstr(makefile->GetStartOutputDirectory(), outputDir.c_str())==0) { continue; } // This means the makefile is a sub-makefile of the current project //get all cmake files const std::vector& listFiles=makefile->GetListFiles(); for (std::vector::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]!='/') { 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::const_iterator ti = targets.begin(); ti != targets.end(); ti++) { const std::vector& sources=ti->second.GetSourceFiles(); for (std::vector::const_iterator si=sources.begin(); si!=sources.end(); si++) { tmp=(*si)->GetFullPath(); cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); if (tmp[0]!='/') { files.insert(tmp); } } for (std::vector::const_iterator lt=listFiles.begin(); lt!=listFiles.end(); lt++) { tmp=*lt; cmSystemTools::ReplaceString(tmp, projectDir.c_str(), ""); if (tmp[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 std::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; } for (std::set::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()); // 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; }