On 28-Oct-15 00:56, Gregor Jasny wrote:
Hello,

I hope to have finished the review by end of this week.

On 25/10/15 15:34, Ruslan Baratov wrote:
+  set(cmd lipo -info "${filename}")
Minor nitpick: lipo should probably be called via xcrun. Otherwise it
might not know how to handle new architectures.
Fixed, rebased patches attached.

Ruslo


>From 75bed9fc6f7597e280b63023323cfe5c3ad6a0c1 Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Thu, 8 Oct 2015 03:09:34 +0300
Subject: [PATCH 1/3] Get target name for universal iOS library install

Add method GetTargetNameForUniversalIosInstall to cmInstallTargetGenerator.

This method will return target name if:
 * Platform is iOS
 * Generator is Xcode
 * Target is library
 * CMake variable CMAKE_IOS_INSTALL_UNIVERSAL_LIBS or target property
   IOS_INSTALL_UNIVERSAL_LIBS is ON

Otherwise an empty string will be returned.
---
 Source/cmInstallTargetGenerator.cxx | 42 +++++++++++++++++++++++++++++++++++++
 Source/cmInstallTargetGenerator.h   |  5 +++++
 2 files changed, 47 insertions(+)

diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index 59d06f6..a5c1ebd 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -861,3 +861,45 @@ cmInstallTargetGenerator::AddRanlibRule(std::ostream& os,
   os << indent << "execute_process(COMMAND \""
      << ranlib << "\" \"" << toDestDirPath << "\")\n";
 }
+
+std::string
+cmInstallTargetGenerator
+::GetTargetNameForUniversalIosInstall(cmInstallType type) const
+{
+  cmMakefile const* mf = this->Target->Target->GetMakefile();
+  if(!mf->PlatformIsAppleIos())
+    {
+    return "";
+    }
+
+  switch(type)
+    {
+    case cmInstallType_STATIC_LIBRARY:
+    case cmInstallType_SHARED_LIBRARY:
+    case cmInstallType_MODULE_LIBRARY:
+      break;
+    default:
+      return "";
+    }
+
+  const char* xcode = mf->GetDefinition("XCODE");
+  if(cmSystemTools::IsOff(xcode))
+    {
+    // Xcode only
+    return "";
+    }
+
+  if(this->Target->Target->GetPropertyAsBool("IOS_INSTALL_UNIVERSAL_LIBS"))
+    {
+    return this->Target->GetName();
+    }
+
+  const char* var = "CMAKE_IOS_INSTALL_UNIVERSAL_LIBS";
+  const char* flag = mf->GetDefinition(var);
+  if (cmSystemTools::IsOff(flag))
+    {
+    return "";
+    }
+
+  return this->Target->GetName();
+}
diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h
index ec89c05..10a1be4 100644
--- a/Source/cmInstallTargetGenerator.h
+++ b/Source/cmInstallTargetGenerator.h
@@ -108,6 +108,11 @@ protected:
   NamelinkModeType NamelinkMode;
   bool ImportLibrary;
   bool Optional;
+
+ private:
+  /** Get target name for installing universal iOS library. If target is not
+      an iOS library or universal build is disabled return empty string. */
+  std::string GetTargetNameForUniversalIosInstall(cmInstallType type) const;
 };
 
 #endif
-- 
1.9.3 (Apple Git-50)

>From 8081f5d3ef8d48da55c7930c72fcb345593ea33e Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Wed, 28 Oct 2015 06:08:43 +0600
Subject: [PATCH 2/3]  CMake module for universal iOS library install

 Add CMake module with function `install_universal_ios_library`.
 Target name and destination passed to the function. This function will be run
 after library installed: will trigger additional build instructions for missing
 platform and fuse libraries into universal in destination directory.

 Module designed to be used in `cmake_install.cmake` script.
---
 Modules/install_universal_ios_library.cmake | 352 ++++++++++++++++++++++++++++
 1 file changed, 352 insertions(+)
 create mode 100644 Modules/install_universal_ios_library.cmake

