Bazel দিয়ে প্রোগ্রাম তৈরি করুন, Bazel দিয়ে প্রোগ্রাম তৈরি করুন

এই পৃষ্ঠাটি কভার করে যে কিভাবে Bazel দিয়ে একটি প্রোগ্রাম তৈরি করা যায়, কমান্ড সিনট্যাক্স তৈরি করা যায় এবং টার্গেট প্যাটার্ন সিনট্যাক্স।

দ্রুত শুরু

Bazel চালানোর জন্য, আপনার বেস ওয়ার্কস্পেস ডিরেক্টরি বা এর যেকোনো সাবডিরেক্টরিতে যান এবং bazel টাইপ করুন। আপনার যদি একটি নতুন কর্মক্ষেত্র তৈরি করতে হয় তবে বিল্ড দেখুন।

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

উপলব্ধ কমান্ড

  • analyze-profile : বিল্ড প্রোফাইল ডেটা বিশ্লেষণ করে।
  • aquery : বিশ্লেষণ-পরবর্তী অ্যাকশন গ্রাফে একটি প্রশ্ন নির্বাহ করে।
  • build : নির্দিষ্ট লক্ষ্য তৈরি করে।
  • canonicalize-flags : ব্যাজেল পতাকাকে ক্যানোনিকালাইজ করুন।
  • clean : আউটপুট ফাইল মুছে দেয় এবং ঐচ্ছিকভাবে সার্ভার বন্ধ করে।
  • cquery : একটি পোস্ট-বিশ্লেষণ নির্ভরতা গ্রাফ ক্যোয়ারী চালায়।
  • dump : ব্যাজেল সার্ভার প্রক্রিয়ার অভ্যন্তরীণ অবস্থা ডাম্প করে।
  • help : কমান্ড বা সূচকের জন্য সাহায্য প্রিন্ট করে।
  • info : বেজেল সার্ভার সম্পর্কে রানটাইম তথ্য প্রদর্শন করে।
  • fetch : একটি লক্ষ্যের সমস্ত বাহ্যিক নির্ভরতা আনয়ন করে।
  • mobile-install : মোবাইল ডিভাইসে অ্যাপ ইনস্টল করে।
  • query : একটি নির্ভরতা গ্রাফ ক্যোয়ারী চালায়।
  • run : নির্দিষ্ট লক্ষ্য চালায়।
  • shutdown : ব্যাজেল সার্ভার বন্ধ করে।
  • test : নির্দিষ্ট পরীক্ষার লক্ষ্যগুলি তৈরি করে এবং চালায়।
  • version : Bazel জন্য সংস্করণ তথ্য মুদ্রণ.

সাহায্য পাচ্ছেন

  • bazel help command : প্রিন্ট সাহায্য এবং command জন্য বিকল্প.
  • bazel help startup_options : JVM হোস্টিং Bazel এর জন্য বিকল্প।
  • bazel help target-syntax : লক্ষ্য নির্দিষ্ট করার জন্য সিনট্যাক্স ব্যাখ্যা করে।
  • bazel help info-keys : info কমান্ড দ্বারা ব্যবহৃত কীগুলির একটি তালিকা প্রদর্শন করে।

bazel টুল অনেক ফাংশন সঞ্চালন করে, কমান্ড বলা হয়। সবচেয়ে বেশি ব্যবহৃত হয় bazel build এবং bazel test । আপনি bazel help ব্যবহার করে অনলাইন সহায়তা বার্তাগুলি ব্রাউজ করতে পারেন।

একটি লক্ষ্য নির্মাণ

আপনি একটি বিল্ড শুরু করার আগে, আপনার একটি ওয়ার্কস্পেস প্রয়োজন। একটি ওয়ার্কস্পেস হল একটি ডিরেক্টরি গাছ যাতে আপনার অ্যাপ্লিকেশন তৈরি করার জন্য প্রয়োজনীয় সমস্ত উৎস ফাইল থাকে। Bazel আপনাকে সম্পূর্ণরূপে পঠনযোগ্য ভলিউম থেকে একটি বিল্ড সম্পাদন করতে দেয়।

ব্যাজেল দিয়ে একটি প্রোগ্রাম তৈরি করতে, আপনি যে টার্গেটটি তৈরি করতে চান তার পরে bazel build টাইপ করুন।

bazel build //foo

বিল্ড করার জন্য কমান্ড জারি করার পরে //foo , আপনি এর অনুরূপ আউটপুট দেখতে পাবেন:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

প্রথমত, Bazel আপনার লক্ষ্যের নির্ভরতা গ্রাফে সমস্ত প্যাকেজ লোড করে। এর মধ্যে রয়েছে ঘোষিত নির্ভরতা , টার্গেটের BUILD ফাইলে সরাসরি তালিকাভুক্ত ফাইল এবং ট্রানজিটিভ ডিপেন্ডেন্সি , আপনার টার্গেটের নির্ভরতাগুলির BUILD ফাইলে তালিকাভুক্ত ফাইল৷ সমস্ত নির্ভরতা সনাক্ত করার পরে, Bazel সঠিকতার জন্য সেগুলিকে বিশ্লেষণ করে এবং বিল্ড অ্যাকশন তৈরি করে ৷ শেষ পর্যন্ত, Bazel বিল্ডের কম্পাইলার এবং অন্যান্য সরঞ্জামগুলি চালায়

বিল্ডের নির্বাহের পর্যায়ে, Bazel অগ্রগতি বার্তা প্রিন্ট করে। অগ্রগতি বার্তাগুলির মধ্যে বর্তমান বিল্ড স্টেপ (যেমন, কম্পাইলার বা লিঙ্কার) শুরু হওয়ার সাথে সাথে বিল্ড অ্যাকশনের মোট সংখ্যার উপর সম্পূর্ণ হওয়া সংখ্যা অন্তর্ভুক্ত থাকে। বিল্ড শুরু হওয়ার সাথে সাথে, মোট অ্যাকশনের সংখ্যা প্রায়ই বৃদ্ধি পায় কারণ Bazel পুরো অ্যাকশন গ্রাফটি আবিষ্কার করে, কিন্তু সংখ্যাটি কয়েক সেকেন্ডের মধ্যে স্থির হয়ে যায়।

বিল্ডের শেষে, Bazel প্রিন্ট করে কোন লক্ষ্যগুলিকে অনুরোধ করা হয়েছিল, সেগুলি সফলভাবে নির্মিত হয়েছে কিনা এবং যদি তাই হয়, আউটপুট ফাইলগুলি কোথায় পাওয়া যাবে। বিল্ড চালানোর স্ক্রিপ্ট নির্ভরযোগ্যভাবে এই আউটপুট পার্স করতে পারে; আরো বিস্তারিত জানার জন্য --show_result দেখুন।

আপনি যদি একই কমান্ড আবার টাইপ করেন, বিল্ডটি অনেক দ্রুত শেষ হয়।

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

এটি একটি নাল বিল্ড . কিছুই পরিবর্তিত না হওয়ায়, পুনরায় লোড করার জন্য কোনও প্যাকেজ নেই এবং কার্যকর করার জন্য কোনও বিল্ড পদক্ষেপ নেই। যদি 'foo' বা এর নির্ভরশীলতায় কিছু পরিবর্তন হয়, Bazel কিছু বিল্ড অ্যাকশন পুনরায় কার্যকর করবে, অথবা একটি বর্ধিত বিল্ড সম্পূর্ণ করবে।

একাধিক লক্ষ্য বিল্ডিং

বেজেল তৈরি করা লক্ষ্যগুলি নির্দিষ্ট করার জন্য বিভিন্ন উপায়ের অনুমতি দেয়। সমষ্টিগতভাবে, এগুলি টার্গেট প্যাটার্ন হিসাবে পরিচিত। এই সিনট্যাক্সটি build , test বা query মতো কমান্ডে ব্যবহৃত হয়।

যেখানে লেবেলগুলি পৃথক লক্ষ্য নির্দিষ্ট করতে ব্যবহার করা হয়, যেমন BUILD ফাইলগুলিতে নির্ভরতা ঘোষণা করার জন্য, Bazel এর টার্গেট প্যাটার্ন একাধিক লক্ষ্য নির্দিষ্ট করে। টার্গেট প্যাটার্ন হল ওয়াইল্ডকার্ড ব্যবহার করে লক্ষ্যের সেটের জন্য লেবেল সিনট্যাক্সের একটি সাধারণীকরণ। সবচেয়ে সহজ ক্ষেত্রে, যেকোন বৈধ লেবেলও একটি বৈধ লক্ষ্য প্যাটার্ন, যা ঠিক একটি লক্ষ্যের একটি সেট সনাক্ত করে।

// দিয়ে শুরু হওয়া সমস্ত টার্গেট প্যাটার্ন বর্তমান ওয়ার্কস্পেসের সাপেক্ষে সমাধান করা হয়েছে।

//foo/bar:wiz শুধুমাত্র একক লক্ষ্য //foo/bar:wiz
//foo/bar //foo/bar:bar সমতুল্য।
//foo/bar:all প্যাকেজ foo/bar এ সমস্ত নিয়ম লক্ষ্য।
//foo/... foo ডিরেক্টরির নীচে সমস্ত প্যাকেজে সমস্ত নিয়ম লক্ষ্য।
//foo/...:all foo ডিরেক্টরির নীচে সমস্ত প্যাকেজে সমস্ত নিয়ম লক্ষ্য।
//foo/...:* foo ডিরেক্টরির নীচে সমস্ত প্যাকেজে সমস্ত লক্ষ্য (নিয়ম এবং ফাইল)।
//foo/...:all-targets foo ডিরেক্টরির নীচে সমস্ত প্যাকেজে সমস্ত লক্ষ্য (নিয়ম এবং ফাইল)।
//... কর্মক্ষেত্রে প্যাকেজে সমস্ত লক্ষ্য। এটি বহিরাগত সংগ্রহস্থল থেকে লক্ষ্যগুলি অন্তর্ভুক্ত করে না।
//:all শীর্ষ-স্তরের প্যাকেজের সমস্ত লক্ষ্য, যদি ওয়ার্কস্পেসের মূলে একটি `বিল্ড` ফাইল থাকে।

