Add support for FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>

This commit is contained in:
Alexandru Croitor 2020-01-27 11:23:13 +01:00
parent d016637eef
commit ad3f69c86e
15 changed files with 240 additions and 18 deletions

View File

@ -200,6 +200,7 @@ Properties on Targets
/prop_tgt/Fortran_FORMAT
/prop_tgt/Fortran_MODULE_DIRECTORY
/prop_tgt/FRAMEWORK
/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG
/prop_tgt/FRAMEWORK_VERSION
/prop_tgt/GENERATOR_FILE_NAME
/prop_tgt/GHS_INTEGRITY_APP

View File

@ -388,6 +388,7 @@ Variables that Control the Build
/variable/CMAKE_EXE_LINKER_FLAGS_INIT
/variable/CMAKE_FOLDER
/variable/CMAKE_FRAMEWORK
/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG
/variable/CMAKE_Fortran_FORMAT
/variable/CMAKE_Fortran_MODULE_DIRECTORY
/variable/CMAKE_GHS_NO_SOURCE_GROUP_FILE

View File

@ -8,3 +8,6 @@ is appended to the target file name built on disk. For non-executable
targets, this property is initialized by the value of the variable
CMAKE_<CONFIG>_POSTFIX if it is set when a target is created. This
property is ignored on the Mac for Frameworks and App Bundles.
For macOS see also the :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
target property.

View File

@ -0,0 +1,25 @@
FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>
---------------------------------------
Postfix to append to the framework file name for configuration <CONFIG>,
when using a multi-config generator (like Xcode and Ninja Multi-Config).
When building with configuration <CONFIG> the value of this property
is appended to the framework file name built on disk.
For example given a framework called ``my_fw``, a value of ``_debug``
for the :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` property, and
``Debug;Release`` in `CMAKE_CONFIGURATION_TYPES`, the following relevant
files would be created for the ``Debug`` and ``Release`` configurations:
- Release/my_fw.framework/my_fw
- Release/my_fw.framework/Versions/A/my_fw
- Debug/my_fw.framework/my_fw_debug
- Debug/my_fw.framework/Versions/A/my_fw_debug
For framework targets, this property is initialized by the value of the
variable :variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` if it
is set when a target is created.
This property is ignored for non-framework targets, and when using single
config generators.

View File

@ -0,0 +1,7 @@
framework-multi-config-postfix
------------------------------
* The :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>` target property
and associated :variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
variable were created to allow adding a postfix to the name of a
framework file name when using a multi-config generator.

View File

@ -0,0 +1,8 @@
CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>
---------------------------------------------
Default framework filename postfix under configuration ``<CONFIG>`` when
using a multi-config generator.
When a framework target is created its :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_<CONFIG>`
target property is initialized with the value of this variable if it is set.

View File

