জিএনইউ মেকফিল নিয়মটি একটি একক উত্স ফাইল থেকে কয়েকটি লক্ষ্য তৈরি করে


105

আমি নিম্নলিখিতটি করার চেষ্টা করছি। একটি প্রোগ্রাম রয়েছে, এটি কল করুন foo-bin, এটি একটি একক ইনপুট ফাইল গ্রহণ করে এবং দুটি আউটপুট ফাইল উত্পন্ন করে। এটির জন্য একটি বোবা Makefile নিয়ম হবে:

file-a.out file-b.out: input.in
    foo-bin input.in file-a.out file-b.out

তবে এটি কোনওভাবেই তা বলে দেয় না makeযে উভয় লক্ষ্য একই সাথে উত্পন্ন হবে। makeসিরিয়ালে চলার সময় এটি ঠিক আছে , তবে কেউ যদি চেষ্টা করে make -j16বা সমান পাগল করে তবে সমস্যা হতে পারে ।

প্রশ্নটি রয়েছে যে এই জাতীয় মামলার জন্য উপযুক্ত মেকফিল বিধি লেখার কোনও উপায় আছে কি না? স্পষ্টতই, এটি একটি ডিএজি উত্পন্ন করবে, তবে কোনওভাবে জিএনইউ মেকস ম্যানুয়ালে এই মামলাটি কীভাবে পরিচালনা করা যায় তা নির্দিষ্ট করে না।

একই কোডটি দু'বার চালানো এবং কেবল একটি ফলাফল তৈরি করা প্রশ্নের বাইরে, কারণ গণনাটি সময় নেয় (চিন্তা করুন: ঘন্টা)। কেবলমাত্র একটি ফাইলের আউটপুট তৈরি করা বরং কঠিন হবে, কারণ ঘন ঘন এটি GNUPLOT এর ইনপুট হিসাবে ব্যবহৃত হয় যা কেবলমাত্র কোনও ডাটা ফাইলের একটি ভগ্নাংশ হ্যান্ডেল করতে জানে না।


উত্তর:


12

আমি নিম্নলিখিত হিসাবে এটি সমাধান করবে:

file-a.out: input.in
    foo-bin input.in file-a.out file-b.out   

file-b.out: file-a.out
    #do nothing
    noop

এই ক্ষেত্রে সমান্তরাল মেক একটি এবং বি তৈরি করে 'সিরিয়ালাইজ' করবে তবে যেহেতু খ তৈরির কিছু হয় না তাতে সময় লাগে না।


16
আসলে, এই সমস্যা আছে। যদি file-b.outবলা হয়েছে এবং যদি রহস্যজনকভাবে মুছে ফেলা হয় তবে makeএটি পুনরায় তৈরি করতে অক্ষম হবে কারণ file-a.outএখনও উপস্থিত থাকবে। কোন চিন্তা?
Makeaurus

আপনি যদি রহস্যজনকভাবে মুছে ফেলেন file-a.outতবে উপরের সমাধানটি ভালভাবে কাজ করে। এটি হ্যাকের পরামর্শ দেয়: যখন কেবল একটি বা বি এর মধ্যে একটির উপস্থিতি থাকে, তখন নির্ভরতাগুলি যেমন অর্ডার করা উচিত যে অনুপস্থিত ফাইলটি আউটপুট হিসাবে উপস্থিত হয় input.in। কয়েকটি $(widcard...)এস, $(filter...)এস, $(filter-out...)এস ইত্যাদি কৌশলটি করা উচিত। বিতৃষ্ণা।
বোবোগো

3
পিএস foo-binঅবশ্যই স্পষ্টতই ফাইলগুলির মধ্যে একটি তৈরি করবে (মাইক্রোসেকেন্ড রেজোলিউশন ব্যবহার করে), সুতরাং উভয় ফাইল উপস্থিত থাকার সময় আপনার অবশ্যই নির্ভরতা ক্রমটি সঠিকভাবে নিশ্চিত করতে হবে।
বোবোগো