টার্গেট প্যাটার্ন যেগুলি // দিয়ে শুরু হয় না সেগুলি বর্তমান কার্যকারী ডিরেক্টরির সাপেক্ষে সমাধান করা হয়। এই উদাহরণগুলি foo এর একটি কার্যকরী ডিরেক্টরি অনুমান করে:

:foo //foo:foo সমতুল্য।
bar:wiz //foo/bar:wiz সমতুল্য।
bar/wiz সমতুল্য:
  • //foo/bar/wiz:wiz যদি foo/bar/wiz একটি প্যাকেজ হয়
  • //foo/bar:wiz যদি foo/bar একটি প্যাকেজ হয়
  • //foo:bar/wiz অন্যথায়
bar:all //foo/bar:all সমতুল্য।
:all //foo:all এর সমতুল্য।
...:all //foo/...:all সমতুল্য।
... //foo/...:all সমতুল্য।
bar/...:all //foo/bar/...:all সমতুল্য।

ডিফল্টরূপে, ডাইরেক্টরি সিমলিঙ্কগুলি পুনরাবৃত্তিমূলক টার্গেট প্যাটার্নগুলির জন্য অনুসরণ করা হয়, যেগুলি আউটপুট বেসের নীচে নির্দেশ করে, যেমন সুবিধার সিমলিঙ্কগুলি যা ওয়ার্কস্পেসের রুট ডিরেক্টরিতে তৈরি করা হয়।

উপরন্তু, Bazel যেকোন ডিরেক্টরিতে রিকার্সিভ টার্গেট প্যাটার্নের মূল্যায়ন করার সময় সিমলিঙ্ক অনুসরণ করে না যার নাম একটি ফাইল রয়েছে: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... প্যাকেজগুলির উপর একটি ওয়াইল্ডকার্ড, যা নির্দেশ করে foo ডিরেক্টরির নীচে সমস্ত প্যাকেজ পুনরাবৃত্তিমূলকভাবে (প্যাকেজ পাথের সমস্ত রুটের জন্য)। :all টার্গেটের উপর একটি ওয়াইল্ডকার্ড, একটি প্যাকেজের মধ্যে সমস্ত নিয়ম মেলে। এই দুটি মিলিত হতে পারে, যেমন foo/...:all , এবং যখন উভয় ওয়াইল্ডকার্ড ব্যবহার করা হয়, তখন এটিকে সংক্ষেপে foo/... বলা যেতে পারে।

উপরন্তু, :* (বা :all-targets ) হল একটি ওয়াইল্ডকার্ড যা মিলিত প্যাকেজের প্রতিটি টার্গেটের সাথে মেলে, সেই ফাইলগুলি সহ যা সাধারণত কোনো নিয়ম দ্বারা নির্মিত হয় না, যেমন java_binary নিয়মের সাথে যুক্ত _deploy.jar ফাইল।

এটি বোঝায় যে :* একটি সুপারসেট বোঝায় :all ; সম্ভাব্য বিভ্রান্তিকর সময়ে, এই সিনট্যাক্সটি পরিচিত :all ওয়াইল্ডকার্ডকে সাধারণ বিল্ডের জন্য ব্যবহার করার অনুমতি দেয়, যেখানে _deploy.jar এর মতো লক্ষ্যমাত্রা তৈরি করা কাঙ্ক্ষিত নয়।

উপরন্তু, Bazel লেবেল সিনট্যাক্স দ্বারা প্রয়োজনীয় কোলনের পরিবর্তে একটি স্ল্যাশ ব্যবহার করার অনুমতি দেয়; Bash ফাইলের নাম সম্প্রসারণ ব্যবহার করার সময় এটি প্রায়ই সুবিধাজনক। উদাহরণস্বরূপ, foo/bar/wiz //foo/bar:wiz (যদি একটি প্যাকেজ foo/bar থাকে) বা //foo:bar/wiz (যদি একটি প্যাকেজ foo থাকে) এর সমতুল্য।

অনেক Bazel কমান্ড আর্গুমেন্ট হিসাবে টার্গেট প্যাটার্নের একটি তালিকা গ্রহণ করে এবং তারা সকলেই প্রিফিক্স নেগেশান অপারেটর - সম্মান করে। এটি পূর্ববর্তী আর্গুমেন্ট দ্বারা নির্দিষ্ট করা সেট থেকে লক্ষ্যগুলির একটি সেট বিয়োগ করতে ব্যবহার করা যেতে পারে। নোট করুন যে এর মানে অর্ডারের ব্যাপার। উদাহরণ স্বরূপ,

bazel build foo/... bar/...

মানে " foo এর নিচে সব টার্গেট এবং bar নিচে সব টার্গেট তৈরি করুন", যেখানে

bazel build -- foo/... -foo/bar/...

মানে "foo-এর নিচে সব টার্গেট তৈরি করুন foo foo/bar নিচে ছাড়া "। (অতিরিক্ত বিকল্প হিসাবে ব্যাখ্যা করা - -- শুরু হওয়া পরবর্তী আর্গুমেন্টগুলিকে প্রতিরোধ করার জন্য যুক্তিটি প্রয়োজন৷)

যদিও এটি উল্লেখ করা গুরুত্বপূর্ণ যে লক্ষ্যগুলিকে এভাবে বিয়োগ করা গ্যারান্টি দেবে না যে সেগুলি নির্মিত হয়নি, কারণ তারা লক্ষ্যগুলির নির্ভরতা হতে পারে যা বিয়োগ করা হয়নি। উদাহরণস্বরূপ, যদি একটি টার্গেট //foo:all-apis থাকে যা অন্যদের মধ্যে //foo/bar:api এর উপর নির্ভর করে, তাহলে পরবর্তীটি পূর্বের নির্মাণের অংশ হিসাবে নির্মিত হবে।

tags = ["manual"] ওয়াইল্ডকার্ড টার্গেট প্যাটার্ন ( ... , :* , :all , etc.) অন্তর্ভুক্ত করা হয় না যখন bazel build এবং bazel test মতো কমান্ডে উল্লেখ করা হয়; আপনি যদি Bazel তৈরি/পরীক্ষা করতে চান তবে কমান্ড লাইনে স্পষ্ট লক্ষ্য প্যাটার্ন সহ এই ধরনের পরীক্ষার লক্ষ্যগুলি নির্দিষ্ট করা উচিত। বিপরীতে, bazel query স্বয়ংক্রিয়ভাবে এই ধরনের কোনো ফিল্টারিং সঞ্চালন করে না (যা bazel query এর উদ্দেশ্যকে হারাতে পারে)।

বাহ্যিক নির্ভরতা আনা হচ্ছে

ডিফল্টরূপে, Bazel নির্মাণের সময় বাহ্যিক নির্ভরতা ডাউনলোড এবং সিমলিঙ্ক করবে। যাইহোক, এটি অবাঞ্ছিত হতে পারে, কারণ হয় আপনি জানতে চান যখন নতুন বাহ্যিক নির্ভরতা যোগ করা হবে বা আপনি নির্ভরতা "প্রিফেচ" করতে চান (বলুন, আপনি অফলাইনে থাকবেন এমন একটি ফ্লাইটের আগে)। আপনি যদি বিল্ড করার সময় নতুন নির্ভরতা যোগ করা থেকে আটকাতে চান, আপনি --fetch=false পতাকা নির্দিষ্ট করতে পারেন। মনে রাখবেন যে এই পতাকা শুধুমাত্র সংগ্রহস্থলের নিয়মের ক্ষেত্রে প্রযোজ্য যা স্থানীয় ফাইল সিস্টেমের কোনো ডিরেক্টরির দিকে নির্দেশ করে না। পরিবর্তন, উদাহরণস্বরূপ, local_repository , new_local_repository এবং Android SDK এবং NDK সংগ্রহস্থলের নিয়ম --fetch মান নির্বিশেষে সর্বদা কার্যকর হবে।

আপনি যদি বিল্ডের সময় আনার অনুমতি না দেন এবং Bazel নতুন বাহ্যিক নির্ভরতা খুঁজে পায়, তাহলে আপনার বিল্ড ব্যর্থ হবে।

আপনি bazel fetch চালিয়ে ম্যানুয়ালি নির্ভরতা আনতে পারেন। আপনি যদি বিল্ড-এর সময় আনয়ন করার অনুমতি না দেন, তাহলে আপনাকে bazel fetch চালাতে হবে:

  • আপনি প্রথমবার নির্মাণ করার আগে।
  • আপনি একটি নতুন বাহ্যিক নির্ভরতা যোগ করার পরে।

একবার এটি চালানো হয়ে গেলে, WORKSPACE ফাইল পরিবর্তন না হওয়া পর্যন্ত আপনাকে এটিকে আবার চালানোর প্রয়োজন হবে না।

fetch এর জন্য নির্ভরতা আনতে লক্ষ্যগুলির একটি তালিকা নেয়। উদাহরণস্বরূপ, এটি //foo:bar এবং //bar:baz : নির্মাণের জন্য প্রয়োজনীয় নির্ভরতা আনবে:

bazel fetch //foo:bar //bar:baz

একটি কর্মক্ষেত্রের জন্য সমস্ত বাহ্যিক নির্ভরতা আনতে, চালান:

bazel fetch //...

আপনার ওয়ার্কস্পেস রুটের অধীনে আপনি যে সমস্ত টুল ব্যবহার করছেন (লাইব্রেরি জার থেকে JDK নিজেই) যদি আপনার কাছে ব্যাজেল ফেচ চালানোর দরকার নেই। যাইহোক, আপনি যদি ওয়ার্কস্পেস ডিরেক্টরির বাইরে কিছু ব্যবহার করেন তাহলে Bazel bazel build চালানোর আগে Bazel স্বয়ংক্রিয়ভাবে bazel fetch চালাবে।

সংগ্রহস্থল ক্যাশে