@ -539,15 +539,43 @@ std::string cmGeneratorTarget::GetFileSuffix(
std::string cmGeneratorTarget::GetFilePostfix(const std::string& config) const
{
const char* postfix = nullptr;
std::string frameworkPostfix;
if (!config.empty()) {
std::string configProp =
cmStrCat(cmSystemTools::UpperCase(config), "_POSTFIX");
postfix = this->GetProperty(configProp);
// Mac application bundles and frameworks have no postfix.
// Mac application bundles and frameworks have no regular postfix like
// libraries do.
if (!this->IsImported() && postfix &&
(this->IsAppBundleOnApple() || this->IsFrameworkOnApple())) {
postfix = nullptr;
}
// Frameworks created by multi config generators can have a special
// framework postfix.
frameworkPostfix = GetFrameworkMultiConfigPostfix(config);
if (!frameworkPostfix.empty()) {
postfix = frameworkPostfix.c_str();
}
}
return postfix ? postfix : std::string();
}
std::string cmGeneratorTarget::GetFrameworkMultiConfigPostfix(
const std::string& config) const
{
const char* postfix = nullptr;
if (!config.empty()) {
std::string configProp = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
cmSystemTools::UpperCase(config));
postfix = this->GetProperty(configProp);
if (!this->IsImported() && postfix &&
(this->IsFrameworkOnApple() &&
!GetGlobalGenerator()->IsMultiConfig())) {
postfix = nullptr;
}
}
return postfix ? postfix : std::string();
}
@ -4241,8 +4269,8 @@ cmGeneratorTarget::Names cmGeneratorTarget::GetLibraryNames(
targetNames.Real += this->GetFrameworkVersion();
targetNames.Real += "/";
}
targetNames.Real += targetNames.Base;
targetNames.SharedObject = targetNames.Real;
targetNames.Real += targetNames.Base + suffix;
targetNames.SharedObject = targetNames.Real + suffix;
} else {
// The library's soname.
this->ComputeVersionedName(targetNames.SharedObject, prefix,
@ -4417,7 +4445,15 @@ void cmGeneratorTarget::GetFullNameInternal(
outBase += this->GetOutputName(config, artifact);
// Append the per-configuration postfix.
outBase += configPostfix;
// When using Xcode, the postfix should be part of the suffix rather than the
// base, because the suffix ends up being used in Xcode's EXECUTABLE_SUFFIX
// attribute.
if (this->IsFrameworkOnApple() &&
GetGlobalGenerator()->GetName() == "Xcode") {
targetSuffix = configPostfix.c_str();
} else {
outBase += configPostfix;
}
// Name shared libraries with their version number on some platforms.
if (const char* soversion = this->GetProperty("SOVERSION")) {

View File

@ -588,6 +588,9 @@ public:
/** Get target file postfix */
std::string GetFilePostfix(const std::string& config) const;
/** Get framework multi-config-specific postfix */
std::string GetFrameworkMultiConfigPostfix(const std::string& config) const;
/** Clears cached meta data for local and external source files.
* The meta data will be recomputed on demand.
*/

View File

@ -812,8 +812,20 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
} else if (gt->IsFrameworkOnApple()) {
// Create the library framework.
cmOSXBundleGenerator::SkipParts bundleSkipParts;
if (globalGen->GetName() == "Ninja Multi-Config") {
const auto postFix = this->GeneratorTarget->GetFilePostfix(config);
// Skip creating Info.plist when there are multiple configurations, and
// the current configuration has a postfix. The non-postfix configuration
// Info.plist can be used by all the other configurations.
if (!postFix.empty()) {
bundleSkipParts.infoPlist = true;
}
}
this->OSXBundleGenerator->CreateFramework(
tgtNames.Output, gt->GetDirectory(config), config);
tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts);
} else if (gt->IsCFBundleOnApple()) {
// Create the core foundation bundle.
this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output,

View File

@ -56,9 +56,9 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
outpath = out;
}
void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
const std::string& outpath,
const std::string& config)
void cmOSXBundleGenerator::CreateFramework(
const std::string& targetName, const std::string& outpath,
const std::string& config, const cmOSXBundleGenerator::SkipParts& skipParts)
{
if (this->MustSkip()) {
return;
@ -77,16 +77,18 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
std::string frameworkVersion = this->GT->GetFrameworkVersion();
// Configure the Info.plist file
std::string plist = newoutpath;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
// Put the Info.plist file into the Resources directory.
this->MacContentFolders->insert("Resources");
plist += "/Resources";
}
plist += "/Info.plist";
std::string name = cmSystemTools::GetFilenameName(targetName);
this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
if (!skipParts.infoPlist) {
// Configure the Info.plist file
std::string plist = newoutpath;
if (!this->Makefile->PlatformIsAppleEmbedded()) {
// Put the Info.plist file into the Resources directory.
this->MacContentFolders->insert("Resources");
plist += "/Resources";
}
plist += "/Info.plist";
this->LocalGenerator->GenerateFrameworkInfoPList(this->GT, name, plist);
}
// Generate Versions directory only for MacOSX frameworks
if (this->Makefile->PlatformIsAppleEmbedded()) {

View File

@ -19,6 +19,15 @@ class cmOSXBundleGenerator
public:
cmOSXBundleGenerator(cmGeneratorTarget* target);
struct SkipParts
{
SkipParts()
: infoPlist(false)
{
}
bool infoPlist; // NOLINT(modernize-use-default-member-init)
};
// create an app bundle at a given root, and return
// the directory within the bundle that contains the executable
void CreateAppBundle(const std::string& targetName, std::string& root,
@ -26,7 +35,8 @@ public:
// create a framework at a given root
void CreateFramework(const std::string& targetName, const std::string& root,
const std::string& config);
const std::string& config,
const SkipParts& skipParts = SkipParts());
// create a cf bundle at a given root
void CreateCFBundle(const std::string& targetName, const std::string& root,

View File

@ -300,6 +300,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("PDB_OUTPUT_DIRECTORY");
initProp("COMPILE_PDB_OUTPUT_DIRECTORY");
initProp("FRAMEWORK");
initProp("FRAMEWORK_MULTI_CONFIG_POSTFIX");
initProp("Fortran_FORMAT");
initProp("Fortran_MODULE_DIRECTORY");
initProp("Fortran_COMPILER_LAUNCHER");
@ -435,6 +436,13 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
cmStrCat(cmSystemTools::UpperCase(configName), "_POSTFIX");
initProp(property);
}
if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
impl->TargetType == cmStateEnums::STATIC_LIBRARY) {
std::string property = cmStrCat("FRAMEWORK_MULTI_CONFIG_POSTFIX_",
cmSystemTools::UpperCase(configName));
initProp(property);
}
}
}

