1
0
Эх сурвалжийг харах

Qbs: Add new 'extra' generator for qbs project files

Stanislav Ionascu 10 жил өмнө
parent
commit
f85db2f323

+ 25 - 0
Help/generator/Qbs.rst

@@ -0,0 +1,25 @@
+Qbs
+---
+
+Generates Qbs project files.
+
+Project files for Qbs 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.
+
+This "extra" generator may be specified as:
+
+``Qbs - MinGW Makefiles``
+ Generate with :generator:`MinGW Makefiles`.
+
+``Qbs - NMake Makefiles``
+ Generate with :generator:`NMake Makefiles`.
+
+``Qbs - Ninja``
+ Generate with :generator:`Ninja`.
+
+``Qbs - Unix Makefiles``
+ Generate with :generator:`Unix Makefiles`.

+ 1 - 0
Help/manual/cmake-generators.7.rst

@@ -85,3 +85,4 @@ The following extra generators are known to CMake.
    /generator/KDevelop3
    /generator/Kate
    /generator/Sublime Text 2
+   /generator/Qbs

+ 6 - 0
Help/release/dev/add-extra-qbs-generator.rst

@@ -0,0 +1,6 @@
+add-extra-qbs-geneator
+----------------------
+
+* It is now possible to generate :generator:`Qbs` project files
+  for use with QtCreator IDE, matching make tool must be used
+  to build the project through the generated makefiles.

+ 2 - 0
Source/CMakeLists.txt

