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

cmake: Add --open option for IDE generators

Gregor Jasny 8 жил өмнө
parent
commit
5de37a4a64

+ 1 - 1
Auxiliary/bash-completion/cmake

@@ -96,7 +96,7 @@ _cmake()
             _filedir
             _filedir
             return
             return
             ;;
             ;;
-        --build)
+        --build|--open)
             _filedir -d
             _filedir -d
             return
             return
             ;;
             ;;

+ 5 - 0
Help/manual/cmake.1.rst

@@ -11,6 +11,7 @@ Synopsis
  cmake [<options>] (<path-to-source> | <path-to-existing-build>)
  cmake [<options>] (<path-to-source> | <path-to-existing-build>)
  cmake [(-D <var>=<value>)...] -P <cmake-script-file>
  cmake [(-D <var>=<value>)...] -P <cmake-script-file>
  cmake --build <dir> [<options>...] [-- <build-tool-options>...]
  cmake --build <dir> [<options>...] [-- <build-tool-options>...]
+ cmake --open <dir>
  cmake -E <command> [<options>...]
  cmake -E <command> [<options>...]
  cmake --find-package <options>...
  cmake --find-package <options>...
 
 
@@ -51,6 +52,10 @@ Options
 ``--build <dir>``
 ``--build <dir>``
  See `Build Tool Mode`_.
  See `Build Tool Mode`_.
 
 
+``--open <dir>``
+ Open the generated project in the associated application.  This is
+ only supported by some generators.
+
 ``-N``
 ``-N``
  View mode only.
  View mode only.
 
 

+ 6 - 0
Help/release/dev/cmake-open.rst

@@ -0,0 +1,6 @@
+cmake-open
+----------
+
+* The :manual:`cmake(1)` ``--open <dir>`` command line option can now
+  be used to open generated IDE projects like Visual Studio solutions
+  or Xcode projects.

+ 23 - 0
Modules/CMakeFindSublimeText2.cmake

@@ -0,0 +1,23 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+
+# This file is included in CMakeSystemSpecificInformation.cmake if
+# the Sublime Text 2 extra generator has been selected.
+
+find_program(CMAKE_SUBLIMETEXT_EXECUTABLE
+    NAMES subl3 subl sublime_text
+    PATHS
+        "/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+        "/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+        "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+        "$ENV{HOME}/Applications/Sublime Text.app/Contents/SharedSupport/bin"
+        "$ENV{HOME}/Applications/Sublime Text 3.app/Contents/SharedSupport/bin"
+        "$ENV{HOME}/Applications/Sublime Text 2.app/Contents/SharedSupport/bin"
+        "/opt/sublime_text"
+        "/opt/sublime_text_3"
+    DOC "The Sublime Text executable")
+
+if(CMAKE_SUBLIMETEXT_EXECUTABLE)
+   set(CMAKE_OPEN_PROJECT_COMMAND "${CMAKE_SUBLIMETEXT_EXECUTABLE} --project <PROJECT_FILE>" )
+endif()

+ 7 - 0
Source/cmExternalMakefileProjectGenerator.cxx

@@ -24,6 +24,13 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
   return fullName;
   return fullName;
 }
 }
 
 
+bool cmExternalMakefileProjectGenerator::Open(
+  const std::string& /*bindir*/, const std::string& /*projectName*/,
+  bool /*dryRun*/)
+{
+  return false;
+}
+
 cmExternalMakefileProjectGeneratorFactory::
 cmExternalMakefileProjectGeneratorFactory::
   cmExternalMakefileProjectGeneratorFactory(const std::string& n,
   cmExternalMakefileProjectGeneratorFactory(const std::string& n,
                                             const std::string& doc)
                                             const std::string& doc)

+ 3 - 0
Source/cmExternalMakefileProjectGenerator.h

@@ -55,6 +55,9 @@ public:
   void SetName(const std::string& n) { Name = n; }
   void SetName(const std::string& n) { Name = n; }
   std::string GetName() const { return Name; }
   std::string GetName() const { return Name; }
 
 
+  virtual bool Open(const std::string& bindir, const std::string& projectName,
+                    bool dryRun);
+
 protected:
 protected:
   ///! Contains the names of the global generators support by this generator.
   ///! Contains the names of the global generators support by this generator.
   std::vector<std::string> SupportedGlobalGenerators;
   std::vector<std::string> SupportedGlobalGenerators;

+ 23 - 0
Source/cmExtraSublimeTextGenerator.cxx

@@ -400,3 +400,26 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines(
 
 
   return definesString;
   return definesString;
 }
 }
+
+bool cmExtraSublimeTextGenerator::Open(const std::string& bindir,
+                                       const std::string& projectName,
+                                       bool dryRun)
+{
+  const char* sublExecutable =
+    this->GlobalGenerator->GetCMakeInstance()->GetCacheDefinition(
+      "CMAKE_SUBLIMETEXT_EXECUTABLE");
+  if (!sublExecutable) {
+    return false;
+  }
+  if (cmSystemTools::IsNOTFOUND(sublExecutable)) {
+    return false;
+  }
+
+  std::string filename = bindir + "/" + projectName + ".sublime-project";
+  if (dryRun) {
+    return cmSystemTools::FileExists(filename, true);
+  }
+
+  return cmSystemTools::RunSingleCommand(
+    { sublExecutable, "--project", filename });
+}

+ 3 - 0
Source/cmExtraSublimeTextGenerator.h

@@ -65,6 +65,9 @@ private:
   std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
   std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg,
                              cmGeneratorTarget* gtgt);
                              cmGeneratorTarget* gtgt);
 
 
+  bool Open(const std::string& bindir, const std::string& projectName,
+            bool dryRun) override;
+
   bool ExcludeBuildFolder;
   bool ExcludeBuildFolder;
   std::string EnvSettings;
   std::string EnvSettings;
 };
 };

+ 10 - 0
Source/cmGlobalGenerator.cxx

@@ -1824,6 +1824,16 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/,
   return retVal;
   return retVal;
 }
 }
 
 
+bool cmGlobalGenerator::Open(const std::string& bindir,
+                             const std::string& projectName, bool dryRun)
+{
+  if (this->ExtraGenerator) {
+    return this->ExtraGenerator->Open(bindir, projectName, dryRun);
+  }
+
+  return false;
+}
+
 std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
 std::string cmGlobalGenerator::GenerateCMakeBuildCommand(
   const std::string& target, const std::string& config,
   const std::string& target, const std::string& config,
   const std::string& native, bool ignoreErrors)
   const std::string& native, bool ignoreErrors)

+ 6 - 0
Source/cmGlobalGenerator.h

@@ -162,6 +162,12 @@ public:
             std::vector<std::string> const& nativeOptions =
             std::vector<std::string> const& nativeOptions =
               std::vector<std::string>());
               std::vector<std::string>());
 
 
+  /**
+   * Open a generated IDE project given the following information.
+   */
+  virtual bool Open(const std::string& bindir, const std::string& projectName,
+                    bool dryRun);
+
   virtual void GenerateBuildCommand(
   virtual void GenerateBuildCommand(
     std::vector<std::string>& makeCommand, const std::string& makeProgram,
     std::vector<std::string>& makeCommand, const std::string& makeProgram,
     const std::string& projectName, const std::string& projectDir,
     const std::string& projectName, const std::string& projectDir,

+ 33 - 0
Source/cmGlobalVisualStudioGenerator.cxx

@@ -4,7 +4,10 @@
 #include "cmGlobalVisualStudioGenerator.h"
 #include "cmGlobalVisualStudioGenerator.h"
 
 
 #include "cmsys/Encoding.hxx"
 #include "cmsys/Encoding.hxx"
+#include <future>
 #include <iostream>
 #include <iostream>
+#include <objbase.h>
+#include <shellapi.h>
 #include <windows.h>
 #include <windows.h>
 
 
 #include "cmAlgorithms.h"
 #include "cmAlgorithms.h"
@@ -928,3 +931,33 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand(
                           commandLines, "Auto build dll exports", ".");
                           commandLines, "Auto build dll exports", ".");
   commands.push_back(command);
   commands.push_back(command);
 }
 }
+
+static bool OpenSolution(std::string sln)
+{
+  HRESULT comInitialized =
+    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
+  if (FAILED(comInitialized)) {
+    return false;
+  }
+
+  HINSTANCE hi =
+    ShellExecuteA(NULL, "open", sln.c_str(), NULL, NULL, SW_SHOWNORMAL);
+
+  CoUninitialize();
+
+  return reinterpret_cast<intptr_t>(hi) > 32;
+}
+
+bool cmGlobalVisualStudioGenerator::Open(const std::string& bindir,
+                                         const std::string& projectName,
+                                         bool dryRun)
+{
+  std::string buildDir = cmSystemTools::ConvertToOutputPath(bindir.c_str());
+  std::string sln = buildDir + "\\" + projectName + ".sln";
+
+  if (dryRun) {
+    return cmSystemTools::FileExists(sln, true);
+  }
+
+  return std::async(std::launch::async, OpenSolution, sln).get();
+}

