این آموزش اصول ساخت برنامه های جاوا با Bazel را پوشش می دهد. شما فضای کاری خود را راهاندازی میکنید و یک پروژه جاوا ساده میسازید که مفاهیم کلیدی Bazel، مانند اهداف و فایلهای BUILD
را نشان میدهد.
زمان تخمینی تکمیل: 30 دقیقه
چیزی که یاد خواهید گرفت
در این آموزش یاد می گیرید که چگونه:
- یک هدف بسازید
- وابستگی های پروژه را تجسم کنید
- پروژه را به چندین هدف و بسته تقسیم کنید
- کنترل دید هدف در سراسر بسته ها
- ارجاع به اهداف از طریق برچسب ها
- یک هدف را مستقر کنید
قبل از اینکه شروع کنی
Bazel را نصب کنید
برای آماده شدن برای آموزش، اگر Bazel را قبلاً نصب نکرده اید، ابتدا آن را نصب کنید.
JDK را نصب کنید
جاوا JDK را نصب کنید (نسخه ترجیحی 11 است، اما نسخه های بین 8 و 15 پشتیبانی می شوند).
متغیر محیطی JAVA_HOME را طوری تنظیم کنید که به JDK اشاره کند.
در Linux/macOS:
export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
در ویندوز:
- کنترل پنل را باز کنید.
- به "System and Security" > "System" > "Advanced System Settings" > "Advanced" تب > "Environment Variables..." بروید.
- در زیر لیست «متغیرهای کاربر» (متغیرهای بالا)، روی «جدید...» کلیک کنید.
- در قسمت "نام متغیر"،
JAVA_HOME
را وارد کنید. - روی "مرور دایرکتوری..." کلیک کنید.
- به فهرست JDK بروید (به عنوان مثال
C:\Program Files\Java\jdk1.8.0_152
). - روی "OK" در تمام پنجره های گفتگو کلیک کنید.
نمونه پروژه را دریافت کنید
نمونه پروژه را از مخزن Bazel's GitHub بازیابی کنید:
git clone https://github.com/bazelbuild/examples
پروژه نمونه این آموزش در پوشه examples/java-tutorial
دارد و ساختار آن به صورت زیر است:
java-tutorial
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── cmdline
│ │ ├── BUILD
│ │ └── Runner.java
│ ├── Greeting.java
│ └── ProjectRunner.java
└── WORKSPACE
ساخت با بازل
فضای کاری را تنظیم کنید
قبل از اینکه بتوانید یک پروژه بسازید، باید فضای کاری آن را تنظیم کنید. فضای کاری دایرکتوری است که فایل های منبع پروژه شما و خروجی های ساخت Bazel را در خود نگه می دارد. همچنین حاوی فایل هایی است که Bazel آنها را به عنوان خاص تشخیص می دهد:
فایل
WORKSPACE
که دایرکتوری و محتویات آن را به عنوان یک فضای کاری Bazel شناسایی می کند و در ریشه ساختار دایرکتوری پروژه قرار دارد.یک یا چند فایل
BUILD
که به بازل میگوید چگونه قسمتهای مختلف پروژه را بسازد. (یک دایرکتوری در فضای کاری که حاوی یک فایلBUILD
است یک بسته است . بعداً در این آموزش با بسته ها آشنا خواهید شد.)
برای تعیین دایرکتوری به عنوان فضای کاری Bazel، یک فایل خالی به نام WORKSPACE
در آن دایرکتوری ایجاد کنید.
وقتی Bazel پروژه را می سازد، همه ورودی ها و وابستگی ها باید در یک فضای کاری باشند. فایلهایی که در محیطهای کاری مختلف قرار دارند مستقل از یکدیگر هستند، مگر اینکه پیوند داده شوند، که خارج از محدوده این آموزش است.
فایل BUILD را درک کنید
یک فایل BUILD
شامل چندین نوع مختلف دستورالعمل برای Bazel است. مهمترین نوع، قانون ساخت است که به Bazel میگوید چگونه خروجیهای مورد نظر مانند باینریهای اجرایی یا کتابخانهها را بسازد. هر نمونه از یک قانون ساخت در فایل BUILD
یک هدف نامیده می شود و به مجموعه خاصی از فایل های منبع و وابستگی ها اشاره می کند. یک هدف همچنین می تواند به اهداف دیگر اشاره کند.
به فایل java-tutorial/BUILD
نگاهی بیندازید:
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
در مثال ما، هدف ProjectRunner
قانون java_binary
را نشان میدهد. این قانون به Bazel میگوید که یک فایل .jar
و یک اسکریپت wrapper shell (هر دو به نام هدف) بسازد.
ویژگی های موجود در هدف به صراحت وابستگی ها و گزینه های آن را بیان می کنند. در حالی که ویژگی name
اجباری است، بسیاری از آنها اختیاری هستند. به عنوان مثال، در هدف قانون ProjectRunner
، name
نام هدف است، srcs
فایلهای منبعی را که Bazel برای ساختن هدف استفاده میکند، و main_class
کلاسی را که متد اصلی را شامل میشود، مشخص میکند. (شاید متوجه شده باشید که مثال ما از glob برای ارسال مجموعه ای از فایل های منبع به Bazel به جای فهرست کردن یک به یک آنها استفاده می کند.)
پروژه را بسازید
برای ساخت نمونه پروژه خود، به دایرکتوری java-tutorial
بروید و اجرا کنید:
bazel build //:ProjectRunner
در برچسب هدف، قسمت //
محل فایل BUILD
نسبت به ریشه فضای کاری (در این مورد، خود ریشه) است و ProjectRunner
نام هدف در فایل BUILD
است. (در پایان این آموزش با برچسب های هدف با جزئیات بیشتری آشنا خواهید شد.)
Bazel خروجی مشابه زیر تولید می کند:
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 1.021s, Critical Path: 0.83s
تبریک میگوییم، شما اولین هدف بازل خود را ساختید! Bazel خروجی های ساخت را در دایرکتوری bazel-bin
در ریشه فضای کاری قرار می دهد. محتویات آن را مرور کنید تا از ساختار خروجی Bazel ایده بگیرید.
اکنون باینری تازه ساخته شده خود را تست کنید:
bazel-bin/ProjectRunner
نمودار وابستگی را مرور کنید
Bazel نیاز دارد که وابستگی های ساخت به صراحت در فایل های BUILD اعلام شوند. Bazel از این عبارات برای ایجاد نمودار وابستگی پروژه استفاده می کند که ساخت های افزایشی دقیق را امکان پذیر می کند.
برای تجسم وابستگی های پروژه نمونه، می توانید با اجرای این دستور در ریشه فضای کاری، یک نمایش متنی از نمودار وابستگی ایجاد کنید:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
دستور بالا به Bazel می گوید که تمام وابستگی ها را برای هدف //:ProjectRunner
(به استثنای وابستگی های میزبان و ضمنی) جستجو کند و خروجی را به صورت نمودار فرمت کند.
سپس، متن را در GraphViz قرار دهید.
همانطور که می بینید، پروژه دارای یک هدف واحد است که دو فایل منبع را بدون وابستگی اضافی می سازد:
بعد از اینکه فضای کاری خود را راه اندازی کردید، پروژه خود را ساختید و وابستگی های آن را بررسی کردید، سپس می توانید کمی پیچیدگی اضافه کنید.
ساخت Bazel خود را اصلاح کنید
در حالی که یک هدف واحد برای پروژههای کوچک کافی است، ممکن است بخواهید پروژههای بزرگتر را به چندین هدف و بسته تقسیم کنید تا امکان ساختهای افزایشی سریع را فراهم کنید (یعنی فقط آنچه را که تغییر کرده است بازسازی کنید) و با ساختن چندین بخش از یک پروژه سرعت ساختهای خود را افزایش دهید. فورا.
چندین هدف ساخت را مشخص کنید
شما می توانید نمونه ساخت پروژه را به دو هدف تقسیم کنید. محتویات فایل java-tutorial/BUILD
را با موارد زیر جایگزین کنید:
java_binary(
name = "ProjectRunner",
srcs = ["src/main/java/com/example/ProjectRunner.java"],
main_class = "com.example.ProjectRunner",
deps = [":greeter"],
)
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
)
با این پیکربندی، Bazel ابتدا کتابخانه greeter
و سپس ProjectRunner
باینری را می سازد. ویژگی deps
در java_binary
به Bazel می گوید که کتابخانه greeter
برای ساخت باینری ProjectRunner
مورد نیاز است.
برای ساخت این نسخه جدید از پروژه، دستور زیر را اجرا کنید:
bazel build //:ProjectRunner
Bazel خروجی مشابه زیر تولید می کند:
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s
اکنون باینری تازه ساخته شده خود را تست کنید:
bazel-bin/ProjectRunner
اگر اکنون ProjectRunner.java
تغییر دهید و پروژه را بازسازی کنید، Bazel فقط آن فایل را دوباره کامپایل می کند.
با نگاهی به نمودار وابستگی، می توانید ببینید که ProjectRunner
به همان ورودی هایی که قبلاً انجام می داد بستگی دارد، اما ساختار ساخت متفاوت است:
شما اکنون پروژه را با دو هدف ساخته اید. هدف ProjectRunner
دو فایل منبع میسازد و به یک هدف دیگر ( :greeter
) وابسته است، که یک فایل منبع اضافی را میسازد.
از بسته های متعدد استفاده کنید
حالا بیایید پروژه را به چند بسته تقسیم کنیم. اگر به دایرکتوری src/main/java/com/example/cmdline
نگاهی بیندازید، می بینید که شامل یک فایل BUILD
به اضافه چند فایل منبع است. بنابراین، برای بازل، فضای کاری اکنون شامل دو بسته است، //src/main/java/com/example/cmdline
و //
(از آنجایی که یک فایل BUILD
در ریشه فضای کاری وجود دارد).
به فایل src/main/java/com/example/cmdline/BUILD
نگاهی بیندازید:
java_binary(
name = "runner",
srcs = ["Runner.java"],
main_class = "com.example.cmdline.Runner",
deps = ["//:greeter"],
)
هدف runner
به هدف استقبال کننده در بسته //
بستگی دارد (از این رو برچسب هدف //:greeter
greeter
- Bazel این را از طریق ویژگی deps
می داند. به نمودار وابستگی نگاهی بیندازید:
با این حال، برای موفقیت ساخت، باید به طور واضح به هدف runner
در //src/main/java/com/example/cmdline/BUILD
قابلیت مشاهده را به اهداف در //BUILD
با استفاده از ویژگی visibility
بدهید. این به این دلیل است که اهداف به طور پیش فرض فقط برای اهداف دیگر در همان فایل BUILD
قابل مشاهده هستند. (بازل از دید هدف برای جلوگیری از نشت مسائلی مانند کتابخانه های حاوی جزئیات پیاده سازی به API های عمومی استفاده می کند.)
برای انجام این کار، مطابق شکل زیر، ویژگی visibility
را به هدف greeter
در java-tutorial/BUILD
اضافه کنید:
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)
اکنون می توانید بسته جدید را با اجرای دستور زیر در ریشه فضای کاری بسازید:
bazel build //src/main/java/com/example/cmdline:runner
Bazel خروجی مشابه زیر تولید می کند:
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner.jar
bazel-bin/src/main/java/com/example/cmdline/runner
INFO: Elapsed time: 1.576s, Critical Path: 0.81s
اکنون باینری تازه ساخته شده خود را تست کنید:
./bazel-bin/src/main/java/com/example/cmdline/runner
شما اکنون پروژه را به گونه ای تغییر داده اید که به صورت دو بسته که هر کدام شامل یک هدف است ساخته شود و وابستگی های بین آنها را درک کنید.
از برچسب ها برای ارجاع به اهداف استفاده کنید
در فایل های BUILD
و در خط فرمان، Bazel از برچسب های هدف برای ارجاع به اهداف استفاده می کند - به عنوان مثال، //:ProjectRunner
یا //src/main/java/com/example/cmdline:runner
. نحو آنها به شرح زیر است:
//path/to/package:target-name
اگر هدف یک هدف قانون است، path/to/package
مسیری است به دایرکتوری حاوی فایل BUILD
، و target-name
همان چیزی است که هدف را در فایل BUILD
نامگذاری کردهاید (ویژگی name
). اگر هدف یک فایل هدف است، path/to/package
مسیری است که به ریشه بسته میرسد، و target-name
نام فایل هدف، شامل مسیر کامل آن است.
هنگام ارجاع به اهداف در ریشه مخزن، مسیر بسته خالی است، فقط از //:target-name
استفاده کنید. هنگام ارجاع به اهداف در یک فایل BUILD
، حتی میتوانید از //
شناسه ریشه فضای کاری رد شوید و فقط از :target-name
استفاده کنید.
به عنوان مثال، برای اهداف در فایل java-tutorial/BUILD
، لازم نیست مسیر بسته را مشخص کنید، زیرا ریشه فضای کاری خود یک بسته ( //
) است و دو برچسب هدف شما به سادگی //:ProjectRunner
و //:greeter
هستند. //:greeter
.
با این حال، برای اهداف در فایل //src/main/java/com/example/cmdline/BUILD
باید مسیر بسته کامل //src/main/java/com/example/cmdline
را مشخص میکردید و برچسب هدف شما //src/main/java/com/example/cmdline:runner
.
یک هدف جاوا را برای استقرار بسته بندی کنید
بیایید اکنون یک هدف جاوا را برای استقرار با ساخت باینری با تمام وابستگیهای زمان اجرا بسته بندی کنیم. این به شما امکان می دهد باینری را خارج از محیط توسعه خود اجرا کنید.
همانطور که به یاد دارید، قانون ساخت java_binary یک .jar
. و یک اسکریپت پوسته wrapper تولید می کند. با استفاده از این دستور به محتویات runner.jar
نگاهی بیندازید:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
مطالب عبارتند از:
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
همانطور که می بینید، runner.jar
حاوی Runner.class
است، اما نه وابستگی آن، Greeting.class
. اسکریپت runner
که Bazel تولید greeter.jar
را به classpath اضافه میکند، بنابراین اگر آن را به این شکل رها کنید، به صورت محلی اجرا میشود، اما بهصورت مستقل روی ماشین دیگری اجرا نمیشود. خوشبختانه، قانون java_binary
به شما امکان می دهد یک باینری مستقل و قابل استقرار بسازید. برای ساخت آن، _deploy.jar
را به نام هدف اضافه کنید:
bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
Bazel خروجی مشابه زیر تولید می کند:
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s
شما runner_deploy.jar
را ساختهاید، که میتوانید آن را بهصورت مستقل و به دور از محیط توسعه خود اجرا کنید زیرا حاوی وابستگیهای زمان اجرا مورد نیاز است. با استفاده از دستور قبلی به محتویات این JAR مستقل نگاهی بیندازید:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
محتویات شامل تمام کلاس های لازم برای اجرا می شود:
META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class
بیشتر خواندن
برای جزئیات بیشتر، نگاه کنید به:
rules_jvm_external برای قوانینی برای مدیریت وابستگی های گذرا Maven.
وابستگی های خارجی برای کسب اطلاعات بیشتر در مورد کار با مخازن محلی و راه دور.
قوانین دیگر برای کسب اطلاعات بیشتر در مورد Bazel.
آموزش ساخت C++ برای شروع ساخت پروژه های C++ با Bazel.
آموزش اپلیکیشن اندروید و آموزش اپلیکیشن iOS برای شروع ساخت اپلیکیشن موبایل برای اندروید و iOS با Bazel.
ساختمان مبارک!