
    !hiA                        d Z ddlZddlZddlZddlZddlZddlZddlmZm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZ ddlmZ ddlZddlmZ ddlmZ  ej<                  e      Z d Z!d Z"d Z#d	 Z$d
 Z%d Z&d Z'de(de)fdZ*d Z+d Z,d Z-d Z. G d de/      Z0 G d de/      Z1d Z2d"dZ3d Z4d"dZ5d Z6d#dZ7d Z8d Z9d  Z:d! Z;y)$z
Utils for macOS platform.
    N)LC_BUILD_VERSIONLC_CODE_SIGNATURELC_ID_DYLIBLC_LOAD_DYLIBLC_LOAD_UPWARD_DYLIBLC_LOAD_WEAK_DYLIBLC_PREBOUND_DYLIBLC_REEXPORT_DYLIBLC_RPATHLC_SEGMENT_64	LC_SYMTABLC_UUIDLC_VERSION_MIN_MACOSX)MachO)compatc                  \    t               } | r t        j                  j                  |       ryy)z
    Check if Python interpreter was installed via Homebrew command 'brew'.

    :return: True if Homebrew else otherwise.
    TF)get_homebrew_prefixr   base_prefix
startswith
env_prefixs    AC:\des-py\Monitor\venv\Lib\site-packages\PyInstaller/utils/osx.pyis_homebrew_envr   .   (     %&Jf((33J?    c                  \    t               } | r t        j                  j                  |       ryy)z
    Check if Python interpreter was installed via Macports command 'port'.

    :return: True if Macports else otherwise.
    TF)get_macports_prefixr   r   r   r   s    r   is_macports_envr   ;   r   r   c                      t        j                  d      } t        j                  j	                  t        j                  j	                  |             } | S )z9
    :return: Root path of the Homebrew environment.
    brewshutilwhichospathdirnameprefixs    r   r   r   H   6     \\&!FWW__RWW__V45FMr   c                      t        j                  d      } t        j                  j	                  t        j                  j	                  |             } | S )z9
    :return: Root path of the Macports environment.
    portr!   r'   s    r   r   r   R   r)   r   c                     | j                   D cg c]   }|d   j                  t        t        hv s|" }}t	        |      dk(  sJ dt	        |       d       |d   S c c}w )zJ
    Helper that finds the version command in the given MachO header.
    r      zNExpected exactly one LC_BUILD_VERSION or LC_VERSION_MIN_MACOSX command, found !)commandscmdr   r   len)headerr0   version_cmds      r   _find_version_cmdr4   \   sr     #)//m3SVZZDTVkCl5l3mKm{q  m
XY\]hYiXjjklm q> ns
    AAc                 |    t        |       }|j                  d   }t        |      }t        |d   j                        S )z
    Obtain the version of macOS SDK against which the given binary was built.

    NOTE: currently, version is retrieved only from the first arch slice in the binary.

    :return: (major, minor, revision) tuple
    r   r-   )r   headersr4   _hex_tripletsdk)filenamebinaryr2   r3   s       r   get_macos_sdk_versionr;   h   s:     8_F^^AF#F+KA**++r   c                 6    | dz  dz	  }| dz  dz	  }| dz  }|||fS )Ni      i          )versionmajorminorrevisions       r   r7   r7   w   s6    xB&Ev!#E$H%!!r   r9   returnc                 (   g }t        |       j                  D ]`  }t        |      }|d   j                  t        k(  r|j                  |d   j                         C|j                  |d   j                         b t        t        t        |            S )z}
    Get the -macosx-version-min used to compile a macOS binary.

    For fat binaries, the minimum version is selected.
    r   r-   )r   r6   r4   r0   r   appendrA   minosminmapr7   )r9   versionsr2   r0   s       r   macosx_version_minrL      s{     H/)) *'q6::..OOCFNN+ OOCFLL)* s<*++r   c                    d|cxk  rdk  sJ d        J d       d|cxk  rdk  sJ d        J d       d|cxk  rdk  sJ d        J d       t        |       }|j                  d   }t        |      }|dz  |dz  z  |z  |d   _        t	        |j
                  d	      5 }|j                  |       d