2
@ বোবোগো হয় তা হয়, বা অনুরোধের touch file-a.outপরে দ্বিতীয় কমান্ড হিসাবে যুক্ত করুন foo-bin
কনার হ্যারিস

এখানে এটির জন্য একটি সম্ভাব্য সংশোধন করা হয়েছে: touch file-b.outপ্রথম নিয়মে দ্বিতীয় কমান্ড হিসাবে যুক্ত করুন এবং দ্বিতীয় নিয়মে কমান্ডগুলি সদৃশ করুন। যদি ফাইলটি অনুপস্থিত বা তার চেয়ে পুরনো হয় input.inতবে কমান্ডটি একবারে কার্যকর করা হবে এবং file-b.outসাম্প্রতিককালের চেয়ে উভয় ফাইলকেই পুনরায় জেনারেট করবে file-a.out
chqrlie

128

কৌশলটি হ'ল একাধিক লক্ষ্য সহ একটি প্যাটার্ন নিয়ম ব্যবহার করা। সেক্ষেত্রে মেকটি ধরে নেবে যে উভয় লক্ষ্য লক্ষ্য কমান্ডের একক অনুরোধ দ্বারা তৈরি করা হয়েছিল।

all: file-a.out ফাইল-বি.আউট
file-a% আউট ফাইল-বি% আউট: ইনপুট.ইন
    ফু-বিন ইনপুট.ইন ফাইল-আ $ * আউট ফাইল-বি $ * আউট

প্যাটার্ন বিধি এবং সাধারণ নিয়মের মধ্যে ব্যাখ্যার এই পার্থক্যটি ঠিক বোঝা যায় না, তবে এটি এই জাতীয় ক্ষেত্রে কার্যকর এবং এটি ম্যানুয়ালটিতে নথিভুক্ত।

এই ট্রিকটি যেকোন সংখ্যক আউটপুট ফাইলের জন্য ব্যবহার করা যেতে পারে যতক্ষণ না তাদের নামের %সাথে ম্যাচের জন্য কিছু সাধারণ স্ট্রিং থাকে । (এক্ষেত্রে সাধারণ সাবস্ট্রিংটি হ'ল "।")


3
এটি আসলে সঠিক নয়। আপনার নিয়মটি উল্লেখ করে যে এই প্যাটার্নগুলির সাথে মেলে ফাইলগুলি ইনপুট.in থেকে নির্দিষ্ট কমান্ডটি ব্যবহার করে তৈরি করা হবে, তবে কোথাও কোথাও বলা হয় নি যে সেগুলি একই সাথে তৈরি করা হয়েছিল। আপনি যদি আসলে এটি সমান্তরালভাবে makeচালনা করেন তবে একই কমান্ডটি একই সাথে দু'বার চালানো হবে।
Makeaurus

47
আপনি এটি বলছেন না এর আগে দয়া করে এটি ব্যবহার করে দেখুন ;-) জিএনইউ মেক ম্যানুয়াল বলেছেন: "প্যাটার্ন বিধিগুলির একাধিক লক্ষ্য থাকতে পারে normal একটি প্যাটার্ন নিয়মের একাধিক লক্ষ্য রয়েছে, জেনে রাখুন যে সমস্ত লক্ষ্যবস্তু তৈরির জন্য নিয়মের আদেশগুলি দায়বদ্ধ। সমস্ত লক্ষ্যবস্তু তৈরি করার জন্য কমান্ডগুলি কেবল একবার কার্যকর করা হয় "" gnu.org/software/make/manual/make.html#
প্যাটার্ন-

4
তবে আমার যদি সম্পূর্ণ আলাদা ইনপুট থাকে ?, foo.in এবং বার.এসআরসি বলুন? প্যাটার্ন বিধিগুলি খালি প্যাটার্ন মেলাকে সমর্থন করে?
grwlf

