1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmExtraCodeBlocksGenerator.cxx,v $
6 Date: $Date: 2009-03-10 21:34:18 $
7 Version: $Revision: 1.22 $
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 "cmExtraCodeBlocksGenerator.h"
20 #include "cmGlobalUnixMakefileGenerator3.h"
21 #include "cmLocalUnixMakefileGenerator3.h"
22 #include "cmMakefile.h"
24 #include "cmSourceFile.h"
25 #include "cmGeneratedFileStream.h"
27 #include "cmSystemTools.h"
29 #include <cmsys/SystemTools.hxx>
33 http://www.codeblocks.org
36 http://wiki.codeblocks.org/index.php?title=File_formats_description
37 http://wiki.codeblocks.org/index.php?title=Workspace_file
38 http://wiki.codeblocks.org/index.php?title=Project_file
41 http://forums.codeblocks.org/index.php/topic,6789.0.html
44 //----------------------------------------------------------------------------
45 void cmExtraCodeBlocksGenerator
46 ::GetDocumentation(cmDocumentationEntry
& entry
, const char*) const
48 entry
.Name
= this->GetName();
49 entry
.Brief
= "Generates CodeBlocks project files.";
51 "Project files for CodeBlocks will be created in the top directory "
52 "and in every subdirectory which features a CMakeLists.txt file "
53 "containing a PROJECT() call. "
54 "Additionally a hierarchy of makefiles is generated into the "
55 "build tree. The appropriate make program can build the project through "
56 "the default make target. A \"make install\" target is also provided.";
59 cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator()
60 :cmExternalMakefileProjectGenerator()
63 this->SupportedGlobalGenerators
.push_back("MinGW Makefiles");
64 // disable until somebody actually tests it:
65 // this->SupportedGlobalGenerators.push_back("NMake Makefiles");
66 // this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
68 this->SupportedGlobalGenerators
.push_back("Unix Makefiles");
72 void cmExtraCodeBlocksGenerator::SetGlobalGenerator(
73 cmGlobalGenerator
* generator
)
75 cmExternalMakefileProjectGenerator::SetGlobalGenerator(generator
);
76 cmGlobalUnixMakefileGenerator3
* mf
= (cmGlobalUnixMakefileGenerator3
*)
78 mf
->SetToolSupportsColor(false);
79 mf
->SetForceVerboseMakefiles(true);
82 void cmExtraCodeBlocksGenerator::Generate()
84 // for each sub project in the project create a codeblocks project
85 for (std::map
<cmStdString
, std::vector
<cmLocalGenerator
*> >::const_iterator
86 it
= this->GlobalGenerator
->GetProjectMap().begin();
87 it
!= this->GlobalGenerator
->GetProjectMap().end();
90 // create a project file
91 this->CreateProjectFile(it
->second
);
96 /* create the project file */
97 void cmExtraCodeBlocksGenerator::CreateProjectFile(
98 const std::vector
<cmLocalGenerator
*>& lgs
)
100 const cmMakefile
* mf
=lgs
[0]->GetMakefile();
101 std::string outputDir
=mf
->GetStartOutputDirectory();
102 std::string projectName
=mf
->GetProjectName();
104 std::string filename
=outputDir
+"/";
105 filename
+=projectName
+".cbp";
106 std::string sessionFilename
=outputDir
+"/";
107 sessionFilename
+=projectName
+".layout";
109 this->CreateNewProjectFile(lgs
, filename
);
113 void cmExtraCodeBlocksGenerator
114 ::CreateNewProjectFile(const std::vector
<cmLocalGenerator
*>& lgs
,
115 const std::string
& filename
)
117 const cmMakefile
* mf
=lgs
[0]->GetMakefile();
118 cmGeneratedFileStream
fout(filename
.c_str());
124 // figure out the compiler
125 std::string compiler
= this->GetCBCompilerId(mf
);
126 std::string make
= mf
->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
128 fout
<<"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n"
129 "<CodeBlocks_project_file>\n"
130 " <FileVersion major=\"1\" minor=\"6\" />\n"
132 " <Option title=\"" << mf
->GetProjectName()<<"\" />\n"
133 " <Option makefile_is_custom=\"1\" />\n"
134 " <Option compiler=\"" << compiler
<< "\" />\n"
137 bool installTargetCreated
= false;
138 bool installStripTargetCreated
= false;
139 bool testTargetCreated
= false;
140 bool experimentalTargetCreated
= false;
141 bool nightlyTargetCreated
= false;
142 bool packageTargetCreated
= false;
143 bool packageSourceTargetCreated
= false;
144 bool rebuildCacheTargetCreated
= false;
146 this->AppendTarget(fout
, "all", 0, make
.c_str(), mf
, compiler
.c_str());
148 // add all executable and library targets and some of the GLOBAL
149 // and UTILITY targets
150 for (std::vector
<cmLocalGenerator
*>::const_iterator lg
=lgs
.begin();
153 cmMakefile
* makefile
=(*lg
)->GetMakefile();
154 cmTargets
& targets
=makefile
->GetTargets();
155 for (cmTargets::iterator ti
= targets
.begin();
156 ti
!= targets
.end(); ti
++)
158 switch(ti
->second
.GetType())
160 case cmTarget::UTILITY
:
161 case cmTarget::GLOBAL_TARGET
:
162 // only add these targets once
163 if ((ti
->first
=="install") && (installTargetCreated
==false))
165 installTargetCreated
=true;
167 else if ((ti
->first
=="install/strip")
168 && (installStripTargetCreated
==false))
170 installStripTargetCreated
=true;
172 else if ((ti
->first
=="test") && (testTargetCreated
==false))
174 testTargetCreated
=true;
176 else if ((ti
->first
=="Experimental")
177 && (experimentalTargetCreated
==false))
179 experimentalTargetCreated
=true;
181 else if ((ti
->first
=="Nightly") && (nightlyTargetCreated
==false))
183 nightlyTargetCreated
=true;
185 else if ((ti
->first
=="package") && (packageTargetCreated
==false))
187 packageTargetCreated
=true;
189 else if ((ti
->first
=="package_source")
190 && (packageSourceTargetCreated
==false))
192 packageSourceTargetCreated
=true;
194 else if ((ti
->first
=="rebuild_cache")
195 && (rebuildCacheTargetCreated
==false))
197 rebuildCacheTargetCreated
=true;
203 this->AppendTarget(fout
, ti
->first
.c_str(), 0,
204 make
.c_str(), makefile
, compiler
.c_str());
206 case cmTarget::EXECUTABLE
:
207 case cmTarget::STATIC_LIBRARY
:
208 case cmTarget::SHARED_LIBRARY
:
209 case cmTarget::MODULE_LIBRARY
:
211 this->AppendTarget(fout
, ti
->first
.c_str(), &ti
->second
,
212 make
.c_str(), makefile
, compiler
.c_str());
213 std::string fastTarget
= ti
->first
;
214 fastTarget
+= "/fast";
215 this->AppendTarget(fout
, fastTarget
.c_str(), &ti
->second
,
216 make
.c_str(), makefile
, compiler
.c_str());
220 case cmTarget::INSTALL_FILES
:
221 case cmTarget::INSTALL_PROGRAMS
:
222 case cmTarget::INSTALL_DIRECTORY
:
232 // Collect all used source files in the project
233 // Sort them into two containers, one for C/C++ implementation files
234 // which may have an acompanying header, one for all other files
235 std::map
<std::string
, cmSourceFile
*> cFiles
;
236 std::set
<std::string
> otherFiles
;
237 for (std::vector
<cmLocalGenerator
*>::const_iterator lg
=lgs
.begin();
240 cmMakefile
* makefile
=(*lg
)->GetMakefile();
241 cmTargets
& targets
=makefile
->GetTargets();
242 for (cmTargets::iterator ti
= targets
.begin();
243 ti
!= targets
.end(); ti
++)
245 switch(ti
->second
.GetType())
247 case cmTarget::EXECUTABLE
:
248 case cmTarget::STATIC_LIBRARY
:
249 case cmTarget::SHARED_LIBRARY
:
250 case cmTarget::MODULE_LIBRARY
:
252 const std::vector
<cmSourceFile
*>&sources
=ti
->second
.GetSourceFiles();
253 for (std::vector
<cmSourceFile
*>::const_iterator si
=sources
.begin();
254 si
!=sources
.end(); si
++)
256 // check whether it is a C/C++ implementation file
257 bool isCFile
= false;
258 if ((*si
)->GetLanguage() && (*(*si
)->GetLanguage() == 'C'))
260 for(std::vector
<std::string
>::const_iterator
261 ext
= mf
->GetSourceExtensions().begin();
262 ext
!= mf
->GetSourceExtensions().end();
265 if ((*si
)->GetExtension() == *ext
)
273 // then put it accordingly into one of the two containers
276 cFiles
[(*si
)->GetFullPath()] = *si
;
280 otherFiles
.insert((*si
)->GetFullPath());
284 default: // intended fallthrough
290 // The following loop tries to add header files matching to implementation
291 // files to the project. It does that by iterating over all source files,
292 // replacing the file name extension with ".h" and checks whether such a
293 // file exists. If it does, it is inserted into the map of files.
294 // A very similar version of that code exists also in the kdevelop
295 // project generator.
296 for (std::map
<std::string
, cmSourceFile
*>::const_iterator
301 std::string headerBasename
=cmSystemTools::GetFilenamePath(sit
->first
);
303 headerBasename
+=cmSystemTools::GetFilenameWithoutExtension(sit
->first
);
305 // check if there's a matching header around
306 for(std::vector
<std::string
>::const_iterator
307 ext
= mf
->GetHeaderExtensions().begin();
308 ext
!= mf
->GetHeaderExtensions().end();
311 std::string hname
=headerBasename
;
314 // if it's already in the set, don't check if it exists on disk
315 std::set
<std::string
>::const_iterator headerIt
=otherFiles
.find(hname
);
316 if (headerIt
!= otherFiles
.end())
321 if(cmSystemTools::FileExists(hname
.c_str()))
323 otherFiles
.insert(hname
);
329 // insert all source files in the CodeBlocks project
330 // first the C/C++ implementation files, then all others
331 for (std::map
<std::string
, cmSourceFile
*>::const_iterator
336 fout
<<" <Unit filename=\""<< sit
->first
<<"\">\n"
339 for (std::set
<std::string
>::const_iterator
340 sit
=otherFiles
.begin();
341 sit
!=otherFiles
.end();
344 fout
<<" <Unit filename=\""<< sit
->c_str() <<"\">\n"
348 fout
<<" </Project>\n"
349 "</CodeBlocks_project_file>\n";
353 // Generate the xml code for one target.
354 void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream
& fout
,
355 const char* targetName
,
358 const cmMakefile
* makefile
,
359 const char* compiler
)
361 std::string makefileName
= makefile
->GetStartOutputDirectory();
362 makefileName
+= "/Makefile";
363 makefileName
= cmSystemTools::ConvertToOutputPath(makefileName
.c_str());
365 fout
<<" <Target title=\"" << targetName
<< "\">\n";
368 int cbTargetType
= this->GetCBTargetType(target
);
369 fout
<<" <Option output=\"" << target
->GetLocation(0)
370 << "\" prefix_auto=\"0\" extension_auto=\"0\" />\n"
371 " <Option working_dir=\""
372 << makefile
->GetStartOutputDirectory() << "\" />\n"
373 " <Option object_output=\"./\" />\n"
374 " <Option type=\"" << cbTargetType
<< "\" />\n"
375 " <Option compiler=\"" << compiler
<< "\" />\n"
377 // the include directories for this target
378 const std::vector
<std::string
>& incDirs
=
379 target
->GetMakefile()->GetIncludeDirectories();
380 for(std::vector
<std::string
>::const_iterator dirIt
=incDirs
.begin();
381 dirIt
!= incDirs
.end();
384 fout
<<" <Add directory=\"" << dirIt
->c_str() << "\" />\n";
386 fout
<<" </Compiler>\n";
388 else // e.g. all and the GLOBAL and UTILITY targets
390 fout
<<" <Option working_dir=\""
391 << makefile
->GetStartOutputDirectory() << "\" />\n"
392 <<" <Option type=\"" << 4 << "\" />\n";
395 fout
<<" <MakeCommands>\n"
397 << this->BuildMakeCommand(make
, makefileName
.c_str(), targetName
)
399 " <CompileFile command=\""
400 << this->BuildMakeCommand(make
, makefileName
.c_str(),""$file"")
403 << this->BuildMakeCommand(make
, makefileName
.c_str(), "clean")
405 " <DistClean command=\""
406 << this->BuildMakeCommand(make
, makefileName
.c_str(), "clean")
414 // Translate the cmake compiler id into the CodeBlocks compiler id
415 std::string
cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile
* mf
)
417 // figure out which language to use
418 // for now care only for C and C++
419 std::string compilerIdVar
= "CMAKE_CXX_COMPILER_ID";
420 if (this->GlobalGenerator
->GetLanguageEnabled("CXX") == false)
422 compilerIdVar
= "CMAKE_C_COMPILER_ID";
425 std::string hostSystemName
= mf
->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME");
426 std::string systemName
= mf
->GetSafeDefinition("CMAKE_SYSTEM_NAME");
427 std::string compilerId
= mf
->GetRequiredDefinition(compilerIdVar
.c_str());
428 std::string compiler
= "gcc";
429 if (compilerId
== "MSVC")
433 else if (compilerId
== "Borland")
437 else if (compilerId
== "SDCC")
441 else if (compilerId
== "Intel")
445 else if (compilerId
== "Watcom")
449 else if (compilerId
== "GNU")
457 // Translate the cmake target type into the CodeBlocks target type id
458 int cmExtraCodeBlocksGenerator::GetCBTargetType(cmTarget
* target
)
460 if ( target
->GetType()==cmTarget::EXECUTABLE
)
462 if ((target
->GetPropertyAsBool("WIN32_EXECUTABLE"))
463 || (target
->GetPropertyAsBool("MACOSX_BUNDLE")))
472 else if ( target
->GetType()==cmTarget::STATIC_LIBRARY
)
476 else if ((target
->GetType()==cmTarget::SHARED_LIBRARY
)
477 || (target
->GetType()==cmTarget::MODULE_LIBRARY
))
484 // Create the command line for building the given target using the selected
486 std::string
cmExtraCodeBlocksGenerator::BuildMakeCommand(
487 const std::string
& make
, const char* makefile
, const char* target
)
489 std::string command
= make
;
490 if (strcmp(this->GlobalGenerator
->GetName(), "NMake Makefiles")==0)
492 command
+= " /NOLOGO /f "";
494 command
+= "" ";
497 else if (strcmp(this->GlobalGenerator
->GetName(), "MinGW Makefiles")==0)
506 command
+= " -f "";
508 command
+= "" ";