diff --git a/Help/prop_tgt/BUNDLE_EXTENSION.rst b/Help/prop_tgt/BUNDLE_EXTENSION.rst index ea265b373..6b3d58023 100644 --- a/Help/prop_tgt/BUNDLE_EXTENSION.rst +++ b/Help/prop_tgt/BUNDLE_EXTENSION.rst @@ -1,7 +1,8 @@ BUNDLE_EXTENSION ---------------- -The file extension used to name a :prop_tgt:`BUNDLE` target on the OS X and iOS. +The file extension used to name a :prop_tgt:`BUNDLE`, a :prop_tgt:`FRAMEWORK`, +or a :prop_tgt:`MACOSX_BUNDLE` target on the OS X and iOS. -The default value is ``bundle`` - you can also use ``plugin`` or whatever -file extension is required by the host app for your bundle. +The default value is ``bundle``, ``framework``, or ``app`` for the respective +target types. diff --git a/Help/release/dev/app-framework-bundle-extension.rst b/Help/release/dev/app-framework-bundle-extension.rst new file mode 100644 index 000000000..01855a2b0 --- /dev/null +++ b/Help/release/dev/app-framework-bundle-extension.rst @@ -0,0 +1,5 @@ +app-framework-bundle-extension +------------------------------ + +* On Apple platforms the :prop_tgt:`BUNDLE_EXTENSION` now also applies to + Frameworks and App Bundles. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index c9cbd0008..793ad2ec1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1350,7 +1350,12 @@ std::string cmGeneratorTarget::GetAppBundleDirectory(const std::string& config, bool contentOnly) const { std::string fpath = this->GetFullName(config, false); - fpath += ".app"; + fpath += "."; + const char* ext = this->GetProperty("BUNDLE_EXTENSION"); + if (!ext) { + ext = "app"; + } + fpath += ext; if (!this->Makefile->PlatformIsAppleIos()) { fpath += "/Contents"; if (!contentOnly) { @@ -1395,7 +1400,12 @@ std::string cmGeneratorTarget::GetFrameworkDirectory(const std::string& config, { std::string fpath; fpath += this->GetOutputName(config, false); - fpath += ".framework"; + fpath += "."; + const char* ext = this->GetProperty("BUNDLE_EXTENSION"); + if (!ext) { + ext = "framework"; + } + fpath += ext; if (!rootDir && !this->Makefile->PlatformIsAppleIos()) { fpath += "/Versions/"; fpath += this->GetFrameworkVersion(); @@ -3011,7 +3021,13 @@ void cmGeneratorTarget::GetFullNameInternal(const std::string& config, std::string fw_prefix; if (this->IsFrameworkOnApple()) { fw_prefix = this->GetOutputName(config, false); - fw_prefix += ".framework/"; + fw_prefix += "."; + const char* ext = this->GetProperty("BUNDLE_EXTENSION"); + if (!ext) { + ext = "framework"; + } + fw_prefix += ext; + fw_prefix += "/"; targetPrefix = fw_prefix.c_str(); targetSuffix = CM_NULLPTR; } diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 23fad512a..b396ea1e6 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1844,6 +1844,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, std::string fw_version = gtgt->GetFrameworkVersion(); buildSettings->AddAttribute("FRAMEWORK_VERSION", this->CreateString(fw_version)); + const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + if (ext) { + buildSettings->AddAttribute("WRAPPER_EXTENSION", + this->CreateString(ext)); + } std::string plist = this->ComputeInfoPListLocation(gtgt); // Xcode will create the final version of Info.plist at build time, @@ -1878,6 +1883,11 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // Handle bundles and normal executables separately. if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) { + const char* ext = gtgt->GetProperty("BUNDLE_EXTENSION"); + if (ext) { + buildSettings->AddAttribute("WRAPPER_EXTENSION", + this->CreateString(ext)); + } std::string plist = this->ComputeInfoPListLocation(gtgt); // Xcode will create the final version of Info.plist at build time, // so let it replace the executable name. This avoids creating diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 448d27853..4b2f40cb9 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -142,13 +142,22 @@ void cmInstallTargetGenerator::GenerateScriptForConfig( if (this->Target->IsAppBundleOnApple()) { cmMakefile const* mf = this->Target->Target->GetMakefile(); + // Get App Bundle Extension + const char* ext = this->Target->GetProperty("BUNDLE_EXTENSION"); + if (!ext) { + ext = "app"; + } + // Install the whole app bundle directory. type = cmInstallType_DIRECTORY; literal_args += " USE_SOURCE_PERMISSIONS"; - from1 += ".app"; + from1 += "."; + from1 += ext; // Tweaks apply to the binary inside the bundle. - to1 += ".app/"; + to1 += "."; + to1 += ext; + to1 += "/"; if (!mf->PlatformIsAppleIos()) { to1 += "Contents/MacOS/"; } diff --git a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake index b77d5d40e..0684d5798 100644 --- a/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake +++ b/Tests/RunCMake/XcodeProject/RunCMakeTest.cmake @@ -31,13 +31,16 @@ if(NOT XCODE_VERSION VERSION_LESS 5) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeBundlesOSX-build) set(RunCMake_TEST_NO_CLEAN 1) - set(RunCMake_TEST_OPTIONS "-DTEST_IOS=OFF") + set(RunCMake_TEST_OPTIONS + "-DTEST_IOS=OFF" + "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/_install") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -45,13 +48,16 @@ if(NOT XCODE_VERSION VERSION_LESS 5) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeBundlesIOS-build) set(RunCMake_TEST_NO_CLEAN 1) - set(RunCMake_TEST_OPTIONS "-DTEST_IOS=ON") + set(RunCMake_TEST_OPTIONS + "-DTEST_IOS=ON" + "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/_install") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -61,13 +67,16 @@ endif() if(NOT XCODE_VERSION VERSION_LESS 7) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeBundlesWatchOS-build) set(RunCMake_TEST_NO_CLEAN 1) - set(RunCMake_TEST_OPTIONS "-DTEST_WATCHOS=ON") + set(RunCMake_TEST_OPTIONS + "-DTEST_WATCHOS=ON" + "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/_install") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) @@ -77,13 +86,16 @@ endif() if(NOT XCODE_VERSION VERSION_LESS 7.1) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/XcodeBundlesTvOS-build) set(RunCMake_TEST_NO_CLEAN 1) - set(RunCMake_TEST_OPTIONS "-DTEST_TVOS=ON") + set(RunCMake_TEST_OPTIONS + "-DTEST_TVOS=ON" + "-DCMAKE_INSTALL_PREFIX:PATH=${RunCMake_TEST_BINARY_DIR}/_install") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") run_cmake(XcodeBundles) run_cmake_command(XcodeBundles-build ${CMAKE_COMMAND} --build .) + run_cmake_command(XcodeBundles-install ${CMAKE_COMMAND} --build . --target install) unset(RunCMake_TEST_BINARY_DIR) unset(RunCMake_TEST_NO_CLEAN) diff --git a/Tests/RunCMake/XcodeProject/XcodeBundles-install-check.cmake b/Tests/RunCMake/XcodeProject/XcodeBundles-install-check.cmake new file mode 100644 index 000000000..758d73053 --- /dev/null +++ b/Tests/RunCMake/XcodeProject/XcodeBundles-install-check.cmake @@ -0,0 +1,8 @@ +file(GLOB DIRECTORIES LIST_DIRECTORIES true + "${RunCMake_TEST_BINARY_DIR}/_install/FooExtension/*.*") + +foreach(DIRECTORY IN LISTS DIRECTORIES) + if(NOT DIRECTORY MATCHES "\\.foo$") + message(SEND_ERROR "Extension does not match ${DIRECTORY}") + endif() +endforeach() diff --git a/Tests/RunCMake/XcodeProject/XcodeBundles.cmake b/Tests/RunCMake/XcodeProject/XcodeBundles.cmake index 0fdc6af59..ad4268df6 100644 --- a/Tests/RunCMake/XcodeProject/XcodeBundles.cmake +++ b/Tests/RunCMake/XcodeProject/XcodeBundles.cmake @@ -36,6 +36,20 @@ add_custom_target(AppBundleTest ALL add_dependencies(AppBundleTest AppBundle) +# with custom extension + +if (NOT TEST_IOS AND NOT TEST_WATCHOS AND NOT TEST_TVOS) + add_executable(AppBundleExt MACOSX_BUNDLE main.m) + set_target_properties(AppBundleExt PROPERTIES BUNDLE_EXTENSION "foo") + install(TARGETS AppBundleExt BUNDLE DESTINATION FooExtension) + + add_custom_target(AppBundleExtTest ALL + COMMAND ${CMAKE_COMMAND} -E copy + "$" "$.old") + + add_dependencies(AppBundleExtTest AppBundleExt) +endif() + # Framework (not supported for iOS on Xcode < 6) if(NOT TEST_IOS OR NOT XCODE_VERSION VERSION_LESS 6) @@ -47,6 +61,19 @@ if(NOT TEST_IOS OR NOT XCODE_VERSION VERSION_LESS 6) "$" "$.old") add_dependencies(FrameworkTest Framework) + + # with custom extension + + add_library(FrameworkExt SHARED main.c) + set_target_properties(FrameworkExt PROPERTIES FRAMEWORK TRUE) + set_target_properties(FrameworkExt PROPERTIES BUNDLE_EXTENSION "foo") + install(TARGETS FrameworkExt FRAMEWORK DESTINATION FooExtension) + + add_custom_target(FrameworkExtTest ALL + COMMAND ${CMAKE_COMMAND} -E copy + "$" "$.old") + + add_dependencies(FrameworkExtTest FrameworkExt) endif() # Bundle @@ -60,4 +87,17 @@ if(NOT CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE) "$" "$.old") add_dependencies(BundleTest Bundle) + + # with custom extension + + add_library(BundleExt MODULE main.c) + set_target_properties(BundleExt PROPERTIES BUNDLE TRUE) + set_target_properties(BundleExt PROPERTIES BUNDLE_EXTENSION "foo") + install(TARGETS BundleExt LIBRARY DESTINATION FooExtension) + + add_custom_target(BundleExtTest ALL + COMMAND ${CMAKE_COMMAND} -E copy + "$" "$.old") + + add_dependencies(BundleExtTest BundleExt) endif()