d
d
       y
# 1 sw Y   y
xY w)z
    Overwrite the macOS SDK version declared in the given binary with the specified version.

    NOTE: currently, only version in the first arch slice is modified.
    r   r?   zInvalid major version value!zInvalid minor version value!zInvalid revision value!r=   r>   r-   rb+N)r   r6   r4   r8   openr9   write)r9   rB   rC   rD   r:   r2   r3   fps           r   set_macos_sdk_versionrR      s     <<<<<<<<<<<<C:!:::!::8_F^^AF#F+K"uz1H<KN	foou	% R  s    B;;Cc                 d   t         j                  j                  |       }t        |       }|j                  d   }|j
                  D cg c]  }|d   j                  t        k(  s| }}t        |      dk(  sJ d       d}|j
                  D cg c].  }|d   j                  t        k(  s|d   j                  |k(  s-|0 }}t        |      dk(  sJ d       |d   d   }|j
                  D cg c]  }|d   j                  t        k(  s| }}t        |      dk(  sJ d       |d   d   }||j                  |j                  z   z
  |_        ||j                  |j                  z   z
  |_        t#        |j$                        j'                  d      rd	nd
}	t)        j*                  |j                   |	z        |	z  |_        t/        | d      5 }
|j1                  |
       ddd       |j2                  r
ddlm}m}m}m}m} t/        | d      5 }
|jA                  |
      }|jB                  |k(  r2tE        |jF                        D cg c]  }|jA                  |
       }}n@|jB                  |k(  r1tE        |jF                        D cg c]  }|jA                  |
       }}d   }||j                  z
  |_$        |
jK                  d       |jM                  |
       |D ]  }|jM                  |
        	 ddd       yyc c}w c c}w c c}w # 1 sw Y   1xY wc c}w c c}w # 1 sw Y   yxY w)a  
    Fixes the Mach-O headers to make code signing possible.

    Code signing on macOS does not work out of the box with embedding .pkg archive into the executable.

    The fix is done this way:
    - Make the embedded .pkg archive part of the Mach-O 'String Table'. 'String Table' is at end of the macOS exe file,
      so just change the size of the table to cover the end of the file.
    - Fix the size of the __LINKEDIT segment.

    Note: the above fix works only if the single-arch thin executable or the last arch slice in a multi-arch fat
    executable is not signed, because LC_CODE_SIGNATURE comes after LC_SYMTAB, and because modification of headers
    invalidates the code signature. On modern arm64 macOS, code signature is mandatory, and therefore compilers
    create a dummy signature when executable is built. In such cases, that signature needs to be removed before this
    function is called.

    Mach-O format specification: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/Mach-O.5.html
    r   z#Executable contains code signature!s   __LINKEDIT      r-   z(Expected exactly one __LINKEDIT segment!z$Expected exactly one SYMTAB section!arm64i @  i   rN   N)	FAT_MAGICFAT_MAGIC_64fat_arch
