From ad3f69c86eb27abd16d2a8534a7b90d59c0d74ed Mon Sep 17 00:00:00 2001 From: Alexandru Croitor Date: Mon, 27 Jan 2020 11:23:13 +0100 Subject: Add support for FRAMEWORK_MULTI_CONFIG_POSTFIX_ --- Help/manual/cmake-properties.7.rst | 1 + Help/manual/cmake-variables.7.rst | 1 + Help/prop_tgt/CONFIG_POSTFIX.rst | 3 ++ .../FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst | 25 ++++++++++++ .../release/dev/framework-multi-config-postfix.rst | 7 ++++ ...CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst | 8 ++++ Source/cmGeneratorTarget.cxx | 44 +++++++++++++++++++-- Source/cmGeneratorTarget.h | 3 ++ Source/cmNinjaNormalTargetGenerator.cxx | 14 ++++++- Source/cmOSXBundleGenerator.cxx | 26 +++++++------ Source/cmOSXBundleGenerator.h | 12 +++++- Source/cmTarget.cxx | 8 ++++ ...eworkMultiConfigPostfix-build-final-check.cmake | 45 ++++++++++++++++++++++ .../Framework/FrameworkMultiConfigPostfix.cmake | 25 ++++++++++++ Tests/RunCMake/Framework/RunCMakeTest.cmake | 36 +++++++++++++++++ 15 files changed, 240 insertions(+), 18 deletions(-) create mode 100644 Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst create mode 100644 Help/release/dev/framework-multi-config-postfix.rst create mode 100644 Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst create mode 100644 Tests/RunCMake/Framework/FrameworkMultiConfigPostfix-build-final-check.cmake create mode 100644 Tests/RunCMake/Framework/FrameworkMultiConfigPostfix.cmake diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 37f8678..15f0cfc 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -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 diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index a639b5d..7696fd9 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -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 diff --git a/Help/prop_tgt/CONFIG_POSTFIX.rst b/Help/prop_tgt/CONFIG_POSTFIX.rst index 11b50b9..5c2fbd7 100644 --- a/Help/prop_tgt/CONFIG_POSTFIX.rst +++ b/Help/prop_tgt/CONFIG_POSTFIX.rst @@ -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__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_` +target property. diff --git a/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst new file mode 100644 index 0000000..2b20bf9 --- /dev/null +++ b/Help/prop_tgt/FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst @@ -0,0 +1,25 @@ +FRAMEWORK_MULTI_CONFIG_POSTFIX_ +--------------------------------------- + +Postfix to append to the framework file name for configuration , +when using a multi-config generator (like Xcode and Ninja Multi-Config). + +When building with configuration 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_` 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_` if it +is set when a target is created. + +This property is ignored for non-framework targets, and when using single +config generators. diff --git a/Help/release/dev/framework-multi-config-postfix.rst b/Help/release/dev/framework-multi-config-postfix.rst new file mode 100644 index 0000000..50cf9ce --- /dev/null +++ b/Help/release/dev/framework-multi-config-postfix.rst @@ -0,0 +1,7 @@ +framework-multi-config-postfix +------------------------------ + +* The :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_` target property + and associated :variable:`CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_` + variable were created to allow adding a postfix to the name of a + framework file name when using a multi-config generator. diff --git a/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst b/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst new file mode 100644 index 0000000..5c7cd23 --- /dev/null +++ b/Help/variable/CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_CONFIG.rst @@ -0,0 +1,8 @@ +CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_ +--------------------------------------------- + +Default framework filename postfix under configuration ```` when +using a multi-config generator. + +When a framework target is created its :prop_tgt:`FRAMEWORK_MULTI_CONFIG_POSTFIX_` +target property is initialized with the value of this variable if it is set. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 0509960..ad142d7 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -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")) { diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 9f90cec..12d30c5 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -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. */ diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 0a6da91..ece958c 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -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, diff --git a/Source/cmOSXBundleGenerator.cxx b/Source/cmOSXBundleGenerator.cxx index 382b563..7eea4b2 100644 --- a/Source/cmOSXBundleGenerator.cxx +++ b/Source/cmOSXBundleGenerator.cxx @@ -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()) { diff --git a/Source/cmOSXBundleGenerator.h b/Source/cmOSXBundleGenerator.h index 232be48..5bf1d98 100644 --- a/Source/cmOSXBundleGenerator.h +++ b/Source/cmOSXBundleGenerator.h @@ -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, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 97d7fce..987f526 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -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); + } } } diff --git a/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix-build-final-check.cmake b/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix-build-final-check.cmake new file mode 100644 index 0000000..76fe6b8 --- /dev/null +++ b/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix-build-final-check.cmake @@ -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() diff --git a/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix.cmake b/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix.cmake new file mode 100644 index 0000000..51e627d --- /dev/null +++ b/Tests/RunCMake/Framework/FrameworkMultiConfigPostfix.cmake @@ -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 \"$\")\n" + "set(target_file_name ${target_name})\n") +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/FrameworkMultiConfigPostfixInfo.cmake + CONTENT "${content}") diff --git a/Tests/RunCMake/Framework/RunCMakeTest.cmake b/Tests/RunCMake/Framework/RunCMakeTest.cmake index 965fbf4..6ee61a3 100644 --- a/Tests/RunCMake/Framework/RunCMakeTest.cmake +++ b/Tests/RunCMake/Framework/RunCMakeTest.cmake @@ -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() -- cgit v0.12