杰瑞科技汇

Python中如何使用loadLibrary加载动态链接库?

Of course! In Python, "loadlibrary" is not a built-in function, but the concept is fundamental. It refers to the process of loading an external, pre-compiled library (like a .dll on Windows, a .so on Linux, or a .dylib on macOS) so that your Python script can call its functions.

Python中如何使用loadLibrary加载动态链接库?-图1
(图片来源网络,侵删)

This is typically done using Python's built-in ctypes module or, for more advanced use cases, the CFFI library.

Let's break down the most common methods.


Method 1: The Standard ctypes Module

ctypes is Python's foreign function interface library. It allows you to call functions in shared/dynamic libraries directly from Python. It's powerful and requires no external packages.

Step-by-Step Guide with ctypes

Let's assume you have a simple C library you want to use.

Python中如何使用loadLibrary加载动态链接库?-图2
(图片来源网络,侵删)

Step 1: Create the C Library

First, let's create a C file named mylib.c.

// mylib.c
#include <stdio.h>
// A function that takes an integer and returns its square
int square(int num) {
    return num * num;
}
// A function that takes two integers and returns their sum
int add(int a, int b) {
    return a + b;
}

Step 2: Compile the Library

You need to compile this C code into a shared library that Python can load.

  • On Linux:

    # The -fPIC flag is for Position-Independent Code, required for shared libraries.
    # The -shared flag creates a shared library.
    # The -o flag specifies the output file name.
    gcc -fPIC -shared -o libmylib.so mylib.c

    This will create a file named libmylib.so.

  • On macOS:

    # The -dynamiclib flag creates a dynamic library (.dylib).
    gcc -dynamiclib -o libmylib.dylib mylib.c

    This will create a file named libmylib.dylib.

  • On Windows:

    # The -LD flag tells the compiler to create a DLL.
    # The -Fe flag specifies the output file name.
    gcc -LD -o mylib.dll mylib.c

    This will create a file named mylib.dll.

Step 3: Load the Library in Python

Now, let's write the Python script to load and use this library.

import ctypes
import os
# --- Find the library file ---
# This makes the script more portable.
# It will look for 'mylib.dll' on Windows, 'libmylib.so' on Linux, etc.
if os.name == 'nt':
    # Windows
    lib_name = "mylib.dll"
else:
    # Linux or macOS
    lib_name = "libmylib.so"
# --- Load the Library ---
# This is the equivalent of "loadlibrary".
try:
    # We use 'cdll' for C-style functions (cdecl calling convention).
    mylib = ctypes.CDLL(lib_name)
    print(f"Successfully loaded library: {lib_name}")
except OSError as e:
    print(f"Error loading library: {e}")
    print("Make sure the library file is in the same directory as your script,")
    print("or provide the full path to the library.")
    exit()
# --- Define Function Signatures (CRITICAL STEP) ---
# By default, ctypes doesn't know the argument types or return types of the functions.
# You must tell it, otherwise it will interpret the memory incorrectly.
# Define the 'square' function
# It takes one integer (c_int) and returns one integer (c_int).
mylib.square.argtypes = [ctypes.c_int]
mylib.square.restype = ctypes.c_int
# Define the 'add' function
# It takes two integers and returns one integer.
mylib.add.argtypes = [ctypes.c_int, ctypes.c_int]
mylib.add.restype = ctypes.c_int
# --- Use the Functions ---
# Now you can call the functions as if they were Python functions.
# Call the 'square' function
num_to_square = 10
result_square = mylib.square(num_to_square)
print(f"The square of {num_to_square} is: {result_square}")
# Call the 'add' function
a, b = 25, 17
result_add = mylib.add(a, b)
print(f"The sum of {a} and {b} is: {result_add}")

Key ctypes Concepts:

  • ctypes.CDLL(name): Loads a shared library using the standard C dlopen mechanism. Use ctypes.WinDLL(name) on Windows for libraries using the stdcall calling convention (common for WinAPI).
  • argtypes: A tuple specifying the data types of the function's arguments.
  • restype: The data type of the value returned by the function.
  • ctypes.c_int, ctypes.c_char_p, ctypes.c_double, etc.: These are the C data types that map to Python types. c_int maps to a C int, c_char_p maps to a C char* (a string in Python), etc.

