mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-16 22:37:30 +08:00
cmake --build: Add support for driving Xcode workspaces
External tools may create a `.xcworkspace` directory next to the `.xcodeproj` directory that CMake generates. If a workspace exists, drive the build through it instead. Closes: #26958 Co-authored-by: Brad King <brad.king@kitware.com>
This commit is contained in:
@@ -736,6 +736,19 @@ following options:
|
|||||||
|
|
||||||
Run :option:`cmake --build` with no options for quick help.
|
Run :option:`cmake --build` with no options for quick help.
|
||||||
|
|
||||||
|
Generator-Specific Build Tool Behavior
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
``cmake --build`` has special behavior with some generators:
|
||||||
|
|
||||||
|
:generator:`Xcode`
|
||||||
|
|
||||||
|
.. versionadded:: 4.1
|
||||||
|
|
||||||
|
If a third-party tool has written a ``.xcworkspace`` next to
|
||||||
|
the CMake-generated ``.xcodeproj``, ``cmake --build`` drives
|
||||||
|
the build through the workspace instead.
|
||||||
|
|
||||||
Install a Project
|
Install a Project
|
||||||
=================
|
=================
|
||||||
|
|
||||||
|
7
Help/release/dev/xcode-build-workspace.rst
Normal file
7
Help/release/dev/xcode-build-workspace.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
xcode-build-workspace
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
* The :ref:`cmake --build <Build Tool Mode>` command-line tool, when used
|
||||||
|
with the :generator:`Xcode` generator, now detects when a third-party
|
||||||
|
tool has wrapped the generated ``.xcodeproj`` in a ``.xcworkspace``,
|
||||||
|
and drives the build through the workspace instead.
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include <cm/memory>
|
#include <cm/memory>
|
||||||
#include <cm/optional>
|
#include <cm/optional>
|
||||||
|
#include <cm/string_view>
|
||||||
#include <cmext/algorithm>
|
#include <cmext/algorithm>
|
||||||
#include <cmext/string_view>
|
#include <cmext/string_view>
|
||||||
|
|
||||||
@@ -294,6 +295,40 @@ bool cmGlobalXCodeGenerator::FindMakeProgram(cmMakefile* mf)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cmGlobalXCodeGenerator::GetAppleSpecificPlatformName()
|
||||||
|
{
|
||||||
|
std::string sdkRoot =
|
||||||
|
this->GetCMakeInstance()->GetState()->GetCacheEntryValue(
|
||||||
|
"CMAKE_OSX_SYSROOT");
|
||||||
|
sdkRoot = cmSystemTools::LowerCase(sdkRoot);
|
||||||
|
|
||||||
|
struct SdkDatabaseEntry
|
||||||
|
{
|
||||||
|
cm::string_view Name;
|
||||||
|
cm::string_view AppleName;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<SdkDatabaseEntry, 6> const sdkDatabase{ {
|
||||||
|
{ "appletvos"_s, "tvOS"_s },
|
||||||
|
{ "appletvsimulator"_s, "tvOS Simulator"_s },
|
||||||
|
{ "iphoneos"_s, "iOS"_s },
|
||||||
|
{ "iphonesimulator"_s, "iOS Simulator"_s },
|
||||||
|
{ "watchos"_s, "watchOS"_s },
|
||||||
|
{ "watchsimulator"_s, "watchOS Simulator"_s },
|
||||||
|
} };
|
||||||
|
|
||||||
|
cm::string_view platformName = "MacOS"_s;
|
||||||
|
for (SdkDatabaseEntry const& entry : sdkDatabase) {
|
||||||
|
if (cmHasPrefix(sdkRoot, entry.Name) ||
|
||||||
|
sdkRoot.find(cmStrCat('/', entry.Name)) != std::string::npos) {
|
||||||
|
platformName = entry.AppleName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(platformName);
|
||||||
|
}
|
||||||
|
|
||||||
std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
|
std::string const& cmGlobalXCodeGenerator::GetXcodeBuildCommand()
|
||||||
{
|
{
|
||||||
if (!this->XcodeBuildCommandInitialized) {
|
if (!this->XcodeBuildCommandInitialized) {
|
||||||
@@ -473,10 +508,15 @@ bool cmGlobalXCodeGenerator::Open(std::string const& bindir,
|
|||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
#ifdef HAVE_APPLICATION_SERVICES
|
#ifdef HAVE_APPLICATION_SERVICES
|
||||||
std::string url = cmStrCat(bindir, '/', projectName, ".xcodeproj");
|
// If an external tool created a workspace then open it instead.
|
||||||
|
std::string url = cmStrCat(bindir, '/', projectName, ".xcworkspace");
|
||||||
|
bool const isWorkspace = cmSystemTools::FileIsDirectory(url);
|
||||||
|
if (!isWorkspace) {
|
||||||
|
url = cmStrCat(bindir, '/', projectName, ".xcodeproj");
|
||||||
|
}
|
||||||
|
|
||||||
if (dryRun) {
|
if (dryRun) {
|
||||||
return cmSystemTools::FileExists(url, false);
|
return cmSystemTools::FileIsDirectory(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
CFStringRef cfStr = CFStringCreateWithCString(
|
CFStringRef cfStr = CFStringCreateWithCString(
|
||||||
@@ -508,33 +548,47 @@ cmGlobalXCodeGenerator::GenerateBuildCommand(
|
|||||||
int jobs, bool /*verbose*/, cmBuildOptions const& /*buildOptions*/,
|
int jobs, bool /*verbose*/, cmBuildOptions const& /*buildOptions*/,
|
||||||
std::vector<std::string> const& makeOptions)
|
std::vector<std::string> const& makeOptions)
|
||||||
{
|
{
|
||||||
|
// If an external tool created a workspace then build it instead.
|
||||||
|
std::string projectPath = cmStrCat(projectName, ".xcworkspace");
|
||||||
|
bool const isWorkspace = cmSystemTools::FileIsDirectory(projectPath);
|
||||||
|
if (!isWorkspace) {
|
||||||
|
projectPath = cmStrCat(projectName, ".xcodeproj");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const targetFlag = isWorkspace ? "-scheme" : "-target";
|
||||||
|
std::string const projectFlag = isWorkspace ? "-workspace" : "-project";
|
||||||
|
|
||||||
GeneratedMakeCommand makeCommand;
|
GeneratedMakeCommand makeCommand;
|
||||||
// now build the test
|
// now build the test
|
||||||
makeCommand.Add(
|
makeCommand.Add(
|
||||||
this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
|
this->SelectMakeProgram(makeProgram, this->GetXcodeBuildCommand()));
|
||||||
|
|
||||||
if (!projectName.empty()) {
|
if (!projectName.empty()) {
|
||||||
makeCommand.Add("-project");
|
makeCommand.Add(projectFlag, projectPath);
|
||||||
std::string projectArg = cmStrCat(projectName, ".xcodeproj");
|
|
||||||
makeCommand.Add(projectArg);
|
|
||||||
}
|
}
|
||||||
if (cm::contains(targetNames, "clean")) {
|
if (cm::contains(targetNames, "clean")) {
|
||||||
makeCommand.Add("clean");
|
makeCommand.Add("clean");
|
||||||
makeCommand.Add("-target", "ALL_BUILD");
|
makeCommand.Add(targetFlag, "ALL_BUILD");
|
||||||
} else {
|
} else {
|
||||||
makeCommand.Add("build");
|
makeCommand.Add("build");
|
||||||
if (targetNames.empty() ||
|
if (targetNames.empty() ||
|
||||||
((targetNames.size() == 1) && targetNames.front().empty())) {
|
((targetNames.size() == 1) && targetNames.front().empty())) {
|
||||||
makeCommand.Add("-target", "ALL_BUILD");
|
makeCommand.Add(targetFlag, "ALL_BUILD");
|
||||||
} else {
|
} else {
|
||||||
for (auto const& tname : targetNames) {
|
for (auto const& tname : targetNames) {
|
||||||
if (!tname.empty()) {
|
if (!tname.empty()) {
|
||||||
makeCommand.Add("-target", tname);
|
makeCommand.Add(targetFlag, tname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWorkspace) {
|
||||||
|
makeCommand.Add(
|
||||||
|
"-destination",
|
||||||
|
cmStrCat("generic/platform=", this->GetAppleSpecificPlatformName()));
|
||||||
|
}
|
||||||
|
|
||||||
if ((this->XcodeBuildSystem >= BuildSystem::Twelve) ||
|
if ((this->XcodeBuildSystem >= BuildSystem::Twelve) ||
|
||||||
(jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) {
|
(jobs != cmake::NO_BUILD_PARALLEL_LEVEL)) {
|
||||||
makeCommand.Add("-parallelizeTargets");
|
makeCommand.Add("-parallelizeTargets");
|
||||||
|
@@ -335,6 +335,7 @@ protected:
|
|||||||
BuildSystem XcodeBuildSystem = BuildSystem::One;
|
BuildSystem XcodeBuildSystem = BuildSystem::One;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string GetAppleSpecificPlatformName();
|
||||||
std::string const& GetXcodeBuildCommand();
|
std::string const& GetXcodeBuildCommand();
|
||||||
std::string FindXcodeBuildCommand();
|
std::string FindXcodeBuildCommand();
|
||||||
std::string XcodeBuildCommand;
|
std::string XcodeBuildCommand;
|
||||||
|
@@ -178,4 +178,13 @@ endfunction()
|
|||||||
|
|
||||||
BundleLinkBundle()
|
BundleLinkBundle()
|
||||||
|
|
||||||
|
if(XCODE_VERSION VERSION_GREATER_EQUAL 12)
|
||||||
|
block()
|
||||||
|
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeWorkspace-build)
|
||||||
|
run_cmake(XcodeWorkspace)
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
run_cmake_command(XcodeWorkspace-build ${CMAKE_COMMAND} --build . --config Debug)
|
||||||
|
endblock()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Please add device-specific tests to '../XcodeProject-Device/RunCMakeTest.cmake'.
|
# Please add device-specific tests to '../XcodeProject-Device/RunCMakeTest.cmake'.
|
||||||
|
@@ -0,0 +1 @@
|
|||||||
|
xcodebuild -workspace XcodeWorkspace\.xcworkspace build -scheme ALL_BUILD -destination generic/platform=MacOS
|
8
Tests/RunCMake/XcodeProject/XcodeWorkspace.cmake
Normal file
8
Tests/RunCMake/XcodeProject/XcodeWorkspace.cmake
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
enable_language(C)
|
||||||
|
add_executable(main main.c)
|
||||||
|
file(WRITE "${CMAKE_BINARY_DIR}/XcodeWorkspace.xcworkspace/contents.xcworkspacedata" [[
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace version = "1.0">
|
||||||
|
<FileRef location = "container:XcodeWorkspace.xcodeproj"/>
|
||||||
|
</Workspace>
|
||||||
|
]])
|
@@ -0,0 +1,4 @@
|
|||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user