+ 3 - 0
Source/cmGlobalVisualStudioGenerator.h

@@ -131,6 +131,9 @@ public:
                               std::vector<cmCustomCommand>& commands,
                               std::vector<cmCustomCommand>& commands,
                               std::string const& configName);
                               std::string const& configName);
 
 
+  bool Open(const std::string& bindir, const std::string& projectName,
+            bool dryRun) override;
+
 protected:
 protected:
   virtual void AddExtraIDETargets();
   virtual void AddExtraIDETargets();
 
 

+ 34 - 0
Source/cmGlobalXCodeGenerator.cxx

@@ -35,6 +35,11 @@
 
 
 struct cmLinkImplementation;
 struct cmLinkImplementation;
 
 
+#if defined(CMAKE_BUILD_WITH_CMAKE) && defined(__APPLE__)
+#define HAVE_APPLICATION_SERVICES
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 #include "cmXMLParser.h"
 #include "cmXMLParser.h"
 
 
@@ -287,6 +292,35 @@ void cmGlobalXCodeGenerator::EnableLanguage(
   this->ComputeArchitectures(mf);
   this->ComputeArchitectures(mf);
 }
 }
 
 
+bool cmGlobalXCodeGenerator::Open(const std::string& bindir,
+                                  const std::string& projectName, bool dryRun)
+{
+  bool ret = false;
+
+#ifdef HAVE_APPLICATION_SERVICES
+  std::string url = bindir + "/" + projectName + ".xcodeproj";
+
+  if (dryRun) {
+    return cmSystemTools::FileExists(url, false);
+  }
+
+  CFStringRef cfStr = CFStringCreateWithCString(
+    kCFAllocatorDefault, url.c_str(), kCFStringEncodingUTF8);
+  if (cfStr) {
+    CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfStr,
+                                                   kCFURLPOSIXPathStyle, true);
+    if (cfUrl) {
+      OSStatus err = LSOpenCFURLRef(cfUrl, nullptr);
+      ret = err == noErr;
+      CFRelease(cfUrl);
+    }
+    CFRelease(cfStr);
+  }
+#endif
+
+  return ret;
+}
+
 void cmGlobalXCodeGenerator::GenerateBuildCommand(
 void cmGlobalXCodeGenerator::GenerateBuildCommand(
   std::vector<std::string>& makeCommand, const std::string& makeProgram,
   std::vector<std::string>& makeCommand, const std::string& makeProgram,
   const std::string& projectName, const std::string& /*projectDir*/,
   const std::string& projectName, const std::string& /*projectDir*/,

+ 7 - 0
Source/cmGlobalXCodeGenerator.h

@@ -55,6 +55,13 @@ public:
    */
    */
   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
   void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*,
                       bool optional) override;
                       bool optional) override;
