أصبحت بايثون اللغة المشتركة لعلوم البيانات، ومع ذلك فإن اعتماد النظام البيئي على بايثون النقي غالبًا ما يخفي عنق زجاجة حرجًا: الأداء. بالنسبة للحسابات العددية الثقيلة، يلجأ علماء البيانات غالبًا إلى المكتبات المبنية على أساس C أو C++ أو Fortran، مثل NumPy وSciPy وPandas. ومع ذلك، فإن توزيع هذه المكتبات يطرح تحديًا فريدًا للمطورين. على عكس حزم بايثون القياسية، لا يمكن تثبيت المكتبات ذات الامتدادات الأصلية ببساطة من المصدر على جهاز كل مستخدم دون الحاجة إلى بيئة بناء معقدة، وسلاسل أدوات المترجم، والتبعيات المتوافقة. النتيجة غالبًا ما تكون توزيعات "من المصدر فقط" بطيئة التثبيت وعرضة لفشل البناء عبر أنظمة تشغيل مختلفة.
هنا تتدخل أدوات تجميع بايثون الحديثة. يتم استبدال تكوين setuptools التقليدي مع scripts setup.py بشكل متزايد بواسطة خلفيات بناء تلتزم بـ PEP 517 وPEP 621. من بين هذه، برز scikit-build-core كمعيار ذهبي للمشاريع التي تتطلب امتدادات C/C++. في هذا الدليل، سنستكشف كيفية الاستفادة من scikit-build-core لإنشاء عجلات ثنائية قوية ومخصصة للهندسة المعمارية، مما يضمن أن مكتبة علوم البيانات الخاصة بك تقدم أقصى أداء لكل مستخدم، بغض النظر عن بيئته.
تطور تجميع بايثون
لفهم سبب كون scikit-build هو الحل، يجب علينا أولاً الاعتراف بنقاط الألم في الماضي. في السابق، اعتمد المطورون على ملفات setup.py التي تخلط منطق البناء مع منطق التثبيت. غالبًا ما أدى هذا النهج الإجرائي إلى فشل "بناء مرة واحدة، نشر في أي مكان" عندما لا تتطابق بيئة البناء مع بيئة الهدف. علاوة على ذلك، كان إنشاء العجلات (التوزيعات الثنائية) لعدة منصات (Linux، macOS، Windows) وهياكل معمارية (x86_64، ARM64) يتطلب تكوينًا يدويًا معقدًا.
انتقل تجميع بايثون نحو التكوينات التصريحية. يسمح PEP 621 بتعريف بيانات المشروع في pyproject.toml، مما يفصل منطق البناء عن تكوين المشروع. Scikit-build-core هو backend بناء حديث قائم على CMake مصمم خصيصًا لهذا سير العمل التصريحي. فهو يتعامل مع تعقيدات استدعاء CMake، وإدارة المترجمين، وتغليف الثنائيات في العجلات تلقائيًا.
هيكل المشروع والتكوين
يبدأ إعداد مشروع مع scikit-build-core بتخطيط دليلي منظم جيدًا. تحتاج إلى مجلد مصدر للكود الخاص بك بلغة بايثون، ومجلد src للكود الخاص بك بلغة C/C++، وملف pyproject.toml يخبر نظام البناء بما يجب فعله.
project-root/
├── src/
│ ├── my_package/
│ │ ├── __init__.py
│ │ └── _core.c
├── pyproject.toml
└── build_requirements.txt
يكمن قلب التكوين في pyproject.toml. نحدد backend البناء كـ scikit_build_core ونحدد متطلبات CMake. هذا يحل محل setup.py القديم بالكامل.
[build-system]
requires = ["scikit-build-core", "cmake>=3.15", "setuptools"]
build-backend = "scikit_build_core.build"
[project]
name = "fast-data-lib"
version = "0.1.0"
description = "High-performance data processing using C extensions"
requires-python = ">=3.9"
dependencies = [
"numpy>=1.24.0",
]
[tool.scikit-build]
cmake.version = "3.20.0"
build.type = "Release"
wheel.install-dir = "fast_data_lib"
# هذا يخبر scikit-build بالبناء لجميع المنصات المتوافقة
manylinux.manylinux_x86_64 = true
كتابة امتداد C مع CMake
بمجرد إعداد تكوين بايثون، يتولى إعداد CMake المهمة. نحتاج إلى ملف CMakeLists.txt في جذر مشروعنا يصف كيفية تجميع مصدر C وربطه كوحدة بايثون. يقوم scikit-build-core تلقائيًا بتمرير متغيرات مثل PYTHON_INCLUDE_DIRS و PYTHON_LIBRARIES إلى CMake، مما يبسط عملية الربط.
cmake_minimum_required(VERSION 3.20)
project(fast_data_lib C)
# استخدام تكوين بايثون من scikit-build-core
include_directories(${PYTHON_INCLUDE_DIRS})
# تعريف وحدة الامتداد
python_add_library(_core MODULE src/my_package/_core.c)
# الربط ضد مكتبات بايثون القياسية
target_link_libraries(_core ${PYTHON_LIBRARIES})
# التأكد من تثبيت المكتبة في الموقع الصحيح
set_target_properties(_core PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/src/my_package"
)
هنا، أمر python_add_library هو ماكرو عالي المستوى يوفره CMake يتعامل مع إنشاء مكتبة مشتركة (.so على Linux، .dll على Windows، .dylib على macOS) متوافقة مع مترجم بايثون. يجب أن يتطابق اسم الامتداد (_core) مع اسم الاستيراد في كود بايثون الخاص بك.
بناء وتوزيع العجلات الثنائية
تكمن قوة scikit-build-core في قدرته على بناء عجلات لمختلف المنصات. يمكنك بناء عجلة محلية باستخدام:
pip wheel . --no-build-isolation
ومع ذلك، للتوزيع الحقيقي عبر المنصات، نوصي باستخدام cibuildwheel، وهي أداة تعمل داخل خط أنابيب CI/CD (مثل GitHub Actions). تقوم تلقائيًا ببناء عجلات لـ Linux وmacOS وWindows عبر جميع إصدارات بايثون المدعومة. عند تحميل هذه العجلات إلى PyPI، سيقوم pip باختيار العجلة الثنائية الصحيحة تلقائيًا لجهاز المستخدم، مما يتجنب الحاجة إلى تجميع أي شيء محليًا.
# مثال على مقتطف .github/workflows/build.yml
jobs:
build_wheels:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- name: Build wheels
uses: pypa/cibuildwheel@v2.19
- uses: pypa/gh-action-pypi-publish@release/v1
الخاتمة
تقديم مكتبات علوم البيانات عالية الأداء يتطلب أكثر من مجرد خوارزميات محسنة؛ فهو يتطلب استراتيجية تجميع قوية. من خلال الانتقال من scripts setup.py القديمة إلى النهج التصريحي الحديث لـ scikit-build-core، يمكن للمطورين تبسيط توزيع امتدادات C والعجلات الثنائية. هذا يضمن حصول المستخدمين على فوائد السرعة من الكود الأصلي دون الاحتكاك الناتج عن بيئات التجميع المحلية المعقدة. مع استمرار تطور النظام البيئي لبايثون، فإن اعتماد هذه الأدوات ليس مجرد أفضل ممارسة، بل هو ضرورة للحفاظ على برامج علمية عالية الجودة وسهلة الوصول.