pylink
pylink copied to clipboard
JLink instantiation looking for DLL on linux platform
After installing JLink tools v6.32d for ARM on Raspbian, I am able to access the device using command line tools. Using python 2.7.9 under a virtual environment and ipython session, pylink cannot create a JLink object:
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
Type "copyright", "credits" or "license" for more information.
IPython 5.7.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import pylink
In [2]: jlink = pylink.JLink()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-2e2659994c13> in <module>()
----> 1 jlink = pylink.JLink()
/home/pi/jlink/JLink_Linux_V632d_arm/venv/local/lib/python2.7/site-packages/pylink/jlink.pyc in __init__(self, lib, log, detailed_log, error, warn, unsecure_hook)
250
251 if lib.dll() is None:
--> 252 raise TypeError('Expected to be given a valid DLL.')
253
254 self._library = lib
TypeError: Expected to be given a valid DLL.
I have already copied the libjlinkarm.so file to /usr/local/lib, as well as creating a symlink in the same directory to libjlinkarm.so.6.32.4 from the JLink installation.
I also tried exporting the library path:
export LD_LIBRARY_PATH=~/jlink/JLink_Linux_V632d_arm/:$LD_LIBRARY_PATH
Is this Linux for ARM? What does sys.platform report, and what's the name of the DLL? On Linux platforms, the logic first searches for libjlinkarm.so (no version in name) using ctypes.util.find_library, then using a platform-specific searching method as defined here: https://github.com/square/pylink/blob/master/pylink/library.py#L264
Yes, linux for ARM:
In [3]: import sys
In [4]: sys.platform
Out[4]: 'linux2'
There is no DLL.
After the previous issue I confirmed I can pass in the library:
In [1]: import pylink
In [2]: lib = pylink.library.Library('./libjlinkarm.so')
In [3]: jlink = pylink.JLink(lib)
Does ctypes.util.find_library('libjlinkarm.so') work when you export the LD_LIBRARY_PATH`?
Doesn't appear to:
In [1]: import ctypes
In [2]: ctypes.util.find_library('libjlinkarm.so')
In [3]: ls
99-jlink.rules GDBServer/ JLinkExe* JLinkLicenseManager@ JLinkRemoteServerCLExe* JLinkSTM32* libjlinkarm.so@ README.txt Samples/
Devices/ JFlashSPI_CL* JLinkGDBServer@ JLinkRegistration@ JLinkRTTClient* JLinkSWOViewer* libjlinkarm.so.6@ RTT__201805301206.log venv/
Doc/ JLinkDevices.xml JLinkGDBServerCLExe* JLinkRemoteServer@ JLinkRTTLogger* JTAGLoadExe* libjlinkarm.so.6.32.4* RTT_Terminal_201805301207.log
(venv) pi@raspberrypi:~/jlink/JLink_Linux_V632d_arm $ echo $LD_LIBRARY_PATH
/home/pi/jlink/JLink_Linux_V632d_arm:
Could this have to do with the version of Python you're using? 64-bit vs 32-bit?
I had this same problem and managed to fix it. Pylink doesn't correctly find installed J-Link libraries on Linux. There are two bugs in Pylink, as follows:
- The code in library.py searches for "libjlinkarm.so" on Linux platforms. However, when searching for a library on Linux using the
ctypes.util.find_libraryfunction, the 'lib' prefix must be omitted. For example:
Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes.util import find_library
>>> find_library('libm.so')
>>> find_library('m.so')
'libm.so.6'
>>> find_library('libjlinkarm.so')
>>> find_library('jlinkarm.so')
'libjlinkarm.so.6'
>>>
- The string returned from
find_librarydoes not contain the full path to the shared library in Linux. This breaks the code inlibrary.loadthat attempts to copy the shared library to a temporary file. I have no idea why the shared library is being copied to a temporary file, but removing this operation and callingctypes.cdll.LoadLibraryon the value returned fromctypes.util.find_libraryjust works.
Re: the second thing. Up until a certain version, the DLL inherently prevented accessing two or more J-Links at the same time. Copying to a temporary file provided a work-around for that.
Here's a patch with changes that fix things for Linux. Note that this patch completely removes the entire "temporary DLL copy", which based on the last comment may cause problems when accessing multiple J-Link simultaneously.
diff --git a/pylink/library.py b/pylink/library.py
index 68d7efd..239f80a 100644
--- a/pylink/library.py
+++ b/pylink/library.py
@@ -82,7 +82,7 @@ class Library(object):
'JLINK_SetFlashProgProgressCallback'
]
- JLINK_SDK_NAME = 'libjlinkarm'
+ JLINK_SDK_NAME = 'jlinkarm'
WINDOWS_JLINK_SDK_NAME = 'JLinkARM'
@@ -315,20 +315,8 @@ class Library(object):
else:
suffix = '.so'
- # 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
- # cleaned up.
- tf = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
- with open(tf.name, 'wb') as outputfile:
- with open(self._path, 'rb') as inputfile:
- outputfile.write(inputfile.read())
-
- # This is needed to work around a WindowsError where the file is not
- # being properly cleaned up after exiting the with statement.
- tf.close()
-
- self._temp = tf
- self._lib = ctypes.cdll.LoadLibrary(tf.name)
+ self._temp = None
+ self._lib = ctypes.cdll.LoadLibrary(self._path)
if self._windows:
# The J-Link library uses a mix of __cdecl and __stdcall function
+1 worked for me on arch linux with JLink V6.40 - thank you @dpalchak
The fix above works for Linux but would break other OS, do I understand that correctly? Otherwise, is there something else that hinders creating a PR for that?
The rename would probably break OSX, and the copy workaround would break multiple device access.
A solution that doesn't require any modification to the code:
jlink = pylink.JLink(lib=pylink.library.Library(dllpath='/path/to/libjlinkarm.so'), ...)
jlink = pylink.JLink(lib=pylink.library.Library
This worked for me with no code changes on a raspberry pi 4
I know this is two years old, but we might have a concrete fix for this as outlined in #132, which removes the need for the workaround; this should be available in v0.14.0.