2
@ডকো: আউটপুট ফাইলগুলিকে কেবল একটি স্ট্রিং ভাগ করতে হবে (এমনকি একটি অক্ষর যেমন "।" যথেষ্ট) একটি উপসর্গের প্রয়োজন হয় না। যদি কোনও সাধারণ সাবস্ট্রিং না থাকে তবে আপনি রিচার্ড এবং ডিমার দ্বারা বর্ণিত একটি মধ্যবর্তী লক্ষ্য ব্যবহার করতে পারেন। @grwlf: আরে, এর অর্থ হল "foo.in" এবং "বার.এসসিআর" করা যেতে পারে: foo%in bar%src: input.in:-)
ধীরে ধীরে

1
যদি সম্পর্কিত আউটপুট ফাইলগুলি ভেরিয়েবলগুলিতে রাখা হয় তবে রেসিপিটি এইভাবে লেখা যেতে পারে: $(subst .,%,$(varA) $(varB)): input.in(GNU Make 4.1 দিয়ে পরীক্ষিত)।
স্টিফ্যান্ট

55

মেক করার মতো কোনও স্বজ্ঞাত উপায় নেই তবে দুটি শালীন কাজের ক্ষেত্র রয়েছে।

প্রথমত, যদি জড়িত লক্ষ্যগুলিতে একটি সাধারণ স্টেম থাকে তবে আপনি একটি উপসর্গ নিয়ম (GNU Make সহ) ব্যবহার করতে পারেন। এটি হল, আপনি যদি নিম্নলিখিত নিয়মটি ঠিক করতে চান:

object.out1 object.out2: object.input
    foo-bin object.input object.out1 object.out2

আপনি এটি এইভাবে লিখতে পারেন:

%.out1 %.out2: %.input
    foo-bin $*.input $*.out1 $*.out2

(প্যাটার্ন-রুল ভেরিয়েবল $ * ব্যবহার করে, যা প্যাটার্নের ম্যাচের অংশটি বোঝায়)

আপনি যদি নন-জিএনইউ-তে বাস্তবায়ন করতে পোর্টেবল হতে চান বা যদি আপনার ফাইলগুলি কোনও প্যাটার্ন নিয়মের সাথে মেলে না দেওয়া যায় তবে অন্য উপায় আছে:

file-a.out file-b.out: input.in.intermediate ;

.INTERMEDIATE: input.in.intermediate
input.in.intermediate: input.in
    foo-bin input.in file-a.out file-b.out

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

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


7
ভাল, Loooks .INTERMEDIATE পদ্ধতির মত কাজ ঠিক আছে। সমস্যাটি বর্ণনা করে অটোমেক নিবন্ধও দেখুন (তবে তারা এটি পোর্টেবল উপায়ে সমাধান করার চেষ্টা করছেন)।
grwlf

3
এটি আমি এটি দেখেছি সেরা উত্তর। আগ্রহের অন্যান্য বিশেষ লক্ষ্যগুলিও হতে পারে: gnu.org/software/make/manual/html_node/Spected-Targets.html
আর্নে

2
@ ডিমার এটি ওএসএক্সে আমার পক্ষে কাজ করছে না। (জিএনইউ Make 3.81)
জর্জি বুকারান

2
আমি এটি চেষ্টা করে এসেছি এবং আমি সমান্তরাল বিল্ডগুলির সাথে সূক্ষ্ম সমস্যাগুলি লক্ষ্য করেছি --- নির্ভরতা সর্বদা মধ্যবর্তী লক্ষ্য জুড়ে সঠিকভাবে প্রচার করে না (যদিও -j1বিল্ডগুলির সাথে সবকিছু ঠিক আছে )। এছাড়াও, যদি মেকফিলটি বাধাগ্রস্ত হয় এবং এটি input.in.intermediateচারপাশের ফাইলটি ফেলে দেয় তবে তা সত্যিই বিভ্রান্ত হয়ে পড়ে।
ডেভিড

