دليل CMake الكامل. الجزء الأول: بناء الجملة


مقدمة


CMake عبارة عن مجموعة من الأدوات المساعدة مفتوحة وعبر النظام الأساسي مصممة لأتمتة اختبار وتجميع وإنشاء حزم المشاريع في C / C ++. من خلال كتابة برنامج نصي صغير يفهمه الجميع ، ستضمن نفس بنية مشروعك على أي نظام أساسي تتوفر فيه CMake.


تحدد لغة CMake ، التي يتم ترجمتها إلى ملف تجميع أصلي (على سبيل المثال ، Makefile أو Ninja) ، عملية إدارة جميع المشاريع. تحت تصرفك ، على الجانب الوظيفي ، هناك فقط فرق يمكن تشكيلها في هياكل معقدة إلى حد ما. سنبدأ معهم.


إطلاق CMake


فيما يلي أمثلة لاستخدام لغة CMake التي يجب عليك ممارستها. تجربة مع شفرة المصدر عن طريق تعديل الأوامر الحالية وإضافة جديدة. لتشغيل هذه الأمثلة ، قم بتثبيت CMake من الموقع الرسمي .


فرق


تشبه الأوامر في CMake الوظائف في العديد من لغات البرمجة. للاتصال بأمر ما ، يجب أن تكتب اسمها ، ثم تقوم بتمرير وسيطات محاطة بأقواس ، مفصولة بمسافات. في المثال أعلاه ، يتم تمرير ست وسائط إلى أمر message لإخراجها إلى وحدة التحكم:


 #    "CMake is the most powerful buildsystem!" message("CMake " "is " "the " "most " "powerful " "buildsystem!") 

الحجج


تسمح لك الحجج المؤطرة بعلامات اقتباس مزدوجة بالهروب واستبدال المتغيرات بداخلك. لا تسمح الوسائط غير المؤطرة بإنتاج مثل هذه الأشياء ولا يمكنها تضمين الأحرف ()#"\ والمسافات ، ولكنها أكثر ملاءمة للاستخدام. مثال:


 #  "Hello, my lovely CMake",    "!": message("Hello, my lovely CMake\t!") #  "Hello,_my_lovely_CMake!"  : message(Hello,_my_lovely_CMake!) 

تجدر الإشارة إلى أن الوسيطة Walk;around;the;forest ستوسع إلى القائمة Walk around the forest ، لأن أي وسيطة غير مؤطرة تتوسع تلقائيًا إلى قائمة من القيم (بشرط أن تكون قيم الوسيطة الأصلية مفصولة بفواصل منقوطة) ، لكن مع وجود فاصلة مزدوجة علامات الاقتباس كحجة لا يحدث مثل هذا التحويل (أحرف الفاصلة المنقوطة تختفي فقط). تم ذكر هذه الميزة في التعليقات.


تعليقات


تبدأ التعليقات بإشارة الجنيه وتنتهي في نهاية السطر حيث تمت طباعتها. يتم تجاهل النص الموجود في التعليقات من قبل نظام البناء وليس له أي تأثير على تشغيله. توضح الأمثلة أعلاه أيضًا استخدام التعليقات.


المتغيرات


يمكن تحديد المتغيرات عن طريق استدعاء الأمر set ، وحذفها عن طريق استدعاء unset . يمكنك الحصول على قيمة المتغير عن طريق إنشاء ${VARIABLE} . إذا لم يتم تحديد المتغير حتى الآن وكان مطلوبًا في مكان ما الحصول على قيمته ، فإن هذا المتغير سيتحول إلى سلسلة فارغة. مثال:


 #   VARIABLE   "Mr. Thomas": set(VARIABLE "Mr. Thomas") #  "His name is: Mr. Thomas": message("His name is: " ${VARIABLE}) #  "'BINGO' is equal to: []",   "BINGO"  : message("'BINGO' is equal to: [${BINGO}]") #   VARIABLE: unset(VARIABLE) 

خيارات


يدعم CMake خيارات الإعداد التي تخضع لتعديلات المستخدم. تتشابه الخيارات مع المتغيرات ويتم تعيينها بواسطة أمر option ، الذي لا يستغرق سوى ثلاث وسائط: اسم المتغير ووصف سلسلة المتغير والقيمة الافتراضية للمتغير ( ON أو OFF ):


 #   `USE_ANOTHER_LIBRARY`   # "Do you want to use an another library?"   "OFF": option(USE_ANOTHER_LIBRARY "Do you want to use an another library?" OFF) 

التعبيرات المنطقية


قبل متابعة دراسة العوامل الشرطية والإنشاءات الدورية ، من الضروري فهم عمل التعبيرات المنطقية. يتم استخدام التعبيرات المنطقية عند التحقق من الشروط ويمكن أن تأخذ إحدى القيمتين: صواب أو خطأ. على سبيل المثال ، سيكون التعبير 52 LESS 58 صحيحًا ، لأن 52 <58. التعبير 88 EQUAL 88 سيكون صحيحًا ، 63 GREATER 104 سيكون خاطئ. يمكنك مقارنة ليس فقط الأرقام ، ولكن أيضًا السلاسل والإصدارات والملفات وعضوية القائمة والتعبيرات العادية. قائمة كاملة من التعبيرات المنطقية ويمكن الاطلاع هنا .