fat_arch64
fat_header)'r$   r%   getsizer   r6   r/   r0   r   r1   r   segnamer   offsetstroffstrsizefileofffilesize_get_arch_stringr2   r   mathceilvmsizerO   rP   fatmacholib.mach_orV   rW   rX   rY   rZ   from_fileobjmagicrange	nfat_archsizeseek
to_fileobj)r9   	file_size
executabler2   r0   sign_sec__LINKEDIT_NAMElinkedit_seg
symtab_sec	page_sizerQ   rV   rW   rX   rY   rZ   rf   iarchsarchs                       r   fix_exe_for_code_signingry      s   ( )I xJ#F  &R#a&**@Q2QRHRx=ADDD <O#)??xCc!fjjM6QVYZ[V\VdVdhwVwCxLx|!M#MM!?1%L!'L#CFJJ)4K#LJLz?aG!GGAq!J  #fmmj6G6G&GHJ%9M9M)MNL ,FMM:EEgNTZI))L$9$9I$EFRL 
h	 "
 ~~__(E" 	$b ))"-CyyI%<A#--<PQq..r2QQl*>CCMM>RS004SS9D!DKK/DIGGAJNN2 $#$	$ 	$ Y S
 y M<  RS	$ 	$sa   L $L L+L>L/L
L
L8L&L)L&L! AL&L
L&&L/c                     | j                   }| j                  dz  }|dk(  r|dk(  ryy|dk(  r|dk(  ryy	|d
k(  ryJ d       )z
    Converts cputype and cpusubtype from mach_o.mach_header_64 into arch string comparible with lipo/codesign.
    The list of supported architectures can be found in man(1) arch.
    ii  r>   x86_64hx86_64i     arm64erU      i386zUnhandled architecture!)cputype
cpusubtype)r2   r   r   s      r   rb   rb     s\     nnG""Z/J. ?	O	#?	A+++5r   c                    ddl }|j                         }t        |d      5 t        fdd      D ]  }|j	                  |        	 ddd       t        |       }|j                  D ]  }|j                  D cg c]  }|d   j                  t        k(  s| }}|s6|d   }|d   j                  }	|j                         }
|
j	                  |	       |
j                         dd }t        |      dk(  sJ ||d   _
         t        | d      5 |j                         ddd       y# 1 sw Y   xY wc c}w # 1 sw Y   yxY w)	aG  
    Modifies the Mach-O image UUID stored in the LC_UUID command (if present) in order to ensure that different
    frozen applications have different identifiers. See TN3178 for details on why this is required:
    https://developer.apple.com/documentation/technotes/tn3178-checking-for-and-resolving-build-uuid-problems
    r   Nrbc                  &     j                  d      S )Ni    )read)rQ   s   r   <lambda>z'update_exe_identifier.<locals>.<lambda>&  s    "''$- r   r   r-   r=   rN   )hashlibsha1rO   iterupdater   r6   r/   r0   r   uuidcopydigestr1   rP   )r9   pkg_filenamer   pkg_hashchunkrp   r2   r0   uuid_cmdoriginal_uuidcombined_hashnew_uuidrQ   s               @r   update_exe_identifierr     sF    ||~H	lD	! #R/5 	#EOOE"	##
 xJ$$ $#)??LCc!fjjG6KCLLA; !((
 !]+ '')#2.8}"""#'$, 
h	 " 9# # M( s#   &D)9D5D5D:)D2:Ec                       e Zd ZdZy)InvalidBinaryErrorz]
    Exception raised by `get_binary_architectures` when it is passed an invalid binary.
    N)__name__
__module____qualname____doc__r@   r   r   r   r   E  s     	r   r   c                   "     e Zd ZdZ fdZ xZS )IncompatibleBinaryArchErrorzq
    Exception raised by `binary_to_target_arch` when the passed binary fails the strict architecture check.
    c                 2    d}t         |   | d|        y )NzMhttps://pyinstaller.org/en/stable/feature-notes.html#macos-multi-arch-supportz, For details about this error message, see: )super__init__)selfmessageurl	__class__s      r   r   z$IncompatibleBinaryArchError.__init__P  s#    ]G9$PQTPUVWr   )r   r   r   r   r   __classcell__)r   s   @r   r   r   L  s    X Xr   r   c                     	 t        |       }t        |j                        |j
                  D cg c]  }t        |j                         c}fS # t        $ r}t        d      |d}~ww xY wc c}w )z
    Inspects the given binary and returns tuple (is_fat, archs), where is_fat is boolean indicating fat/thin binary,
    and arch is list of architectures with lipo/codesign compatible names.
    zInvalid Mach-O binary!N)r   
ValueErrorr   boolrf   r6   rb   r2   )r9   rp   ehdrs       r   get_binary_architecturesr   U  sf    
B8_
 
