باستخدام Swift 6.3 أو إصدار أحدث، ضع السمة @c على دالة عامة، وأنشئ ترويسة التوافق الخاصة بها، وصرّف المستدعي على أنه C، ثم اربطه باستخدام swiftc. يشرح هذا الدليل خطوة بخطوة بناء برنامج صغير أصلي لسطر الأوامر على Mac يوضح كل حد من هذه الحدود.
مهمة القارئ محددة: استدعاء عملية حسابية مكتوبة بـ Swift من ملف .c عادي، من دون تصريف هذا الملف على أنه Objective-C أو C++. توضح وثائق الإصدار الرسمية لـ Swift أن @c هي ميزة التوافق مع C المدعومة التي أُضيفت في Swift 6.3. تحقّق من إصدار المصرّف المثبّت لديك قبل اتباع نصائح قديمة عن السمات التجريبية. إصدار Swift 6.3
ما الذي يجعل دالة Swift قابلة للاستدعاء من C؟
يجب أن تتوافق ثلاثة أمور: التصريح الذي يقرأه مصفّر C، واتفاقية الاستدعاء التي يستخدمها التنفيذ، وملفات الكائنات التي تُمرر إلى الرابط. تعالج الترويسة الأمر الأول؛ لكنها لا توفر تنفيذًا مفقودًا ولا تغيّر ABI لدالة موجودة.
تمنح السمة @c دالة Swift عامة اتفاقية استدعاء C، وتقصر توقيعها على أنواع يمكن تمثيلها في C. وتتيح وسيطة اختيارية للسمة تحديد اسمها في C. ويصدر Swift التصريح المقابل في قسم C المتوافق من ترويسة التوافق المُنشأة. ترد هذه السلوكيات في اقتراح Swift Evolution الذي نُفّذ. دوال وتعدادات متوافقة مع C
في هذا المثال، تقبل الواجهة عددًا صحيحًا من C وتعيده. تحصر العملية الحسابية الافتراضية نسبة العرض ضمن المجال الشامل من صفر إلى 100. لا توجد مخازن مؤقتة أو نتائج مخصصة أو أعمار للكائنات ينبغي تنسيقها. وهذا يُبقي عملية البناء الأولى مركزة على التصريف والربط.
تحقّق أولًا من سلسلة أدوات Mac
تحتاج إلى بيئة تطوير macOS تتضمن Clang وSDK لـ macOS وSwift 6.3 أو إصدارًا أحدث. توفر Apple أدوات سطر الأوامر مع Xcode، كما تقدم حزمة منفصلة لأدوات سطر الأوامر. إذا كان Xcode مثبتًا لديك بالفعل، فتذكر Apple أن تثبيت الأدوات المنفصلة غير ضروري. تثبيت أدوات سطر الأوامر
نفّذ عمليات التحقق هذه في Terminal:
xcode-select --print-path
xcrun --sdk macosx swiftc --version
xcrun --sdk macosx clang --version
تحقّق من إصدار مصفّر Swift نفسه. فوجود SDK أحدث لا يضيف ميزة @c إلى مصفّر أقدم. إذا كانت لديك إصدارات متعددة من Xcode، توثّق Apple اختيار الإصدار النشط من Xcode > Settings > Locations > Command Line Tools، أو تجاوزه لجلسة shell باستخدام DEVELOPER_DIR. تهيئة إعدادات أدوات سطر الأوامر
تستخدم الأوامر أدناه xcrun لاستدعاء أدوات التطوير المحددة. توثّق Apple دور اكتشاف الأدوات هذا في مرجع البناء من سطر الأوامر. الأسئلة الشائعة حول البناء من سطر الأوامر باستخدام Xcode
أنشئ مجلد عمل فارغًا واحفظ ملفي المصدر أدناه فيه. نفّذ أوامر البناء من ذلك المجلد. هذا بناء أصلي لـ Mac المحلي؛ ولا ينشئ ملفًا ثنائيًا عالميًا أو يهيئ منصة أخرى.
اكتب تنفيذ Swift ومستدعي C
عرّف دالة Swift المُصدّرة
احفظ ملف مصدر Swift الكامل هذا باسم Percent.swift:
@c(demo_clamp_percent)
public func clampPercent(_ value: CInt) -> CInt {
if value < 0 {
return 0
}
if value > 100 {
return 100
}
return value
}
اسم Swift هو clampPercent؛ والاسم المخصص لـ C هو demo_clamp_percent. يُطابق CInt النوع int في C. يجنّب هذا الاقتران الصريح افتراض أن Swift Int يعني C int: فالتطابق الموثق لـ Swift Int هو ptrdiff_t. دوال وتعدادات متوافقة مع C
تقارن الدالة القيم وتعيد إما قيمة إدخال أو ثابتًا. ولا تتسبب عمليتها الحسابية في تجاوز سعة الأعداد، حتى مع قيم إدخال خارج مجال النسبة. والبادئة في الاسم المُصدّر مثال على اصطلاح يُستخدم لتمييز هذه الواجهة عن الدوال الأخرى في برنامج أكبر.
استدعِها من برنامج C كامل
احفظ هذا الملف باسم main.c. سيُنشئ البناء الترويسة المُضمّنة:
#include <stddef.h>
#include <stdio.h>
#include "Percent-Swift.h"
int main(void) {
const int inputs[] = {-12, 42, 140};
const int expected[] = {0, 42, 100};
const size_t count = sizeof inputs / sizeof inputs[0];
for (size_t i = 0; i < count; ++i) {
const int actual = demo_clamp_percent(inputs[i]);
printf("%d -> %d\n", inputs[i], actual);
if (actual != expected[i]) {
fprintf(stderr, "Unexpected result at index %zu\n", i);
return 1;
}
}
return 0;
}
تختبر قيم الإدخال الثلاث الحد الأدنى، وقيمة لا تتغير، والحد الأقصى. يتحقق البرنامج من النتائج صراحةً ويعيد حالة غير صفرية عند عدم التطابق، لذا تكون مخرجاته أفيد من عرض يكتفي بطباعة رقم.
أنشئ الترويسة، وصرف C، واربط البرنامج
نفّذ هذا التسلسل في shell من المجلد الذي يحتوي على الملفين. تتوقف كل خطوة بناء إذا فشلت:
(
set -eu
SDK_PATH="$(xcrun --sdk macosx --show-sdk-path)"
xcrun --sdk macosx swiftc \
-sdk "$SDK_PATH" \
-parse-as-library \
-module-name Percent \
-emit-object Percent.swift \
-emit-objc-header-path Percent-Swift.h \
-o Percent.o
xcrun --sdk macosx clang \
-isysroot "$SDK_PATH" \
-x c -std=c11 \
-Wall -Wextra -Werror \
-c main.c -o main.o
xcrun --sdk macosx swiftc \
-sdk "$SDK_PATH" \
main.o Percent.o \
-o percent-demo
./percent-demo
)
ينشئ الأمر الأول كائن Swift وترويسة التوافق. يعرّف مشغّل Swift الخيار -emit-object بأنه إخراج لملف كائن، والخيار -parse-as-library بأنه تحليل مصدر مكتبة بدلًا من تحليل نص برمجي. وبذلك يبقى مدخل البرنامج في ملف C. خيارات مشغّل مصفّر Swift
على الرغم من اسمه التاريخي، يطلب -emit-objc-header-path أيضًا قسم C من ترويسة التوافق لإعلانات @c. ويحافظ الاقتراح المنفّذ صراحةً على هذا الخيار لهذا الغرض. لا تستبدل الترويسة المُنشأة يدويًا بتصريح مفترض. دوال وتعدادات متوافقة مع C
الأمر الثاني هو التحقق الحاسم من لغة المصدر. توثّق Clang أن -x يحدد لغة الإدخال، وأن -c ينتج ملف كائن من دون ربط. هنا، يجعل -x c -std=c11 المستدعي يُصرّف وفق C11 مع قراءة الترويسة المُنشأة فعليًا. دليل أوامر Clang
يربط استدعاء المصرّف الأخير كلا ملفي الكائن باستخدام مشغّل Swift. ويوصي دليل مصفّر Swift نفسه بأن تطلب من swiftc ربط الملفات بدلًا من تركيب أمر ربط منخفض المستوى يدويًا. تنقيح أخطاء المصرّف
المخرجات المتوقعة، استنادًا إلى فروع المثال، هي:
-12 -> 0
42 -> 42
140 -> 100
تمت مراجعة هذه الأوامر بالاستناد إلى الوثائق التي جرى استرجاعها، لكن لم تُنفّذ هنا: فبيئة البحث تعمل بنظام Linux ولا يتوفر فيها swiftc ولا Clang. المخرجات أعلاه نتيجة متوقعة، وليست تقريرًا عن اختبار أُجري على Mac.
اختر الواجهة التي تناسب شيفرتك الحالية
لواجهة جديدة وصغيرة على Swift 6.3 أو إصدار أحدث، يربط أسلوب الترويسة المُنشأة أعلاه التصريح مباشرةً بالتنفيذ. وتدعم وثائق الإصدار أيضًا اتجاهًا ثانيًا: تنفّذ @c @implementation دالة معلنة مسبقًا في ترويسة C مستوردة، ويتحقق Swift من تطابق التوقيعات. يفيد ذلك عندما يجب أن تظل واجهة C الحالية هي عقد الواجهة. إصدار Swift 6.3
إذا كان المشروع المحيط يستدعي Swift عبر C++ بالفعل، فتتيح روابط C++ المُنشأة في Swift مسارًا آخر. تُمثّل دوال Swift العامة بدوال C++ مضمّنة داخل مساحة أسماء للوحدة. وسيحتاج مستدعٍ مكتوب بـ C إلى محوّل منفصل مُصرّف على أنه C++، يكشف تصريحًا صغيرًا مخصصًا لـ C. وستضم وحدة الترجمة المكتوبة بـ C ترويسة C الخاصة بذلك المحوّل. مزج Swift وC++
في هذا المحوّل، تحدد extern "C" ربط لغة C في تصريح C++ أو تعريفه. لكنها لا تحوّل محتويات ترويسة C++ إلى صياغة C. وتعرّف المسودة العاملة لـ C++ مواصفات الربط، وتُميّز بين ربط اللغة والتصريحات العادية. المسودة العاملة لـ C++: مواصفات الربط
في هذا الدليل، يُعد تحديث مصفّر قديم إلى إصدار يدعم @c المسار المباشر المدعوم. يصف الاقتراح @_cdecl بأنه سلفها التجريبي؛ ونسخ تلك الصيغة القديمة إلى مثال جديد سيخفي حدًا مهمًا بين الإصدارات. دوال وتعدادات متوافقة مع C
شخّص الأعطال عند الحد الذي تقع فيه
استخدم أول خطوة بناء فاشلة لتضييق نطاق البحث. ففشل إنشاء الترويسة، وخطأ محلل C، والرمز غير المحلول تتطلب تصحيحات مختلفة.
| أول إخفاق | الخطوة التالية للتحقق |
|---|---|
يرفض Swift السمة @c |
أعد التحقق من إصدار مصفّر Swift المحدد؛ يتطلب هذا المثال Swift 6.3 أو إصدارًا أحدث. |
لا يستطيع C العثور على Percent-Swift.h |
تأكد من نجاح أمر Swift ومن بناء الملفين من المجلد المقصود. |
لا يستطيع C العثور على demo_clamp_percent |
افحص الترويسة المُنشأة حديثًا وتحقق من كتابة السمة؛ أعد البناء بعد تغيير المصدر. |
| يُبلغ C عن صياغة C++ أو Objective-C | تحقّق من الترويسة التي أُدرجت وسلسلة الأدوات التي أنشأتها. أبقِ التصريف الصريح على أنه C أثناء التحقق. |
| يتعذر على الرابط إيجاد الدالة المُصدّرة | تأكد من تضمين Percent.o في الأمر الأخير ومن إعادة بنائه من مصدر Swift الحالي. |
| يُبلغ البرنامج التنفيذي عن نتائج غير متوقعة | اقرأ زوج الإدخال/النتيجة المطبوع وقارنه بفروع Swift. |
يتبع هذا التسلسل مراحل المصرّف التي توثقها Clang: يحدد التحليل ما إذا كان المصدر صالحًا، وينتج إنشاء الكائن شيفرة مُصرّفة، ويجمع الربط المدخلات المُصرّفة. لذلك لا يثبت نجاح تصريف C سوى جزء من المهمة. دليل أوامر Clang
عند تكييف المثال، أبقِ الدالة المخصصة لـ C صغيرة وحدد عقدًا صريحًا لكل وسيط جديد. بالنسبة إلى النص، حدّد الترميز وطريقة التعامل مع الطول؛ وبالنسبة إلى المخازن المؤقتة، حدّد السعة والملكية قبل كتابة الغلاف. فهذه قرارات تصميم للواجهة تتجاوز هذا المثال التوضيحي الذي يقتصر على الأعداد الصحيحة.
يتحقق الفحص المحلي المكتمل من ثلاث نتائج ملموسة: قبول الترويسة المُنشأة أثناء التصريف الصريح على أنه C، وربط كلا التنفيذين في ملف تنفيذي واحد، والتحقق من قيم الإدخال المختارة في المستدعي. حافظ على هذه الفحوص عند استبدال العملية الحسابية الافتراضية بدالة Swift الخاصة بك.
المصادر
- إصدار Swift 6.3 — Swift.org
- دوال وتعدادات متوافقة مع C — Swift Evolution
- تثبيت أدوات سطر الأوامر — Apple
- تهيئة إعدادات أدوات سطر الأوامر — Apple
- الأسئلة الشائعة حول البناء من سطر الأوامر باستخدام Xcode — Apple
- خيارات مشغّل مصفّر Swift — Swift Project
- دليل أوامر Clang — LLVM Project
- تنقيح أخطاء المصرّف — Swift Project
- مزج Swift وC++ — Swift.org
- المسودة العاملة لـ C++: مواصفات الربط — C++ Working Draft