diff --git a/Modules/install_universal_ios_library.cmake b/Modules/install_universal_ios_library.cmake
new file mode 100644
index 0000000..fca1c3d
--- /dev/null
+++ b/Modules/install_universal_ios_library.cmake
@@ -0,0 +1,352 @@
+#=============================================================================
+# Copyright 2014-2015 Ruslan Baratov
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Function to print messages of this module
+function(install_universal_ios_message str)
+  message("[iOS universal] ${str}")
+endfunction()
+
+# Get build settings for the current target/config/SDK by running
+# `xcodebuild -sdk ... -showBuildSettings` and parsing it's output
+function(install_universal_ios_get sdk variable resultvar)
+  if("${sdk}" STREQUAL "")
+    message(FATAL_ERROR "`sdk` is empty")
+  endif()
+
+  if("${variable}" STREQUAL "")
+    message(FATAL_ERROR "`variable` is empty")
+  endif()
+
+  if("${resultvar}" STREQUAL "")
+    message(FATAL_ERROR "`resultvar` is empty")
+  endif()
+
+  set(
+      cmd
+      xcodebuild -showBuildSettings
+      -sdk "${sdk}"
+      -target "${CURRENT_TARGET}"
+      -config "${CURRENT_CONFIG}"
+  )
+
+  execute_process(
+      COMMAND ${cmd}
+      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE output
+  )
+
+  if(NOT result EQUAL 0)
+    message(FATAL_ERROR "Command failed (${result}): ${cmd}")
+  endif()
+
+  string(REPLACE "\n" ";" output "${output}")
+
+  set(var_pattern "    ${variable} = ")
+  string(LENGTH "${var_pattern}" var_pattern_len)
+
+  set(result "")
+  foreach(x ${output})
+    string(FIND "${x}" "${var_pattern}" index)
+    if(index EQUAL 0)
+      if(NOT "${result}" STREQUAL "")
+        message(FATAL_ERROR "${variable} already found: ${result}")
+      endif()
+      string(SUBSTRING "${x}" "${var_pattern_len}" -1 result)
+      if("${result}" STREQUAL "")
+        message(FATAL_ERROR "Empty value of variable: ${variable}")
+      endif()
+    endif()
+  endforeach()
+
+  set("${resultvar}" "${result}" PARENT_SCOPE)
+endfunction()
+
+# Get architectures of given SDK (iphonesimulator/iphoneos)
+function(install_universal_ios_get_archs sdk resultvar)
+  cmake_policy(SET CMP0007 NEW)
+
+  if("${resultvar}" STREQUAL "")
+    message(FATAL_ERROR "`resultvar` is empty")
+  endif()
+
+  install_universal_ios_get("${sdk}" "VALID_ARCHS" valid_archs)
+
+  string(REPLACE " " ";" valid_archs "${valid_archs}")
+
+  list(REMOVE_ITEM valid_archs "") # remove empty elements
+  list(REMOVE_DUPLICATES valid_archs)
+
+  set("${resultvar}" "${valid_archs}" PARENT_SCOPE)
+endfunction()
+
+# Final target can contain more architectures that specified by SDK. This
+# function will run 'lipo -info' and parse output. Result will be returned
+# as a CMake list.
+function(install_universal_ios_get_real_archs filename resultvar)
+  set(cmd "${_lipo_path}" -info "${filename}")
+  execute_process(
+      COMMAND ${cmd}
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE output
+      ERROR_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_STRIP_TRAILING_WHITESPACE
+  )
+  if(NOT result EQUAL 0)
+    message(
+        FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
+    )
+  endif()
+
+  # 'lipo -info' succeeded, check file has only one architecture
+  string(
+      REGEX
+      REPLACE ".*Non-fat file: .* is architecture: " ""
+      single_arch
+      "${output}"
+  )
+  if(NOT "${single_arch}" STREQUAL "${output}")
+    # REGEX matches
+    string(REPLACE " " ";" single_arch "${single_arch}")
+    list(LENGTH single_arch len)
+    if(NOT len EQUAL 1)
+      message(FATAL_ERROR "Expected one architecture for output: ${output}")
+    endif()
+    set(${resultvar} "${single_arch}" PARENT_SCOPE)
+    return()
+  endif()
+
+  # 'lipo -info' succeeded, check file has multiple architectures
+  string(
+      REGEX
+      REPLACE "^Architectures in the fat file: .* are: " ""
+      architectures
+      "${output}"
+  )
+  if("${architectures}" STREQUAL "${output}")
+    # REGEX doesn't match
+    message(FATAL_ERROR "Unexpected output: ${output}")
+  endif()
+  string(REPLACE " " ";" architectures "${architectures}")
+  list(LENGTH architectures len)
+  if(len EQUAL 0 OR len EQUAL 1)
+    message(FATAL_ERROR "Expected >1 architecture for output: ${output}")
+  endif()
+  set(${resultvar} "${architectures}" PARENT_SCOPE)
+endfunction()
+
+# Run build command for the given SDK
+function(install_universal_ios_build sdk)
+  if("${sdk}" STREQUAL "")
+    message(FATAL_ERROR "`sdk` is empty")
+  endif()
+
+  install_universal_ios_message("Build `${CURRENT_TARGET}` for `${sdk}`")
+
+  execute_process(
+      COMMAND
+      "${CMAKE_COMMAND}"
+      --build
+      .
+      --target "${CURRENT_TARGET}"
+      --config ${CURRENT_CONFIG}
+      --
+      -sdk "${sdk}"
+      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+      RESULT_VARIABLE result
+  )
+
+  if(NOT result EQUAL 0)
+    message(FATAL_ERROR "Build failed")
+  endif()
+endfunction()
+
+# Remove given architecture from file. This step needed only in rare cases
+# when target was built in "unusual" way. Emit warning message.
+function(install_universal_ios_remove_arch lib arch)
+  set(msg_p1 "Warning! Unexpected architecture `${arch}` detected")
+  set(msg_p2 "and will be removed from file `${lib}`")
+  install_universal_ios_message("${msg_p1} ${msg_p2}")
+  set(cmd "${_lipo_path}" -remove ${arch} -output ${lib} ${lib})
+  execute_process(
+      COMMAND ${cmd}
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE output
+      ERROR_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_STRIP_TRAILING_WHITESPACE
+  )
+  if(NOT result EQUAL 0)
+    message(
+        FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
+    )
+  endif()
+endfunction()
+
+# Check that 'lib' contains only 'archs' architectures (remove others).
+function(install_universal_ios_keep_archs lib archs)
+  install_universal_ios_get_real_archs("${lib}" real_archs)
+  set(archs_to_remove ${real_archs})
+  list(REMOVE_ITEM archs_to_remove ${archs})
+  foreach(x ${archs_to_remove})
+    install_universal_ios_remove_arch("${lib}" "${x}")
+  endforeach()
+endfunction()
+
+# Create universal library for the given target.
+#
+# Preconditions:
+#  * Library already installed to ${destination} directory
+#    for the ${PLATFORM_NAME} platform
+#
+# This function will:
+#  * Run build for the lacking platform,
+#    i.e. opposite to the ${PLATFORM_NAME}
+#  * Fuse both libraries by running `lipo -create ${src} ${dst} -output ${dst}`
+#     src: library that was just built
+#     dst: installed library
+function(install_universal_ios_library target destination)
+  if("${target}" STREQUAL "")
+    message(FATAL_ERROR "`target` is empty")
+  endif()
+
+  if("${destination}" STREQUAL "")
+    message(FATAL_ERROR "`destination` is empty")
+  endif()
+
+  if(NOT IS_ABSOLUTE "${destination}")
+    message(FATAL_ERROR "`destination` is not absolute: ${destination}")
+  endif()
+
+  if(NOT IS_DIRECTORY "${destination}")
+    message(FATAL_ERROR "`destination` is not absolute: ${destination}")
+  endif()
+
+  if(NOT EXISTS "${destination}")
+    message(FATAL_ERROR "`destination` not exists: ${destination}")
+  endif()
+
+  if("${CMAKE_BINARY_DIR}" STREQUAL "")
+    message(FATAL_ERROR "`CMAKE_BINARY_DIR` is empty")
+  endif()
+
+  if(NOT IS_DIRECTORY "${CMAKE_BINARY_DIR}")
+    message(FATAL_ERROR "Is not a directory: ${CMAKE_BINARY_DIR}")
+  endif()
+
+  if(NOT EXISTS "${CMAKE_BINARY_DIR}")
+    message(FATAL_ERROR "Not exists: ${CMAKE_BINARY_DIR}")
+  endif()
+
+  if("${CMAKE_INSTALL_CONFIG_NAME}" STREQUAL "")
+    message(FATAL_ERROR "CMAKE_INSTALL_CONFIG_NAME is empty")
+  endif()
+
+  set(platform_name "$ENV{PLATFORM_NAME}")
+  if("${platform_name}" STREQUAL "")
+    message(FATAL_ERROR "Environment variable PLATFORM_NAME is empty")
+  endif()
+
+  set(all_platforms "$ENV{SUPPORTED_PLATFORMS}")
+  if("${all_platforms}" STREQUAL "")
+    message(FATAL_ERROR "Environment variable SUPPORTED_PLATFORMS is empty")
+  endif()
+
+  set(cmd xcrun -f lipo)
+  execute_process(
+      COMMAND ${cmd}
+      RESULT_VARIABLE result
+      OUTPUT_VARIABLE output
+      ERROR_VARIABLE output
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_STRIP_TRAILING_WHITESPACE
+  )
+  if(NOT result EQUAL 0)
+    message(
+        FATAL_ERROR "Command failed (${result}): ${cmd}\n\nOutput:\n${output}"
+    )
+  endif()
+  set(_lipo_path ${output})
+
+  set(this_sdk "${platform_name}")
+
+  string(REPLACE " " ";" corr_sdk "${all_platforms}")
+  list(FIND corr_sdk "${this_sdk}" this_sdk_index)
+  if(this_sdk_index EQUAL -1)
+    message(FATAL_ERROR "`${this_sdk}` not found in `${corr_sdk}`")
+  endif()
+
+  list(REMOVE_ITEM corr_sdk "" "${this_sdk}")
+  list(LENGTH corr_sdk corr_sdk_length)
+  if(NOT corr_sdk_length EQUAL 1)
+    message(FATAL_ERROR "Expected one element: ${corr_sdk}")
+  endif()
+
+  set(CURRENT_CONFIG "${CMAKE_INSTALL_CONFIG_NAME}")
+  set(CURRENT_TARGET "${target}")
+
+  install_universal_ios_message("Target: ${CURRENT_TARGET}")
+  install_universal_ios_message("Config: ${CURRENT_CONFIG}")
+  install_universal_ios_message("Destination: ${destination}")
+
+  # Get architectures of the target
+  install_universal_ios_get_archs("${corr_sdk}" corr_archs)
+  install_universal_ios_get_archs("${this_sdk}" this_archs)
+
+  # Return if there are no valid architectures for the SDK.
+  # (note that library already installed)
+  if("${corr_archs}" STREQUAL "")
+    install_universal_ios_message(
+        "No architectures detected for `${corr_sdk}` (skip)"
+    )
+    return()
+  endif()
+
+  # Get location of the library in build directory
+  install_universal_ios_get("${corr_sdk}" "CODESIGNING_FOLDER_PATH" src)
+
+  # Library output name
+  install_universal_ios_get("${corr_sdk}" "EXECUTABLE_NAME" corr_libname)
+  install_universal_ios_get("${this_sdk}" "EXECUTABLE_NAME" this_libname)
+
+  if("${corr_libname}" STREQUAL "${this_libname}")
+    set(libname "${corr_libname}")
+  else()
+    message(FATAL_ERROR "Library names differs: ${corr_libname} ${this_libname}")
+  endif()
+
+  set(dst "${destination}/${libname}")
+
+  install_universal_ios_build("${corr_sdk}")
+
+  install_universal_ios_keep_archs("${src}" "${corr_archs}")
+  install_universal_ios_keep_archs("${dst}" "${this_archs}")
+
+  install_universal_ios_message("Current: ${dst}")
+  install_universal_ios_message("Corresponding: ${src}")
+
+  set(cmd "${_lipo_path}" -create ${src} ${dst} -output ${dst})
+
+  execute_process(
+      COMMAND ${cmd}
+      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+      RESULT_VARIABLE result
+  )
+
+  if(NOT result EQUAL 0)
+    message(FATAL_ERROR "Command failed: ${cmd}")
+  endif()
+
+  install_universal_ios_message("Install done: ${dst}")
+endfunction()
-- 
1.9.3 (Apple Git-50)

