/*========================================================================= 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 "cmExtraCodeBlocksGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLocalUnixMakefileGenerator3.h" #include "cmMakefile.h" #include "cmake.h" #include "cmSourceFile.h" #include "cmGeneratedFileStream.h" #include "cmTarget.h" #include "cmSystemTools.h" #include <cmsys/SystemTools.hxx> /* Some useful URLs: Homepage: http://www.codeblocks.org File format docs: http://wiki.codeblocks.org/index.php?title=File_formats_description http://wiki.codeblocks.org/index.php?title=Workspace_file http://wiki.codeblocks.org/index.php?title=Project_file Discussion: http://forums.codeblocks.org/index.php/topic,6789.0.html */ //---------------------------------------------------------------------------- void cmExtraCodeBlocksGenerator ::GetDocumentation(cmDocumentationEntry& entry, const char*) const { entry.Name = this->GetName(); entry.Brief = "Generates CodeBlocks project files."; entry.Full = "Project files for CodeBlocks will be created in the top directory " "and in every subdirectory which features a CMakeLists.txt file " "containing a PROJECT() call. " "Additionally a hierarchy of makefiles is generated into the " "build tree. The appropriate make program can build the project through " "the default make target. A \"make install\" target is also provided."; } cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() :cmExternalMakefileProjectGenerator() { #if defined(_WIN32) this->SupportedGlobalGenerators.push_back("MinGW Makefiles"); // disable until somebody actually tests it: // this->SupportedGlobalGenerators.push_back("NMake Makefiles"); // this->SupportedGlobalGenerators.push_back("MSYS Makefiles"); #endif this->SupportedGlobalGenerators.push_back("Unix Makefiles"); } void cmExtraCodeBlocksGenerator::SetGlobalGenerator( cmGlobalGenerator* generator) { cmExternalMakefileProjectGenerator::SetGlobalGenerator(generator); cmGlobalUnixMakefileGenerator3* mf = (cmGlobalUnixMakefileGenerator3*) generator; mf->SetToolSupportsColor(false); mf->SetForceVerboseMakefiles(true); } void cmExtraCodeBlocksGenerator::Generate() { // for each sub project in the project create a codeblocks project for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator it = this->GlobalGenerator->GetProjectMap().begin(); it!= this->GlobalGenerator->GetProjectMap().end(); ++it) { // create a project file this->CreateProjectFile(it->second); } } /* create the project file, if it already exists, merge it with the existing one, otherwise create a new one */ void cmExtraCodeBlocksGenerator::CreateProjectFile( const std::vector<cmLocalGenerator*>& lgs) { const cmMakefile* mf=lgs[0]->GetMakefile(); std::string outputDir=mf->GetStartOutputDirectory(); std::string projectDir=mf->GetHomeDirectory(); std::string projectName=mf->GetProjectName(); std::string filename=outputDir+"/"; filename+=projectName+".cbp"; std::string sessionFilename=outputDir+"/"; sessionFilename+=projectName+".layout"; /* if (cmSystemTools::FileExists(filename.c_str())) { this->MergeProjectFiles(outputDir, projectDir, filename, cmakeFilePattern, sessionFilename); } else */ { this->CreateNewProjectFile(lgs, filename); } } void cmExtraCodeBlocksGenerator ::CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs, const std::string& filename) { const cmMakefile* mf=lgs[0]->GetMakefile(); cmGeneratedFileStream fout(filename.c_str()); if(!fout) { return; } // figure out the compiler std::string compiler = this->GetCBCompilerId(mf); std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); fout<<"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n" "<CodeBlocks_project_file>\n" " <FileVersion major=\"1\" minor=\"6\" />\n" " <Project>\n" " <Option title=\"" << mf->GetProjectName()<<"\" />\n" " <Option makefile_is_custom=\"1\" />\n" " <Option compiler=\"" << compiler << "\" />\n" " <Build>\n"; bool installTargetCreated = false; bool installStripTargetCreated = false; bool testTargetCreated = false; bool experimentalTargetCreated = false; bool nightlyTargetCreated = false; bool packageTargetCreated = false; bool packageSourceTargetCreated = false; bool rebuildCacheTargetCreated = false; this->AppendTarget(fout, "all", 0, make.c_str(), mf, compiler.c_str()); // add all executable and library targets and some of the GLOBAL // and UTILITY targets for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin(); lg!=lgs.end(); lg++) { cmMakefile* makefile=(*lg)->GetMakefile(); cmTargets& targets=makefile->GetTargets(); for (cmTargets::iterator ti = targets.begin(); ti != targets.end(); ti++) { switch(ti->second.GetType()) { case cmTarget::UTILITY: case cmTarget::GLOBAL_TARGET: // only add these targets once if ((ti->first=="install") && (installTargetCreated==false)) { installTargetCreated=true; } else if ((ti->first=="install/strip") && (installStripTargetCreated==false)) { installStripTargetCreated=true; } else if ((ti->first=="test") && (testTargetCreated==false)) { testTargetCreated=true; } else if ((ti->first=="Experimental") && (experimentalTargetCreated==false)) { experimentalTargetCreated=true; } else if ((ti->first=="Nightly") && (nightlyTargetCreated==false)) { nightlyTargetCreated=true; } else if ((ti->first=="package") && (packageTargetCreated==false)) { packageTargetCreated=true; } else if ((ti->first=="package_source") && (packageSourceTargetCreated==false)) { packageSourceTargetCreated=true; } else if ((ti->first=="rebuild_cache") && (rebuildCacheTargetCreated==false)) { rebuildCacheTargetCreated=true; } else { break; } this->AppendTarget(fout, ti->first.c_str(), 0, make.c_str(), makefile, compiler.c_str()); break; case cmTarget::EXECUTABLE: case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: { this->AppendTarget(fout, ti->first.c_str(), &ti->second, make.c_str(), makefile, compiler.c_str()); std::string fastTarget = ti->first; fastTarget += "/fast"; this->AppendTarget(fout, fastTarget.c_str(), &ti->second, make.c_str(), makefile, compiler.c_str()); } break; // ignore these: case cmTarget::INSTALL_FILES: case cmTarget::INSTALL_PROGRAMS: case cmTarget::INSTALL_DIRECTORY: default: break; } } } fout<<" </Build>\n"; // Collect all used source files in the project std::map<std::string, std::string> sourceFiles; for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin(); lg!=lgs.end(); lg++) { cmMakefile* makefile=(*lg)->GetMakefile(); cmTargets& targets=makefile->GetTargets(); for (cmTargets::iterator ti = targets.begin(); ti != targets.end(); ti++) { switch(ti->second.GetType()) { case cmTarget::EXECUTABLE: case cmTarget::STATIC_LIBRARY: case cmTarget::SHARED_LIBRARY: case cmTarget::MODULE_LIBRARY: { const std::vector<cmSourceFile*>&sources=ti->second.GetSourceFiles(); for (std::vector<cmSourceFile*>::const_iterator si=sources.begin(); si!=sources.end(); si++) { sourceFiles[(*si)->GetFullPath()] = ti->first; } } default: // intended fallthrough break; } } } // insert all used source files in the CodeBlocks project for (std::map<std::string, std::string>::const_iterator sit=sourceFiles.begin(); sit!=sourceFiles.end(); ++sit) { fout<<" <Unit filename=\""<<sit->first <<"\">\n" " </Unit>\n"; } fout<<" </Project>\n" "</CodeBlocks_project_file>\n"; } // Generate the xml code for one target. void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, const char* targetName, cmTarget* target, const char* make, const cmMakefile* makefile, const char* compiler) { std::string makefileName = makefile->GetStartOutputDirectory(); makefileName += "/Makefile"; makefileName = cmSystemTools::ConvertToOutputPath(makefileName.c_str()); fout<<" <Target title=\"" << targetName << "\">\n"; if (target!=0) { int cbTargetType = this->GetCBTargetType(target); fout<<" <Option output=\"" << target->GetLocation(0) << "\" prefix_auto=\"0\" extension_auto=\"0\" />\n" " <Option working_dir=\"" << makefile->GetStartOutputDirectory() << "\" />\n" " <Option object_output=\"./\" />\n" " <Option type=\"" << cbTargetType << "\" />\n" " <Option compiler=\"" << compiler << "\" />\n" " <Compiler>\n"; // the include directories for this target const std::vector<std::string>& incDirs = target->GetMakefile()->GetIncludeDirectories(); for(std::vector<std::string>::const_iterator dirIt=incDirs.begin(); dirIt != incDirs.end(); ++dirIt) { fout <<" <Add directory=\"" << dirIt->c_str() << "\" />\n"; } fout<<" </Compiler>\n"; } else // e.g. all and the GLOBAL and UTILITY targets { fout<<" <Option working_dir=\"" << makefile->GetStartOutputDirectory() << "\" />\n" <<" <Option type=\"" << 4 << "\" />\n"; } fout<<" <MakeCommands>\n" " <Build command=\"" << this->BuildMakeCommand(make, makefileName.c_str(), targetName) << "\" />\n" " <CompileFile command=\"" << this->BuildMakeCommand(make, makefileName.c_str(),""$file"") << "\" />\n" " <Clean command=\"" << this->BuildMakeCommand(make, makefileName.c_str(), "clean") << "\" />\n" " <DistClean command=\"" << this->BuildMakeCommand(make, makefileName.c_str(), "clean") << "\" />\n" " </MakeCommands>\n" " </Target>\n"; } // Translate the cmake compiler id into the CodeBlocks compiler id std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) { // figure out which language to use // for now care only for C and C++ std::string compilerIdVar = "CMAKE_CXX_COMPILER_ID"; if (this->GlobalGenerator->GetLanguageEnabled("CXX") == false) { compilerIdVar = "CMAKE_C_COMPILER_ID"; } std::string hostSystemName = mf->GetSafeDefinition("CMAKE_HOST_SYSTEM_NAME"); std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME"); std::string compilerId = mf->GetRequiredDefinition(compilerIdVar.c_str()); std::string compiler = "gcc"; if (compilerId == "MSVC") { compiler = "msvc"; } else if (compilerId == "Borland") { compiler = "bcc"; } else if (compilerId == "SDCC") { compiler = "sdcc"; } else if (compilerId == "Intel") { compiler = "icc"; } else if (compilerId == "Watcom") { compiler = "ow"; } else if (compilerId == "GNU") { compiler = "gcc"; } return compiler; } // Translate the cmake target type into the CodeBlocks target type id int cmExtraCodeBlocksGenerator::GetCBTargetType(cmTarget* target) { if ( target->GetType()==cmTarget::EXECUTABLE) { if ((target->GetPropertyAsBool("WIN32_EXECUTABLE")) || (target->GetPropertyAsBool("MACOSX_BUNDLE"))) { return 0; } else { return 1; } } else if ( target->GetType()==cmTarget::STATIC_LIBRARY) { return 2; } else if ((target->GetType()==cmTarget::SHARED_LIBRARY) || (target->GetType()==cmTarget::MODULE_LIBRARY)) { return 3; } return 4; } // Create the command line for building the given target using the selected // make std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( const std::string& make, const char* makefile, const char* target) { std::string command = make; if (strcmp(this->GlobalGenerator->GetName(), "NMake Makefiles")==0) { command += " /NOLOGO /f ""; command += makefile; command += "" "; command += target; } else { command += " -f ""; command += makefile; command += "" "; command += target; } return command; }