[cmake-developers] [PATCH 3/4] Add handling for XCTest bundles
Gregor Jasny
gjasny at googlemail.com
Tue Dec 16 16:22:09 EST 2014
An XCTest bundle is a CFBundle with a special product-type and bundle
extension. It gets loaded directly into the AppBundle
it should test. For more information about XCTest visit the Mac
Developer library at:
http://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/testing_with_xcode/
To build a XCTest bundle, you need to create a CFBundle and set the
XCTEST property. Additionally you need to specify the application
target to test within the XCTEST_HOST property. CMake
and Xcode will then setup the correct target dependencies.
add_library(CocoaExampleTest MODULE ...)
set_target_properties(CocoaExampleTest PROPERTIES
XCTEST TRUE
XCTEST_HOST CocoaExample)
Signed-off-by: Gregor Jasny <gjasny at googlemail.com>
---
Help/manual/cmake-properties.7.rst | 2 ++
Help/prop_tgt/XCTEST.rst | 11 +++++++
Help/prop_tgt/XCTEST_HOST.rst | 8 +++++
Source/cmGlobalXCodeGenerator.cxx | 67 ++++++++++++++++++++++++++++++++++++--
Source/cmTarget.cxx | 19 +++++++++--
Source/cmTarget.h | 3 ++
6 files changed, 106 insertions(+), 4 deletions(-)
create mode 100644 Help/prop_tgt/XCTEST.rst
create mode 100644 Help/prop_tgt/XCTEST_HOST.rst
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index cca6d28..7b8aa66 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -242,6 +242,8 @@ Properties on Targets
/prop_tgt/VS_WINRT_REFERENCES
/prop_tgt/WIN32_EXECUTABLE
/prop_tgt/XCODE_ATTRIBUTE_an-attribute
+ /prop_tgt/XCTEST
+ /prop_tgt/XCTEST_HOST
Properties on Tests
===================
diff --git a/Help/prop_tgt/XCTEST.rst b/Help/prop_tgt/XCTEST.rst
new file mode 100644
index 0000000..9086485
--- /dev/null
+++ b/Help/prop_tgt/XCTEST.rst
@@ -0,0 +1,11 @@
+XCTEST
+------
+
+This target is a XCTest CFBundle on the Mac.
+
+If a module library target has this property set to true it will be
+built as a CFBundle when built on the mac. It will have the directory
+structure required for a CFBundle.
+
+This property implies :prop_tgt:`BUNDLE` and also requires the
+:prop_tgt:`XCTEST_HOST` property to be set.
diff --git a/Help/prop_tgt/XCTEST_HOST.rst b/Help/prop_tgt/XCTEST_HOST.rst
new file mode 100644
index 0000000..5284246
--- /dev/null
+++ b/Help/prop_tgt/XCTEST_HOST.rst
@@ -0,0 +1,8 @@
+XCTEST_HOST
+-----------
+
+XCTest works by injecting an XCTest CFBundle directly into an AppBundle.
+This property names this destination target under test.
+
+This property is only useful with the Xcode Generator and also needs the
+:prop_tgt:`XCTEST` property enabled on the target.
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 6a480a9..7a71e70 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -493,6 +493,15 @@ cmGlobalXCodeGenerator::AddExtraTargets(cmLocalGenerator* root,
allbuild->AddUtility(target.GetName());
}
+ if(target.IsXCTestOnApple())
+ {
+ const char *testHostName = target.GetProperty("XCTEST_HOST");
+ if(testHostName && this->CurrentMakefile->FindTargetToUse(testHostName))
+ {
+ target.AddUtility(testHostName);
+ }
+ }
+
// Refer to the build configuration file for easy editing.
listfile = lg->GetMakefile()->GetStartDirectory();
listfile += "/";
@@ -761,6 +770,10 @@ GetSourcecodeValueFromFileExtension(const std::string& _ext,
{
sourcecode = "compiled.mach-o.objfile";
}
+ else if(ext == "xctest")
+ {
+ sourcecode = "wrapper.cfbundle";
+ }
else if(ext == "xib")
{
keepLastKnownFileType = true;
@@ -2321,6 +2334,52 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
this->CreateString(vso.str().c_str()));
}
+
+ if(target.IsXCTestOnApple())
+ {
+ if(this->XcodeVersion < 50)
+ {
+ this->CMakeInstance->IssueMessage(cmake::WARNING,
+ "Xcode 5.0 or later is required for XCTEST support.",
+ target.GetBacktrace());
+ }
+
+ const char *testHostName = target.GetProperty("XCTEST_HOST");
+ if(!testHostName)
+ {
+ this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR,
+ "target has XCTEST property but no XCTEST_HOST one.",
+ target.GetBacktrace());
+ return;
+ }
+
+ cmTarget *testHostTarget =
+ this->CurrentMakefile->FindTargetToUse(testHostName);
+ if(!testHostTarget)
+ {
+ cmOStringStream e;
+ e << "Cannot find XCTEST_HOST target: " << testHostName;
+ this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR,
+ e.str(), target.GetBacktrace());
+ return;
+ }
+
+ if (!testHostTarget->IsAppBundleOnApple())
+ {
+ cmOStringStream e;
+ e << "XCTEST_HOST target " << testHostName;
+ e << " is not an App Bundle";
+ this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR,
+ e.str(), target.GetBacktrace());
+ return;
+ }
+
+ buildSettings->AddAttribute("BUNDLE_LOADER",
+ this->CreateString("$(TEST_HOST)"));
+ buildSettings->AddAttribute("TEST_HOST",
+ this->CreateString(testHostTarget->GetLocationForBuild()));
+ }
+
// put this last so it can override existing settings
// Convert "XCODE_ATTRIBUTE_*" properties directly.
{
@@ -2519,7 +2578,9 @@ const char* cmGlobalXCodeGenerator::GetTargetFileType(cmTarget& cmtarget)
case cmTarget::STATIC_LIBRARY:
return "archive.ar";
case cmTarget::MODULE_LIBRARY:
- if (cmtarget.IsCFBundleOnApple())
+ if (cmtarget.IsXCTestOnApple())
+ return "wrapper.cfbundle";
+ else if (cmtarget.IsCFBundleOnApple())
return "wrapper.plug-in";
else
return ((this->XcodeVersion >= 22)?
@@ -2543,7 +2604,9 @@ const char* cmGlobalXCodeGenerator::GetTargetProductType(cmTarget& cmtarget)
case cmTarget::STATIC_LIBRARY:
return "com.apple.product-type.library.static";
case cmTarget::MODULE_LIBRARY:
- if (cmtarget.IsCFBundleOnApple())
+ if (cmtarget.IsXCTestOnApple())
+ return "com.apple.product-type.bundle.unit-test";
+ else if (cmtarget.IsCFBundleOnApple())
return "com.apple.product-type.bundle";
else
return ((this->XcodeVersion >= 22)?
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 90295c8..db1d0f2 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -624,7 +624,15 @@ bool cmTarget::IsCFBundleOnApple() const
{
return (this->GetType() == cmTarget::MODULE_LIBRARY &&
this->Makefile->IsOn("APPLE") &&
- this->GetPropertyAsBool("BUNDLE"));
+ (this->GetPropertyAsBool("BUNDLE") ||
+ this->GetPropertyAsBool("XCTEST")));
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::IsXCTestOnApple() const
+{
+ return (this->IsCFBundleOnApple() &&
+ this->GetPropertyAsBool("XCTEST"));
}
//----------------------------------------------------------------------------
@@ -6842,7 +6850,14 @@ std::string cmTarget::GetCFBundleDirectory(const std::string& config,
const char *ext = this->GetProperty("BUNDLE_EXTENSION");
if (!ext)
{
- ext = "bundle";
+ if (this->IsXCTestOnApple())
+ {
+ ext = "xctest";
+ }
+ else
+ {
+ ext = "bundle";
+ }
}
fpath += ext;
fpath += "/Contents";
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index a3ecca0..5786d78 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -526,6 +526,9 @@ public:
/** Return whether this target is a CFBundle (plugin) on Apple. */
bool IsCFBundleOnApple() const;
+ /** Return whether this target is a XCTest on Apple. */
+ bool IsXCTestOnApple() const;
+
/** Return whether this target is an executable Bundle on Apple. */
bool IsAppBundleOnApple() const;
--
1.9.3 (Apple Git-50)
More information about the cmake-developers
mailing list