البيانات الشرطية


عوامل التشغيل الشرطية في CMake تعمل تمامًا كما هي الحال في لغات البرمجة الأخرى. في هذا المثال ، سيعمل المشغل الشرطي الأول فقط ، والذي يتحقق من 5> 1. الشرط الثاني والثالث خاطئان ، لأن 5 لا يمكن أن يكون أقل من أو يساوي واحد. تكون كتل الأوامر elseif و else اختيارية ، و endif مطلوبة وتشير إلى اكتمال عمليات الفحص السابقة.


 #  "Of course, 5 > 1!": if(5 GREATER 1) message("Of course, 5 > 1!") elseif(5 LESS 1) message("Oh no, 5 < 1!") else() message("Oh my god, 5 == 1!") endif() 

دورات


تشبه الحلقات في CMake الحلقات في لغات البرمجة الأخرى. في المثال أعلاه ، يتم تعيين قيمة المتغير VARIABLE إلى Airport ، ثم يتم تنفيذ أربعة أوامر متداخلة بالتسلسل حتى قيمة المتغير VARIABLE تساوي Airport . يعيّن أمر set(VARIABLE "Police station") الرابعة الأخير set(VARIABLE "Police station") قيمة المتغير set(VARIABLE "Police station") في مركز Police station ، لذلك ستتوقف الحلقة فورًا قبل الوصول إلى التكرار الثاني. يشير الأمر endwhile إلى إكمال قائمة الأوامر المتداخلة في الحلقة.


 #      "VARIABLE is still 'Airport'": set(VARIABLE Airport) while(${VARIABLE} STREQUAL Airport) message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") set(VARIABLE "Police station") endwhile() 

يعمل هذا المثال foreach النحو التالي: في كل تكرار لهذه الحلقة ، يتم تعيين متغير VARIABLE القيمة التالية من القائمة Give me the sugar please! ثم يتم تنفيذ الأمر message(${VARIABLE}) ، والذي يعرض القيمة الحالية للمتغير VARIABLE . عندما لا توجد قيم في القائمة ، تنتهي الحلقة من تنفيذها. endforeach الأمر endforeach إلى إكمال قائمة الأوامر المتداخلة في الحلقة.


 #  "Give me the sugar please!"   : foreach(VARIABLE Give me the sugar please!) message(${VARIABLE}) endforeach() 

هناك 3 أشكال أخرى من كتابة foreach . تقوم الدورة الأولى في هذا المثال بإنشاء أعداد صحيحة من 0 إلى 10 بدلاً من القائمة ، بينما يتم إنشاء الدورة الثانية في النطاق من 3 إلى 15 ، وتعمل الدورة الثالثة في المقطع من 50 إلى 90 ، ولكن مع الخطوة 10.


 #  "0 1 2 3 4 5 6 7 8 9 10"   : foreach(VARIABLE RANGE 10) message(${VARIABLE}) endforeach() #  "3 4 5 6 7 8 9 10 11 12 13 14 15"   : foreach(VARIABLE RANGE 3 15) message(${VARIABLE}) endforeach() #  "50 60 70 80 90"   : foreach(VARIABLE RANGE 50 90 10) message(${VARIABLE}) endforeach() 

وظائف ووحدات الماكرو


يسمح لك بناء جملة CMake بتعريف الأوامر الخاصة بك والتي يمكن استدعاؤها تمامًا على أنها مدمجة. يوضح المثال التالي استخدام الدالات ووحدات الماكرو: أولاً ، يتم تعريف الدالة والماكرو بأوامرها الخاصة ، وعندما يتم استدعاء الأوامر الخاصة بها يتم تنفيذها بالتسلسل.


 #   "print_numbers": function(print_numbers NUM1 NUM2 NUM3) message(${NUM1} " " ${NUM2} " " ${NUM3}) endfunction() #   "print_words": macro(print_words WORD1 WORD2 WORD3) message(${WORD1} " " ${WORD2} " " ${WORD3}) endmacro() #   "print_numbers",   "12 89 225": print_numbers(12 89 225) #   "print_words",   "Hey Hello Goodbye": print_words(Hey Hello Goodbye) 

يأخذ الأمر function اسم الدالة المستقبلية كالوسيطة الأولى ، وبقية الوسائط هي أسماء المعلمات التي يمكن استخدامها كمتغيرات عادية. تكون المعلمات مرئية فقط للوظيفة التي يتم تعريفها ، مما يعني أنه لا يمكننا الوصول إلى المعلمات الخاصة بها خارج الوظيفة. علاوة على ذلك ، فإن جميع المتغيرات الأخرى المعرفة وإعادة التعريف داخل الوظيفة تكون مرئية فقط لنفسها.


