Commit 10c9c73d authored by Gregor Jasny's avatar Gregor Jasny Committed by Brad King
Browse files

Xcode: Control emission of EFFECTIVE_PLATFORM_NAME

When building with multiple SDKs within one project Xcode requires
the usage of ${EFFECTIVE_PLATFORM_NAME} to put temporary and build
outout into separate directories. For example an iOS device and
simulator build use two different SDKs (iphoneos and iphonesimulator).

In the past cmake tries to detect embedded toolchains that could
possibly use simulators and emitted EFFECTIVE_PLATFORM_NAME (EPN)
at the proper locations. In #16253 Mark noticed that if he
uses macosx and iphoneos in combination the necessary EPN is not
emitted. This is because CMake by default assumes macosx SDK which
does not trigger EPN emission.

The fist naive approach - enabling EPN unconditionally revealed that
then the EPN leaks into generator expressions like $<TARGET_FILE:xxx>
which might be a regression and thus is unacceptable.

The next approach was to add an CMake property to enable EPN emission
unconditionally. This solved the reported problem.

But the EPN leakage also happened for the embedded toolchains already
without anyone noticing. So the control property was turned into a
tri-state one:

 * No definition: EPN is activated for embedded toolchains like before
 * ON: EPN is always emitted
 * OFF: EPN is never emitted

That approach gives the user the chance to disable EPN for embedded
toolchains and restores generator expression functionality for those.

