Python ctypes 在 Linux 上调用 .so 库失败,OSError:./libEFWFilter.so.1.7:未定义符号:udev_enumerate_new

问题描述 投票:0回答:1

有一个滤镜轮SDK,名为“libEFWFilter.so”,由ZWO公司提供。下载链接是

https://dl.zwoastro.com/software?app=DeveloperEfwSdk&platform=windows86&region=China

我想在Ubuntu20.04或CentOS7上使用python的ctypes或CFFI模块来调用这个动态库。以下是我的python程序:test.py.

#!/usr/bin/python3

import ctypes
from ctypes.util import find_library
import os

print(find_library("udev"))
print(find_library("EFWFilter"))
print(os.getcwd() + "/libEFWFilter.so.1.7")

libefw = ctypes.cdll.LoadLibrary(os.getcwd() + "/libEFWFilter.so.1.7")

当我运行这个test.py时,输出错误信息如下。

libudev.so.1
libEFWFilter.so.1.7
/home/ls/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64/libEFWFilter.so.1.7
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    libefw = ctypes.cdll.LoadLibrary(os.getcwd() + "/libEFWFilter.so.1.7")
  File "/usr/lib/python3.8/ctypes/__init__.py", line 451, in LoadLibrary
    return self._dlltype(name)
  File "/usr/lib/python3.8/ctypes/__init__.py", line 373, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: /home/ls/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64/libEFWFilter.so.1.7: undefined symbol: udev_enumerate_new

但是我已经安装了libudev库。

ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ whereis libudev
libudev: /usr/lib/x86_64-linux-gnu/libudev.so /usr/include/libudev.h /usr/share/man/man3/libudev.3.gz

该公司提供的demo可以正确编译,可执行文件运行正常。 演示包含“main.cpp”、“EFW_filter.h”、“Makefile”。如下。

main.cpp

#include "stdio.h"
#include "EFW_filter.h"
#ifdef _WINDOWS
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#define Sleep(a) usleep((a)*1000)
#endif
int  main()
{
    
    int EFW_count = EFWGetNum();  
    if(EFW_count <= 0)
    {
        printf("no filter wheel connected, press any key to exit\n");
        getchar();
        return -1;
    }
    else
        printf("attached filter wheel:\n");

    EFW_INFO EFWInfo;
    

    for(int i = 0; i < EFW_count; i++)
    {
        EFWGetID(i, &EFWInfo.ID);
        EFWGetProperty(EFWInfo.ID, &EFWInfo);
        printf("index %d: %s\n",i, EFWInfo.Name);
    }

    printf("\nselect one \n");

    int EFWIndex, iSelectedID;
    scanf("%d", & EFWIndex);
    EFWGetID(EFWIndex, &iSelectedID);

    if(EFWOpen(iSelectedID) != EFW_SUCCESS)
    {
        printf("open error,are you root?,press any key to exit\n");
        getchar();
        return -1;
    }

    
    if(iSelectedID < 0)
        {
    
            printf("open error,are you root?,press any key to exit\n");
        getchar();
        return -1;   
     }
     else
    {      
        
        EFW_ERROR_CODE err;
        while(1){
            err = EFWGetProperty(iSelectedID, & EFWInfo);
            if(err != EFW_ERROR_MOVING )
                break;
            Sleep(500);
        } 
            printf("%d slots: ", EFWInfo.slotNum);
        for(int i = 0; i < EFWInfo.slotNum; i++)
            printf("%d ", i + 1);
       
        int currentSlot;
        while(1)
            {

                err = EFWGetPosition(iSelectedID, &currentSlot);
                if(err != EFW_SUCCESS || currentSlot != -1 )
                        break;
                Sleep(500);
            } 
        printf("\ncurrent position: %d\n", currentSlot + 1);

        int targetSlot;
        char c;
        printf("\nPlease input target position, type \'q\' to quit:\n");
        while(1)
        {   
            c = getchar();
     
                if (EOF == c)
                continue;
            if(c == 'q')
                break;
            if(c >= '0' && c <= '9')
                targetSlot = c - '0';
            else
                continue;
            
            targetSlot--;
            if(targetSlot < 0 || targetSlot >=  EFWInfo.slotNum)
                continue;
            
            err = EFWSetPosition(iSelectedID, targetSlot);
            if(err == EFW_SUCCESS)
                printf("\nMoving...\n");
            while(1)
                {
                     err = EFWGetPosition(iSelectedID, &currentSlot);
                    if(err != EFW_SUCCESS ||currentSlot != -1 )
                            break;
                    Sleep(500);
                } 
            printf("\nPlease input target position, type \'q\' to quit:\n");

        }
        EFWClose(iSelectedID);
        printf("main function over\n");
        return 1;
    }
}

EFW_filter.h