*J\J\!]3"23::">!]]]  B !9:AB!]s   A A,	A)A$$A)c                     |xs | }dd|| d|g}t        j                  |t         j                  t         j                  d      }|j                  r(t        d| d|j                   d|j                         y	)
z\
    Convert the given fat binary into thin one with the specified target architecture.
    lipoz-thin-outpututf-8stdoutstderrencodinglipo command () failed with error code 
!
output: N
subprocessrunPIPESTDOUT
returncodeSystemErrorr   )r9   	thin_archoutput_filenamecmd_argsps        r   convert_binary_to_thin_archr   a  sw     &1OHiQHx

@Q@Q\cdA||N8*4Mall^[fghgogofpqrr r   c                     ddd| g|}t        j                  |t         j                  t         j                  d      }|j                  r(t        d| d|j                   d|j                         y	)
zJ
    Merge the given single-arch thin binary files into a fat binary.
    r   z-creater   r   r   r   r   r   Nr   )r   slice_filenamesr   r   s       r   merge_into_fat_binaryr   l  sn     	9oPPHx

@Q@Q\cdA||N8*4Mall^[fghgogofpqrr r   c                    |s| }t        |       \  }}|dk(  r|st        | d      y
|r:||vrt        | d| d      t        j                  d| ||       t	        | |       y
||vrt        | d| d|d    d	      y
)z
    Check that the given binary contains required architecture slice(s) and convert the fat binary into thin one,
    if necessary.
    
universal2z is not a fat binary!z does not contain slice for r.   z1Converting fat binary %s (%s) to thin binary (%s)z" is incompatible with target arch z (has arch: r   z)!N)r   r   loggerdebugr   )r9   target_archdisplay_nameis_fatrw   s        r   binary_to_target_archr   v  s    
 ,X6MFEl"->S.TUU  %'1\NB^_j^kkl2mnnLLLhXdfqr'+>%'1#n$F{mS_`efg`h_iikl  (r   c                    t         j                  d|        ddd| g}t        j                  |t        j                  t        j
                  d      }|j                  r(t        d| d|j                   d	|j                         y
)zp
    Remove the signature from all architecture slices of the given binary file using the codesign utility.
    zRemoving signature from file %r/usr/bin/codesignz--remove--all-architecturesr   r   codesign command (r   r   N)	r   r   r   r   r   r   r   r   r   )r9   r   r   s      r   remove_signature_from_binaryr     s~     LL2H=#Z1FQHx

@Q@Q\cdA||.xj8QRSR^R^Q__jklksksjtuvv r   c                    g }|sd}n|j                  d       |r"|j                  d       |j                  |       |r|j                  d       t        j                  d|        dd|dd	d
g|| }t        j                  |t        j
                  t        j                  d      }|j                  r(t        d| d|j                   d|j                         y)zj
    Sign the binary using codesign utility. If no identity is provided, ad-hoc signing is performed.
    -z--options=runtimez--entitlementsz--deepzSigning file %rr   z-sz--forcer   z--timestampr   r   r   r   r   N)
rG   r   r   r   r   r   r   r   r   r   )r9   identityentitlements_filedeep
extra_argsr   r   s          r   sign_binaryr     s     J-.*++,(#
LL"H-T8Y8M}_iksH 	x

@Q@Q\cdA||.xj8QRSR^R^Q__jklksksjtuvv r   c                 P   t        |       \  }}|r~t        j                         5 }g }|D ]M  }t        j                  j                  ||      }t        | ||       t        ||       |j                  |       O t        | g|  ddd       yt        | |       y# 1 sw Y   yxY w)a  
    Modify the given dylib's identity (in LC_ID_DYLIB command) and the paths to dependent dylibs (in LC_LOAD_DYLIB)
    commands into `@rpath/<basename>` format, remove any existing rpaths (LC_RPATH commands), and add a new rpath
    (LC_RPATH command) with the specified path.

    Uses `install-tool-name` utility to make the changes.

    The system libraries (e.g., the ones found in /usr/lib) are exempted from path rewrite.

    For multi-arch fat binaries, this function extracts each slice into temporary file, processes it separately,
    and then merges all processed slices back into fat binary. This is necessary because `install-tool-name` cannot
    modify rpaths in cases when an existing rpath is present only in one slice.
    )r   N)