Closes: #16253
parent fe8e00f6
Pipeline #43709 passed with stage
......@@ -44,6 +44,7 @@ Properties of Global Scope
/prop_gbl/TARGET_MESSAGES
/prop_gbl/TARGET_SUPPORTS_SHARED_LIBS
/prop_gbl/USE_FOLDERS
/prop_gbl/XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
.. _`Directory Properties`:
......
XCODE_EMIT_EFFECTIVE_PLATFORM_NAME
----------------------------------
Control emission of ``EFFECTIVE_PLATFORM_NAME`` by the Xcode generator.
It is required for building the same target with multiple SDKs. A
common use case is the parallel use of ``iphoneos`` and
``iphonesimulator`` SDKs.
Three different states possible that control when the Xcode generator
emits the ``EFFECTIVE_PLATFORM_NAME`` variable:
- If set to ``ON`` it will always be emitted
- If set to ``OFF`` it will never be emitted
- If unset (the default) it will only be emitted when the project was
configured for an embedded Xcode SDK like iOS, tvOS, watchOS or any
of the simulators.
.. note::
When this behavior is enable for generated Xcode projects, the
``EFFECTIVE_PLATFORM_NAME`` variable will leak into
:manual:`Generator expressions <cmake-generator-expressions(7)>`
like ``TARGET_FILE`` and will render those mostly unusable.
xcode-effective-platform-name
-----------------------------
* The Xcode generator can now control emission of the
``EFFECTIVE_PLATFORM_NAME`` variable through the
:prop_gbl:`XCODE_EMIT_EFFECTIVE_PLATFORM_NAME` global property.
This is useful when building with multiple SDKs like macosx and
iphoneos in parallel.
......@@ -4419,9 +4419,10 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config,
// The generator may add the configuration's subdirectory.
if (!conf.empty()) {
bool iosPlatform = this->Makefile->PlatformIsAppleIos();
bool useEPN =
this->GlobalGenerator->UseEffectivePlatformName(this->Makefile);
std::string suffix =
usesDefaultOutputDir && iosPlatform ? "${EFFECTIVE_PLATFORM_NAME}" : "";
usesDefaultOutputDir && useEPN ? "${EFFECTIVE_PLATFORM_NAME}" : "";
this->LocalGenerator->GetGlobalGenerator()->AppendDirectoryForConfig(
"/", conf, suffix, out);
}
......
......@@ -2342,8 +2342,8 @@ void cmGlobalGenerator::AddGlobalTarget_Install(
singleLine.push_back(cmd);
if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') {
std::string cfgArg = "-DBUILD_TYPE=";
bool iosPlatform = mf->PlatformIsAppleIos();
if (iosPlatform) {
bool useEPN = this->UseEffectivePlatformName(mf);
if (useEPN) {
cfgArg += "$(CONFIGURATION)";
singleLine.push_back(cfgArg);
cfgArg = "-DEFFECTIVE_PLATFORM_NAME=$(EFFECTIVE_PLATFORM_NAME)";
......
......@@ -333,6 +333,10 @@ public:
virtual bool UseFolderProperty() const;
/** Return whether the generator should use EFFECTIVE_PLATFORM_NAME. This is
relevant for mixed macOS and iOS builds. */
virtual bool UseEffectivePlatformName(cmMakefile*) const { return false; }
std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
/** Generate an <output>.rule file path for a given command output. */
......
......@@ -22,6 +22,7 @@
#include "cmOutputConverter.h"
#include "cmSourceFile.h"
#include "cmSourceGroup.h"
#include "cmState.h"
#include "cmStateTypes.h"
#include "cmSystemTools.h"
#include "cmTarget.h"
......@@ -3544,6 +3545,19 @@ bool cmGlobalXCodeGenerator::IsMultiConfig() const
return true;
}
bool cmGlobalXCodeGenerator::UseEffectivePlatformName(cmMakefile* mf) const
{
const char* epnValue =
this->GetCMakeInstance()->GetState()->GetGlobalProperty(
"XCODE_EMIT_EFFECTIVE_PLATFORM_NAME");
if (!epnValue) {
return mf->PlatformIsAppleIos();
}
return cmSystemTools::IsOn(epnValue);
}
void cmGlobalXCodeGenerator::ComputeTargetObjectDirectory(
cmGeneratorTarget* gt) const
{
......
......@@ -86,6 +86,8 @@ public:
i.e. "Can I build Debug and Release in the same tree?" */
bool IsMultiConfig() const CM_OVERRIDE;
bool UseEffectivePlatformName(cmMakefile* mf) const CM_OVERRIDE;
bool SetGeneratorToolset(std::string const& ts, cmMakefile* mf) CM_OVERRIDE;
void AppendFlag(std::string& flags, std::string const& flag);
......
......@@ -166,3 +166,24 @@ if(NOT XCODE_VERSION VERSION_LESS 6)
unset(RunCMake_TEST_NO_CLEAN)
unset(RunCMake_TEST_OPTIONS)
endif()
if(NOT XCODE_VERSION VERSION_LESS 5)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeMultiplatform-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(XcodeMultiplatform)
# build ios before macos
run_cmake_command(XcodeMultiplatform-iphonesimulator-build ${CMAKE_COMMAND} --build . -- -sdk iphonesimulator)
run_cmake_command(XcodeMultiplatform-iphonesimulator-install ${CMAKE_COMMAND} --build . --target install -- -sdk iphonesimulator DESTDIR=${RunCMake_TEST_BINARY_DIR}/_install_iphonesimulator)
run_cmake_command(XcodeMultiplatform-macosx-build ${CMAKE_COMMAND} --build . -- -sdk macosx)
run_cmake_command(XcodeMultiplatform-macosx-install ${CMAKE_COMMAND} --build . --target install -- -sdk macosx DESTDIR=${RunCMake_TEST_BINARY_DIR}/_install_macosx)
unset(RunCMake_TEST_BINARY_DIR)
unset(RunCMake_TEST_NO_CLEAN)
unset(RunCMake_TEST_OPTIONS)
endif()
cmake_minimum_required(VERSION 3.3)
enable_language(CXX)
set_property(GLOBAL PROPERTY XCODE_EMIT_EFFECTIVE_PLATFORM_NAME ON)
set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx iphonesimulator")
set(CMAKE_MACOSX_BUNDLE true)
add_library(library STATIC foo.cpp)
add_executable(main main.cpp)
target_link_libraries(main library)
install(TARGETS library ARCHIVE DESTINATION lib)
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