Skip to content

Commit

Permalink
Dynamically determine value of use_tmpcpy based on library (DLL) ve…
Browse files Browse the repository at this point in the history
…rsion (#223)
  • Loading branch information
bbrown1867 authored Feb 19, 2025
1 parent 65eb19e commit 3d63d10
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ In the order of appearance in the commit history:
| Dominic Shelton | @frogamic |
| Fletcher D | @FletcherD |
| G Towers | @gtowers-dukosi |
| Ben Brown | @bbrown1867 |
5 changes: 3 additions & 2 deletions pylink/jlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ def wrapper(self, *args, **kwargs):
return _interface_required

def __init__(self, lib=None, log=None, detailed_log=None, error=None, warn=None, unsecure_hook=None,
serial_no=None, ip_addr=None, open_tunnel=False, use_tmpcpy=True):
serial_no=None, ip_addr=None, open_tunnel=False, use_tmpcpy=None):
"""Initializes the J-Link interface object.
Note:
Expand Down Expand Up @@ -279,7 +279,8 @@ def __init__(self, lib=None, log=None, detailed_log=None, error=None, warn=None,
of ``open`` method.
If ``None``, the driver will not be opened automatically
(however, it is still closed when exiting the context manager).
use_tmpcpy (bool): True to load a temporary copy of J-Link DLL
use_tmpcpy (Optional[bool]): ``True`` to load a temporary copy of
J-Link DLL, ``None`` to dynamically decide based on DLL version.
Returns:
``None``
Expand Down
27 changes: 25 additions & 2 deletions pylink/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import ctypes.util as ctypes_util
import os
import platform
import re
import sys
import tempfile

Expand Down Expand Up @@ -279,7 +280,7 @@ def find_library_darwin(cls):
if f.startswith(dll):
yield os.path.join(dir_path, f)

def __init__(self, dllpath=None, use_tmpcpy=True):
def __init__(self, dllpath=None, use_tmpcpy=None):
"""Initializes an instance of a ``Library``.
Loads the default J-Link DLL if ``dllpath`` is ``None``, otherwise
Expand All @@ -288,7 +289,8 @@ def __init__(self, dllpath=None, use_tmpcpy=True):
Args:
self (Library): the ``Library`` instance
dllpath (str): the DLL to load into the library
use_tmpcpy (bool): True to load a temporary copy of J-Link DLL
use_tmpcpy (Optional[bool]): ``True`` to load a temporary copy of
J-Link DLL, ``None`` to dynamically decide based on DLL version.
Returns:
``None``
Expand Down Expand Up @@ -410,6 +412,11 @@ def load(self, path=None):

lib_path = self._path

if self._use_tmpcpy is None:
# Fall back to ``True`` if version lookup failed (old pylink default)
maybe_version = self.dll_version()
self._use_tmpcpy = (maybe_version <= 6.10) if maybe_version else True

if self._use_tmpcpy:
# Copy the J-Link DLL to a temporary file. This will be cleaned up the
# next time we load a DLL using this library or if this library is
Expand Down Expand Up @@ -500,6 +507,22 @@ def dll(self):
"""
return self._lib

def dll_version(self):
"""Returns the DLL version number.
Args:
self (Library): the ``Library`` instance
Returns:
DLL version number (e.g. 7.96) or ``None`` if parsing fails.
"""
if self._path is not None:
match = re.search(r"JLink(?:_Linux)?_V(\d+)", self._path)
if match:
num_part = match.group(1)
return float(f"{num_part[0]}.{num_part[1:]}")
return None


class JLinkarmDlInfo:
"""Helper to retrieve the absolute path of the JLink library (aka DLL)
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,18 @@ def test_linux_dl_oserror(self, mock_load_library, mock_find_library, mock_libc_
self.assertEqual(2, mock_find_library.call_count)
self.assertEqual(2, mock_load_library.call_count)

@mock.patch('ctypes.cdll.LoadLibrary')
def test_dll_version_linux(self, _mock_load_library):
path = "/opt/SEGGER/JLink_Linux_V684b_x86_64/libjlinkarm.so"
lib = library.Library(path)
self.assertEqual(lib.dll_version(), 6.84)

@mock.patch('ctypes.cdll.LoadLibrary')
def test_dll_version_mac(self, _mock_load_library):
path = "/Applications/SEGGER/JLink_V796n/libjlinkarm.dylib"
lib = library.Library(path)
self.assertEqual(lib.dll_version(), 7.96)


if __name__ == '__main__':
unittest.main()

0 comments on commit 3d63d10

Please sign in to comment.