/**************************************************
this is the ZWO filter wheel EFW SDK
any question feel free contact us:[email protected]

here is the suggested procedure.

--> EFWGetNum
--> EFWGetID for each filter wheel

--> EFWGetProperty
--> EFWOpen
--> EFWGetPosition
--> EFWSetPosition
    ...
--> EFWClose

***************************************************/
#ifndef EFW_FILTER_H
#define EFW_FILTER_H


#ifdef _WINDOWS
#define EFW_API __declspec(dllexport)
#else
#define EFW_API 
#endif

#define EFW_ID_MAX 128

typedef struct _EFW_INFO
{
    int ID;
    char Name[64];
    int slotNum;
} EFW_INFO;


typedef enum _EFW_ERROR_CODE{
    EFW_SUCCESS = 0,
    EFW_ERROR_INVALID_INDEX,
    EFW_ERROR_INVALID_ID,
    EFW_ERROR_INVALID_VALUE,
    EFW_ERROR_REMOVED, //failed to find the filter wheel, maybe the filter wheel has been removed
    EFW_ERROR_MOVING,//filter wheel is moving
    EFW_ERROR_ERROR_STATE,//filter wheel is in error state
    EFW_ERROR_GENERAL_ERROR,//other error
    EFW_ERROR_NOT_SUPPORTED,
    EFW_ERROR_CLOSED,
    EFW_ERROR_END = -1
}EFW_ERROR_CODE;

typedef struct _EFW_ID{
    unsigned char id[8];
}EFW_ID;

typedef EFW_ID EFW_SN;

#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************
Descriptions:
this should be the first API to be called
get number of connected EFW filter wheel, call this API to refresh device list if EFW is connected
or disconnected

Return: number of connected EFW filter wheel. 1 means 1 filter wheel is connected.
***************************************************************************/
EFW_API int EFWGetNum();

/***************************************************************************
Descriptions:
get the product ID of each wheel, at first set pPIDs as 0 and get length and then malloc a buffer to load the PIDs

Paras:
int* pPIDs: pointer to array of PIDs

Return: length of the array.
***************************************************************************/
EFW_API int EFWGetProductIDs(int* pPIDs);

/***************************************************************************
Descriptions:
get ID of filter wheel

Paras:
int index: the index of filter wheel, from 0 to N - 1, N is returned by GetNum()

int* ID: pointer to ID. the ID is a unique integer, between 0 to EFW_ID_MAX - 1, after opened,
all the operation is base on this ID, the ID will not change.


Return: 
EFW_ERROR_INVALID_INDEX: index value is invalid
EFW_SUCCESS:  operation succeeds

***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetID(int index, int* ID);

/***************************************************************************
Descriptions:
open filter wheel

Paras:
int ID: the ID of filter wheel

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_GENERAL_ERROR: number of opened filter wheel reaches the maximum value.
EFW_ERROR_REMOVED: the filter wheel is removed.
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWOpen(int ID);

/***************************************************************************
Descriptions:
get property of filter wheel. SlotNum is 0 if not opened.

Paras:
int ID: the ID of filter wheel

EFW_INFO *pInfo:  pointer to structure containing the property of EFW

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_MOVING: slot number detection is in progress, generally this error will happen soon after filter wheel is connected.
EFW_SUCCESS: operation succeeds
EFW_ERROR_REMOVED: filter wheel is removed

***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetProperty(int ID, EFW_INFO *pInfo); 

/***************************************************************************
Descriptions:
get position of slot

Paras:
int ID: the ID of filter wheel

int *pPosition:  pointer to slot position, this value is between 0 to M - 1, M is slot number
this value is -1 if filter wheel is moving

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed

***************************************************************************/    
EFW_API EFW_ERROR_CODE EFWGetPosition(int ID, int *pPosition);
    
/***************************************************************************
Descriptions:
set position of slot

Paras:
int ID: the ID of filter wheel

int Position:  slot position, this value is between 0 to M - 1, M is slot number

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_INVALID_VALUE: Position value is invalid
EFW_ERROR_MOVING: filter wheel is moving, should wait until idle
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed

***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetPosition(int ID, int Position);

/***************************************************************************
Descriptions:
set unidirection of filter wheel

Paras:
int ID: the ID of filter wheel

bool bUnidirectional: if set as true, the filter wheel will rotate along one direction

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetDirection(int ID, bool bUnidirectional);

/***************************************************************************
Descriptions:
get unidirection of filter wheel

Paras:
int ID: the ID of filter wheel

bool *bUnidirectional: pointer to unidirection value .

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetDirection(int ID, bool *bUnidirectional);

/***************************************************************************
Descriptions:
calibrate filter wheel

Paras:
int ID: the ID of filter wheel

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
EFW_ERROR_MOVING: filter wheel is moving, should wait until idle
EFW_ERROR_ERROR_STATE: filter wheel is in error state
EFW_ERROR_REMOVED: filter wheel is removed
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWCalibrate(int ID);

/***************************************************************************
Descriptions:
close filter wheel

Paras:
int ID: the ID of filter wheel

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWClose(int ID);

/***************************************************************************
Descriptions:
get version string, like "0, 4, 0824"
***************************************************************************/
EFW_API char* EFWGetSDKVersion();


