
    f1                         d Z dZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
 ddlmZmZmZ  e
e	          dz  Zdd	lmZ d
 Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdS )a  
Lib/ctypes.util.find_library() support for AIX
Similar approach as done for Darwin support by using separate files
but unlike Darwin - no extension such as ctypes.macholib.*

dlopen() is an interface to AIX initAndLoad() - primary documentation at:
https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/dlopen.htm
https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/load.htm

AIX supports two styles for dlopen(): svr4 (System V Release 4) which is common on posix
platforms, but also a BSD style - aka SVR3.

From AIX 5.3 Difference Addendum (December 2004)
2.9 SVR4 linking affinity
Nowadays, there are two major object file formats used by the operating systems:
XCOFF: The COFF enhanced by IBM and others. The original COFF (Common
Object File Format) was the base of SVR3 and BSD 4.2 systems.
ELF:   Executable and Linking Format that was developed by AT&T and is a
base for SVR4 UNIX.

While the shared library content is identical on AIX - one is located as a filepath name
(svr4 style) and the other is located as a member of an archive (and the archive
is located as a filepath name).

The key difference arises when supporting multiple abi formats (i.e., 32 and 64 bit).
For svr4 either only one ABI is supported, or there are two directories, or there
are different file names. The most common solution for multiple ABI is multiple
directories.

For the XCOFF (aka AIX) style - one directory (one archive file) is sufficient
as multiple shared libraries can be in the archive - even sharing the same name.
In documentation the archive is also referred to as the "base" and the shared
library object is referred to as the "member".

For dlopen() on AIX (read initAndLoad()) the calls are similar.
Default activity occurs when no path information is provided. When path
information is provided dlopen() does not search any other directories.

For SVR4 - the shared library name is the name of the file expected: libFOO.so
For AIX - the shared library is expressed as base(member). The search is for the
base (e.g., libFOO.a) and once the base is found the shared library - identified by
member (e.g., libFOO.so, or shr.o) is located and loaded.

The mode bit RTLD_MEMBER tells initAndLoad() that it needs to use the AIX (SVR3)
naming style.
z%Michael Felt <aixtools@felt.demon.nl>    N)environpath)
executable)c_void_psizeof)PopenPIPEDEVNULL   )maxsizec                 J    fd}t          t          |           |          S )Nc                     |                                }g }	 |r7|                    dt          |                                                     |7n# t          $ r Y nw xY w|pt
          gS )Nr   )splitinsertintpop
ValueErrorr   )libnamepartsnumsseps       ../lib/python3.11/ctypes/_aix.py_num_versionz#_last_version.<locals>._num_version>   s    c""	 1As599;;//000  1 	 	 	D	 y s   9A 
A! A!)key)maxreversed)libnamesr   r   s    ` r   _last_versionr   =   s9    	! 	! 	! 	! 	! x!!|4444    c                     d }| j         D ]5}|                    d          r|}d|v r|                    d          c S 6d S )N)/z./z../INDEX
)stdout
startswithrstrip)p	ld_headerlines      r   get_ld_headerr*   J   sa    I * *??-.. 	*II__##D))))) 4r   c                 t    g }| j         D ]-}t          j        d|          r|                    |           - |S )Nz[0-9])r$   rematchappend)r'   infor)   s      r   get_ld_header_infor0   T   sM     D  8GT"" 	KK Kr   c                 (   g }t          ddt           d| gdt          t                    }	 t	          |          }|r%|                    |t          |          f           nn8|j                                         |	                                 |S )z
    Parse the header of the loader section of executable and archives
    This function calls /usr/bin/dump -H as a subprocess
    and returns a list of (ld_header, ld_header_info) tuples.
    z/usr/bin/dumpz-Xz-HT)universal_newlinesr$   stderr)
r   AIX_ABIr	   r
   r*   r.   r0   r$   closewait)fileldr_headersr'   r(   s       r   get_ld_headersr9   a   s     KWd;W	> 	> 	>A!!$$	 		+=a+@+@ABBBB HNNFFHHHr   c                     g }| D ]9\  }}d|v r0|                     ||                    d          d                    :|S )z
    extract the shareable objects from ld_headers
    character "[" is used to strip off the path information.
    Note: the "[" and "]" characters that are part of dump -H output
    are not removed here.
    [)r.   index)
ld_headerssharedr)   _s       r   
get_sharedrA   y   sS     F 4 4	q $;;MM$tzz#r12333Mr   c                      d  d t          t          d fd|D                                 }t          |          dk    r|d                             d          S dS )zy
    Must be only one match, otherwise result is None.
    When there is a match, strip leading "[" and trailing "]"
    z\[(z)\]Nc              3   B   K   | ]}t          j        |          V  d S )N)r,   search).0r)   exprs     r   	<genexpr>z get_one_match.<locals>.<genexpr>   s/       I I44!6!6 I I I I I Ir      r   )listfilterlengroup)rF   linesmatchess   `  r   get_one_matchrO      so     $D6$ I I I I5 I I IJJKKG