@@ -229,6 +229,8 @@ set(SRCS
   cmExtraKateGenerator.h
   cmExtraSublimeTextGenerator.cxx
   cmExtraSublimeTextGenerator.h
+  cmExtraQbsGenerator.cxx
+  cmExtraQbsGenerator.h
   cmFileLock.cxx
   cmFileLock.h
   cmFileLockPool.cxx

+ 260 - 0
Source/cmExtraQbsGenerator.cxx

@@ -0,0 +1,260 @@
+#include "cmExtraQbsGenerator.h"
+
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSourceFile.h"
+
+cmExtraQbsGenerator::cmExtraQbsGenerator()
+{
+#if defined(_WIN32)
+  this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
+  this->SupportedGlobalGenerators.push_back("NMake Makefiles");
+#endif
+  this->SupportedGlobalGenerators.push_back("Ninja");
+  this->SupportedGlobalGenerators.push_back("Unix Makefiles");
+}
+
+cmExtraQbsGenerator::~cmExtraQbsGenerator() {}
+
+void cmExtraQbsGenerator::GetDocumentation(cmDocumentationEntry &entry,
+                                           const std::string &) const
+{
+  entry.Name = this->GetName();
+  entry.Brief = "Generates Qbs project files.";
+}
+
+void cmExtraQbsGenerator::Generate()
+{
+  for (std::map<std::string, std::vector<cmLocalGenerator *> >::const_iterator
+       it = this->GlobalGenerator->GetProjectMap().begin();
+       it != this->GlobalGenerator->GetProjectMap().end(); ++it)
+    {
+    // create a project file
+    this->CreateProjectFile(it->first, it->second);
+    }
+}
+
+void cmExtraQbsGenerator::CreateProjectFile(
+        const std::string &name,
+        const std::vector<cmLocalGenerator *> &lgs)
+{
+  const cmMakefile *mf = lgs[0]->GetMakefile();
+  std::string outputDir = mf->GetStartOutputDirectory();
+
+  const std::string filename = outputDir + "/" + name + ".qbs";
+
+  this->CreateNewProjectFile(name, lgs, filename);
+}
+
+void cmExtraQbsGenerator::CreateNewProjectFile(
+    const std::string &projectName, const std::vector<cmLocalGenerator *> &lgs,
+    const std::string &filename)
+{
+  cmGeneratedFileStream fout(filename.c_str());
+  if (!fout)
+    {
+    return;
+    }
+
+  fout << "import qbs\n"
+       << "import qbs.File\n\n"
+       << "Project {\n"
+       << "\tname:\"" << projectName << "\"\n";
+  std::vector<cmLocalGenerator *>::const_iterator itr = lgs.begin();
+  for (; itr != lgs.end(); ++itr)
+    {
+    cmLocalGenerator *lg = (*itr);
+    this->AppendSubProject(fout, lg);
+    }
+  fout << "}\n";
+}
+
+void cmExtraQbsGenerator::AppendSubProject(cmGeneratedFileStream &fout,
+                                           cmLocalGenerator *lg)
+{
+  const cmMakefile *mk = lg->GetMakefile();
+  if (!mk || mk->GetTargets().size() == 0)
+    {
+    return;
+    }
+
+  const std::string &relativePath = cmSystemTools::RelativePath(
+      mk->GetHomeDirectory(), mk->GetCurrentDirectory());
+  fout << "\tProject {\n"
+       << "\t\tname:\"" << relativePath << "\"\n";
+  this->AppendProduct(fout, lg);
+  fout << "\t}\n";
+}
+
+void cmExtraQbsGenerator::AppendProduct(cmGeneratedFileStream &fout,
+                                        cmLocalGenerator *lg)
+{
+  const cmMakefile *mk = lg->GetMakefile();
+  const cmTargets &ts = mk->GetTargets();
+  std::string cfg = mk->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  cmTargets::const_iterator itr = ts.begin();
+  for (; itr != ts.end(); ++itr)
+    {
+    const cmTarget &t = itr->second;
+    this->AppendTarget(fout, lg, t, cfg);
+    }
+}
+
+void cmExtraQbsGenerator::AppendTarget(cmGeneratedFileStream &fout,
+                                       cmLocalGenerator *lg, const cmTarget &t,
+                                       const std::string &cfg)
+{
+  std::string type;
+  bool isBuildable = true;
+  switch (t.GetType())
+    {
+    case cmTarget::EXECUTABLE:
+      type = "application";
+      break;
+    case cmTarget::SHARED_LIBRARY:
+      type = "dynamiclibrary";
+      break;
+    case cmTarget::STATIC_LIBRARY:
+      type = "staticlibrary";
+      break;
+    default:
+      isBuildable = false;
+      break;
+    }
+
+  if (type.empty())
+    {
+    fout << "\t\tProject {\n";
+    }
+  else
+    {
+    fout << "\t\tProduct {\n";
+    fout << "\t\t\tdestinationDirectory: \"" << t.GetDirectory(cfg) << "\"\n";
+    }
+  fout << "\t\t\tname:\"" << t.GetName() << "\"\n";
+
+  if (!type.empty())
+    {
+    fout << "\t\t\ttype: \"" << type << "\"\n";
+    fout << "\t\t\ttargetName: \"" << t.GetName() << "\"\n";
+    }
+
+  if (isBuildable)
+    {
+    fout << "\t\t\tDepends { name: \"cpp\" }\n";
+    cmGeneratorTarget *gt = this->GlobalGenerator->GetGeneratorTarget(&t);
+    this->AppendSources(fout, gt, t, cfg);
+
+    std::set<std::string> langs, incPaths, defs;
+    t.GetLanguages(langs, cfg);
+    for (std::set<std::string>::const_iterator lang = langs.begin();
+         lang != langs.end();
+         ++ lang)
+      {
+      const std::vector<std::string> &paths =
+          gt->GetIncludeDirectories(cfg, *lang);
+      std::copy(paths.begin(), paths.end(),
+                std::inserter(incPaths, incPaths.end()));
+
+      lg->AddCompileDefinitions(defs, &t, cfg, *lang);
+      }
+    this->AppendIncludePaths(fout, incPaths);
+    this->AppendCompileDefinitions(fout, defs);
+    }
+
+  fout << "\t\t}\n";
+}
+
+void cmExtraQbsGenerator::AppendSources(cmGeneratedFileStream &fout,
+                                        cmGeneratorTarget *gt,
+                                        const cmTarget &t,
+                                        const std::string &cfg)
+{
+  std::vector<cmSourceFile *> sources;
+  gt->GetSourceFiles(sources, cfg);
+  if (sources.empty())
+    {
+    return;
+    }
+
+  std::vector<cmSourceFile *> genSources;
+  std::vector<cmSourceFile *>::const_iterator itr = sources.begin();
+  fout << "\t\t\tfiles: [\n"
+       << "\t\t\t\t\"" << t.GetMakefile()->GetCurrentListFile() << "\",\n";
+  for (; itr != sources.end(); ++itr)
+    {
+    if (!(*itr)->GetPropertyAsBool("GENERATED"))
+      {
+      fout << "\t\t\t\t\"" << (*itr)->GetFullPath() << "\",\n";
+      }
+    else
+      {
+      genSources.push_back(*itr);
+      }
+    }
+  fout << "\t\t\t]\n";
+
+  if (!genSources.empty())
+    {
+    fout << "\t\t\tGroup {\n"
+         << "\t\t\t\tname:\"Generated\"\n"
+         << "\t\t\t\tfiles: [\n";
+    itr = genSources.begin();
+    std::string groupCondition;
+    bool initialCondition = true;
+    for (; itr != genSources.end(); ++itr)
+      {
+      const std::string &path = (*itr)->GetFullPath();
+      fout << "\t\t\t\t\t\"" << path << "\",\n";
+      if (initialCondition)
+        {
+        initialCondition = false;
+        }
+      else
+        {
+        groupCondition += "\t\t\t\t\t && ";
+        }
+      groupCondition += "File.exists(\"" + path + "\")\n";
+      }
+    fout << "\t\t\t\t]\n"
+         << "\t\t\t\tcondition: " << groupCondition << "\t\t\t}\n";
+  }
+}
+
+void cmExtraQbsGenerator::AppendIncludePaths(
+    cmGeneratedFileStream &fout,
+    const std::set<std::string> &paths)
+{
+  if (paths.empty())
+    {
+    return;
+    }
+
+  std::set<std::string>::const_iterator itr = paths.begin();
+  fout << "\t\t\tcpp.includePaths: [\n";
+  for (; itr != paths.end(); ++ itr)
+    {
+    fout << "\t\t\t\t\"" << (*itr) << "\",\n";
+    }
+  fout << "\t\t\t]\n";
+}
+
+void cmExtraQbsGenerator::AppendCompileDefinitions(
+    cmGeneratedFileStream &fout,
+    const std::set<std::string> &defs)
+{
+  if (defs.empty())
+    {
+    return;
+    }
+
+  std::set<std::string>::const_iterator itr = defs.begin();
+  fout << "\t\t\tcpp.defines: [\n";
+  for (; itr != defs.end(); ++ itr)
+    {
+    fout << "\t\t\t\t'" << (*itr) << "',\n";
+    }
+  fout << "\t\t\t]\n";
+}

+ 48 - 0
Source/cmExtraQbsGenerator.h

@@ -0,0 +1,48 @@
+#ifndef CMEXTRAQBSGENERATOR_H
+#define CMEXTRAQBSGENERATOR_H
+
+#include "cmExternalMakefileProjectGenerator.h"
+
+class cmGeneratorTarget;
+
+class cmExtraQbsGenerator : public cmExternalMakefileProjectGenerator
+{
+public:
+  cmExtraQbsGenerator();
+  ~cmExtraQbsGenerator();
+
+  virtual std::string GetName() const
+  { return cmExtraQbsGenerator::GetActualName(); }
+  static std::string GetActualName() { return "Qbs"; }
+  static cmExternalMakefileProjectGenerator *New()
+  { return new cmExtraQbsGenerator; }
+
+  /** Get the documentation entry for this generator.  */
+  virtual void GetDocumentation(cmDocumentationEntry &entry,
+                                const std::string &fullName) const;
+
+  virtual void Generate();
+
+private:
+  void CreateProjectFile(const std::string &name,
+                         const std::vector<cmLocalGenerator *> &lgs);
+  void CreateNewProjectFile(const std::string &projectName,
+                            const std::vector<cmLocalGenerator *> &lgs,
+                            const std::string &filename);
+  void AppendSubProject(cmGeneratedFileStream &fout, cmLocalGenerator *lg);
+  void AppendProduct(cmGeneratedFileStream &fout, cmLocalGenerator *lg);
+  void AppendTarget(cmGeneratedFileStream &fout,
+                    cmLocalGenerator *lg,
+                    const cmTarget &t,
+                    const std::string &cfg);
+  void AppendSources(cmGeneratedFileStream &fout,
+                     cmGeneratorTarget *gt,
+                     const cmTarget &t,
+                     const std::string &cfg);
+  void AppendIncludePaths(cmGeneratedFileStream &fout,
+                          const std::set<std::string> &paths);
+  void AppendCompileDefinitions(cmGeneratedFileStream &fout,
+                                const std::set<std::string> &defs);
+};
+
+#endif // CMEXTRAQBSGENERATOR_H

+ 4 - 0
Source/cmake.cxx

@@ -86,6 +86,8 @@
 # include "cmGlobalKdevelopGenerator.h"
 #endif
 
+#include "cmExtraQbsGenerator.h"
+
 #ifdef CMAKE_USE_ECLIPSE
 # include "cmExtraEclipseCDT4Generator.h"
 #endif
@@ -1029,6 +1031,8 @@ void cmake::AddDefaultExtraGenerators()
                           &cmExtraSublimeTextGenerator::New);
   this->AddExtraGenerator(cmExtraKateGenerator::GetActualName(),
                           &cmExtraKateGenerator::New);
+  this->AddExtraGenerator(cmExtraQbsGenerator::GetActualName(),
+                          &cmExtraQbsGenerator::New);
 
 #ifdef CMAKE_USE_ECLIPSE
   this->AddExtraGenerator(cmExtraEclipseCDT4Generator::GetActualName(),

+ 15 - 1
Tests/CMakeLists.txt

@@ -560,7 +560,21 @@ if(BUILD_TESTING)
          --test-command Simple)
       list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_KDevelop3Generator")
     endif ()
-
+    # check for the Qbs generator
+    if ("${cmakeOutput}" MATCHES Qbs)
+      add_test(Simple_QbsGenerator ${CMAKE_CTEST_COMMAND}
+         --build-and-test
+         "${CMake_SOURCE_DIR}/Tests/Simple"
+         "${CMake_BINARY_DIR}/Tests/Simple_QbsGenerator"
+         --build-two-config
+         --build-generator "Qbs - Unix Makefiles"
+         --build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
+         --build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
+         --build-project Simple
+         --build-options ${build_options}
+         --test-command Simple)
+      list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Simple_QbsGenerator")
+    endif ()
   endif()
 
   # test for correct sub-project generation