parameters: (self)
docstring: Process Qt libraries for packaging for macOS. 
  
          This function will copy the Qt framework/libraries that an application
          needs into the specific location for App bundles (Frameworks directory)
          and perform any cleanup on the copied framework to conform to Apple's
          framework bundle structure. This is required so that App bundles can
          be properly code signed.
docstring_summary: Process Qt libraries for packaging for macOS.
docstring_tokens: Process Qt libraries for packaging for macOS .
function: def process_qt(self):
          """
          Process Qt libraries for packaging for macOS. 
  
          This function will copy the Qt framework/libraries that an application
          needs into the specific location for App bundles (Frameworks directory)
          and perform any cleanup on the copied framework to conform to Apple's
          framework bundle structure. This is required so that App bundles can
          be properly code signed.
          """
          if not self.bld.is_mac_platform(self.bld.platform):
              return
  
          # Don't need the process_resources method to process the qtlibs folder
          # since we are handling it
          self.dir_resources.remove('qtlibs')
          executable_dest_node = self.binaries_out
  
          output_folder_node = self.standard_out
          qt_plugin_source_node = output_folder_node.make_node("qtlibs/plugins")
          qt_plugins_dest_node = executable_dest_node.make_node("qtlibs/plugins")
  
          # To be on the safe side check if the destination qtlibs is a link and
          # unlink it before we creat the plugins copy/link
          if os.path.islink(qt_plugins_dest_node.parent.abspath()):
              os.unlink(qt_plugins_dest_node.parent.abspath())
  
          self.bld.create_symlink_or_copy(qt_plugin_source_node, qt_plugins_dest_node.abspath(), postpone=False)
          self.codesign_executables_in_directory(qt_plugins_dest_node.abspath())
  
          qt_libs_source_node = output_folder_node.make_node("qtlibs/lib")
  
          # Executable destination node will be something like
          # Application.app/Contents/MacOS. The parent will be Contents, which
          # needs to contain the Frameworks folder according to macOS Framework
          # bundle structure 
          frameworks_node = executable_dest_node.parent.make_node("Frameworks")
          frameworks_node.mkdir()
  
          def post_copy_cleanup(dst_framework_node):
              # Apple does not like any file in the top level directory of an
              # embedded framework. In 5.6 Qt has Perl scripts for their build in the
              # top level directory so we will just delete them from the embedded
              # framework since we won't be building anything.
              pearl_files = dst_framework_node.ant_glob("*.prl")
              for file in pearl_files:
                  file.delete()
          
          # on macOS there is not a clean way to get Qt dependencies on itself,
          # so we have to scan the lib using otool and then add any of those Qt
          # dependencies to our set.
  
          qt_frameworks_to_copy = set()
  
          qt5_vars = Utils.to_list(QT5_LIBS)
          for i in qt5_vars:
              uselib = i.upper()
              if uselib in self.dependencies:
                  # QT for darwin does not have '5' in the name, so we need to remove it
                  darwin_adjusted_name = i.replace('Qt5','Qt')
                  framework_name = darwin_adjusted_name + ".framework"
                  src = qt_libs_source_node.make_node(framework_name).abspath()
  
                  if os.path.exists(src):
                      qt_frameworks_to_copy.add(framework_name)
  
                      # otool -L will generate output like this:
                      #     @rpath/QtWebKit.framework/Versions/5/QtWebKit (compatibility version 5.6.0, current version 5.6.0)
                      # cut -d ' ' -f 1 will slice the line by spaces and returns the first field. That results in: @rpath/QtWebKit.framework/Versions/5/QtWebKit
                      # grep @rpath will make sure we only have QtLibraries and not system libraries
                      # cut -d '/' -f 2 slices the line by '/' and selects the second field resulting in: QtWebKit.framework
                      otool_command = "otool -L '%s' | cut -d ' ' -f 1 | grep @rpath.*Qt | cut -d '/' -f 2" % (os.path.join(src, darwin_adjusted_name)) 
                      output = subprocess.check_output(otool_command, shell=True).decode(sys.stdout.encoding or 'iso8859-1', 'replace')
                      qt_dependent_libs = re.split("\s+", output.strip())
  
                      for lib in qt_dependent_libs:
                          qt_frameworks_to_copy.add(lib)
  
          for framework_name in qt_frameworks_to_copy:
              src_node = qt_libs_source_node.make_node(framework_name)
              src = src_node.abspath()
              dst = frameworks_node.make_node(framework_name).abspath()
              if os.path.islink(dst):
                  os.unlink(dst)
              if os.path.isdir(dst):
                  shutil.rmtree(dst)
              Logs.info('Copying Qt Framework {} to {}'.format(src, dst))
              self.bld.create_symlink_or_copy(src_node, dst)
              self.codesign_framework(frameworks_node.make_node(framework_name))
              
              if not os.path.islink(dst):
                  post_copy_cleanup(frameworks_node.make_node(framework_name))