r   tempfileTemporaryDirectoryr$   r%   joinr   _set_dylib_dependency_pathsrG   r   )r9   target_rpathr   rw   tmpdirr   rx   slice_filenames           r   set_dylib_dependency_pathsr     s    $ -X6MFE((* 	>f O 7!#fd!;+HdN[+NLI&&~6	7
 "(=_=	> 	> 	$Hl;	> 	>s   A!BB%c                    t         t        t        t        t        h}t        |       }d}t               }t               }|j                  D ]  }|j                  D ]  }|d   j                  }	|	|vr|	t        t        hvr%|d   j                  d      j                  d      }
|	|v r|j                  |
       ^|	t        k(  r|j                  |
       y|	t        k(  s|
}  ~d}|r>t        t!        j"                  d      t!        j"                  |      j$                  z        }g }d}|D ]  }t&        j(                  j+                  |      r#dd	g}t-        |D cg c]  }||v  c}      rCd
}t        t!        j"                  d      t!        j"                  |      j$                  z        }||k(  r|j/                  ||f        g }|r||k7  r|d|gz  }|D ]  \  }}|d||gz  } |D ]  }||k(  r	|d|gz  } |r||vr|d|gz  }|sydg|| }t1        j2                  |t0        j4                  t0        j6                  d      }|j8                  r(t;        d| d|j8                   d|j<                         yc c}w )z
    The actual implementation of set_dylib_dependency_paths functionality.

    Implicitly assumes that a single-arch thin binary is given.
    Nr   r}   r    z@rpathFz"/Library/Frameworks/Tcl.framework/z!/Library/Frameworks/Tk.framework/Tz-idz-changez-delete_rpathz
-add_rpathinstall_name_toolr   zinstall_name_tool command (r   r   )r   r   r   r	   r
   r   setr6   r/   r0   r   r   decoderstripaddstrpathlibPurePathnamemacholibutilin_system_pathanyrG   r   r   r   r   r   r   r   )r9   r   _RELOCATABLEr:   dylib_idrpathslinked_libsr2   r0   lc_typer%   normalized_dylib_idchanged_lib_pathsrpath_required
linked_lib_exemptionsxnew_pathinstall_name_tool_argsoriginal_pathrpathr   r   s                          r   r   r     s    	L 8_FHUF%K..  ?? 	 C!fjjGl*wx>U/U q6==)008D,&%H$

4 K'	    	 !'"2"28"<w?O?OPX?Y?^?^"^_
 N! 9
==''
3 1/
 5AZ56 w''1G4D4DZ4P4U4UUV!  *h!78196   2h>5*=">> $5 Gx9mX"FFG
  
L #
 	

 ,f4#
 	
 " $G&<GhGHx

@Q@Q\cdA||)(3LQ\\NZefgfnfneop
 	
 a 6s   I?
c                     t        j                  |       } | j                  j                  j                  dk7  ry| j                  j                  j                  j                  | j                  dz   k7  ryy)zK
    Check if the given shared library is part of a .framework bundle.
    VersionsFz
.frameworkT)r   r   parentr   )lib_paths    r   is_framework_bundle_libr  Q  s^    
 )H ""j0$$))X]]\-IIr   c           
         d}t               }t               }t               | D ]k  \  }}}|dk7  rt        j                  |      }t        j                  |      }t	        |      sDt	        |      sP|j
                  dz  dz  }	|	j                         s|j
                  j
                  j
                  dz  dz  }
|
j                         sYd}|j
                  j
                  j
                  }t        j                  rt        d| d      t        j                  d|       |
}	|j
                  dz  dz  }|j                  t        |      t        |	      d	f       |j                  t        |j
                  j
                  d