Bazel একই ফাইল একাধিকবার আনা এড়াতে চেষ্টা করে, এমনকি যদি একই ফাইল বিভিন্ন ওয়ার্কস্পেসে প্রয়োজন হয়, অথবা যদি একটি বাহ্যিক সংগ্রহস্থলের সংজ্ঞা পরিবর্তিত হয় কিন্তু ডাউনলোড করার জন্য এটি এখনও একই ফাইলের প্রয়োজন হয়। এটি করার জন্য, bazel সংগ্রহস্থল ক্যাশে ডাউনলোড করা সমস্ত ফাইল ক্যাশে করে যা ডিফল্টরূপে ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ এ অবস্থিত। অবস্থান --repository_cache বিকল্প দ্বারা পরিবর্তন করা যেতে পারে। ক্যাশে সমস্ত ওয়ার্কস্পেস এবং বেজেলের ইনস্টল করা সংস্করণগুলির মধ্যে ভাগ করা হয়। ক্যাশে থেকে একটি এন্ট্রি নেওয়া হয় যদি Bazel নিশ্চিতভাবে জানে যে এটিতে সঠিক ফাইলের একটি অনুলিপি রয়েছে, অর্থাৎ, যদি ডাউনলোডের অনুরোধে নির্দিষ্ট ফাইলের একটি SHA256 যোগফল থাকে এবং সেই হ্যাশ সহ একটি ফাইল ক্যাশে থাকে। তাই প্রতিটি বাহ্যিক ফাইলের জন্য একটি হ্যাশ নির্দিষ্ট করা শুধুমাত্র একটি নিরাপত্তা দৃষ্টিকোণ থেকে একটি ভাল ধারণা নয়; এটি অপ্রয়োজনীয় ডাউনলোড এড়াতেও সাহায্য করে।

প্রতিটি ক্যাশে আঘাত করার পরে, ক্যাশে ফাইলের পরিবর্তনের সময় আপডেট করা হয়। এইভাবে, ক্যাশে ডিরেক্টরিতে একটি ফাইলের শেষ ব্যবহার সহজেই নির্ধারণ করা যেতে পারে, উদাহরণস্বরূপ ম্যানুয়ালি ক্যাশে পরিষ্কার করা। ক্যাশে কখনই স্বয়ংক্রিয়ভাবে পরিষ্কার করা হয় না, কারণ এতে একটি ফাইলের একটি অনুলিপি থাকতে পারে যা আপস্ট্রিমে আর উপলব্ধ নেই।

ডিস্ট্রিবিউশন ফাইল ডিরেক্টরি

অপ্রয়োজনীয় ডাউনলোড এড়াতে ডিস্ট্রিবিউশন ডিরেক্টরি হল আরেকটি বেজেল মেকানিজম। Bazel সংগ্রহস্থল ক্যাশের আগে বিতরণ ডিরেক্টরি অনুসন্ধান করে। প্রাথমিক পার্থক্য হল যে বিতরণ ডিরেক্টরির জন্য ম্যানুয়াল প্রস্তুতির প্রয়োজন।

--distdir=/path/to-directory বিকল্পটি ব্যবহার করে, ফাইলগুলি আনার পরিবর্তে আপনি অতিরিক্ত পঠনযোগ্য ডিরেক্টরিগুলি নির্দিষ্ট করতে পারেন। ফাইলের নাম URL-এর বেস নামের সমান হলে এবং ডাউনলোড অনুরোধে উল্লেখিত ফাইলটির হ্যাশের সমান হলে এই ধরনের একটি ডিরেক্টরি থেকে একটি ফাইল নেওয়া হয়। এটি শুধুমাত্র কাজ করে যদি ফাইল হ্যাশ WORKSPACE ঘোষণায় নির্দিষ্ট করা থাকে।

যদিও ফাইলের নামের শর্তটি সঠিকতার জন্য প্রয়োজনীয় নয়, এটি প্রতি নির্দিষ্ট ডিরেক্টরির জন্য প্রার্থী ফাইলের সংখ্যা কমিয়ে দেয়। এইভাবে, ডিস্ট্রিবিউশন ফাইল ডিরেক্টরিগুলি নির্দিষ্ট করা কার্যকর থাকে, এমনকি যদি এই ধরনের ডিরেক্টরিতে ফাইলের সংখ্যা বড় হয়।

এয়ারগ্যাপড পরিবেশে বেজেল চালানো

Bazel এর বাইনারি আকার ছোট রাখতে, Bazel এর অন্তর্নিহিত নির্ভরতা প্রথমবার চালানোর সময় নেটওয়ার্কে আনা হয়। এই অন্তর্নিহিত নির্ভরতাগুলিতে টুলচেইন এবং নিয়ম রয়েছে যা সবার জন্য প্রয়োজনীয় নাও হতে পারে। উদাহরণস্বরূপ, অ্যান্ড্রয়েড টুলগুলিকে আনবান্ডেড করা হয় এবং শুধুমাত্র Android প্রকল্পগুলি তৈরি করার সময় আনা হয়৷

যাইহোক, এই অন্তর্নিহিত নির্ভরতাগুলি একটি এয়ারগ্যাপড পরিবেশে Bazel চালানোর সময় সমস্যার কারণ হতে পারে, এমনকি যদি আপনি আপনার সমস্ত WORKSPACE নির্ভরতা বিক্রি করে থাকেন। এটি সমাধান করার জন্য, আপনি নেটওয়ার্ক অ্যাক্সেস সহ একটি মেশিনে এই নির্ভরতাগুলি সহ একটি বিতরণ ডিরেক্টরি প্রস্তুত করতে পারেন এবং তারপরে অফলাইন পদ্ধতির সাথে এয়ারগ্যাপড পরিবেশে স্থানান্তর করতে পারেন।

বিতরণ ডিরেক্টরি প্রস্তুত করতে, --distdir পতাকা ব্যবহার করুন। প্রতিটি নতুন Bazel বাইনারি সংস্করণের জন্য আপনাকে একবার এটি করতে হবে, যেহেতু প্রতিটি প্রকাশের জন্য অন্তর্নিহিত নির্ভরতা ভিন্ন হতে পারে।

আপনার এয়ারগ্যাপড পরিবেশের বাইরে এই নির্ভরতাগুলি তৈরি করতে, প্রথমে সঠিক সংস্করণে বেজেল উত্স গাছটি পরীক্ষা করুন:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

তারপরে, সেই নির্দিষ্ট ব্যাজেল সংস্করণের জন্য অন্তর্নিহিত রানটাইম নির্ভরতা ধারণকারী টারবল তৈরি করুন:

bazel build @additional_distfiles//:archives.tar

এই টারবলটি একটি ডিরেক্টরিতে রপ্তানি করুন যা আপনার এয়ারগ্যাপড পরিবেশে অনুলিপি করা যেতে পারে। --strip-components পতাকা নোট করুন, কারণ --distdir ডিরেক্টরি নেস্টিং স্তরের সাথে বেশ চটকদার হতে পারে:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

অবশেষে, যখন আপনি আপনার এয়ারগ্যাপড পরিবেশে Bazel ব্যবহার করেন, তখন ডিরেক্টরির দিকে নির্দেশ করে --distdir পতাকাটি পাস করুন। সুবিধার জন্য, আপনি এটি একটি .bazelrc এন্ট্রি হিসাবে যোগ করতে পারেন:

build --distdir=path/to/directory

কনফিগারেশন এবং ক্রস-সংকলন তৈরি করুন

প্রদত্ত বিল্ডের আচরণ এবং ফলাফল নির্দিষ্ট করে এমন সমস্ত ইনপুটগুলিকে দুটি স্বতন্ত্র বিভাগে বিভক্ত করা যেতে পারে। প্রথম ধরনের হল আপনার প্রোজেক্টের BUILD ফাইলে সংরক্ষিত অন্তর্নিহিত তথ্য: বিল্ড নিয়ম, এর বৈশিষ্ট্যের মান এবং এর ট্রানজিটিভ নির্ভরতার সম্পূর্ণ সেট। দ্বিতীয় ধরনের হল বাহ্যিক বা পরিবেশগত ডেটা, ব্যবহারকারীর দ্বারা বা বিল্ড টুল দ্বারা সরবরাহ করা হয়: টার্গেট আর্কিটেকচারের পছন্দ, সংকলন এবং লিঙ্ক করার বিকল্প, এবং অন্যান্য টুলচেন কনফিগারেশন বিকল্প। আমরা কনফিগারেশন হিসাবে পরিবেশগত ডেটার একটি সম্পূর্ণ সেট উল্লেখ করি।

যেকোনো প্রদত্ত বিল্ডে, একাধিক কনফিগারেশন থাকতে পারে। একটি ক্রস-কম্পাইল বিবেচনা করুন, যেখানে আপনি একটি 64-বিট আর্কিটেকচারের জন্য এক্সিকিউটেবল একটি //foo:bin তৈরি করেন, কিন্তু আপনার ওয়ার্কস্টেশন একটি 32-বিট মেশিন। স্পষ্টতই, বিল্ডের জন্য বিল্ডিং //foo:bin প্রয়োজন হবে একটি টুলচেন ব্যবহার করে যা 64-বিট এক্সিকিউটেবল তৈরি করতে সক্ষম, তবে বিল্ড সিস্টেমকে অবশ্যই বিল্ডের সময় ব্যবহৃত বিভিন্ন সরঞ্জামগুলিও তৈরি করতে হবে - যেমন টুলগুলি যেগুলি উত্স থেকে তৈরি করা হয়, তারপরে ব্যবহার করা হয় বলুন, একটি genrule-এ এবং এগুলি অবশ্যই আপনার ওয়ার্কস্টেশনে চালানোর জন্য তৈরি করা উচিত। এইভাবে আমরা দুটি কনফিগারেশন শনাক্ত করতে পারি: হোস্ট কনফিগারেশন , যা বিল্ডিং টুলের জন্য ব্যবহৃত হয় যা বিল্ড চলাকালীন চলে এবং টার্গেট কনফিগারেশন (অথবা কনফিগারেশনের অনুরোধ , কিন্তু আমরা প্রায়শই "টার্গেট কনফিগারেশন" বলি যদিও সেই শব্দের ইতিমধ্যে অনেক অর্থ রয়েছে) , যা আপনি শেষ পর্যন্ত অনুরোধ করা বাইনারি তৈরির জন্য ব্যবহার করা হয়।

