নির্ভরতা

একটি লক্ষ্য A একটি লক্ষ্য B এর উপর নির্ভর করে যদি B নির্মাণ বা সম্পাদনের সময় A এর প্রয়োজন হয়। সম্পর্কের উপর নির্ভর করে টার্গেটের উপর একটি ডাইরেক্টেড অ্যাসাইক্লিক গ্রাফ (DAG) প্ররোচিত করে এবং একে বলা হয় নির্ভরতা গ্রাফ

একটি লক্ষ্যের সরাসরি নির্ভরতা হল সেই অন্যান্য লক্ষ্যগুলি যা নির্ভরতা গ্রাফে দৈর্ঘ্য 1 এর পথ দ্বারা পৌঁছানো যায়। একটি লক্ষ্যের ট্রানজিটিভ নির্ভরতা হল সেই লক্ষ্যগুলি যার উপর এটি গ্রাফের মাধ্যমে যেকোনো দৈর্ঘ্যের পথের মাধ্যমে নির্ভর করে।

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

প্রকৃত এবং ঘোষিত নির্ভরতা

একটি টার্গেট X প্রকৃতপক্ষে টার্গেট Y এর উপর নির্ভরশীল যদি সঠিকভাবে X তৈরি করার জন্য Y অবশ্যই উপস্থিত, নির্মিত এবং আপ-টু-ডেট থাকতে হবে। বিল্ট বলতে বোঝায় তৈরি করা, প্রক্রিয়া করা, কম্পাইল করা, লিঙ্ক করা, আর্কাইভ করা, সংকুচিত করা, এক্সিকিউট করা বা অন্য যে কোনো ধরনের কাজ যা একটি বিল্ডের সময় নিয়মিতভাবে ঘটে থাকে।

যদি X এর প্যাকেজে X থেকে Y পর্যন্ত একটি নির্ভরতা প্রান্ত থাকে তবে লক্ষ্য X এর লক্ষ্য Y এর উপর একটি ঘোষিত নির্ভরতা রয়েছে।

সঠিক বিল্ডের জন্য, প্রকৃত নির্ভরতার গ্রাফ A অবশ্যই ঘোষিত নির্ভরতা D এর গ্রাফের একটি সাবগ্রাফ হতে হবে। অর্থাৎ, A- তে সরাসরি-সংযুক্ত নোডের প্রতিটি জোড়া x --> y অবশ্যই D- এ সরাসরি সংযুক্ত থাকতে হবে। এটা বলা যেতে পারে যে D হল A এর ওভারপ্রোক্সিমেশন

BUILD ফাইল রাইটারদের অবশ্যই বিল্ড সিস্টেমে প্রতিটি নিয়মের জন্য সমস্ত প্রকৃত সরাসরি নির্ভরতা স্পষ্টভাবে ঘোষণা করতে হবে এবং আর নয়।

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

আপনি পরোক্ষভাবে আমদানি করা সমস্ত কিছু তালিকাভুক্ত করার চেষ্টা করবেন না (এবং উচিত নয়), এমনকি যদি এটি সম্পাদনের সময় A দ্বারা প্রয়োজন হয়।

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

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

1. ঘোষিত নির্ভরতা প্রকৃত নির্ভরতার সাথে মেলে

প্রথম দিকে, সবকিছু কাজ করে। প্যাকেজের কোড a প্যাকেজ b এ কোড ব্যবহার করে। প্যাকেজ b এর কোড প্যাকেজ c এর কোড ব্যবহার করে, এবং এইভাবে a ট্রানজিটিভভাবে c এর উপর নির্ভর করে।

a/BUILD b /BUILD
rule(
    name = "a",
    srcs = "a.in",
    deps = "//b:b",
)
      
rule(
    name = "b",
    srcs = "b.in",
    deps = "//c:c",
)
      
a / a.in b / b.in
import b;
b.foo();
    
import c;
function foo() {
  c.bar();
}
      
a, b, এবং c সংযোগকারী তীর সহ ঘোষিত নির্ভরতা গ্রাফ
ঘোষিত নির্ভরতা গ্রাফ
প্রকৃত নির্ভরতা গ্রাফ যা a, b, এবং c সংযোগকারী তীরগুলির সাথে ঘোষিত নির্ভরতা গ্রাফের সাথে মেলে
প্রকৃত নির্ভরতা গ্রাফ

ঘোষিত নির্ভরতাগুলি প্রকৃত নির্ভরতাগুলির চেয়ে আনুমানিক। সবকিছু ঠিক আছে.

2. একটি অঘোষিত নির্ভরতা যোগ করা

একটি সুপ্ত বিপত্তি চালু হয় যখন কেউ a কোড যোগ করে যা c এর উপর সরাসরি প্রকৃত নির্ভরতা তৈরি করে, কিন্তু বিল্ড ফাইল a/BUILD এ এটি ঘোষণা করতে ভুলে যায়।

a / a.in
        import b;
        import c;
        b.foo();
        c.garply();
      
a, b, এবং c সংযোগকারী তীর সহ ঘোষিত নির্ভরতা গ্রাফ
ঘোষিত নির্ভরতা গ্রাফ
a, b, এবং c সংযোগকারী তীরগুলির সাথে প্রকৃত নির্ভরতা গ্রাফ। একটি তীর এখন A কে C এর সাথে সংযুক্ত করে। এটি ঘোষিত নির্ভরতা গ্রাফের সাথে মেলে না
প্রকৃত নির্ভরতা গ্রাফ