+
+  /**
+   * Open a generated IDE project given the following information.
+   */
+  bool Open(const std::string& bindir, const std::string& projectName,
+            bool dryRun) override;
+
   /**
   /**
    * Try running cmake and building a file. This is used for dynalically
    * Try running cmake and building a file. This is used for dynalically
    * loaded commands, not as part of the usual build process.
    * loaded commands, not as part of the usual build process.

+ 43 - 0
Source/cmake.cxx

@@ -2425,6 +2425,49 @@ int cmake::Build(const std::string& dir, const std::string& target,
                     nativeOptions);
                     nativeOptions);
 }
 }
 
 
+bool cmake::Open(const std::string& dir, bool dryRun)
+{
+  this->SetHomeDirectory("");
+  this->SetHomeOutputDirectory("");
+  if (!cmSystemTools::FileIsDirectory(dir)) {
+    std::cerr << "Error: " << dir << " is not a directory\n";
+    return false;
+  }
+
+  std::string cachePath = FindCacheFile(dir);
+  if (!this->LoadCache(cachePath)) {
+    std::cerr << "Error: could not load cache\n";
+    return false;
+  }
+  const char* genName = this->State->GetCacheEntryValue("CMAKE_GENERATOR");
+  if (!genName) {
+    std::cerr << "Error: could not find CMAKE_GENERATOR in Cache\n";
+    return false;
+  }
+  const char* extraGenName =
+    this->State->GetInitializedCacheValue("CMAKE_EXTRA_GENERATOR");
+  std::string fullName =
+    cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
+      genName, extraGenName ? extraGenName : "");
+
+  std::unique_ptr<cmGlobalGenerator> gen(
+    this->CreateGlobalGenerator(fullName));
+  if (!gen.get()) {
+    std::cerr << "Error: could create CMAKE_GENERATOR \"" << fullName
+              << "\"\n";
+    return false;
+  }
+
+  const char* cachedProjectName =
+    this->State->GetCacheEntryValue("CMAKE_PROJECT_NAME");
+  if (!cachedProjectName) {
+    std::cerr << "Error: could not find CMAKE_PROJECT_NAME in Cache\n";
+    return false;
+  }
+
+  return gen->Open(dir, cachedProjectName, dryRun);
+}
+
 void cmake::WatchUnusedCli(const std::string& var)
 void cmake::WatchUnusedCli(const std::string& var)
 {
 {
 #ifdef CMAKE_BUILD_WITH_CMAKE
 #ifdef CMAKE_BUILD_WITH_CMAKE

+ 3 - 0
Source/cmake.h

@@ -401,6 +401,9 @@ public:
             const std::string& config,
             const std::string& config,
             const std::vector<std::string>& nativeOptions, bool clean);
             const std::vector<std::string>& nativeOptions, bool clean);
 
 
+  ///! run the --open option
+  bool Open(const std::string& dir, bool dryRun);
+
   void UnwatchUnusedCli(const std::string& var);
   void UnwatchUnusedCli(const std::string& var);
   void WatchUnusedCli(const std::string& var);
   void WatchUnusedCli(const std::string& var);
 
 

+ 43 - 0
Source/cmakemain.cxx

@@ -66,6 +66,7 @@ static const char* cmDocumentationOptions[][2] = {
   { "-E", "CMake command mode." },
   { "-E", "CMake command mode." },
   { "-L[A][H]", "List non-advanced cached variables." },
   { "-L[A][H]", "List non-advanced cached variables." },
   { "--build <dir>", "Build a CMake-generated project binary tree." },
   { "--build <dir>", "Build a CMake-generated project binary tree." },
+  { "--open <dir>", "Open generated project in the associated application." },
   { "-N", "View mode only." },
   { "-N", "View mode only." },
   { "-P <file>", "Process script mode." },
   { "-P <file>", "Process script mode." },
   { "--find-package", "Run in pkg-config like mode." },
   { "--find-package", "Run in pkg-config like mode." },
@@ -100,6 +101,7 @@ static int do_command(int ac, char const* const* av)
 
 
 int do_cmake(int ac, char const* const* av);
 int do_cmake(int ac, char const* const* av);
 static int do_build(int ac, char const* const* av);
 static int do_build(int ac, char const* const* av);
+static int do_open(int ac, char const* const* av);
 
 
 static cmMakefile* cmakemainGetMakefile(void* clientdata)
 static cmMakefile* cmakemainGetMakefile(void* clientdata)
 {
 {
@@ -186,6 +188,9 @@ int main(int ac, char const* const* av)
     if (strcmp(av[1], "--build") == 0) {
     if (strcmp(av[1], "--build") == 0) {
       return do_build(ac, av);
       return do_build(ac, av);
     }
     }
+    if (strcmp(av[1], "--open") == 0) {
+      return do_open(ac, av);
+    }
     if (strcmp(av[1], "-E") == 0) {
     if (strcmp(av[1], "-E") == 0) {
       return do_command(ac, av);
       return do_command(ac, av);
     }
     }
@@ -423,3 +428,41 @@ static int do_build(int ac, char const* const* av)
   return cm.Build(dir, target, config, nativeOptions, clean);
   return cm.Build(dir, target, config, nativeOptions, clean);
 #endif
 #endif
 }
 }
+
+static int do_open(int ac, char const* const* av)
+{
+#ifndef CMAKE_BUILD_WITH_CMAKE
+  std::cerr << "This cmake does not support --open\n";
+  return -1;
+#else
+  std::string dir;
+
+  enum Doing
+  {
+    DoingNone,
+    DoingDir,
+  };
+  Doing doing = DoingDir;
+  for (int i = 2; i < ac; ++i) {
+    switch (doing) {
+      case DoingDir:
+        dir = cmSystemTools::CollapseFullPath(av[i]);
+        doing = DoingNone;
+        break;
+      default:
+        std::cerr << "Unknown argument " << av[i] << std::endl;
+        dir.clear();
+        break;
+    }
+  }
+  if (dir.empty()) {
+    std::cerr << "Usage: cmake --open <dir>\n";
+    return 1;
+  }
+
+  cmake cm(cmake::RoleInternal);
+  cmSystemTools::SetMessageCallback(cmakemainMessageCallback, &cm);
+  cm.SetProgressCallback(cmakemainProgressCallback, &cm);
+  return cm.Open(dir, false) ? 0 : 1;
+#endif
+}