تشبه وحدات الماكرو الوظائف باستثناء أنه ليس لديها نطاق خاص بها: تعتبر جميع المتغيرات الموجودة داخل وحدات الماكرو عالمية. يمكنك قراءة المزيد حول الاختلافات بين وحدات الماكرو والوظائف هنا .


كما هو موضح في التعليقات ، تشبه وحدات الماكرو في CMake وحدات الماكرو في المعالج المسبق C: إذا وضعت أمر return في نص الماكرو ، فستخرج من وظيفة الاستدعاء (أو البرنامج النصي بأكمله) ، كما يوضح هذا المثال:


 #  ,   : macro(demonstrate_macro) return() endmacro() #  ,   : function(demonstrate_func) demonstrate_macro() message("The function was invoked!") endfunction() #  "Something happened with the function!" demonstrate_func() message("Something happened with the function!") 

في المثال أعلاه ، لن يكون لدى The function was invoked! الوقت لطباعة الرسالة The function was invoked! ، كما كان من قبل ، سيتم استبدال مكان استدعاء الماكرو demonstrate_macro وسيتم تنفيذ أمر الخروج.


تحليل الحجج


كما هو موضح في التعليقات ، تسمح آلية cmake_parse_arguments القوية cmake_parse_arguments الوسائط التي تم تمريرها إلى دالة أو ماكرو.


يقبل هذا الأمر البادئة المستخدمة في تعريف المتغيرات (انظر الفقرة التالية) ، وقائمة الخيارات المستخدمة بدون قيم لاحقة ، وقائمة بالكلمات الأساسية متبوعة بقيمة واحدة ، وقائمة بالكلمات الأساسية متبوعة بمجموعات من القيم ، وقائمة بجميع القيم التي تم تمريرها إلى الوظيفة أو ماكرو.


عمل آلية تحليل الوسيطة هو تحويل الوسائط المستلمة إلى قيم متغيرة. وبالتالي ، فإن الأمر المدروس لكل خيار وكلمة أساسية يحدد المتغير الخاص به من النموذج <Prefix>_<OptionOrKeyword> ، والذي يتضمن قيمة معينة. بالنسبة للخيارات ، هذه هي القيم المنطقية (صواب - الخيار موضح ؛ وإلا ، خطأ) ، وبالنسبة للكلمات الرئيسية ، فإن جميع القيم المنقولة موجودة بعدها.


تحتوي الدالة custom_function على استدعاء cmake_parse_arguments ، ثم تقوم بطباعة قيم بعض المتغيرات. بعد ذلك ، يتم استدعاء الوظيفة باستخدام الوسائط LOW NUMBER 30 COLORS red green blue ، وبعد ذلك يتم طباعتها على الشاشة:


 function(custom_function) #       : cmake_parse_arguments(CUSTOM_FUNCTION "LOW;HIGH" "NUMBER" "COLORS" ${ARGV}) #  "'LOW' = [TRUE]": message("'LOW' = [${CUSTOM_FUNCTION_LOW}]") # "'HIGH' = [FALSE]": message("'HIGH' = [${CUSTOM_FUNCTION_HIGH}]") #  "'NUMBER' = [30]": message("'NUMBER' = [${CUSTOM_FUNCTION_NUMBER}]") #  "'COLORS' = [red;green;blue]": message("'COLORS' = [${CUSTOM_FUNCTION_COLORS}]") endfunction() #   "custom_function"   : custom_function(LOW NUMBER 30 COLORS red green blue) 

النطاقات


في القسم السابق ، تعلمت أن بعض التركيبات في CMake يمكنها تحديد نطاقها الخاص. في الواقع ، تعتبر جميع المتغيرات عالمية بشكل افتراضي (الوصول إليها في كل مكان) ، باستثناء المتغيرات التي تم تعريفها وإعادة تعريفها في الوظائف. هناك أيضًا متغيرات ذاكرة التخزين المؤقت لها نطاقها الخاص ، لكن لا يتم استخدامها كثيرًا.


كما ذكر في التعليقات ، يمكن تعريف المتغيرات في نطاق "الأصل" باستخدام الأمر set(VARIABLE ... PARENT_SCOPE) . يوضح هذا المثال هذه الميزة:


 # ,   "VARIABLE"   # "In the parent scope..."    : function(demonstrate_variable) set(VARIABLE "In the parent scope..." PARENT_SCOPE) endfunction() #   "VARIABLE"    : demonstrate_variable() #      "VARIABLE" : message("'VARIABLE' is equal to: ${VARIABLE}") 

إذا تمت إزالة PARENT_SCOPE من تعريف المتغير VARIABLE ، فسيكون المتغير متاحًا فقط PARENT_SCOPE ، وفي النطاق العام سيستغرق ذلك قيمة فارغة.


الخاتمة


هذا يخلص بناء جملة CMake. سيتم إصدار المقالة التالية في غضون يومين تقريبًا وستقدم استخدام نظام بناء CMake. اراك قريبا!

Source: https://habr.com/ru/post/ar431428/


All Articles