Method 2: The Modern CFFI Library

CFFI (C Foreign Function Interface) is a more modern and powerful alternative to ctypes. It's often preferred for complex projects because it can generate Python wrapper code and has a cleaner API for some tasks.

First, install it: pip install cffi

Step-by-Step Guide with CFFI

The workflow is slightly different. You usually create a separate file to define the C interface.

Step 1: Create the C Library Same as before. Compile mylib.c into libmylib.so (or .dll/.dylib).

Step 2: Create the CFFI "Build" File

This file will describe the C functions you want to use.

# build_mylib.py
from cffi import FFI
ffi = FFI()
# Define the C functions and their signatures.
# This is similar to ctypes' argtypes and restype.
ffi.cdef("""
    int square(int num);
    int add(int a, int b);
""")
# Load the shared library.
# The name should match the compiled library file.
# The '...' is a placeholder for the path, but cffi can often find it.
lib = ffi.dlopen("./libmylib.so") # Use "mylib.dll" on Windows
# Now, you can use 'lib' just like in the ctypes example.
# Note: CFFI automatically handles type conversions for basic types.

Step 3: Use the Library in Your Main Python Script

Your main script will import the library object created by build_mylib.py.

# main.py
# Import the library and ffi object from the build file.
from build_mylib import lib, ffi
print("Successfully loaded library using CFFI.")
# Call the functions
num_to_square = 10
result_square = lib.square(num_to_square)
print(f"The square of {num_to_square} is: {result_square}")
a, b = 25, 17
result_add = lib.add(a, b)
print(f"The sum of {a} and {b} is: {result_add}")

To run this, you can either:

  1. Run build_mylib.py once to generate a _cffi_backend module, and then run main.py.
  2. Or, combine them into a single script for simpler cases.

Method 3: The "Low-Level" ctypes.windll (Windows Specific)

On Windows, you can load system libraries directly without needing a .dll file. This is how you interact with the Windows API.

import ctypes
# Load the Windows User32 library
user32 = ctypes.windll.user32
# Define the function signature for MessageBoxW
# It takes a handle (HWND), two wide-character strings (LPCWSTR), and a title (LPCWSTR)
user32.MessageBoxW.argtypes = [
    ctypes.c_void_p,  # HWND
    ctypes.c_wchar_p,  # LPCWSTR text
    ctypes.c_wchar_p,  # LPCWSTR title
    ctypes.c_uint     # UINT uType
]
user32.MessageBoxW.restype = ctypes.c_int
# Call the function
# We pass None for the parent window handle.
# "Hello from Python!" is the message.
# "ctypes Demo" is the title.
# 0 is the message box type (just an OK button).
user32.MessageBoxW(None, "Hello from Python!", "ctypes Demo", 0)

Comparison: ctypes vs. CFFI

Feature ctypes CFFI
Built-in? Yes, part of the standard library. No, needs to be installed (pip install cffi).
Learning Curve Simpler for basic tasks. Slightly more complex initially due to the build step.
API Can feel a bit clunky and C-centric. Generally considered cleaner and more Pythonic.
C Header Parsing No, you must define signatures manually. Yes, can parse .h files to automatically generate ffi.cdef().
Use Case Quick and dirty loading, standard library use. Larger projects, complex C libraries, performance-critical code.
Platform Excellent cross-platform support. Excellent cross-platform support.

Summary

  • For quick, simple tasks or when you can't install packages, use ctypes. It's the built-in, no-fuss solution.
  • For more serious projects, complex C/C++ libraries, or if you want to leverage C header files, use CFFI. It's more robust and scalable.
  • On Windows, remember ctypes.windll for direct access to system libraries like user32.dll or kernel32.dll.
分享:
扫描分享到社交APP
上一篇
下一篇