3
এই উত্তরের একটি ত্রুটি রয়েছে। আপনার সমান্তরাল বিল্ডগুলি নিখুঁতভাবে কাজ করতে পারে। আপনি শুধু পরিবর্তন করতে হবে file-a.out file-b.out: input.in.intermediateকরতে file-a.out file-b.out: input.in.intermediate ;দেখুন stackoverflow.com/questions/37873522/... আরো বিস্তারিত জানার জন্য।
siulkilulki

10

এটি @ ডিমারের দ্বিতীয় উত্তরের উপর ভিত্তি করে যা প্যাটার্ন বিধিগুলির উপর নির্ভর করে না এবং এটি এমন একটি সমস্যা সমাধান করে যা আমি কার্যনির্বাহী নেস্টেড ব্যবহারের সাথে সম্মুখীন হয়েছি।

file-a.out file-b.out: input.in.intermediate
    @# Empty recipe to propagate "newness" from the intermediate to final targets

.INTERMEDIATE: input.in.intermediate
input.in.intermediate: input.in
    foo-bin input.in file-a.out file-b.out

আমি @ ডিমারের উত্তরে একটি মন্তব্য হিসাবে এটি যুক্ত করতে পারি, তবে আমি করতে পারি না কারণ আমি এই অ্যাকাউন্টটি তৈরি করেছি এবং কোনও খ্যাতি নেই।

ব্যাখ্যা: মেককে যথাযথ বুককিপিং চিহ্নিত করতে file-a.outএবং file-b.outপুনর্নির্মাণের জন্য যাতে অনুমতি দেওয়া হয় তার জন্য খালি রেসিপিটি প্রয়োজন । আপনার যদি এখনও অন্য কোনও মধ্যবর্তী টার্গেট থাকে যা নির্ভর করে file-a.out, তবে মেক বাইরের মধ্যবর্তীটি তৈরি না করে বেছে নেবেন, দাবি করে:

No recipe for 'file-a.out' and no prerequisites actually changed.
No need to remake target 'file-a.out'.

9

জিএনইউ 4.3 ​​করার পরে (19 জানুয়ারী 2020) আপনি "গ্রুপযুক্ত সুস্পষ্ট লক্ষ্য" ব্যবহার করতে পারেন। :সঙ্গে প্রতিস্থাপন &:

file-a.out file-b.out &: input.in
    foo-bin input.in file-a.out file-b.out

জিএনইউ মেকের নিউজ ফাইলটি বলে:

নতুন বৈশিষ্ট্য: গোষ্ঠীগত সুস্পষ্ট লক্ষ্যগুলি

প্যাটার্ন বিধিগুলির সবসময় রেসিপিটির একক অনুরোধ সহ একাধিক লক্ষ্যমাত্রা উত্পন্ন করার ক্ষমতা ছিল। এখন ঘোষণা করা সম্ভব যে একটি সুস্পষ্ট নিয়ম একক অনুরোধ সহ একাধিক লক্ষ্য তৈরি করে। এটি ব্যবহার করতে, নিয়মে ":" টোকেনটি "&:" এর সাথে প্রতিস্থাপন করুন। এই বৈশিষ্ট্যটি সনাক্ত করার জন্য .FEATURES বিশেষ ভেরিয়েবলে 'দলবদ্ধ-লক্ষ্য' অনুসন্ধান করুন। বাস্তবায়ন কাজ কিলহেকু <kaz@kylheku.com> দ্বারা অবদান


2

এইভাবেই আমি এটি করি। প্রথমে আমি সবসময় রেসিপিগুলি থেকে প্রাক-প্রয়োজনীয়গুলি আলাদা করি। তারপরে এই ক্ষেত্রে রেসিপিটি করার জন্য একটি নতুন টার্গেট।

all: file-a.out file-b.out #first rule

file-a.out file-b.out: input.in

file-a.out file-b.out: dummy-a-and-b.out

