cmExtraCodeLiteGenerator.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2004-2009 Kitware, Inc.
  4. Copyright 2004 Alexander Neundorf ([email protected])
  5. Copyright 2013 Eran Ifrah ([email protected])
  6. Distributed under the OSI-approved BSD License (the "License");
  7. see accompanying file Copyright.txt for details.
  8. This software is distributed WITHOUT ANY WARRANTY; without even the
  9. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the License for more information.
  11. ============================================================================*/
  12. #include "cmExtraCodeLiteGenerator.h"
  13. #include "cmGlobalUnixMakefileGenerator3.h"
  14. #include "cmLocalUnixMakefileGenerator3.h"
  15. #include "cmMakefile.h"
  16. #include "cmake.h"
  17. #include "cmSourceFile.h"
  18. #include "cmGeneratedFileStream.h"
  19. #include "cmSystemTools.h"
  20. #include <cmsys/SystemTools.hxx>
  21. #include <cmsys/SystemInformation.hxx>
  22. #include <cmsys/Directory.hxx>
  23. #include "cmXMLSafe.h"
  24. #include <sstream>
  25. //----------------------------------------------------------------------------
  26. void cmExtraCodeLiteGenerator::GetDocumentation(cmDocumentationEntry& entry,
  27. const std::string&) const
  28. {
  29. entry.Name = this->GetName();
  30. entry.Brief = "Generates CodeLite project files.";
  31. }
  32. cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator()
  33. : cmExternalMakefileProjectGenerator()
  34. , ConfigName("NoConfig")
  35. , CpuCount(2)
  36. {
  37. #if defined(_WIN32)
  38. this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
  39. this->SupportedGlobalGenerators.push_back("NMake Makefiles");
  40. #endif
  41. this->SupportedGlobalGenerators.push_back("Ninja");
  42. this->SupportedGlobalGenerators.push_back("Unix Makefiles");
  43. }
  44. void cmExtraCodeLiteGenerator::Generate()
  45. {
  46. // Hold root tree information for creating the workspace
  47. std::string workspaceProjectName;
  48. std::string workspaceOutputDir;
  49. std::string workspaceFileName;
  50. std::string workspaceSourcePath;
  51. std::string lprjdebug;
  52. cmGeneratedFileStream fout;
  53. // loop projects and locate the root project.
  54. // and extract the information for creating the worspace
  55. for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
  56. it = this->GlobalGenerator->GetProjectMap().begin();
  57. it!= this->GlobalGenerator->GetProjectMap().end();
  58. ++it)
  59. {
  60. const cmMakefile* mf =it->second[0]->GetMakefile();
  61. this->ConfigName = GetConfigurationName( mf );
  62. if (strcmp(mf->GetStartOutputDirectory(),
  63. mf->GetHomeOutputDirectory()) == 0)
  64. {
  65. workspaceOutputDir = mf->GetStartOutputDirectory();
  66. workspaceProjectName = mf->GetProjectName();
  67. workspaceSourcePath = mf->GetHomeDirectory();
  68. workspaceFileName = workspaceOutputDir+"/";
  69. workspaceFileName += workspaceProjectName + ".workspace";
  70. this->WorkspacePath = mf->GetStartOutputDirectory();;
  71. fout.Open(workspaceFileName.c_str(), false, false);
  72. fout << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  73. "<CodeLite_Workspace Name=\"" << workspaceProjectName << "\" >\n";
  74. }
  75. }
  76. // for each sub project in the workspace create a codelite project
  77. for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
  78. it = this->GlobalGenerator->GetProjectMap().begin();
  79. it!= this->GlobalGenerator->GetProjectMap().end();
  80. ++it)
  81. {
  82. // retrive project information
  83. const cmMakefile* mf = it->second[0]->GetMakefile();
  84. std::string outputDir = mf->GetStartOutputDirectory();
  85. std::string projectName = mf->GetProjectName();
  86. std::string filename = outputDir + "/" + projectName + ".project";
  87. // Make the project file relative to the workspace
  88. filename = cmSystemTools::RelativePath(this->WorkspacePath.c_str(),
  89. filename.c_str());
  90. // create a project file
  91. this->CreateProjectFile(it->second);
  92. fout << " <Project Name=\"" << projectName << "\" Path=\""
  93. << filename << "\" Active=\"No\"/>\n";
  94. lprjdebug += "<Project Name=\"" + projectName
  95. + "\" ConfigName=\"" + this->ConfigName + "\"/>\n";
  96. }
  97. fout << " <BuildMatrix>\n"
  98. " <WorkspaceConfiguration Name=\""
  99. << this->ConfigName << "\" Selected=\"yes\">\n"
  100. " " << lprjdebug << ""
  101. " </WorkspaceConfiguration>\n"
  102. " </BuildMatrix>\n"
  103. "</CodeLite_Workspace>\n";
  104. }
  105. /* create the project file */
  106. void cmExtraCodeLiteGenerator::CreateProjectFile(
  107. const std::vector<cmLocalGenerator*>& lgs)
  108. {
  109. const cmMakefile* mf = lgs[0]->GetMakefile();
  110. std::string outputDir = mf->GetStartOutputDirectory();
  111. std::string projectName = mf->GetProjectName();
  112. std::string filename = outputDir + "/";
  113. filename += projectName + ".project";
  114. this->CreateNewProjectFile(lgs, filename);
  115. }
  116. void cmExtraCodeLiteGenerator
  117. ::CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
  118. const std::string& filename)
  119. {
  120. const cmMakefile* mf=lgs[0]->GetMakefile();
  121. cmGeneratedFileStream fout(filename.c_str());
  122. if(!fout)
  123. {
  124. return;
  125. }
  126. // figure out the compiler
  127. //std::string compiler = this->GetCBCompilerId(mf);
  128. std::string workspaceSourcePath = mf->GetHomeDirectory();
  129. std::string workspaceOutputDir = mf->GetHomeOutputDirectory();
  130. std::vector<std::string> outputFiles = mf->GetOutputFiles();
  131. std::string projectName = mf->GetProjectName();
  132. std::string incDirs;
  133. std::vector<cmValueWithOrigin> incDirsVec =
  134. mf->GetIncludeDirectoriesEntries();
  135. std::vector<cmValueWithOrigin>::const_iterator iterInc = incDirsVec.begin();
  136. //std::cout << "GetIncludeDirectories:" << std::endl;
  137. for(; iterInc != incDirsVec.end(); ++iterInc )
  138. {
  139. //std::cout << (*ItStrVec) << std::endl;
  140. incDirs += iterInc->Value + " ";
  141. }
  142. ////////////////////////////////////
  143. fout << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  144. "<CodeLite_Project Name=\"" << mf->GetProjectName()
  145. << "\" InternalType=\"\">\n";
  146. // Collect all used source files in the project
  147. // Sort them into two containers, one for C/C++ implementation files
  148. // which may have an acompanying header, one for all other files
  149. std::string projectType;
  150. std::map<std::string, cmSourceFile*> cFiles;
  151. std::set<std::string> otherFiles;
  152. for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin();
  153. lg!=lgs.end(); lg++)
  154. {
  155. cmMakefile* makefile=(*lg)->GetMakefile();
  156. cmTargets& targets=makefile->GetTargets();
  157. for (cmTargets::iterator ti = targets.begin();
  158. ti != targets.end(); ti++)
  159. {
  160. switch(ti->second.GetType())
  161. {
  162. case cmTarget::EXECUTABLE:
  163. {
  164. projectType = "Executable";
  165. }
  166. break;
  167. case cmTarget::STATIC_LIBRARY:
  168. {
  169. projectType = "Static Library";
  170. }
  171. break;
  172. case cmTarget::SHARED_LIBRARY:
  173. {
  174. projectType = "Dynamic Library";
  175. }
  176. break;
  177. case cmTarget::MODULE_LIBRARY:
  178. {
  179. projectType = "Dynamic Library";
  180. }
  181. break;
  182. default: // intended fallthrough
  183. break;
  184. }
  185. switch(ti->second.GetType())
  186. {
  187. case cmTarget::EXECUTABLE:
  188. case cmTarget::STATIC_LIBRARY:
  189. case cmTarget::SHARED_LIBRARY:
  190. case cmTarget::MODULE_LIBRARY:
  191. {
  192. std::vector<cmSourceFile*> sources;
  193. ti->second.GetSourceFiles(sources);
  194. for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
  195. si!=sources.end(); si++)
  196. {
  197. // check whether it is a C/C++ implementation file
  198. bool isCFile = false;
  199. std::string lang = (*si)->GetLanguage();
  200. if (lang == "C" || lang == "CXX")
  201. {
  202. std::string srcext = (*si)->GetExtension();
  203. for(std::vector<std::string>::const_iterator
  204. ext = mf->GetSourceExtensions().begin();
  205. ext != mf->GetSourceExtensions().end();
  206. ++ext)
  207. {
  208. if (srcext == *ext)
  209. {
  210. isCFile = true;
  211. break;
  212. }
  213. }
  214. }
  215. // then put it accordingly into one of the two containers
  216. if (isCFile)
  217. {
  218. cFiles[(*si)->GetFullPath()] = *si ;
  219. }
  220. else
  221. {
  222. otherFiles.insert((*si)->GetFullPath());
  223. }
  224. }
  225. }
  226. default: // intended fallthrough
  227. break;
  228. }
  229. }
  230. }
  231. // The following loop tries to add header files matching to implementation
  232. // files to the project. It does that by iterating over all source files,
  233. // replacing the file name extension with ".h" and checks whether such a
  234. // file exists. If it does, it is inserted into the map of files.
  235. // A very similar version of that code exists also in the kdevelop
  236. // project generator.
  237. for (std::map<std::string, cmSourceFile*>::const_iterator
  238. sit=cFiles.begin();
  239. sit!=cFiles.end();
  240. ++sit)
  241. {
  242. std::string headerBasename=cmSystemTools::GetFilenamePath(sit->first);
  243. headerBasename+="/";
  244. headerBasename+=cmSystemTools::GetFilenameWithoutExtension(sit->first);
  245. // check if there's a matching header around
  246. for(std::vector<std::string>::const_iterator
  247. ext = mf->GetHeaderExtensions().begin();
  248. ext != mf->GetHeaderExtensions().end();
  249. ++ext)
  250. {
  251. std::string hname=headerBasename;
  252. hname += ".";
  253. hname += *ext;
  254. // if it's already in the set, don't check if it exists on disk
  255. std::set<std::string>::const_iterator headerIt=otherFiles.find(hname);
  256. if (headerIt != otherFiles.end())
  257. {
  258. break;
  259. }
  260. if(cmSystemTools::FileExists(hname.c_str()))
  261. {
  262. otherFiles.insert(hname);
  263. break;
  264. }
  265. }
  266. }
  267. // Get the project path ( we need it later to convert files to
  268. // their relative path)
  269. std::string projectPath = cmSystemTools::GetFilenamePath(filename);
  270. // Create 2 virtual folders: src and include
  271. // and place all the implementation files into the src
  272. // folder, the rest goes to the include folder
  273. fout<< " <VirtualDirectory Name=\"src\">\n";
  274. // insert all source files in the codelite project
  275. // first the C/C++ implementation files, then all others
  276. for (std::map<std::string, cmSourceFile*>::const_iterator
  277. sit=cFiles.begin();
  278. sit!=cFiles.end();
  279. ++sit)
  280. {
  281. std::string relativePath =
  282. cmSystemTools::RelativePath(projectPath.c_str(), sit->first.c_str());
  283. fout<< " <File Name=\"" << relativePath.c_str() << "\"/>\n";
  284. }
  285. fout<< " </VirtualDirectory>\n";
  286. fout<< " <VirtualDirectory Name=\"include\">\n";
  287. for (std::set<std::string>::const_iterator
  288. sit=otherFiles.begin();
  289. sit!=otherFiles.end();
  290. ++sit)
  291. {
  292. std::string relativePath =
  293. cmSystemTools::RelativePath(projectPath.c_str(), sit->c_str());
  294. fout << " <File Name=\"" << relativePath.c_str() << "\"/>\n";
  295. }
  296. fout << " </VirtualDirectory>\n";
  297. // Get the number of CPUs. We use this information for the make -jN
  298. // command
  299. cmsys::SystemInformation info;
  300. info.RunCPUCheck();
  301. this->CpuCount = info.GetNumberOfLogicalCPU() *
  302. info.GetNumberOfPhysicalCPU();
  303. std::string cleanCommand = GetCleanCommand(mf);
  304. std::string buildCommand = GetBuildCommand(mf);
  305. std::string rebuildCommand = GetRebuildCommand(mf);
  306. std::string singleFileCommand = GetSingleFileBuildCommand(mf);
  307. std::string codeliteCompilerName = this->GetCodeLiteCompilerName(mf);
  308. fout << "\n"
  309. " <Settings Type=\"" << projectType << "\">\n"
  310. " <Configuration Name=\"" << this->ConfigName << "\" CompilerType=\""
  311. << codeliteCompilerName << "\" DebuggerType=\"GNU gdb debugger\" "
  312. "Type=\""
  313. << projectType << "\" BuildCmpWithGlobalSettings=\"append\" "
  314. "BuildLnkWithGlobalSettings=\"append\" "
  315. "BuildResWithGlobalSettings=\"append\">\n"
  316. " <Compiler Options=\"-g\" "
  317. "Required=\"yes\" PreCompiledHeader=\"\">\n"
  318. " <IncludePath Value=\".\"/>\n"
  319. " </Compiler>\n"
  320. " <Linker Options=\"\" Required=\"yes\"/>\n"
  321. " <ResourceCompiler Options=\"\" Required=\"no\"/>\n"
  322. " <General OutputFile=\"$(IntermediateDirectory)/$(ProjectName)\" "
  323. "IntermediateDirectory=\"./\" Command=\"./$(ProjectName)\" "
  324. "CommandArguments=\"\" WorkingDirectory=\"$(IntermediateDirectory)\" "
  325. "PauseExecWhenProcTerminates=\"yes\"/>\n"
  326. " <Debugger IsRemote=\"no\" RemoteHostName=\"\" "
  327. "RemoteHostPort=\"\" DebuggerPath=\"\">\n"
  328. " <PostConnectCommands/>\n"
  329. " <StartupCommands/>\n"
  330. " </Debugger>\n"
  331. " <PreBuild/>\n"
  332. " <PostBuild/>\n"
  333. " <CustomBuild Enabled=\"yes\">\n"
  334. " <RebuildCommand>" << rebuildCommand << "</RebuildCommand>\n"
  335. " <CleanCommand>" << cleanCommand << "</CleanCommand>\n"
  336. " <BuildCommand>" << buildCommand << "</BuildCommand>\n"
  337. " <SingleFileCommand>" << singleFileCommand
  338. << "</SingleFileCommand>\n"
  339. " <PreprocessFileCommand/>\n"
  340. " <WorkingDirectory>$(WorkspacePath)</WorkingDirectory>\n"
  341. " </CustomBuild>\n"
  342. " <AdditionalRules>\n"
  343. " <CustomPostBuild/>\n"
  344. " <CustomPreBuild/>\n"
  345. " </AdditionalRules>\n"
  346. " </Configuration>\n"
  347. " <GlobalSettings>\n"
  348. " <Compiler Options=\"\">\n"
  349. " <IncludePath Value=\".\"/>\n"
  350. " </Compiler>\n"
  351. " <Linker Options=\"\">\n"
  352. " <LibraryPath Value=\".\"/>\n"
  353. " </Linker>\n"
  354. " <ResourceCompiler Options=\"\"/>\n"
  355. " </GlobalSettings>\n"
  356. " </Settings>\n"
  357. "</CodeLite_Project>\n";
  358. }
  359. std::string
  360. cmExtraCodeLiteGenerator::GetCodeLiteCompilerName(const cmMakefile* mf) const
  361. {
  362. // figure out which language to use
  363. // for now care only for C and C++
  364. std::string compilerIdVar = "CMAKE_CXX_COMPILER_ID";
  365. if (this->GlobalGenerator->GetLanguageEnabled("CXX") == false)
  366. {
  367. compilerIdVar = "CMAKE_C_COMPILER_ID";
  368. }
  369. std::string compilerId = mf->GetSafeDefinition(compilerIdVar);
  370. std::string compiler = "gnu g++"; // default to g++
  371. // Since we need the compiler for parsing purposes only
  372. // it does not matter if we use clang or clang++, same as
  373. // "gnu gcc" vs "gnu g++"
  374. if (compilerId == "MSVC")
  375. {
  376. compiler = "VC++";
  377. }
  378. else if (compilerId == "Clang")
  379. {
  380. compiler = "clang++";
  381. }
  382. else if (compilerId == "GNU")
  383. {
  384. compiler = "gnu g++";
  385. }
  386. return compiler;
  387. }
  388. std::string
  389. cmExtraCodeLiteGenerator::GetConfigurationName(const cmMakefile* mf) const
  390. {
  391. std::string confName = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
  392. // Trim the configuration name from whitespaces (left and right)
  393. confName.erase(0, confName.find_first_not_of(" \t\r\v\n"));
  394. confName.erase(confName.find_last_not_of(" \t\r\v\n")+1);
  395. if ( confName.empty() )
  396. {
  397. confName = "NoConfig";
  398. }
  399. return confName;
  400. }
  401. std::string
  402. cmExtraCodeLiteGenerator::GetBuildCommand(const cmMakefile* mf) const
  403. {
  404. std::stringstream ss;
  405. std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
  406. std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
  407. std::string buildCommand = make; // Default
  408. if ( generator == "NMake Makefiles" )
  409. {
  410. buildCommand = make;
  411. }
  412. else if ( generator == "MinGW Makefiles" ||
  413. generator == "Unix Makefiles" )
  414. {
  415. ss << make << " -j " << this->CpuCount;
  416. buildCommand = ss.str();
  417. }
  418. else if ( generator == "Ninja" )
  419. {
  420. ss << make;
  421. buildCommand = ss.str();
  422. }
  423. return buildCommand;
  424. }
  425. std::string
  426. cmExtraCodeLiteGenerator::GetCleanCommand(const cmMakefile* mf) const
  427. {
  428. return GetBuildCommand(mf) + " clean";
  429. }
  430. std::string
  431. cmExtraCodeLiteGenerator::GetRebuildCommand(const cmMakefile* mf) const
  432. {
  433. return GetCleanCommand(mf) + cmXMLSafe(" && ").str() + GetBuildCommand(mf);
  434. }
  435. std::string
  436. cmExtraCodeLiteGenerator::GetSingleFileBuildCommand
  437. (const cmMakefile* mf) const
  438. {
  439. std::string buildCommand;
  440. std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
  441. std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
  442. if ( generator == "Unix Makefiles" || generator == "MinGW Makefiles" )
  443. {
  444. std::stringstream ss;
  445. ss << make << " -f$(ProjectPath)/Makefile $(CurrentFileName).cpp.o";
  446. buildCommand = ss.str();
  447. }
  448. return buildCommand;
  449. }