function_tokens: def process_qt ( self ) : if not self . bld . is_mac_platform ( self . bld . platform ) : return # Don't need the process_resources method to process the qtlibs folder # since we are handling it self . dir_resources . remove ( 'qtlibs' ) executable_dest_node = self . binaries_out output_folder_node = self . standard_out qt_plugin_source_node = output_folder_node . make_node ( "qtlibs/plugins" ) qt_plugins_dest_node = executable_dest_node . make_node ( "qtlibs/plugins" ) # To be on the safe side check if the destination qtlibs is a link and # unlink it before we creat the plugins copy/link if os . path . islink ( qt_plugins_dest_node . parent . abspath ( ) ) : os . unlink ( qt_plugins_dest_node . parent . abspath ( ) ) self . bld . create_symlink_or_copy ( qt_plugin_source_node , qt_plugins_dest_node . abspath ( ) , postpone = False ) self . codesign_executables_in_directory ( qt_plugins_dest_node . abspath ( ) ) qt_libs_source_node = output_folder_node . make_node ( "qtlibs/lib" ) # Executable destination node will be something like # Application.app/Contents/MacOS. The parent will be Contents, which # needs to contain the Frameworks folder according to macOS Framework # bundle structure  frameworks_node = executable_dest_node . parent . make_node ( "Frameworks" ) frameworks_node . mkdir ( ) def post_copy_cleanup ( dst_framework_node ) : # Apple does not like any file in the top level directory of an # embedded framework. In 5.6 Qt has Perl scripts for their build in the # top level directory so we will just delete them from the embedded # framework since we won't be building anything. pearl_files = dst_framework_node . ant_glob ( "*.prl" ) for file in pearl_files : file . delete ( ) # on macOS there is not a clean way to get Qt dependencies on itself, # so we have to scan the lib using otool and then add any of those Qt # dependencies to our set. qt_frameworks_to_copy = set ( ) qt5_vars = Utils . to_list ( QT5_LIBS ) for i in qt5_vars : uselib = i . upper ( ) if uselib in self . dependencies : # QT for darwin does not have '5' in the name, so we need to remove it darwin_adjusted_name = i . replace ( 'Qt5' , 'Qt' ) framework_name = darwin_adjusted_name + ".framework" src = qt_libs_source_node . make_node ( framework_name ) . abspath ( ) if os . path . exists ( src ) : qt_frameworks_to_copy . add ( framework_name ) # otool -L will generate output like this: #     @rpath/QtWebKit.framework/Versions/5/QtWebKit (compatibility version 5.6.0, current version 5.6.0) # cut -d ' ' -f 1 will slice the line by spaces and returns the first field. That results in: @rpath/QtWebKit.framework/Versions/5/QtWebKit # grep @rpath will make sure we only have QtLibraries and not system libraries # cut -d '/' -f 2 slices the line by '/' and selects the second field resulting in: QtWebKit.framework otool_command = "otool -L '%s' | cut -d ' ' -f 1 | grep @rpath.*Qt | cut -d '/' -f 2" % ( os . path . join ( src , darwin_adjusted_name ) ) output = subprocess . check_output ( otool_command , shell = True ) . decode ( sys . stdout . encoding or 'iso8859-1' , 'replace' ) qt_dependent_libs = re . split ( "\s+" , output . strip ( ) ) for lib in qt_dependent_libs : qt_frameworks_to_copy . add ( lib ) for framework_name in qt_frameworks_to_copy : src_node = qt_libs_source_node . make_node ( framework_name ) src = src_node . abspath ( ) dst = frameworks_node . make_node ( framework_name ) . abspath ( ) if os . path . islink ( dst ) : os . unlink ( dst ) if os . path . isdir ( dst ) : shutil . rmtree ( dst ) Logs . info ( 'Copying Qt Framework {} to {}' . format ( src , dst ) ) self . bld . create_symlink_or_copy ( src_node , dst ) self . codesign_framework ( frameworks_node . make_node ( framework_name ) ) if not os . path . islink ( dst ) : post_copy_cleanup ( frameworks_node . make_node ( framework_name ) )