/***************************************************************************
Descriptions:
get hardware error code of filter wheel

Paras:
int ID: the ID of filter wheel

bool *pErrCode: pointer to error code .

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetHWErrorCode(int ID, int *pErrCode);

/***************************************************************************
Descriptions:
Get firmware version of filter wheel

Paras:
int ID: the ID of filter wheel

int *major, int *minor, int *build: pointer to value.

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetFirmwareVersion(int ID, unsigned char *major, unsigned char *minor, unsigned char *build);

/***************************************************************************
Descriptions:
Get the serial number from a EFW

Paras:
int ID: the ID of focuser

EFW_SN* pSN: pointer to SN

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_ERROR_NOT_SUPPORTED: the firmware does not support serial number
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWGetSerialNumber(int ID, EFW_SN* pSN);

/***************************************************************************
Descriptions:
Set the alias to a EFW

Paras:
int ID: the ID of filter

EFW_ID alias: the struct which contains the alias

Return: 
EFW_ERROR_INVALID_ID: invalid ID value
EFW_ERROR_CLOSED: not opened
EFW_ERROR_NOT_SUPPORTED: the firmware does not support setting alias
EFW_SUCCESS: operation succeeds
***************************************************************************/
EFW_API EFW_ERROR_CODE EFWSetID(int ID, EFW_ID alias);

#ifdef __cplusplus
}
#endif

#endif

生成文件

platform = x64

CC = g++

ifeq ($(platform), mac32)
CFLAGS += -m32 -framework IOKit -framework CoreFoundation

endif

ifeq ($(platform), mac64)

CFLAGS += -framework IOKit -framework CoreFoundation
endif

ifeq ($(platform), mac)
CFLAGS += -arch i386 -arch x86_64 -framework IOKit -framework CoreFoundation

endif

ifeq ($(platform), x86)
CFLAGS += -ludev
endif


ifeq ($(platform), x64)
CFLAGS += -ludev
endif

ifeq ($(platform), armv5)
CFLAGS += -ludev
endif


ifeq ($(platform), armv6)
CFLAGS += -ludev

endif

ifeq ($(platform), armv8)
CFLAGS += -ludev

endif

all:test_console
test_console: main.cpp
    $(CC) main.cpp -o test_console $(CFLAGS) ../../lib/$(platform)/libEFWFilter.a -I../../include $(CFLAGS) -lpthread
    cp test_console bin/$(platform)/
clean:
    rm -f test_console

当我构建演示时,一切正常,没有错误。

我尝试过的事情:

  1. 在 CentOS7 上测试此程序。
  2. 使用Python的最高版本:python3.10.13。

但是上面的方法并没有解决这个“未定义符号”的问题。我注意到解决这个类似问题的一些解决方案是在 cpp 函数中添加“extern C”。但我无法做到这一点,因为我不知道 libEFWFilter.so 库的源代码。 那么我应该怎么做才能用python解决这个问题呢?非常感谢您的帮助!

python linux shared-libraries ctypes undefined-symbol
1个回答
0
投票

@CristiFati,以下是当我在Python控制台中输入“ctypes.CDLL(“libudev.so”).udev_enumerate_new”并输入“dpkg -s libudev1:amd64”和“ldd ./libEFWFilter.so.1.7”时的输出信息在 Linux 终端中。

ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ python3
Python 3.8.10 (default, Nov 22 2023, 10:22:35) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes
>>> print(ctypes.CDLL("libudev.so").udev_enumerate_new)
<_FuncPtr object at 0x7f70be96bb80>
>>> from ctypes.util import find_library
>>> print(find_library("udev"))
libudev.so.1
>>> 
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ dpkg -s libudev1:amd64
Package: libudev1
Status: install ok installed
Priority: required
Section: libs
Installed-Size: 340
Maintainer: Ubuntu Developers <[email protected]>
Architecture: amd64
Multi-Arch: same
Source: systemd
Version: 245.4-4ubuntu3.23
Depends: libc6 (>= 2.30)
Description: libudev shared library
 This library provides access to udev device information.
Homepage: https://www.freedesktop.org/wiki/Software/systemd
Original-Maintainer: Debian systemd Maintainers <[email protected]>
ls@ubuntu64:~/libEFW/EFW_linux_mac_SDK_V1.7/lib/x64$ ldd ./libEFWFilter.so.1.7 
        linux-vdso.so.1 (0x00007ffd491f3000)
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6866b1d000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f68669ce000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f68669b3000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f68667c1000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f6866f6e000)

从上面的消息来看,似乎没有问题。 但是“ldd ./libEFWFilter.so.1.7”的输出中没有“libudev.so”,可能是错误?,如何解决这个问题?再次感谢。

© www.soinside.com 2019 - 2024. All rights reserved.