7||qqz"""tr   c                     t           dk    rd}t          ||           }|r|S n-dD ]*}t          t          j        |          |           }|r|c S +dS )z
    This routine provides historical aka legacy naming schemes started
    in AIX4 shared library support for library members names.
    e.g., in /usr/lib/libc.a the member name shr.o for 32-bit binary and
    shr_64.o for 64-bit binary.
    @   zshr4?_?64\.o)zshr.ozshr4.oN)r4   rO   r,   escape)membersrF   membernames       r   
get_legacyrV      sv     "}}tW-- 	M	 ( 	 	D"29T??G<<F 4r   c                     d|  dd|  dg}|D ]\}g }|D ]A}t          j        ||          }|r(|                    |                    d                     B|rt	          |d          c S ]dS )a  
    Sort list of members and return highest numbered version - if it exists.
    This function is called when an unversioned libFOO.a(libFOO.so) has
    not been found.

    Versioning for the member name is expected to follow
    GNU LIBTOOL conventions: the highest version (x, then X.y, then X.Y.z)
     * find [libFoo.so.X]
     * find [libFoo.so.X.Y]
     * find [libFoo.so.X.Y.Z]

    Before the GNU convention became the standard scheme regardless of
    binary size AIX packagers used GNU convention "as-is" for 32-bit
    archive members but used an "distinguishing" name for 64-bit members.
    This scheme inserted either 64 or _64 between libFOO and .so
    - generally libFOO_64.so, but occasionally libFOO64.so
    libz\.so\.[0-9]+[0-9.]*z_?64\.so\.[0-9]+[0-9.]*r   .N)r,   rD   r.   rL   r   )rU   rS   exprsrF   versionsr)   ms          r   get_versionr]      s    4 .D---,t,,,.E 0 0 	, 	,D	$%%A ,

+++ 	0 3/////	04r   c                     d|  d}t          ||          }|r|S t          dk    rd|  d}t          ||          }|r|S t          | |          }|r|S t          |          S )ab  
    Return an archive member matching the request in name.
    Name is the library name without any prefix like lib, suffix like .so,
    or version number.
    Given a list of members find and return the most appropriate result
    Priority is given to generic libXXX.so, then a versioned libXXX.so.a.b.c
    and finally, legacy AIX naming scheme.
    rX   z\.sorQ   z64\.so)rO   r4   r]   rV   )rU   rS   rF   rT   s       r   
get_memberr_      s     $D4))F .	B"d"""tW--  w''F #'"""r   c                  R   t          j        d          } | t          j        d          } | g } n|                     d          } t          t                    }|D ]K\  }}|D ]C}|                                d         }d|v r#|                      |j        d                     DL| S )a  
    On AIX, the buildtime searchpath is stored in the executable.
    as "loader header information".
    The command /usr/bin/dump -H extracts this info.
    Prefix searched libraries with LD_LIBRARY_PATH (preferred),
    or LIBPATH if defined. These paths are appended to the paths
    to libraries the python executable is linked with.
    This mimics AIX dlopen() behavior.
    LD_LIBRARY_PATHNLIBPATH:rH   r!   )r   getr   r9   r   extend)libpathsobjectsr@   rM   r)   r   s         r   get_libpathsrh      s     {,--H;y))>>#&&Z((G 1 1
E 	1 	1D::<<?Dd{{

3000		1
 Or   c                    | D ]}|dk    r	d| d}t          j        ||          }t          j        |          rIt          t	          |                    }t          t          j        |          |          }|||fc S  dS dS )a  
    paths is a list of directories to search for an archive.
    name is the abbreviated name given to find_library().
    Process: search "paths" for archive, and if an archive is found
    return the result of get_member().
    If an archive is not found then return None
    /librX   z.aN)NN)r   joinexistsrA   r9   r_   r,   rR   )pathsrU   dirbasearchiverS   rT   s          r   find_sharedrq   
  s      $ $&== T~~~)C&&;w 	$ !8!899G	$99F!f~%%%#||	$ <r   c                     t                      }t          ||           \  }}|| d| dS d|  d}|D ]6}|dk    r	t          j        ||          }t          j        |          r|c S 7dS )a  AIX implementation of ctypes.util.find_library()
    Find an archive member that will dlopen(). If not available,
    also search for a file (or link) with a .so suffix.

    AIX supports two types of schemes that can be used with dlopen().
    The so-called SystemV Release4 (svr4) format is commonly suffixed
    with .so while the (default) AIX scheme has the library (archive)
    ending with the suffix .a
    As an archive has multiple members (e.g., 32-bit and 64-bit) in one file
    the argument passed to dlopen must include both the library and
    the member names in a single string.

    find_library() looks first for an archive (.a) with a suitable member.
    If no archive+member pair is found, look for a .so file.
    N()rX   z.sorj   )rh   rq   r   rk   rl   )rU   rf   ro   rT   sonamern   shlibs          r   find_libraryrw   #  s    " ~~H 400NT6"""""" 4___F  &==	#v&&;u 	MMM	 4r   )__doc__
__author__r,   osr   r   sysr   ctypesr   r   
subprocessr   r	   r
   r4   r   r   r*   r0   r9   rA   rO   rV   r]   r_   rh   rq   rw    r   r   <module>r      si  - -\ 5
 				               # # # # # # # # + + + + + + + + + + &

Q
      5 5 5      0       .$ $ $L# # #8  4  2( ( ( ( (r   