View File

@ -0,0 +1,45 @@
include("${RunCMake_TEST_BINARY_DIR}/FrameworkMultiConfigPostfixInfo.cmake")
get_filename_component(framework_location "${framework_dir}" DIRECTORY)
set(non_existent_debug_framework_dir "${framework_location}/${target_file_name}_debug.framework")
set(framework_resources "${framework_dir}/Resources")
set(plist_file "${framework_resources}/Info.plist")
set(symlink_release_path "${framework_dir}/${target_file_name}")
set(framework_release_path "${framework_dir}/Versions/A/${target_file_name}")
# When using a multi config generator (like Ninja Multi-Config and Xcode),
# the postfix will be applied to the debug framework library name and the symlink name.
# For single config generators, the name stays the same as the the release framework.
if(is_multi_config)
set(symlink_debug_path "${framework_dir}/${target_file_name}_debug")
set(framework_debug_path "${framework_dir}/Versions/A/${target_file_name}_debug")
else()
set(symlink_debug_path "${framework_dir}/${target_file_name}")
set(framework_debug_path "${framework_dir}/Versions/A/${target_file_name}")
endif()
if(NOT IS_DIRECTORY ${framework_dir})
message(SEND_ERROR "Framework dir not found at ${framework_dir}")
endif()
if(IS_DIRECTORY ${non_existent_debug_framework_dir})
message(SEND_ERROR
"A framework dir with a debug suffix should not exist at ${non_existent_debug_framework_dir}")
endif()
if(NOT IS_SYMLINK "${symlink_release_path}")
message(SEND_ERROR "Release framework symlink not found at ${symlink_release_path}")
endif()
if(NOT IS_SYMLINK "${symlink_debug_path}")
message(SEND_ERROR "Debug framework symlink not found at ${symlink_debug_path}")
endif()
if(NOT EXISTS "${framework_release_path}")
message(SEND_ERROR "Release framework not found at ${framework_release_path}")
endif()
if(NOT EXISTS "${framework_debug_path}")
message(SEND_ERROR "Debug framework not found at ${framework_debug_path}")
endif()

View File

@ -0,0 +1,25 @@
enable_language(C)
set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_DEBUG "_debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(target_name "mylib")
add_library(${target_name} SHARED foo.c)
set_property(TARGET ${target_name} PROPERTY FRAMEWORK ON)
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
string(APPEND content
"set(is_multi_config \"${is_multi_config}\")\n"
"set(framework_dir \"$<TARGET_BUNDLE_DIR:${target_name}>\")\n"
"set(target_file_name ${target_name})\n")
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/FrameworkMultiConfigPostfixInfo.cmake
CONTENT "${content}")

View File

@ -45,3 +45,39 @@ framework_type_test(ios SHARED YES)
framework_type_test(ios STATIC YES)
framework_type_test(osx SHARED YES)
framework_type_test(osx STATIC YES)
function(framework_multi_config_postfix_test)
set(configure_name "FrameworkMultiConfigPostfix")
set(build_name "${configure_name}-build-intermediate")
set(build_name_final "${configure_name}-build-final")
if(RunCMake_GENERATOR MATCHES "Ninja Multi-Config")
set(RunCMake_TEST_OPTIONS
"-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release;-DCMAKE_CROSS_CONFIGS=all")
elseif(RunCMake_GENERATOR MATCHES "Xcode")
set(RunCMake_TEST_OPTIONS
"-DCMAKE_CONFIGURATION_TYPES=Debug\\;Release")
else()
set(RunCMake_TEST_OPTIONS "-DCMAKE_BUILD_TYPE=Debug")
endif()
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${configure_name})
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${configure_name})
unset(RunCMake_TEST_OPTIONS)
if(RunCMake_GENERATOR MATCHES "Ninja Multi-Config")
run_cmake_command(${build_name_final} ${CMAKE_COMMAND} --build . --target all:all)
elseif(RunCMake_GENERATOR MATCHES "Xcode")
run_cmake_command(${build_name} ${CMAKE_COMMAND} --build . --config Release)
run_cmake_command(${build_name} ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(${build_name_final} ${CMAKE_COMMAND} --build . --config Debug)
else()
run_cmake_command(${build_name_final} ${CMAKE_COMMAND} --build .)
endif()
endfunction()
framework_multi_config_postfix_test()