Commit 5de37a4a authored by Gregor Jasny's avatar Gregor Jasny

cmake: Add --open option for IDE generators

parent d0b6c2da
......@@ -96,7 +96,7 @@ _cmake()
_filedir
return
;;
--build)
--build|--open)
_filedir -d
return
;;
......
......@@ -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.
......
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.
# 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()
......@@ -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)
......
......@@ -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;
......
......@@ -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 });
}
......@@ -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;
};
......
......@@ -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)
......
......@@ -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,
......
......@@ -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();
}
......@@ -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();
......
......@@ -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*/,
......
......@@ -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.
......
......@@ -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
......
......@@ -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);
......
......@@ -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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment