با قسمت سیزدهم از دوره ورود به دنیای امبدد لینوکس که دوره مقدماتی آموزش امبدد لینوکس می باشد همراه ما باشید.
(فصل دوم – بخش نهم)
خوب! توی قسمت قبل اجزا تولچین رو بررسی کردیم و کمی بیشتر با ابزار های داخل اون آشنا شدیم. در این قسمت از آموزش های امبدد لینوکس، با انواع روش های بیلد کردن، کراس کامپایل و چالش های آن آشنا خواهیم شد.
در قسمتهای قبلی آموزش، مسیر حرکت و فصلهای پیش رو، بسیاری از مفاهیم مورد نیاز و سؤالها و ابهامات شما در این دوره پاسخ داده شده است.
پس اگر اولین بار است که این آموزش را شروع میکنید، با توجه به سلسله مراتب پیش بینی شده برای آموزشها، بهتر است از جلسه اول شروع کنید!
جلسه اول آموزش، ورود به دنیای امبدد لینوکس
استاتیک یا داینامیک
هر برنامهای که واسه لینوکس به زبان C/C++ مینویسم به یه سری کتابخانهها نیاز داره که حداقلش همون libc هست که به صورت پیش فرض با همه برنامهها لینک هست و نیازی نیست به کامپایلر بگیم لینکش کن.
بقیه کتابخانهها رو با آپشن –l به کامپایلر میگیم لینک کنه.
این لینک کردن به دو صورت استاتیک و داینامیک میتونه انجام بشه.
استاتیک یعنی تمام توابعی که برنامه ما استفاده میکنه و وابستههاشون همشون از کتابخانه اصلی استخراج میشن و توی برنامه اجرایی ما گونجونده میشه.
داینامیک یعنی ارجاعات به فایلهای کتابخانه و توابعش در کد هست ولی لینک اصلی هنگام اجرا صورت میگیره.
کاربرد استایتک بیشتر زمانی هست که ما میخوایم در مصرف حافظه صرفه جویی کنیم یا مجبوریم صرفه جویی کنیم و برنامههای زیادی هم نداریم. مثلا میخوایم کل سیستم عامل و برنامههاش رو روی یه SPI فش جا بدیم.
توی امبددهای امروزی بیشتر از حالت داینامیک استفاده میشه و در این حالت دونستن ورژنهای کتابخانهها مهمه.
چرا اینقدر کتابخانه با یک اسم داریم؟
مثلا یه نگاهی به این خروجی بندازین
1 2 3 | ls usr/lib/libmenu* usr/lib/libmenu.a usr/lib/libmenu.so.5 usr/lib/libmenu.so usr/lib/libmenu.so.5.9 |
خوب یکم دقیقتر بش نگاه کنیم:
1 2 3 4 5 | ls -l usr/lib/libmenu* -r--r--r-- 1 at00 at00 60710 Aug 30 2020 usr/lib/libmenu.a lrwxrwxrwx 1 at00 at00 12 Aug 30 2020 usr/lib/libmenu.so -> libmenu.so.5 lrwxrwxrwx 1 at00 at00 14 Aug 30 2020 usr/lib/libmenu.so.5 -> libmenu.so.5.9 -r-xr-xr-x 1 at00 at00 48316 Aug 30 2020 usr/lib/libmenu.so.5.9 |
کتابخانه libmenu.a واسه زمانی هست که میخوایم استایتک بیلد کنیم.
libmenu.so.5.9 که کتابخانه اصلی هست واسه داینامیک لینک ولی چرا این دو تا سافت لینک (شرتکات!) رو داریم libmenu.so libmenu.so.5؟
libmenu.so واسه داینامیک لینک زمان کامپایل هست و libmenu.so.5 هم یک soname هست و در زمان اجرا ازش استفاده میشه.
و اما soname چی هست؟ گوگل ایت!
هنر کراس کامپایل
داشتن تولچین شروع قصه است.
ادامه قصه میشه کامپایل کردن کتابخانهها یا برنامههای متن بازی که زیاد میبینید برای امبدد لینوکستون.
خوب راه آنچنان راحتی نیست!
معمولا برای بیلد کردن این برنامهها از بیلد سیستمها استفاده میشه.
بیلد سیستمهای مختلفی وجود داره که سه تا از معروفترینهاش رو معرفی میکنیم.
Makefiles خالص
توی این makefileها معمولا کامپایلر از طریق متغیر CROSS_COMPILE تعیین میشه.
خوشبختانه اکثر پکیجها و برنامههای مهم مثل کرنل لینوکس و BusyBox این جوری هستن.
برای کراس کامپایل کردن این برنامهها فقط کافیه پیشوند تولچین رو به متغیر CROSS_COMPILE بدیم. دو مدل میشه این کار رو کرد: (اولش اون فایل رو سورس کنید.)
1 | make CROSS_COMPILE=arm-richdad-linux-gnueabi- |
یا
1 2 | export CROSS_COMPILE= arm-richdad-linux-gnueabi- make |
البته برای کراس کامپایل کرنل یا کراس کامپایل BusyBox یه سری متغیرهای دیگه مثل ARCH هم باید ست بشن که توی فصل خودشون بشون میرسیم.
بیلد سیستم گنو که به Autotools شناخته میشه
احتمالا این چند خط واستون خیلی آشنا باشه، چند خطی که واسه خودم تا چند سال هیچ وقت جواب ندادن واسه هیچ برنامهای!
1 2 3 | $ ./configure $ make $ sudo make install |
این دستورات واسه زمانی هست که نمیخوایم کراس کامپایل کنیم و نیتیو داریم کامپایل میکنیم.
اما Autotools واسه کراس کامپایل کردن هم راه حل داره. یه سری متغیرها هست که هر کدوم لازم باشه باید ست کنیم:
CC: The C compiler command
CFLAGS: Additional C compiler flags
LDFLAGS: Additional linker flags; for example, if you have libraries in a non-standard directory <lib dir> , you would add it to the library search path by adding -L<lib dir>
LIBS: Contains a list of additional libraries to pass to the linker; for instance, -lm for the math library
CPPFLAGS: Contains C/C++ preprocessor flags; for example, you would add -I<include dir> to search for headers in a non-standard directory <include dir>
CPP: The C preprocessor to use
تمرین: SQLite را برای F1C100s کراس کامپایل کنید!
کراس کامپایل SQLite برای F1C100s
فرض میکنیم در فولدر F1C100s هستیم:
1 2 3 4 | source at00exports.sh cd project wget https://www.sqlite.org/2021/sqlite-autoconf-3350200.tar.gz tar xf sqlite-autoconf-3350200.tar.gz |
خب تا اینجا که آسون بود ?
حالا میریم توی فولدر و کار اصلی رو شروع میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | cd sqlite-autoconf-3350200/ CC=$GCC ./configure checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p checking for gawk... gawk checking whether make sets $(MAKE)... yes checking whether make supports nested variables... yes checking for style of include used by make... GNU checking for gcc... /home/at00/EmbeddedLinux/F1C100s/build-tools/at00toolchain/bin/arm-richdad-linux-gnueabi-gcc checking whether the C compiler works... yes checking for C compiler default output file name... a.out checking for suffix of executables... checking whether we are cross compiling... configure: error: in `/home/at00/EmbeddedLinux/F1C100s/project/sqlite-autoconf-3350200': configure: error: cannot run C compiled programs. If you meant to cross compile, use `--host'. See `config.log' for more details |
و طبیعتا به خطا برمیخوریم.
خوب باید host رو مشخص کنیم. این جا هم مثل زمان ساختن کراس تولچین سه تا اصطلاح رو داریم که تعاریفش یکم فرق کرده:
Build: is the computer that builds the package, which defaults to the current machine.
Host: is the computer the program will run on; for a native compile, this is left blank and it defaults to be the same computer as build. When you are cross compiling, set it to be the tuple of your toolchain.
Target: is the computer the program will generate code for; you would set this when building a cross compiler, for example.
این host در حقیقت چندتایی (tuple) تولچین هست.
به جز host یه چیز دیگه هم لازمه، محل نصب پیش فرض معمولا مسیر زیر هست:
1 | <sysroot>/usr/local/* |
ولی بهتره به این مسیر تغییرش بدیم (چرا؟):
1 | <sysroot>/usr/* |
پس در نهایت دستور کامل این میشه:
1 | CC=$GCC ./configure --host=arm-richdad-linux-gnueabi --prefix=/usr |
خوشبختانه واسه من این دستور جواب داد واسه شما هم اگه تا الان مثل من پیش اومده باشین باید جواب بده.
و حالا بریم واسه make کردنش
1 | make -j$(nproc) |
سوال: -j$(nproc) چی هست و آیا باید باشد؟ جواب بایدی وجود ندارد، برای بقیه توضیحات گوگل ایت!
باورش سخته ولی make شد ?
خوب حالا بریم واسه نصب ولی قبلش یکم مرتب سازی انجام بدیم. ما الان میدونیم یه sysroot داریم و از قبل هم داخل فولدر پروژه مون یه فولدر ساخته بودیم به نام rootfs، خوب محتویات اون رو بریزیم توی این که دست به فایلهای اصلی نزده باشیم، هرچند خروجی crosstool-NG به صورت Read Only هست.
1 2 | cp -r ../../build-tools/at00toolchain/arm-richdad-linux-gnueabi/sysroot/* ../../rootfs/ chmod –R 777 ../../rootfs/* |
خوب حالا بریم واسه نصب:
1 | make DESTDIR=/home/at00/EmbeddedLinux/F1C100s/rootfs/ install |
سوال: چه فایلهایی نصب شد؟
جواب: فایلهای بسیاری از جمله این فایل که ببینید به درد چی میخوره!
1 | usr/lib/pkgconfig/sqlite3.pc |
سوال: آیا الان به راحتی میتوان برنامهای که از SQLite استفاده میکنه رو کراس کامپایل کرد با این دستور؟
1 | $GCC -lsqlite3 sqlite-test.c -o sqlite-test |
جواب: خیر، چون فایلهای سرآیند و کتابخانهها را در sysroot نصب نکردیم.
سوال: خوب چه باید کرد؟
جواب: -L و –I رو گوگل کنید!
هشدار
کراس کامپایل همیشه به این راحتی نیست و در مورد برخی پکیجها به صورت دستی شاید نشدنی باشه یا وقت بسیار زیاد بخواد.
محیط توسعه و سایر ابزارهای لازم برای امبدد لینوکس
به جز minicom ابزار خاصی لازم نیست!
کرنل نویسها کماکان از vi استفاده میکنن برای نوشتن کدهاشون!
با اطلاعاتی که الان دارید به راحتی میتونید تنظیمات لازم رو برای کیوت یا اکلیپس انجام بدین و از اونا برای نوشتن، بیلد کردن و دیپلوی کردن کدهاتون روی بردتون استفاده کنید.
من خودم از کیوت استفاده میکنم.
یکی دیگه از ابزارهایی که خوبه بدونید وجود داره gdb یا دیباگر GNU هست.
به پایان این فصل رسیدیم. در فصل بعد بیشتر وارد عمل میشیم و بوت لودر رو میریزیم روی بردمون تا آمادهش کنیم برای لینوکس.
پایان بخش نهم از فصل دوم
یه سری هم به نظرات این پایین بندازید، نظرات رو بخونید و اگر شما هم نظری دارید، مشارکت کنید!
سلام ممنون از آموزش های خوبتون
نمی دونم درست متوجه شدم یا نه؟!
یعنی منظور از کراس کامپایل کردن qtlite می شه توی پروژه از کتابخانه هاش اتستفاده کرد؟
پس اگر با این حال می شه پایتون هم کراس کامپایل کرد و بدون این که لینوکسی بالا بیاد از پایتون هم استفاده کرد ؟
درست متوجه شدم؟
یا مثلا می شه یک نرم افزار که گرافیک هم داره رو کراس کامپایل کرد و ازش استفاده کرد بدون لینوکس؟
چون توی یوکتو گفته شده چنین قابلیتی هست اما واقعا برای من که مبتدی ام پیچیده هست و پیدا کردن راه ها و فهمیدن مفاهیم مقداری دشواره
می شه بیشتر توضیح بدین
باسلام
بنده تشکر میکنم بابت زحمتی که کشیدید ولی واقعیت اینه که من از یه جایی به بعد دیگه نخوندم. اولش خیلی خوب شروع کردید در مورد دغدغه و سوالهایی که برای افراد ایجاد میشه ولی وسطای کار دیگه یه جوری شده که باید از قبل بلد بوده باشی. یکم مباحث بدون توضیح و گنگ شدند و انگار عجله دارید سریعتر به آخرش برسید برای همین از بخشهای زیادی بدون توضیح با شوخی و خنده عبور کردید.
البته بنده برای گردآوری و نگارش این موضوعات از شما ممنونم ولی ترجیح میدم یه منبع مناسب دیگه پیدا کنم که سوالاتم پاسخ داده بشه و توضیحاتش مدون تر باشه.
Cmake و ninja هم فک کنم بیلد سیستم هستن ؟
cmake فکر میکنم بیلدسیستم جنراتور باشه ولی ninja یه بیلد سیستم هست
سلام
ممنون از مطالبتون
پس فصل جدید چی شد؟؟؟ کی میاد؟؟؟
سلام معین جان
ممنون که پیگیر مطلب هستید، باعث دلگرمی ماست ?
اتفاق های زیادی در این مدت افتاده ?? و ما در تلاش هستیم مقاله ها را به سایت برسونیم تا عزیزانی مثل شما بتوانند استفاده کنند.
متشکریم از همه دوستان و همراهان
سلام
خیلی مطالب عالی میذارید امیدوارم همیشه تندرست باشید و موفق
همه مطالب شما رو دنبال میکنم
سلام احسان جان
خیلی ممنون که پیگیر موضوع مقاله هستید
امیدوارم در حال تمرین هم باشید