.SECONDARY:dummy-a-and-b.out
dummy-a-and-b.out:
    echo creating: file-a.out file-b.out
    touch file-a.out file-b.out

প্রথমবার:
১. আমরা ফাইল-এ.আউট তৈরির চেষ্টা করি, তবে ডামি-এ-ও-বি.আউটকে প্রথমে করা দরকার তাই ডামি-এ-বি-আউট রেসিপিটি চালানো উচিত।
২. আমরা ফাইল-বি.আউট তৈরির চেষ্টা করি, ডামি-এ-ও-বি.আউট আপ টু ডেট।

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


1
এটি ভেঙে গেছে আপনি যদি মুছে file-b.outফেলেন তবে এটিকে পুনরায় তৈরি করার কোনও উপায় নেই।
বোবোগো

সমস্ত যোগ করা হয়েছে: প্রথম নিয়ম হিসাবে file-a.out file-b.out। যেন ফাইল-বি.আউট সরানো হয়েছে এবং কমান্ড লাইনে কোনও লক্ষ্য ছাড়াই মেক চালানো হয়েছে, এটি এটি পুনর্নির্মাণ করবে না।
ctrl-alt-delor

@ বোবোগো স্থির: উপরের মন্তব্য দেখুন।
ctrl-alt-delor

0

@ ডিমারের উত্তরের এক্সটেনশন হিসাবে, আমি এটিকে একটি ক্রিয়ায় সাধারণীকরণ করেছি।

sp :=
sp +=
inter = .inter.$(subst $(sp),_,$(subst /,_,$1))

ATOMIC=\
    $(eval s1=$(strip $1)) \
    $(eval target=$(call inter,$(s1))) \
    $(eval $(s1): $(target) ;) \
    $(eval .INTERMEDIATE: $(target) ) \
    $(target)

$(call ATOMIC, file-a.out file-b.out): input.in
    foo-bin input.in file-a.out file-b.out

ভাঙ্গন:

$(eval s1=$(strip $1))

প্রথম আর্গুমেন্ট থেকে যে কোনও শীর্ষস্থানীয় / চলমান শ্বেত স্পেসটি স্ট্রিপ করুন

$(eval target=$(call inter,$(s1)))

মধ্যবর্তী টার্গেট হিসাবে ব্যবহার করতে একটি অনন্য মানের একটি পরিবর্তনশীল লক্ষ্য তৈরি করুন। এই ক্ষেত্রে, মান .inter.file-a.out_file-b.out হবে।

$(eval $(s1): $(target) ;)

নিম্নচাপ হিসাবে অনন্য লক্ষ্য নিয়ে আউটপুটগুলির জন্য একটি খালি রেসিপি তৈরি করুন।

$(eval .INTERMEDIATE: $(target) ) 

একটি মধ্যবর্তী হিসাবে অনন্য লক্ষ্য ঘোষণা করুন।

$(target)

অনন্য টার্গেটের রেফারেন্স দিয়ে শেষ করুন যাতে এই ফাংশনটি সরাসরি একটি রেসিপিটিতে ব্যবহার করা যায়।

এছাড়াও এখানে নোট করুন eval এর ব্যবহার হ'ল কারণ Eval কিছুই প্রসারিত করে না তাই ফাংশনটির সম্পূর্ণ সম্প্রসারণ কেবল অনন্য লক্ষ্য।

এই ফাংশনটি থেকে অনুপ্রাণিত হয় জিনু মেকের পারমাণবিক বিধিকে অবশ্যই ক্রেডিট দিতে হবে ।


0

একাধিক আউটপুট সহ কোনও নিয়মের সমান্তরাল একাধিক প্রয়োগ রোধ করতে make -jN, ব্যবহার করুন .NOTPARALLEL: outputs। তোমার ক্ষেত্রে :

.NOTPARALLEL: file-a.out file-b.out

file-a.out file-b.out: input.in
    foo-bin input.in file-a.out file-b.out
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.