z        t        |j
                  j                        df       j                  |j
                  j
                  d
z         |j
                  j
                  j
                  }|j                  t        ||j                  z        t        t        j                  d      |j                  z        df       |j                  t        |dz        ddf       j                  |dz         |j                  |       n h d}|D ]  }| D ]  \  }}}t        j                  |      }	 |j                  |      }|j"                  }|d   dk7  rC|d   }||vrM|j                  t        ||z        t        t        j                  d      |z        df       j                  ||z           rVg }| D ]N  \  }}}t        j                  |      }t%        fd|j&                  D              r;|j)                  |||f       P n| }|rt        j                  d       |t+        |      z   S # t         $ r Y /w xY w)a  
    Scan the given TOC list of collected files for shared libraries that are collected from macOS .framework bundles,
    and collect the bundles' Info.plist files. Additionally, create/restore the following symbolic links:
      - `Versions/Current` pointing to the `Versions/<version>` directory containing the binary
      - `<name>` in the top-level .framework directory, pointing to `Versions/Current/<name>`
      - `Resources` in the top-level .framework directory, pointing to `Versions/Current/Resources`
      - additional directories in top-level .framework directory, pointing to their counterparts in `Versions/Current`
        directory.

    Returns updated TOC list with added entries for the discovered Info.plist files and generated symbolic links.
    FBINARY	Resourcesz
Info.plistTzCould not find Info.plist in r.   z Could not find Info.plist in %s!DATACurrentSYMLINKzVersions/CurrentzVersions/Current/Resources>   HeadersHelpers	Librariesr	  
FrameworksDocumentationr   r  r}   c              3   &   K   | ]  }|v  
 y wNr@   ).0dest_parentframework_symlinked_dirss     r   	<genexpr>z7collect_files_from_framework_bundles.<locals>.<genexpr>  s     `{;"::`s   zOne or more collected .framework bundles have missing Info.plist file. If you are building an .app bundle, you will most likely not be able to code-sign it.)r   r   Pathr   r  r  is_filer   strict_collect_moder   r   warningr   r   r   relative_tor   partsr   parentsrG   sorted)collected_filesinvalid_framework_foundframework_entriesframework_paths	dest_namesrc_nametypecodesrc_path	dest_pathinfo_plist_srcinfo_plist_src_topframework_dirinfo_plist_destdest_framework_pathVALID_SUBDIRSremaining_pathremaining_path_partsdir_namefiltered_tocr  s                      @r   $collect_files_from_framework_bundlesr3  a  s    $eO"u *9 A1%	8Xx<<)$$Y/	 'x0 'y1 ";6E%%' "*!7!7!>!>!L|![%--/ +/' ( 6 6 = =--%(Em_TU&VWWNN#E}U/N#**[8<Gs?3S5H&QR
 	s9#3#3#:#:Y#FGYM]M]MbMbIcenop $$Y%5%5%<%<y%HI'..55<<
 	#inn45  !34y~~EF
 	 	#k12(
 	
 	!$$%8;%FG 	/0CA1L dM. I-< 	I)Ix((3I!*!6!67J!K $2#7#7  $A&*4 ,A.H},!!'(23G$$%788CD# 
 %(()<x)GH3	II@  -< 	A)Ix((3I`iN_N_``Hh ?@	A ' H	

 &!2333]  s   ;O	OOr  )NNF)<r   rc   r$   r   r   r"   r   rg   r   r   r   r   r   r   r	   r
   r   r   r   r   r   macholib.MachOr   macholib.utilr   PyInstaller.loglogloggingPyInstallerr   	getLoggerr   r   r   r   r   r   r4   r;   r7   r   tuplerL   rR   ry   rb   r   	Exceptionr   r   r   r   r   r   r   r   r   r   r  r3  r@   r   r   <module>r=     s     	        !  ! 			8	$

	,", , ,$,Z$z,.'T	 	X) X	^ss8ww0<Dw
t T4r   