ঘোষিত নির্ভরতাগুলি আর প্রকৃত নির্ভরতাগুলির চেয়ে বেশি আনুমানিক নয়৷ এটি ঠিক হতে পারে, কারণ দুটি গ্রাফের ট্রানজিটিভ ক্লোজার সমান, তবে একটি সমস্যাকে মুখোশ দেয়: a এর একটি বাস্তব কিন্তু অঘোষিত নির্ভরতা c এর উপর রয়েছে।

3. ঘোষিত এবং প্রকৃত নির্ভরতা গ্রাফের মধ্যে পার্থক্য

বিপত্তিটি তখন প্রকাশিত হয় যখন কেউ b রিফ্যাক্টর করে যাতে এটি আর c এর উপর নির্ভর না করে, অসাবধানতাবশত তাদের নিজের কোন দোষের মাধ্যমে a ভাঙতে না পারে।

b /BUILD
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
b / b.in
      import d;
      function foo() {
        d.baz();
      }
      
a এবং b সংযোগকারী তীর সহ ঘোষিত নির্ভরতা গ্রাফ। b আর c এর সাথে সংযোগ করে না, যা c এর সাথে a এর সংযোগ ভেঙে দেয়
ঘোষিত নির্ভরতা গ্রাফ
প্রকৃত নির্ভরতা গ্রাফ যা b এবং c এর সাথে একটি সংযোগ দেখায়, কিন্তু b আর c এর সাথে সংযোগ করে না
প্রকৃত নির্ভরতা গ্রাফ

ঘোষিত নির্ভরতা গ্রাফটি এখন প্রকৃত নির্ভরতাগুলির একটি কম অনুমান, এমনকি ট্রানজিটিভলি বন্ধ থাকা অবস্থায়ও; নির্মাণ ব্যর্থ হওয়ার সম্ভাবনা রয়েছে।

ধাপ 2 এ প্রবর্তিত a থেকে c থেকে প্রকৃত নির্ভরতা BUILD ফাইলে সঠিকভাবে ঘোষণা করা হয়েছে তা নিশ্চিত করে সমস্যাটি এড়ানো যেতে পারে।

নির্ভরতার প্রকারভেদ

বেশিরভাগ বিল্ড নিয়মে বিভিন্ন ধরণের জেনেরিক নির্ভরতা নির্দিষ্ট করার জন্য তিনটি বৈশিষ্ট্য রয়েছে: srcs , deps এবং data । এগুলি নীচে ব্যাখ্যা করা হয়েছে। আরও বিশদ বিবরণের জন্য, সমস্ত নিয়মে সাধারণ বৈশিষ্ট্যগুলি দেখুন।

অনেক নিয়মে নিয়ম-নির্দিষ্ট ধরণের নির্ভরতার জন্য অতিরিক্ত বৈশিষ্ট্যও রয়েছে, উদাহরণস্বরূপ, compiler বা resources । এগুলো বিল্ড এনসাইক্লোপিডিয়ায় বিস্তারিত আছে।

srcs নির্ভরতা

ফাইলগুলি সরাসরি সেই নিয়ম বা নিয়ম দ্বারা ক্ষয়প্রাপ্ত হয় যা উৎস ফাইলগুলিকে আউটপুট করে৷

deps নির্ভরতা

শিরোনাম ফাইল, প্রতীক, লাইব্রেরি, ডেটা, ইত্যাদি প্রদানকারী পৃথকভাবে সংকলিত মডিউলগুলির দিকে নির্দেশ করে নিয়ম।

data নির্ভরতা

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

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

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "//data:file1.txt",
        "//data:file2.txt",
        ...
    ],
)

এই ফাইলগুলি আপেক্ষিক পাথ path/to/data/file ব্যবহার করে উপলব্ধ। পরীক্ষায়, আপনি পরীক্ষার সোর্স ডিরেক্টরির পাথ এবং ওয়ার্কস্পেস-রিলেটিভ পাথের সাথে যোগ দিয়ে এই ফাইলগুলি উল্লেখ করতে পারেন, উদাহরণস্বরূপ, ${TEST_SRCDIR}/workspace/path/to/data/file

রেফারেন্স ডিরেক্টরিতে লেবেল ব্যবহার করা

আপনি যখন আমাদের BUILD ফাইলগুলি দেখেন, আপনি লক্ষ্য করতে পারেন যে কিছু data লেবেল ডিরেক্টরিগুলিকে নির্দেশ করে৷ এই লেবেলগুলি /. বা / এই উদাহরণগুলির মত, যা আপনার ব্যবহার করা উচিত নয়:

প্রস্তাবিত নয়data = ["//data/regression:unittest/."]

প্রস্তাবিত নয়data = ["testdata/."]

প্রস্তাবিত নয়data = ["testdata/"]

এটি সুবিধাজনক বলে মনে হচ্ছে, বিশেষ করে পরীক্ষার জন্য কারণ এটি একটি পরীক্ষাকে ডিরেক্টরির সমস্ত ডেটা ফাইল ব্যবহার করার অনুমতি দেয়।

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

প্রস্তাবিতdata = glob(["testdata/**"])

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

আপনি যদি অবশ্যই ডিরেক্টরি লেবেল ব্যবহার করেন, মনে রাখবেন যে আপনি কোনও আত্মীয় ../ পথের সাথে প্যারেন্ট প্যাকেজ উল্লেখ করতে পারবেন না; পরিবর্তে, একটি পরম পথ ব্যবহার করুন যেমন //data/regression:unittest/. .

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

filegroup(
        name = 'my_data',
        srcs = glob(['my_unittest_data/*'])
)

আপনি তারপর আপনার পরীক্ষায় ডেটা নির্ভরতা হিসাবে my_data লেবেলটি উল্লেখ করতে পারেন।

ফাইল তৈরি করুন দৃশ্যমানতা