>From 083692c8e513176d00f9baaf1ae1372974044b60 Mon Sep 17 00:00:00 2001
From: Ruslan Baratov <ruslan_bara...@yahoo.com>
Date: Thu, 8 Oct 2015 03:13:57 +0300
Subject: [PATCH 3/3] Universal iOS library install

Run `install_universal_ios_library` function in `cmake_install.cmake` script if
`GetTargetNameForUniversalIosInstall` returns non-empty target name.
---
 Source/cmInstallGenerator.cxx       | 10 +++++++++-
 Source/cmInstallGenerator.h         |  3 ++-
 Source/cmInstallTargetGenerator.cxx |  2 +-
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/Source/cmInstallGenerator.cxx b/Source/cmInstallGenerator.cxx
index 2e1c5f0..5c2cd21 100644
--- a/Source/cmInstallGenerator.cxx
+++ b/Source/cmInstallGenerator.cxx
@@ -45,7 +45,8 @@ void cmInstallGenerator
                  const char* permissions_dir /* = 0 */,
                  const char* rename /* = 0 */,
                  const char* literal_args /* = 0 */,
-                 Indent const& indent
+                 Indent const& indent,
+                 std::string target_name_for_universal_ios_install
                  )
 {
   // Use the FILE command to install the file.
@@ -142,6 +143,13 @@ void cmInstallGenerator
     os << literal_args;
     }
   os << ")\n";