সাধারণত, অনেক লাইব্রেরি আছে যেগুলো অনুরোধ করা বিল্ড টার্গেট ( //foo:bin ) এবং এক বা একাধিক হোস্ট টুলের পূর্বশর্ত, যেমন কিছু বেস লাইব্রেরি। এই ধরনের লাইব্রেরি অবশ্যই দুবার তৈরি করতে হবে, একবার হোস্ট কনফিগারেশনের জন্য এবং একবার টার্গেট কনফিগারেশনের জন্য। ব্যাজেল নিশ্চিত করে যে উভয় রূপই তৈরি করা হয়েছে এবং হস্তক্ষেপ এড়াতে প্রাপ্ত ফাইলগুলি আলাদা রাখা হয়েছে; সাধারণত এই ধরনের লক্ষ্যগুলি একযোগে তৈরি করা যেতে পারে, যেহেতু তারা একে অপরের থেকে স্বাধীন। আপনি যদি অগ্রগতি বার্তাগুলি দেখেন যে ইঙ্গিত করে যে একটি প্রদত্ত লক্ষ্য দুবার নির্মিত হচ্ছে, এটি সম্ভবত ব্যাখ্যা।

Bazel হোস্ট কনফিগারেশন নির্বাচন করার জন্য দুটি উপায়ের একটি ব্যবহার করে, --distinct_host_configuration বিকল্পের উপর ভিত্তি করে। এই বুলিয়ান বিকল্পটি কিছুটা সূক্ষ্ম, এবং সেটিং আপনার বিল্ডের গতি উন্নত (বা খারাপ) করতে পারে।

--distinct_host_configuration=false

এই বিকল্পটি মিথ্যা হলে, হোস্ট এবং অনুরোধ কনফিগারেশনগুলি অভিন্ন: বিল্ড করার সময় প্রয়োজনীয় সমস্ত সরঞ্জামগুলি লক্ষ্য প্রোগ্রামগুলির মতোই তৈরি করা হবে। এই সেটিং এর মানে হল যে একটি একক বিল্ডের সময় কোন লাইব্রেরি দুবার তৈরি করার দরকার নেই।

যাইহোক, এর মানে এই যে আপনার অনুরোধ কনফিগারেশনের যেকোন পরিবর্তন আপনার হোস্ট কনফিগারেশনকেও প্রভাবিত করে, যার ফলে সমস্ত টুল পুনর্নির্মাণ করা হয়, এবং তারপরে যেকোন কিছু যা টুল আউটপুটের উপর নির্ভর করে তাও পুনর্নির্মাণ করা হবে। এইভাবে, উদাহরণস্বরূপ, বিল্ডগুলির মধ্যে একটি লিঙ্কার বিকল্প পরিবর্তন করার ফলে সমস্ত সরঞ্জামগুলি পুনরায় লিঙ্ক করা হতে পারে, এবং তারপরে সেগুলি ব্যবহার করে সমস্ত ক্রিয়াগুলি পুনরায় কার্যকর করা হয় এবং এর ফলে একটি খুব বড় পুনর্নির্মাণ হয়।

--distinct_host_configuration=true (ডিফল্ট)

যদি এই বিকল্পটি সত্য হয়, তাহলে হোস্ট এবং অনুরোধের জন্য একই কনফিগারেশন ব্যবহার করার পরিবর্তে, একটি সম্পূর্ণ স্বতন্ত্র হোস্ট কনফিগারেশন ব্যবহার করা হয়। হোস্ট কনফিগারেশন নিম্নরূপ লক্ষ্য কনফিগারেশন থেকে উদ্ভূত হয়:

  • অনুরোধ কনফিগারেশনে নির্দিষ্ট করা ক্রসস্টুল ( --crosstool_top ) এর একই সংস্করণ ব্যবহার করুন, যদি না --host_crosstool_top নির্দিষ্ট করা হয়।
  • --cpu (ডিফল্ট: k8 ) এর জন্য --host_cpu এর মান ব্যবহার করুন।
  • অনুরোধ কনফিগারেশনে উল্লেখ করা এই বিকল্পগুলির একই মান ব্যবহার করুন: --compiler , --use_ijars , এবং যদি --host_crosstool_top ব্যবহার করা হয়, তাহলে ক্রসস্টুলে একটি default_toolchain দেখতে --host_cpu এর মান ব্যবহার করা হয় (- উপেক্ষা করে --compiler ) হোস্ট কনফিগারেশনের জন্য।
  • --host_javabase এর জন্য --javabase এর মান ব্যবহার করুন
  • --host_java_toolchain এর জন্য --java_toolchain এর মান ব্যবহার করুন
  • C++ কোডের জন্য অপ্টিমাইজ করা বিল্ড ব্যবহার করুন ( -c opt )।
  • কোনো ডিবাগিং তথ্য তৈরি করবেন না ( --copt=-g0 )।
  • এক্সিকিউটেবল এবং শেয়ার্ড লাইব্রেরি ( --strip=always ) থেকে স্ট্রিপ ডিবাগ তথ্য।
  • সমস্ত প্রাপ্ত ফাইল একটি বিশেষ স্থানে রাখুন, যে কোনো সম্ভাব্য অনুরোধ কনফিগারেশন দ্বারা ব্যবহৃত ফাইল থেকে আলাদা।
  • বিল্ড ডেটা সহ বাইনারিগুলির স্ট্যাম্পিং দমন করুন ( --embed_* বিকল্পগুলি দেখুন)।
  • অন্যান্য সমস্ত মান তাদের ডিফল্টে থাকে।

অনুরোধ কনফিগারেশন থেকে একটি স্বতন্ত্র হোস্ট কনফিগারেশন নির্বাচন করা পছন্দনীয় হতে পারে এমন অনেক কারণ রয়েছে। কিছু এখানে উল্লেখ করার জন্য খুব গুপ্ত, কিন্তু তাদের মধ্যে দুটি উল্লেখ করার মতো।

প্রথমত, স্ট্রাইপড, অপ্টিমাইজ করা বাইনারি ব্যবহার করে, আপনি টুলগুলিকে লিঙ্ক এবং এক্সিকিউট করার সময়, টুল দ্বারা দখল করা ডিস্ক স্পেস এবং ডিস্ট্রিবিউটেড বিল্ডে নেটওয়ার্ক I/O সময় কমিয়ে দেন।

দ্বিতীয়ত, হোস্ট ডিকপলিং করে এবং সমস্ত বিল্ডে কনফিগারেশনের অনুরোধ করে, আপনি খুব ব্যয়বহুল পুনর্নির্মাণগুলি এড়াতে পারেন যা অনুরোধ কনফিগারেশনে ছোটখাটো পরিবর্তনের ফলে (যেমন লিঙ্কার বিকল্পগুলি পরিবর্তন করা হয়), যেমনটি আগে বর্ণিত হয়েছে।

এটি বলেছে, নির্দিষ্ট বিল্ডের জন্য, এই বিকল্পটি একটি বাধা হতে পারে। বিশেষ করে, যে বিল্ডে কনফিগারেশনের পরিবর্তন বিরল (বিশেষ করে কিছু জাভা বিল্ড করে) এবং বিল্ড যেখানে হোস্ট এবং টার্গেট কনফিগারেশন উভয় ক্ষেত্রেই তৈরি করা আবশ্যক কোডের পরিমাণ বেশি, তাতে লাভ নাও হতে পারে।

সঠিক ক্রমবর্ধমান পুনর্নির্মাণ

Bazel প্রকল্পের প্রাথমিক লক্ষ্যগুলির মধ্যে একটি হল সঠিক ক্রমবর্ধমান পুনর্নির্মাণ নিশ্চিত করা। পূর্ববর্তী বিল্ড টুল, বিশেষ করে মেক-এর উপর ভিত্তি করে, তাদের ক্রমবর্ধমান বিল্ড বাস্তবায়নে বেশ কিছু অযৌক্তিক অনুমান করে।

প্রথমত, ফাইলগুলির টাইমস্ট্যাম্প একঘেয়েভাবে বৃদ্ধি পায়। যদিও এটি সাধারণ ঘটনা, তবে এই অনুমান থেকে দূরে থাকা খুব সহজ; একটি ফাইলের আগের রিভিশনে সিঙ্ক করার ফলে ফাইলের পরিবর্তনের সময় কমে যায়; মেক-ভিত্তিক সিস্টেম পুনর্নির্মাণ হবে না।

আরও সাধারণভাবে, যখন মেক ফাইলগুলিতে পরিবর্তন সনাক্ত করে, এটি কমান্ডের পরিবর্তন সনাক্ত করে না। আপনি যদি একটি প্রদত্ত বিল্ড ধাপে কম্পাইলারের কাছে পাস করা বিকল্পগুলি পরিবর্তন করেন, তবে মেক কম্পাইলারটিকে পুনরায় চালাবে না এবং make clean ব্যবহার করে পূর্ববর্তী বিল্ডের অবৈধ আউটপুটগুলি ম্যানুয়ালি বাতিল করতে হবে।

এছাড়াও, সাবপ্রসেস তার আউটপুট ফাইলে লেখা শুরু করার পরে এটির একটি সাবপ্রসেসের অসফল সমাপ্তির বিরুদ্ধে মেক শক্তিশালী নয়। যদিও মেকের বর্তমান এক্সিকিউশন ব্যর্থ হবে, মেকের পরবর্তী আমন্ত্রণ অন্ধভাবে ধরে নেবে যে ছাঁটাই করা আউটপুট ফাইলটি বৈধ (কারণ এটি তার ইনপুটগুলির চেয়ে নতুন), এবং এটি পুনর্নির্মাণ করা হবে না। একইভাবে, যদি মেক প্রক্রিয়াটি মেরে ফেলা হয় তবে একই রকম পরিস্থিতি ঘটতে পারে।

Bazel এই অনুমান, এবং অন্যান্য এড়ায়. Bazel পূর্বে করা সমস্ত কাজের একটি ডাটাবেস রক্ষণাবেক্ষণ করে এবং শুধুমাত্র একটি বিল্ড স্টেপ বাদ দেবে যদি এটি দেখতে পায় যে সেই বিল্ড স্টেপে ইনপুট ফাইলের সেট (এবং তাদের টাইমস্ট্যাম্প) এবং সেই বিল্ড স্টেপের জন্য কম্পাইলেশন কমান্ডের সাথে হুবহু মেলে ডাটাবেস, এবং, ডাটাবেস এন্ট্রির জন্য আউটপুট ফাইলের সেট (এবং তাদের টাইমস্ট্যাম্প) ডিস্কের ফাইলগুলির টাইমস্ট্যাম্পের সাথে হুবহু মিলে যায়। ইনপুট ফাইল বা আউটপুট ফাইলে বা কমান্ডে যেকোনো পরিবর্তন বিল্ড ধাপের পুনঃনির্বাহের কারণ হবে।

সঠিক ক্রমবর্ধমান বিল্ডের ব্যবহারকারীদের সুবিধা হল: বিভ্রান্তির কারণে কম সময় নষ্ট হয়। (এছাড়াও, make clean ব্যবহারের কারণে পুনঃনির্মাণের অপেক্ষায় কম সময় ব্যয় করা হয়েছে, তা প্রয়োজনীয় হোক বা প্রি-এমপ্টিভ হোক।)

ধারাবাহিকতা এবং ক্রমবর্ধমান বিল্ড তৈরি করুন

আনুষ্ঠানিকভাবে, যখন সমস্ত প্রত্যাশিত আউটপুট ফাইল বিদ্যমান থাকে তখন আমরা একটি বিল্ডের অবস্থাকে সামঞ্জস্যপূর্ণ হিসাবে সংজ্ঞায়িত করি, এবং তাদের বিষয়বস্তু সঠিক, যেমন সেগুলি তৈরি করার জন্য প্রয়োজনীয় পদক্ষেপ বা নিয়ম দ্বারা নির্দিষ্ট করা হয়েছে। আপনি যখন একটি সোর্স ফাইল সম্পাদনা করেন, তখন বিল্ডের অবস্থাকে অসামঞ্জস্যপূর্ণ বলা হয় এবং যতক্ষণ না আপনি পরবর্তীতে বিল্ড টুলটি সফলভাবে সম্পন্ন করার জন্য চালান ততক্ষণ পর্যন্ত অসামঞ্জস্যপূর্ণ থাকে। আমরা এই পরিস্থিতিটিকে অস্থির অসঙ্গতি হিসাবে বর্ণনা করি, কারণ এটি শুধুমাত্র অস্থায়ী, এবং বিল্ড টুল চালানোর মাধ্যমে সামঞ্জস্য পুনরুদ্ধার করা হয়।

আরেকটি ধরনের অসঙ্গতি আছে যা ক্ষতিকর: স্থিতিশীল অসঙ্গতি । যদি বিল্ডটি একটি স্থিতিশীল অসামঞ্জস্যপূর্ণ অবস্থায় পৌঁছায়, তাহলে বিল্ড টুলের বারবার সফল আহ্বান ধারাবাহিকতা পুনরুদ্ধার করে না: বিল্ডটি "আটকে গেছে" এবং আউটপুটগুলি ভুল থেকে যায়। মেক (এবং অন্যান্য বিল্ড টুল) টাইপের ব্যবহারকারীদের make clean করার প্রধান কারণ স্থিতিশীল অসঙ্গতিপূর্ণ অবস্থা। আবিষ্কার করা যে বিল্ড টুলটি এই পদ্ধতিতে ব্যর্থ হয়েছে (এবং তারপরে এটি থেকে পুনরুদ্ধার করা) সময়সাপেক্ষ এবং খুব হতাশাজনক হতে পারে।

ধারণাগতভাবে, একটি সামঞ্জস্যপূর্ণ বিল্ড অর্জনের সবচেয়ে সহজ উপায় হল আগের সমস্ত বিল্ড আউটপুট ফেলে দেওয়া এবং আবার শুরু করা: প্রতিটি বিল্ডকে একটি পরিষ্কার বিল্ড করুন। এই পদ্ধতিটি ব্যবহারিক হওয়ার জন্য স্পষ্টতই খুব সময়সাপেক্ষ (সম্ভবত রিলিজ ইঞ্জিনিয়ারদের জন্য) এবং সেইজন্য দরকারী হতে, বিল্ড টুলটিকে অবশ্যই সামঞ্জস্যপূর্ণতা ছাড়াই ক্রমবর্ধমান বিল্ডগুলি সম্পাদন করতে সক্ষম হতে হবে।

সঠিক ক্রমবর্ধমান নির্ভরতা বিশ্লেষণ করা কঠিন, এবং উপরে বর্ণিত হিসাবে, অন্যান্য অনেক বিল্ড টুল ক্রমবর্ধমান বিল্ডের সময় স্থিতিশীল অসঙ্গতিপূর্ণ অবস্থাগুলি এড়াতে একটি দুর্বল কাজ করে। বিপরীতে, Bazel নিম্নলিখিত গ্যারান্টি অফার করে: বিল্ড টুলের একটি সফল আহ্বানের পরে যার সময় আপনি কোনো সম্পাদনা করেননি, বিল্ডটি একটি সামঞ্জস্যপূর্ণ অবস্থায় থাকবে। (যদি আপনি একটি বিল্ড করার সময় আপনার সোর্স ফাইলগুলি সম্পাদনা করেন, তবে Bazel বর্তমান বিল্ডের ফলাফলের ধারাবাহিকতা সম্পর্কে কোন গ্যারান্টি দেয় না। তবে এটি গ্যারান্টি দেয় যে পরবর্তী বিল্ডের ফলাফলগুলি ধারাবাহিকতা পুনরুদ্ধার করবে।)

সমস্ত গ্যারান্টির মতো, কিছু সূক্ষ্ম মুদ্রণ আসে: Bazel-এর সাথে একটি স্থিতিশীল অসামঞ্জস্যপূর্ণ অবস্থায় যাওয়ার কিছু পরিচিত উপায় রয়েছে। আমরা ক্রমবর্ধমান নির্ভরতা বিশ্লেষণে বাগগুলি খুঁজে বের করার ইচ্ছাকৃত প্রচেষ্টা থেকে উদ্ভূত এই জাতীয় সমস্যাগুলি তদন্ত করার গ্যারান্টি দেব না, তবে আমরা বিল্ড টুলের স্বাভাবিক বা "যুক্তিসঙ্গত" ব্যবহার থেকে উদ্ভূত সমস্ত স্থিতিশীল অসামঞ্জস্যপূর্ণ অবস্থার তদন্ত করব এবং ঠিক করার জন্য আমাদের যথাসাধ্য চেষ্টা করব৷

আপনি যদি কখনও Bazel-এর সাথে একটি স্থিতিশীল অসামঞ্জস্যপূর্ণ অবস্থা সনাক্ত করেন, দয়া করে একটি বাগ রিপোর্ট করুন৷

স্যান্ডবক্স করা মৃত্যুদন্ড

ব্যাজেল স্যান্ডবক্স ব্যবহার করে গ্যারান্টি দিতে যে ক্রিয়াগুলি হর্মেটিকভাবে এবং সঠিকভাবে চালানো হয়। বেজেল স্যান্ডবক্সে স্প্যান চালায় (ঢিলেঢালাভাবে বললে: অ্যাকশন) যেটিতে শুধুমাত্র ন্যূনতম ফাইলের সেট থাকে যা টুলটির কাজ করতে প্রয়োজন। বর্তমানে স্যান্ডবক্সিং CONFIG_USER_NS বিকল্প সক্রিয় থাকা Linux 3.12 বা তার চেয়ে নতুন, এবং এছাড়াও macOS 10.11 বা তার চেয়ে নতুন তে কাজ করে।

আপনার সিস্টেম স্যান্ডবক্সিং সমর্থন না করলে Bazel একটি সতর্কতা প্রিন্ট করবে যে বিল্ডগুলি হারমেটিক হওয়ার গ্যারান্টিযুক্ত নয় এবং অজানা উপায়ে হোস্ট সিস্টেমকে প্রভাবিত করতে পারে। এই সতর্কতা অক্ষম করতে আপনি Bazel-এ --ignore_unsupported_sandboxing পতাকা পাস করতে পারেন৷

গুগল কুবারনেটস ইঞ্জিন ক্লাস্টার নোড বা ডেবিয়ানের মতো কিছু প্ল্যাটফর্মে, সুরক্ষা উদ্বেগের কারণে ব্যবহারকারীর নামস্থানগুলি ডিফল্টরূপে নিষ্ক্রিয় করা হয়। /proc/sys/kernel/unprivileged_userns_clone ফাইলটি দেখে এটি পরীক্ষা করা যেতে পারে : যদি এটি বিদ্যমান থাকে এবং একটি 0 থাকে, তাহলে sudo sysctl kernel.unprivileged_userns_clone=1 দিয়ে ব্যবহারকারীর নামস্থান সক্রিয় করা যেতে পারে।

কিছু ক্ষেত্রে, ব্যাজেল স্যান্ডবক্স সিস্টেম সেটআপের কারণে নিয়মগুলি কার্যকর করতে ব্যর্থ হয়৷ উপসর্গটি সাধারণত একটি ব্যর্থতা যা namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory । সেক্ষেত্রে, --strategy=Genrule=standalone এর সাথে এবং অন্যান্য নিয়মের জন্য --spawn_strategy=standalone =standalone-এর মাধ্যমে স্যান্ডবক্স নিষ্ক্রিয় করার চেষ্টা করুন। এছাড়াও অনুগ্রহ করে আমাদের সমস্যা ট্র্যাকারে একটি বাগ রিপোর্ট করুন এবং উল্লেখ করুন যে আপনি কোন Linux ডিস্ট্রিবিউশন ব্যবহার করছেন যাতে আমরা তদন্ত করতে পারি এবং পরবর্তী রিলিজে একটি সমাধান দিতে পারি।

একটি নির্মাণ পর্যায়

বাজেলে, একটি বিল্ড তিনটি স্বতন্ত্র পর্যায়ে ঘটে; একজন ব্যবহারকারী হিসাবে, তাদের মধ্যে পার্থক্য বোঝা একটি বিল্ড নিয়ন্ত্রণকারী বিকল্পগুলির অন্তর্দৃষ্টি প্রদান করে (নীচে দেখুন)।

লোডিং ফেজ

প্রথমটি লোড হচ্ছে যার সময় প্রাথমিক লক্ষ্যগুলির জন্য প্রয়োজনীয় সমস্ত BUILD ফাইল এবং তাদের নির্ভরশীলতার ট্রানজিটিভ ক্লোজার লোড, পার্স, মূল্যায়ন এবং ক্যাশে করা হয়।

একটি Bazel সার্ভার শুরু হওয়ার পরে প্রথম বিল্ডের জন্য, লোডিং পর্বে সাধারণত অনেক সেকেন্ড সময় লাগে কারণ অনেকগুলি BUILD ফাইল ফাইল সিস্টেম থেকে লোড হয়। পরবর্তী বিল্ডে, বিশেষ করে যদি কোনো বিল্ড ফাইল পরিবর্তিত না হয়, লোডিং খুব দ্রুত ঘটে।

এই পর্যায়ে রিপোর্ট করা ত্রুটিগুলির মধ্যে রয়েছে: প্যাকেজ পাওয়া যায়নি, লক্ষ্য খুঁজে পাওয়া যায়নি, একটি বিল্ড ফাইলে আভিধানিক এবং ব্যাকরণগত ত্রুটি এবং মূল্যায়ন ত্রুটি।

বিশ্লেষণ পর্যায়

দ্বিতীয় পর্যায়, বিশ্লেষণ , প্রতিটি বিল্ড নিয়মের শব্দার্থগত বিশ্লেষণ এবং বৈধতা, একটি বিল্ড নির্ভরতা গ্রাফ নির্মাণ এবং বিল্ডের প্রতিটি ধাপে ঠিক কী কাজ করতে হবে তা নির্ধারণ করে।

লোডিংয়ের মতো, বিশ্লেষণটি সম্পূর্ণরূপে গণনা করার সময়ও কয়েক সেকেন্ড সময় নেয়। যাইহোক, Bazel এক বিল্ড থেকে পরের বিল্ডে নির্ভরতা গ্রাফ ক্যাশে করে এবং শুধুমাত্র এটির কী আছে তা পুনঃবিশ্লেষণ করে, যা পূর্ববর্তী বিল্ডের পর থেকে প্যাকেজগুলি পরিবর্তিত না হওয়ার ক্ষেত্রে অত্যন্ত দ্রুত ক্রমবর্ধমান বিল্ড তৈরি করতে পারে।

এই পর্যায়ে রিপোর্ট করা ত্রুটিগুলির মধ্যে রয়েছে: অনুপযুক্ত নির্ভরতা, একটি নিয়মে অবৈধ ইনপুট এবং সমস্ত নিয়ম-নির্দিষ্ট ত্রুটি বার্তা৷

লোডিং এবং বিশ্লেষণের পর্যায়গুলি দ্রুত কারণ Bazel এই পর্যায়ে অপ্রয়োজনীয় ফাইল I/O এড়িয়ে চলে, কাজটি নির্ধারণ করার জন্য শুধুমাত্র BUILD ফাইলগুলি পড়ে। এটি ডিজাইন দ্বারা, এবং Bazel কে বিশ্লেষণ সরঞ্জামগুলির জন্য একটি ভাল ভিত্তি তৈরি করে, যেমন Bazel এর ক্যোয়ারী কমান্ড, যা লোডিং পর্যায়ে প্রয়োগ করা হয়।

মৃত্যুদন্ডের পর্যায়

নির্মাণের তৃতীয় এবং শেষ ধাপটি কার্যকর করা হয়। এই পর্যায়টি নিশ্চিত করে যে বিল্ডের প্রতিটি ধাপের আউটপুট তার ইনপুটগুলির সাথে সামঞ্জস্যপূর্ণ, সংকলন/লিঙ্কিং/ইত্যাদি পুনরায় চালু করা। প্রয়োজনীয় সরঞ্জাম। এই ধাপে বিল্ডটি তার বেশিরভাগ সময় ব্যয় করে, একটি বড় বিল্ডের জন্য কয়েক সেকেন্ড থেকে এক ঘন্টা পর্যন্ত। এই পর্যায়ে রিপোর্ট করা ত্রুটিগুলির মধ্যে রয়েছে: অনুপস্থিত উৎস ফাইল, কিছু বিল্ড অ্যাকশন দ্বারা কার্যকর করা একটি টুলে ত্রুটি, বা প্রত্যাশিত আউটপুট সেট তৈরি করতে একটি টুলের ব্যর্থতা।

,

এই পৃষ্ঠাটি কভার করে যে কিভাবে Bazel দিয়ে একটি প্রোগ্রাম তৈরি করা যায়, কমান্ড সিনট্যাক্স তৈরি করা যায় এবং টার্গেট প্যাটার্ন সিনট্যাক্স।

দ্রুত শুরু

Bazel চালানোর জন্য, আপনার বেস ওয়ার্কস্পেস ডিরেক্টরি বা এর যেকোনো সাবডিরেক্টরিতে যান এবং bazel টাইপ করুন। আপনার যদি একটি নতুন কর্মক্ষেত্র তৈরি করতে হয় তবে বিল্ড দেখুন।

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

উপলব্ধ কমান্ড

  • analyze-profile : বিল্ড প্রোফাইল ডেটা বিশ্লেষণ করে।
  • aquery : বিশ্লেষণ-পরবর্তী অ্যাকশন গ্রাফে একটি প্রশ্ন নির্বাহ করে।
  • build : নির্দিষ্ট লক্ষ্য তৈরি করে।
  • canonicalize-flags : ব্যাজেল পতাকাকে ক্যানোনিকালাইজ করুন।
  • clean : আউটপুট ফাইল মুছে দেয় এবং ঐচ্ছিকভাবে সার্ভার বন্ধ করে।
  • cquery : একটি পোস্ট-বিশ্লেষণ নির্ভরতা গ্রাফ ক্যোয়ারী চালায়।
  • dump : ব্যাজেল সার্ভার প্রক্রিয়ার অভ্যন্তরীণ অবস্থা ডাম্প করে।
  • help : কমান্ড বা সূচকের জন্য সাহায্য প্রিন্ট করে।
  • info : বেজেল সার্ভার সম্পর্কে রানটাইম তথ্য প্রদর্শন করে।
  • fetch : একটি লক্ষ্যের সমস্ত বাহ্যিক নির্ভরতা আনয়ন করে।
  • mobile-install : মোবাইল ডিভাইসে অ্যাপ ইনস্টল করে।
  • query : একটি নির্ভরতা গ্রাফ ক্যোয়ারী চালায়।
  • run : নির্দিষ্ট লক্ষ্য চালায়।
  • shutdown : ব্যাজেল সার্ভার বন্ধ করে।
  • test : নির্দিষ্ট পরীক্ষার লক্ষ্যগুলি তৈরি করে এবং চালায়।
  • version : Bazel জন্য সংস্করণ তথ্য মুদ্রণ.

সাহায্য পাচ্ছেন

  • bazel help command : প্রিন্ট সাহায্য এবং command জন্য বিকল্প.
  • bazel help startup_options : JVM হোস্টিং Bazel এর জন্য বিকল্প।
  • bazel help target-syntax : লক্ষ্য নির্দিষ্ট করার জন্য সিনট্যাক্স ব্যাখ্যা করে।
  • bazel help info-keys : info কমান্ড দ্বারা ব্যবহৃত কীগুলির একটি তালিকা প্রদর্শন করে।

bazel টুল অনেক ফাংশন সঞ্চালন করে, কমান্ড বলা হয়। সবচেয়ে বেশি ব্যবহৃত হয় bazel build এবং bazel test । আপনি bazel help ব্যবহার করে অনলাইন সহায়তা বার্তাগুলি ব্রাউজ করতে পারেন।

একটি লক্ষ্য নির্মাণ

আপনি একটি বিল্ড শুরু করার আগে, আপনার একটি ওয়ার্কস্পেস প্রয়োজন। একটি ওয়ার্কস্পেস হল একটি ডিরেক্টরি গাছ যাতে আপনার অ্যাপ্লিকেশন তৈরি করার জন্য প্রয়োজনীয় সমস্ত উৎস ফাইল থাকে। Bazel আপনাকে সম্পূর্ণরূপে পঠনযোগ্য ভলিউম থেকে একটি বিল্ড সম্পাদন করতে দেয়।

ব্যাজেল দিয়ে একটি প্রোগ্রাম তৈরি করতে, আপনি যে টার্গেট তৈরি করতে চান তার পরে bazel build টাইপ করুন।

bazel build //foo

বিল্ড করার জন্য কমান্ড জারি করার পরে //foo , আপনি এর অনুরূপ আউটপুট দেখতে পাবেন:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

প্রথমত, Bazel আপনার লক্ষ্যের নির্ভরতা গ্রাফে সমস্ত প্যাকেজ লোড করে। এর মধ্যে রয়েছে ঘোষিত নির্ভরতা , টার্গেটের BUILD ফাইলে সরাসরি তালিকাভুক্ত ফাইল এবং ট্রানজিটিভ ডিপেন্ডেন্সি , আপনার টার্গেটের নির্ভরতাগুলির BUILD ফাইলে তালিকাভুক্ত ফাইল৷ সমস্ত নির্ভরতা সনাক্ত করার পরে, Bazel সঠিকতার জন্য তাদের বিশ্লেষণ করে এবং বিল্ড অ্যাকশন তৈরি করে । শেষ পর্যন্ত, Bazel বিল্ডের কম্পাইলার এবং অন্যান্য সরঞ্জামগুলি চালায়

বিল্ডের নির্বাহের পর্যায়ে, Bazel অগ্রগতি বার্তা প্রিন্ট করে। অগ্রগতি বার্তাগুলির মধ্যে বর্তমান বিল্ড স্টেপ (যেমন, কম্পাইলার বা লিঙ্কার) শুরু হওয়ার সাথে সাথে বিল্ড অ্যাকশনের মোট সংখ্যার উপর সম্পূর্ণ হওয়া সংখ্যা অন্তর্ভুক্ত থাকে। বিল্ড শুরু হওয়ার সাথে সাথে, মোট অ্যাকশনের সংখ্যা প্রায়ই বৃদ্ধি পায় কারণ Bazel পুরো অ্যাকশন গ্রাফটি আবিষ্কার করে, কিন্তু সংখ্যাটি কয়েক সেকেন্ডের মধ্যে স্থির হয়ে যায়।

বিল্ডের শেষে, Bazel প্রিন্ট করে কোন লক্ষ্যগুলিকে অনুরোধ করা হয়েছিল, সেগুলি সফলভাবে নির্মিত হয়েছে কিনা এবং যদি তাই হয়, আউটপুট ফাইলগুলি কোথায় পাওয়া যাবে। বিল্ড চালানোর স্ক্রিপ্ট নির্ভরযোগ্যভাবে এই আউটপুট পার্স করতে পারে; আরো বিস্তারিত জানার জন্য --show_result দেখুন।

আপনি যদি একই কমান্ড আবার টাইপ করেন, বিল্ডটি অনেক দ্রুত শেষ হয়।

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

এটি একটি নাল বিল্ড . কিছুই পরিবর্তিত না হওয়ায়, পুনরায় লোড করার জন্য কোনও প্যাকেজ নেই এবং কার্যকর করার জন্য কোনও বিল্ড পদক্ষেপ নেই। যদি 'foo' বা এর নির্ভরশীলতায় কিছু পরিবর্তন হয়, Bazel কিছু বিল্ড অ্যাকশন পুনরায় কার্যকর করবে, অথবা একটি বর্ধিত বিল্ড সম্পূর্ণ করবে।

একাধিক লক্ষ্য বিল্ডিং

বেজেল তৈরি করা লক্ষ্যগুলি নির্দিষ্ট করার জন্য বিভিন্ন উপায়ের অনুমতি দেয়। সমষ্টিগতভাবে, এগুলি টার্গেট প্যাটার্ন হিসাবে পরিচিত। এই সিনট্যাক্সটি build , test বা query মতো কমান্ডে ব্যবহৃত হয়।

যেখানে লেবেলগুলি পৃথক লক্ষ্য নির্দিষ্ট করতে ব্যবহার করা হয়, যেমন BUILD ফাইলগুলিতে নির্ভরতা ঘোষণা করার জন্য, Bazel এর টার্গেট প্যাটার্ন একাধিক লক্ষ্য নির্দিষ্ট করে। টার্গেট প্যাটার্ন হল ওয়াইল্ডকার্ড ব্যবহার করে লক্ষ্যের সেটের জন্য লেবেল সিনট্যাক্সের একটি সাধারণীকরণ। In the simplest case, any valid label is also a valid target pattern, identifying a set of exactly one target.

All target patterns starting with // are resolved relative to the current workspace.

//foo/bar:wiz Just the single target //foo/bar:wiz .
//foo/bar Equivalent to //foo/bar:bar .
//foo/bar:all All rule targets in the package foo/bar .
//foo/... All rule targets in all packages beneath the directory foo .
//foo/...:all All rule targets in all packages beneath the directory foo .
//foo/...:* All targets (rules and files) in all packages beneath the directory foo .
//foo/...:all-targets All targets (rules and files) in all packages beneath the directory foo .
//... All targets in packages in the workspace. This does not include targets from external repositories .
//:all All targets in the top-level package, if there is a `BUILD` file at the root of the workspace.

Target patterns that do not begin with // are resolved relative to the current working directory . These examples assume a working directory of foo :

:foo Equivalent to //foo:foo .
bar:wiz Equivalent to //foo/bar:wiz .
bar/wiz Equivalent to:
  • //foo/bar/wiz:wiz if foo/bar/wiz is a package
  • //foo/bar:wiz if foo/bar is a package
  • //foo:bar/wiz otherwise
bar:all Equivalent to //foo/bar:all .
:all Equivalent to //foo:all .
...:all Equivalent to //foo/...:all .
... Equivalent to //foo/...:all .
bar/...:all Equivalent to //foo/bar/...:all .

By default, directory symlinks are followed for recursive target patterns, except those that point to under the output base, such as the convenience symlinks that are created in the root directory of the workspace.

In addition, Bazel does not follow symlinks when evaluating recursive target patterns in any directory that contains a file named as follows: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... is a wildcard over packages , indicating all packages recursively beneath directory foo (for all roots of the package path). :all is a wildcard over targets , matching all rules within a package. These two may be combined, as in foo/...:all , and when both wildcards are used, this may be abbreviated to foo/... .

In addition, :* (or :all-targets ) is a wildcard that matches every target in the matched packages, including files that aren't normally built by any rule, such as _deploy.jar files associated with java_binary rules.

This implies that :* denotes a superset of :all ; while potentially confusing, this syntax does allow the familiar :all wildcard to be used for typical builds, where building targets like the _deploy.jar is not desired.

In addition, Bazel allows a slash to be used instead of the colon required by the label syntax; this is often convenient when using Bash filename expansion. For example, foo/bar/wiz is equivalent to //foo/bar:wiz (if there is a package foo/bar ) or to //foo:bar/wiz (if there is a package foo ).

Many Bazel commands accept a list of target patterns as arguments, and they all honor the prefix negation operator - . This can be used to subtract a set of targets from the set specified by the preceding arguments. Note that this means order matters. For example,

bazel build foo/... bar/...

means "build all targets beneath foo and all targets beneath bar ", whereas

bazel build -- foo/... -foo/bar/...

means "build all targets beneath foo except those beneath foo/bar ". (The -- argument is required to prevent the subsequent arguments starting with - from being interpreted as additional options.)

It's important to point out though that subtracting targets this way will not guarantee that they are not built, since they may be dependencies of targets that weren't subtracted. For example, if there were a target //foo:all-apis that among others depended on //foo/bar:api , then the latter would be built as part of building the former.

Targets with tags = ["manual"] are not included in wildcard target patterns ( ... , :* , :all , etc.) when specified in commands like bazel build and bazel test ; you should specify such test targets with explicit target patterns on the command line if you want Bazel to build/test them. In contrast, bazel query doesn't perform any such filtering automatically (that would defeat the purpose of bazel query ).

Fetching external dependencies

By default, Bazel will download and symlink external dependencies during the build. However, this can be undesirable, either because you'd like to know when new external dependencies are added or because you'd like to "prefetch" dependencies (say, before a flight where you'll be offline). If you would like to prevent new dependencies from being added during builds, you can specify the --fetch=false flag. Note that this flag only applies to repository rules that do not point to a directory in the local file system. Changes, for example, to local_repository , new_local_repository and Android SDK and NDK repository rules will always take effect regardless of the value --fetch .

If you disallow fetching during builds and Bazel finds new external dependencies, your build will fail.

You can manually fetch dependencies by running bazel fetch . If you disallow during-build fetching, you'll need to run bazel fetch :

  • Before you build for the first time.
  • After you add a new external dependency.

Once it has been run, you should not need to run it again until the WORKSPACE file changes.

fetch takes a list of targets to fetch dependencies for. For example, this would fetch dependencies needed to build //foo:bar and //bar:baz :

bazel fetch //foo:bar //bar:baz

To fetch all external dependencies for a workspace, run:

bazel fetch //...

You do not need to run bazel fetch at all if you have all of the tools you are using (from library jars to the JDK itself) under your workspace root. However, if you're using anything outside of the workspace directory then Bazel will automatically run bazel fetch before running bazel build .

The repository cache

Bazel tries to avoid fetching the same file several times, even if the same file is needed in different workspaces, or if the definition of an external repository changed but it still needs the same file to download. To do so, bazel caches all files downloaded in the repository cache which, by default, is located at ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ . The location can be changed by the --repository_cache option. The cache is shared between all workspaces and installed versions of bazel. An entry is taken from the cache if Bazel knows for sure that it has a copy of the correct file, that is, if the download request has a SHA256 sum of the file specified and a file with that hash is in the cache. So specifying a hash for each external file is not only a good idea from a security perspective; it also helps avoiding unnecessary downloads.

Upon each cache hit, the modification time of the file in the cache is updated. In this way, the last use of a file in the cache directory can easily be determined, for example to manually clean up the cache. The cache is never cleaned up automatically, as it might contain a copy of a file that is no longer available upstream.

Distribution files directories

The distribution directory is another Bazel mechanism to avoid unnecessary downloads. Bazel searches distribution directories before the repository cache. The primary difference is that the distribution directory requires manual preparation.

Using the --distdir=/path/to-directory option, you can specify additional read-only directories to look for files instead of fetching them. A file is taken from such a directory if the file name is equal to the base name of the URL and additionally the hash of the file is equal to the one specified in the download request. This only works if the file hash is specified in the WORKSPACE declaration.

While the condition on the file name is not necessary for correctness, it reduces the number of candidate files to one per specified directory. In this way, specifying distribution files directories remains efficient, even if the number of files in such a directory grows large.

Running Bazel in an airgapped environment

To keep Bazel's binary size small, Bazel's implicit dependencies are fetched over the network while running for the first time. These implicit dependencies contain toolchains and rules that may not be necessary for everyone. For example, Android tools are unbundled and fetched only when building Android projects.

However, these implicit dependencies may cause problems when running Bazel in an airgapped environment, even if you have vendored all of your WORKSPACE dependencies. To solve that, you can prepare a distribution directory containing these dependencies on a machine with network access, and then transfer them to the airgapped environment with an offline approach.

To prepare the distribution directory , use the --distdir flag. You will need to do this once for every new Bazel binary version, since the implicit dependencies can be different for every release.

To build these dependencies outside of your airgapped environment, first checkout the Bazel source tree at the right version:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

Then, build the tarball containing the implicit runtime dependencies for that specific Bazel version:

bazel build @additional_distfiles//:archives.tar

Export this tarball to a directory that can be copied into your airgapped environment. Note the --strip-components flag, because --distdir can be quite finicky with the directory nesting level:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

Finally, when you use Bazel in your airgapped environment, pass the --distdir flag pointing to the directory. For convenience, you can add it as an .bazelrc entry:

build --distdir=path/to/directory

Build configurations and cross-compilation

All the inputs that specify the behavior and result of a given build can be divided into two distinct categories. The first kind is the intrinsic information stored in the BUILD files of your project: the build rule, the values of its attributes, and the complete set of its transitive dependencies. The second kind is the external or environmental data, supplied by the user or by the build tool: the choice of target architecture, compilation and linking options, and other toolchain configuration options. We refer to a complete set of environmental data as a configuration .

In any given build, there may be more than one configuration. Consider a cross-compile, in which you build a //foo:bin executable for a 64-bit architecture, but your workstation is a 32-bit machine. Clearly, the build will require building //foo:bin using a toolchain capable of creating 64-bit executables, but the build system must also build various tools used during the build itself—for example tools that are built from source, then subsequently used in, say, a genrule—and these must be built to run on your workstation. Thus we can identify two configurations: the host configuration , which is used for building tools that run during the build, and the target configuration (or request configuration , but we say "target configuration" more often even though that word already has many meanings), which is used for building the binary you ultimately requested.

Typically, there are many libraries that are prerequisites of both the requested build target ( //foo:bin ) and one or more of the host tools, for example some base libraries. Such libraries must be built twice, once for the host configuration, and once for the target configuration. Bazel takes care of ensuring that both variants are built, and that the derived files are kept separate to avoid interference; usually such targets can be built concurrently, since they are independent of each other. If you see progress messages indicating that a given target is being built twice, this is most likely the explanation.

Bazel uses one of two ways to select the host configuration, based on the --distinct_host_configuration option. This boolean option is somewhat subtle, and the setting may improve (or worsen) the speed of your builds.

--distinct_host_configuration=false

When this option is false, the host and request configurations are identical: all tools required during the build will be built in exactly the same way as target programs. This setting means that no libraries need to be built twice during a single build.

However, it does mean that any change to your request configuration also affects your host configuration, causing all the tools to be rebuilt, and then anything that depends on the tool output to be rebuilt too. Thus, for example, simply changing a linker option between builds might cause all tools to be re-linked, and then all actions using them re-executed, and so on, resulting in a very large rebuild.

--distinct_host_configuration=true (default)

If this option is true, then instead of using the same configuration for the host and request, a completely distinct host configuration is used. The host configuration is derived from the target configuration as follows:

  • Use the same version of Crosstool ( --crosstool_top ) as specified in the request configuration, unless --host_crosstool_top is specified.
  • Use the value of --host_cpu for --cpu (default: k8 ).
  • Use the same values of these options as specified in the request configuration: --compiler , --use_ijars , and if --host_crosstool_top is used, then the value of --host_cpu is used to look up a default_toolchain in the Crosstool (ignoring --compiler ) for the host configuration.
  • Use the value of --host_javabase for --javabase
  • Use the value of --host_java_toolchain for --java_toolchain
  • Use optimized builds for C++ code ( -c opt ).
  • Generate no debugging information ( --copt=-g0 ).
  • Strip debug information from executables and shared libraries ( --strip=always ).
  • Place all derived files in a special location, distinct from that used by any possible request configuration.
  • Suppress stamping of binaries with build data (see --embed_* options).
  • All other values remain at their defaults.

There are many reasons why it might be preferable to select a distinct host configuration from the request configuration. Some are too esoteric to mention here, but two of them are worth pointing out.

Firstly, by using stripped, optimized binaries, you reduce the time spent linking and executing the tools, the disk space occupied by the tools, and the network I/O time in distributed builds.

Secondly, by decoupling the host and request configurations in all builds, you avoid very expensive rebuilds that would result from minor changes to the request configuration (such as changing a linker options does), as described earlier.

That said, for certain builds, this option may be a hindrance. In particular, builds in which changes of configuration are infrequent (especially certain Java builds), and builds where the amount of code that must be built in both host and target configurations is large, may not benefit.

Correct incremental rebuilds

One of the primary goals of the Bazel project is to ensure correct incremental rebuilds. Previous build tools, especially those based on Make, make several unsound assumptions in their implementation of incremental builds.

Firstly, that timestamps of files increase monotonically. While this is the typical case, it is very easy to fall afoul of this assumption; syncing to an earlier revision of a file causes that file's modification time to decrease; Make-based systems will not rebuild.

More generally, while Make detects changes to files, it does not detect changes to commands. If you alter the options passed to the compiler in a given build step, Make will not re-run the compiler, and it is necessary to manually discard the invalid outputs of the previous build using make clean .

Also, Make is not robust against the unsuccessful termination of one of its subprocesses after that subprocess has started writing to its output file. While the current execution of Make will fail, the subsequent invocation of Make will blindly assume that the truncated output file is valid (because it is newer than its inputs), and it will not be rebuilt. Similarly, if the Make process is killed, a similar situation can occur.

Bazel avoids these assumptions, and others. Bazel maintains a database of all work previously done, and will only omit a build step if it finds that the set of input files (and their timestamps) to that build step, and the compilation command for that build step, exactly match one in the database, and, that the set of output files (and their timestamps) for the database entry exactly match the timestamps of the files on disk. Any change to the input files or output files, or to the command itself, will cause re-execution of the build step.

The benefit to users of correct incremental builds is: less time wasted due to confusion. (Also, less time spent waiting for rebuilds caused by use of make clean , whether necessary or pre-emptive.)

Build consistency and incremental builds

Formally, we define the state of a build as consistent when all the expected output files exist, and their contents are correct, as specified by the steps or rules required to create them. When you edit a source file, the state of the build is said to be inconsistent , and remains inconsistent until you next run the build tool to successful completion. We describe this situation as unstable inconsistency , because it is only temporary, and consistency is restored by running the build tool.

There is another kind of inconsistency that is pernicious: stable inconsistency . If the build reaches a stable inconsistent state, then repeated successful invocation of the build tool does not restore consistency: the build has gotten "stuck", and the outputs remain incorrect. Stable inconsistent states are the main reason why users of Make (and other build tools) type make clean . Discovering that the build tool has failed in this manner (and then recovering from it) can be time consuming and very frustrating.

Conceptually, the simplest way to achieve a consistent build is to throw away all the previous build outputs and start again: make every build a clean build. This approach is obviously too time-consuming to be practical (except perhaps for release engineers), and therefore to be useful, the build tool must be able to perform incremental builds without compromising consistency.

Correct incremental dependency analysis is hard, and as described above, many other build tools do a poor job of avoiding stable inconsistent states during incremental builds. In contrast, Bazel offers the following guarantee: after a successful invocation of the build tool during which you made no edits, the build will be in a consistent state. (If you edit your source files during a build, Bazel makes no guarantee about the consistency of the result of the current build. But it does guarantee that the results of the next build will restore consistency.)

As with all guarantees, there comes some fine print: there are some known ways of getting into a stable inconsistent state with Bazel. We won't guarantee to investigate such problems arising from deliberate attempts to find bugs in the incremental dependency analysis, but we will investigate and do our best to fix all stable inconsistent states arising from normal or "reasonable" use of the build tool.

If you ever detect a stable inconsistent state with Bazel, please report a bug.

Sandboxed execution

Bazel uses sandboxes to guarantee that actions run hermetically and correctly. Bazel runs spawns (loosely speaking: actions) in sandboxes that only contain the minimal set of files the tool requires to do its job. Currently sandboxing works on Linux 3.12 or newer with the CONFIG_USER_NS option enabled, and also on macOS 10.11 or newer.

Bazel will print a warning if your system does not support sandboxing to alert you to the fact that builds are not guaranteed to be hermetic and might affect the host system in unknown ways. To disable this warning you can pass the --ignore_unsupported_sandboxing flag to Bazel.

On some platforms such as Google Kubernetes Engine cluster nodes or Debian, user namespaces are deactivated by default due to security concerns. This can be checked by looking at the file /proc/sys/kernel/unprivileged_userns_clone : if it exists and contains a 0, then user namespaces can be activated with sudo sysctl kernel.unprivileged_userns_clone=1 .

In some cases, the Bazel sandbox fails to execute rules because of the system setup. The symptom is generally a failure that output a message similar to namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory . In that case, try to deactivate the sandbox for genrules with --strategy=Genrule=standalone and for other rules with --spawn_strategy=standalone . Also please report a bug on our issue tracker and mention which Linux distribution you're using so that we can investigate and provide a fix in a subsequent release.

Phases of a build

In Bazel, a build occurs in three distinct phases; as a user, understanding the difference between them provides insight into the options which control a build (see below).

Loading phase

The first is loading during which all the necessary BUILD files for the initial targets, and their transitive closure of dependencies, are loaded, parsed, evaluated and cached.

For the first build after a Bazel server is started, the loading phase typically takes many seconds as many BUILD files are loaded from the file system. In subsequent builds, especially if no BUILD files have changed, loading occurs very quickly.

Errors reported during this phase include: package not found, target not found, lexical and grammatical errors in a BUILD file, and evaluation errors.

Analysis phase

The second phase, analysis , involves the semantic analysis and validation of each build rule, the construction of a build dependency graph, and the determination of exactly what work is to be done in each step of the build.

Like loading, analysis also takes several seconds when computed in its entirety. However, Bazel caches the dependency graph from one build to the next and only reanalyzes what it has to, which can make incremental builds extremely fast in the case where the packages haven't changed since the previous build.

Errors reported at this stage include: inappropriate dependencies, invalid inputs to a rule, and all rule-specific error messages.

The loading and analysis phases are fast because Bazel avoids unnecessary file I/O at this stage, reading only BUILD files in order to determine the work to be done. This is by design, and makes Bazel a good foundation for analysis tools, such as Bazel's query command, which is implemented atop the loading phase.

Execution phase

The third and final phase of the build is execution . This phase ensures that the outputs of each step in the build are consistent with its inputs, re-running compilation/linking/etc. tools as necessary. This step is where the build spends the majority of its time, ranging from a few seconds to over an hour for a large build. Errors reported during this phase include: missing source files, errors in a tool executed by some build action, or failure of a tool to produce the expected set of outputs.