diff options
-rw-r--r-- | Auxiliary/bash-completion/cmake | 2 | ||||
-rw-r--r-- | Help/manual/cmake.1.rst | 5 | ||||
-rw-r--r-- | Help/release/dev/cmake-open.rst | 6 | ||||
-rw-r--r-- | Modules/CMakeFindSublimeText2.cmake | 23 | ||||
-rw-r--r-- | Source/cmExternalMakefileProjectGenerator.cxx | 7 | ||||
-rw-r--r-- | Source/cmExternalMakefileProjectGenerator.h | 3 | ||||
-rw-r--r-- | Source/cmExtraSublimeTextGenerator.cxx | 23 | ||||
-rw-r--r-- | Source/cmExtraSublimeTextGenerator.h | 3 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 10 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 6 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 33 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.h | 3 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 34 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.h | 7 | ||||
-rw-r--r-- | Source/cmake.cxx | 43 | ||||
-rw-r--r-- | Source/cmake.h | 3 | ||||
-rw-r--r-- | Source/cmakemain.cxx | 43 |
17 files changed, 253 insertions, 1 deletions
diff --git a/Auxiliary/bash-completion/cmake b/Auxiliary/bash-completion/cmake index 0a862fa079..5d67b0b85f 100644 --- a/Auxiliary/bash-completion/cmake +++ b/Auxiliary/bash-completion/cmake @@ -96,7 +96,7 @@ _cmake() _filedir return ;; - --build) + --build|--open) _filedir -d return ;; diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 6a21683210..ff8c6c7aa3 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -11,6 +11,7 @@ Synopsis cmake [<options>] (<path-to-source> | <path-to-existing-build>) cmake [(-D <var>=<value>)...] -P <cmake-script-file> cmake --build <dir> [<options>...] [-- <build-tool-options>...] + cmake --open <dir> cmake -E <command> [<options>...] cmake --find-package <options>... @@ -51,6 +52,10 @@ Options ``--build <dir>`` See `Build Tool Mode`_. +``--open <dir>`` + Open the generated project in the associated application. This is + only supported by some generators. + ``-N`` View mode only. diff --git a/Help/release/dev/cmake-open.rst b/Help/release/dev/cmake-open.rst new file mode 100644 index 0000000000..a8f77ae2cd --- /dev/null +++ b/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. diff --git a/Modules/CMakeFindSublimeText2.cmake b/Modules/CMakeFindSublimeText2.cmake new file mode 100644 index 0000000000..022d0109e7 --- /dev/null +++ b/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() diff --git a/Source/cmExternalMakefileProjectGenerator.cxx b/Source/cmExternalMakefileProjectGenerator.cxx index 825ec654ef..fecd8216ed 100644 --- a/Source/cmExternalMakefileProjectGenerator.cxx +++ b/Source/cmExternalMakefileProjectGenerator.cxx @@ -24,6 +24,13 @@ std::string cmExternalMakefileProjectGenerator::CreateFullGeneratorName( return fullName; } +bool cmExternalMakefileProjectGenerator::Open( + const std::string& /*bindir*/, const std::string& /*projectName*/, + bool /*dryRun*/) +{ + return false; +} + cmExternalMakefileProjectGeneratorFactory:: cmExternalMakefileProjectGeneratorFactory(const std::string& n, const std::string& doc) diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index a1734eef2a..7f332a8bb6 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -55,6 +55,9 @@ public: void SetName(const std::string& n) { Name = n; } std::string GetName() const { return Name; } + virtual bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun); + protected: ///! Contains the names of the global generators support by this generator. std::vector<std::string> SupportedGlobalGenerators; diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 73a9c8521f..3d72ae3f7e 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -400,3 +400,26 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( 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 }); +} diff --git a/Source/cmExtraSublimeTextGenerator.h b/Source/cmExtraSublimeTextGenerator.h index 7fb304e118..57ba1cfa13 100644 --- a/Source/cmExtraSublimeTextGenerator.h +++ b/Source/cmExtraSublimeTextGenerator.h @@ -65,6 +65,9 @@ private: std::string ComputeDefines(cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt); + bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun) override; + bool ExcludeBuildFolder; std::string EnvSettings; }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 05efff317b..38669c9ab4 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1824,6 +1824,16 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, 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( const std::string& target, const std::string& config, const std::string& native, bool ignoreErrors) diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 18ca682c73..04e9dc16e9 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -162,6 +162,12 @@ public: std::vector<std::string> const& nativeOptions = 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( std::vector<std::string>& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& projectDir, diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 0651536a96..b752f84f16 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -4,7 +4,10 @@ #include "cmGlobalVisualStudioGenerator.h" #include "cmsys/Encoding.hxx" +#include <future> #include <iostream> +#include <objbase.h> +#include <shellapi.h> #include <windows.h> #include "cmAlgorithms.h" @@ -928,3 +931,33 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( commandLines, "Auto build dll exports", "."); 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(); +} diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 62bfd3bdb3..55a6813c0d 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -131,6 +131,9 @@ public: std::vector<cmCustomCommand>& commands, std::string const& configName); + bool Open(const std::string& bindir, const std::string& projectName, + bool dryRun) override; + protected: virtual void AddExtraIDETargets(); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index c79ee475c1..e5471f2022 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -35,6 +35,11 @@ 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) #include "cmXMLParser.h" @@ -287,6 +292,35 @@ void cmGlobalXCodeGenerator::EnableLanguage( 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( std::vector<std::string>& makeCommand, const std::string& makeProgram, const std::string& projectName, const std::string& /*projectDir*/, diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index e9ca91ce4b..b758e97ff0 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -55,6 +55,13 @@ public: */ void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, 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 * loaded commands, not as part of the usual build process. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index fd7151f08a..d7ed772661 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2425,6 +2425,49 @@ int cmake::Build(const std::string& dir, const std::string& target, 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) { #ifdef CMAKE_BUILD_WITH_CMAKE diff --git a/Source/cmake.h b/Source/cmake.h index b31b6f5ce5..ed3ebe02a8 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -401,6 +401,9 @@ public: const std::string& config, 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 WatchUnusedCli(const std::string& var); diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index a1dfc3e893..59b908a167 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -66,6 +66,7 @@ static const char* cmDocumentationOptions[][2] = { { "-E", "CMake command mode." }, { "-L[A][H]", "List non-advanced cached variables." }, { "--build <dir>", "Build a CMake-generated project binary tree." }, + { "--open <dir>", "Open generated project in the associated application." }, { "-N", "View mode only." }, { "-P <file>", "Process script 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); 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) { @@ -186,6 +188,9 @@ int main(int ac, char const* const* av) if (strcmp(av[1], "--build") == 0) { return do_build(ac, av); } + if (strcmp(av[1], "--open") == 0) { + return do_open(ac, av); + } if (strcmp(av[1], "-E") == 0) { 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); #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 +} |