+  if(!target_name_for_universal_ios_install.empty())
+    {
+    os << indent << "include(install_universal_ios_library)\n";
+    os << indent << "install_universal_ios_library(";
+    os << "\"" << target_name_for_universal_ios_install << "\" ";
+    os << "\"" << absDest << "\")\n";
+    }
 }
 
 //----------------------------------------------------------------------------
diff --git a/Source/cmInstallGenerator.h b/Source/cmInstallGenerator.h
index b8e5b53..ee10b0c 100644
--- a/Source/cmInstallGenerator.h
+++ b/Source/cmInstallGenerator.h
@@ -49,7 +49,8 @@ public:
     const char* permissions_dir = 0,
     const char* rename = 0,
     const char* literal_args = 0,
-    Indent const& indent = Indent()
+    Indent const& indent = Indent(),
+    std::string target_name_for_universal_ios_install = ""
     );
 
   /** Get the install destination as it should appear in the
diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx
index a5c1ebd..da8b472 100644
--- a/Source/cmInstallTargetGenerator.cxx
+++ b/Source/cmInstallTargetGenerator.cxx
@@ -337,7 +337,7 @@ void cmInstallTargetGenerator::GenerateScriptForConfig(std::ostream& os,
                        type, filesFrom, optional,
                        this->FilePermissions.c_str(), no_dir_permissions,
                        no_rename, literal_args.c_str(),
-                       indent);
+                       indent, this->GetTargetNameForUniversalIosInstall(type));
 
   // Add post-installation tweaks.
   this->AddTweak(os, indent, config, filesTo,
-- 
1.9.3 (Apple Git-50)

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to