পূর্বশর্ত হিসাবে Makefile পরিবর্তনশীল


134

মেকফাইলে একটি deployরেসিপিটির পরিবেশগত পরিবর্তনশীল ENVসঠিকভাবে সম্পাদন করার জন্য সেট করতে হয়, অন্যরা যত্ন নেয় না, যেমন:

ENV = 

.PHONY: deploy hello

deploy:
    rsync . $(ENV).example.com:/var/www/myapp/

hello:
    echo "I don't care about ENV, just saying hello!"

এই পরিবর্তনশীলটি কীভাবে সেট করা যায় তা আমি কীভাবে নিশ্চিত করতে পারি, উদাহরণস্বরূপ: এই মেকফিল ভেরিয়েবলটিকে মোতায়েনের রেসিপিটির পূর্বশর্ত হিসাবে ঘোষণা করার কোনও উপায় আছে:

deploy: make-sure-ENV-variable-is-set

?

ধন্যবাদ.


আপনার অর্থ কী, "নিশ্চিত হয়ে নিন যে এই পরিবর্তনশীলটি সেট করা আছে"? আপনার অর্থ যাচাই বা নিশ্চিত করা? যদি এটি আগে makeসেট করা না হয়, এটি সেট করা উচিত , বা একটি সতর্কতা দেওয়া উচিত, বা মারাত্মক ত্রুটি তৈরি করা উচিত?
বিটা

1
এই পরিবর্তনশীল নিজে ব্যবহারকারী দ্বারা নির্দিষ্ট করা হয়েছে - কল করে - উদাহরণস্বরূপ তিনি একমাত্র ব্যক্তি যিনি তার এনভায়রনমেন্ট (দেবের শঙ্কু ...) জানে make ENV=devকিন্তু যদি সে ভুলে যায় ENV=dev, deployরেসিপি ব্যর্থ হবে ...
abernier

উত্তর:


171

যদি ENVঅপরিজ্ঞাত হয় এবং যদি এর কিছু প্রয়োজন হয় তবে এটি মারাত্মক ত্রুটির সৃষ্টি করবে (GNUMake এ, যাইহোক)।

.ফোনি: চেক-এনভির মতো মোতায়েন করুন

স্থাপনা: চেক-এনভিভ
	...

অন্যান্য জিনিস-যে-প্রয়োজন-env: চেক- env
	...

চেক-env:
ifndef ENV
	$ (ত্রুটি ENV অপরিবর্তিত)
যদি শেষ

(দ্রষ্টব্য যে ifndef এবং endif ইন্ডেন্টড নয় - তারা মেকফিল চালানোর আগে কার্যকর করে "কী দেখায়" তা নিয়ন্ত্রণ করে "" error (ত্রুটি "একটি ট্যাব সহ এন্টেন্ট করা যাতে এটি কেবল নিয়মের প্রসঙ্গে চলে))


12
পূর্বশর্ত হিসাবে চেক-এনভির মতো কোনওENV is undefined কাজ চালানোর সময় আমি পাচ্ছি ।
বৃষ্টি

@ ক্রম: এটি আকর্ষণীয়। আপনি একটি ন্যূনতম সম্পূর্ণ উদাহরণ দিতে পারেন?
বিটা

2
@ ক্রম কোনও ট্যাব চরিত্রের তুলনায় স্পেসের পার্থক্য রয়েছে?

8
@ এসমিট: হ্যাঁ; আমার এই সম্পর্কে জবাব দেওয়া উচিত ছিল। আমার সমাধানে, লাইনটি একটি ট্যাব দিয়ে শুরু হয়, সুতরাং এটি check-envনিয়মের একটি আদেশ ; বিধিটি কার্যকর না করা অবধি Make তা প্রসারিত করবে না। এটি যদি কোনও ট্যাব দিয়ে শুরু না হয় (যেমন @ রানের উদাহরণ হিসাবে), এটি কোনও নিয়মে না হিসাবে ব্যাখ্যা করে এবং লক্ষ্য নির্বিশেষে কোনও নিয়ম চালানোর আগে এটি মূল্যায়ন করে।
বিটা

1
Solution `my আমার সমাধানে, লাইনটি একটি ট্যাব দিয়ে শুরু হয়, সুতরাং এটি চেক-এনভির নিয়মের একটি কমান্ড;` `` আপনি কোন লাইনের কথা বলছেন? আমার ক্ষেত্রে, যদি শর্তটি মূল্যায়ন করা হয় তবুও যদি ইফডিফের পরে লাইনটি ট্যাব দিয়ে শুরু হয়
ধাওয়াল

103

আপনি একটি অন্তর্নিহিত গার্ড লক্ষ্য তৈরি করতে পারেন, এটি স্টেমের ভেরিয়েবলকে সংজ্ঞায়িত করা হয়েছে কিনা তা পরীক্ষা করে:

guard-%:
    @ if [ "${${*}}" = "" ]; then \
        echo "Environment variable $* not set"; \
        exit 1; \
    fi

তারপরে আপনি guard-ENVVARযে কোনও স্থানে একটি টার্গেট যুক্ত করুন যে কোনও ভেরিয়েবল সংজ্ঞায়িত করা হয়েছে তা এইরকম:

change-hostname: guard-HOSTNAME
        ./changeHostname.sh ${HOSTNAME}

আপনি যদি কলটিতে make change-hostnameযোগ HOSTNAME=somehostnameনা করে কল করেন, তবে আপনি একটি ত্রুটি পাবেন এবং বিল্ডটি ব্যর্থ হবে।


5
এটি একটি চতুর সমাধান, আমি এটি পছন্দ করি :)
এলিয়ট চান্স

আমি জানি যে এটি একটি প্রাচীন জবাব, তবে সম্ভবত এখনও কেউ এটি পর্যবেক্ষণ করছেন অন্যথায় আমি এটি একটি নতুন প্রশ্ন হিসাবে পুনরায় পোস্ট করতে পারি ... সেট পরিবেশের ভেরিয়েবলগুলি পরীক্ষা করার জন্য আমি এই নিখুঁত লক্ষ্য "গার্ড" বাস্তবায়নের চেষ্টা করছি এবং এটি কাজ করে নীতিগতভাবে, তবে "গার্ড-%" নিয়মের কমান্ডগুলি আসলে শেলের সাথে মুদ্রিত হয়। এই আমি দমন করতে চাই। এটা কিভাবে সম্ভব?
জিনোমিক্সি

2
ঠিক আছে. সমাধানটি আমি নিজেই খুঁজে পেয়েছি ... @ বিধি কমান্ড লাইনের শুরুতে আমার বন্ধু ...
জিনোমিকসো

4
ওয়ান-লাইনার:: if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fiডি
সি 24 ডাব্লু

4
এটি নির্বাচিত উত্তর হওয়া উচিত। এটি একটি পরিচ্ছন্ন বাস্তবায়ন।
sb32134

46

ইনলাইন বৈকল্পিক

আমার মেকফিলগুলিতে, আমি সাধারণত:

deploy:
    test -n "$(ENV)"  # $$ENV
    rsync . $(ENV).example.com:/var/www/myapp/

কারণ:

  • এটি একটি সাধারণ এক-লাইনার
  • এটা কমপ্যাক্ট
  • এটি কমান্ডগুলির নিকটে অবস্থিত যা ভেরিয়েবল ব্যবহার করে

ডিবাগিংয়ের জন্য গুরুত্বপূর্ণ মন্তব্যটি ভুলে যাবেন না:

test -n ""
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1

... আপনাকে মেকফাইলটি অনুসন্ধান করতে বাধ্য করে ...

test -n ""  # $ENV
Makefile:3: recipe for target 'deploy' failed
make: *** [deploy] Error 1

... কী ভুল হয়েছে তা সরাসরি ব্যাখ্যা করে

গ্লোবাল বৈকল্পিক (সম্পূর্ণতার জন্য, তবে জিজ্ঞাসা করা হয়নি)

আপনার মেকফিলের শীর্ষে, আপনি আরও লিখতে পারেন:

ifeq ($(ENV),)
  $(error ENV is not set)
endif

সতর্কবাণী:

  • সেই ব্লকে ট্যাব ব্যবহার করবেন না
  • যত্ন সহ ব্যবহার করুন: এমনকি cleanENV সেট না করা থাকলেও লক্ষ্য ব্যর্থ হবে। অন্যথায় হুদনের উত্তর দেখুন যা আরও জটিল

কি দারুন. "That ব্লকটিতে ট্যাব ব্যবহার করবেন না" এমনটি না হওয়া পর্যন্ত আমি এ নিয়ে সমস্যায় পড়েছিলাম। ধন্যবাদ!
অ্যালেক্স কে

এটি একটি ভাল বিকল্প, তবে আমি পছন্দ করি না যে "ত্রুটি বার্তা" সফল হলেও উপস্থিত হয় (পুরো লাইনটি মুদ্রিত)
জেফ

@ জেফ এটি মেকফাইল বেসিক। শুধু একটি দিয়ে লাইন উপসর্গ @। -> gnu.org/software/make/manual/make.html#Echoing
ড্যানিয়েল অ্যাল্ডার

আমি চেষ্টা করেছিলাম, তবে ব্যর্থতার ক্ষেত্রে ত্রুটি বার্তা উপস্থিত হবে না appear হুম আমি আবার চেষ্টা করব। নিশ্চিতভাবে আপনার উত্তরকে উজ্জীবিত করেছেন।
জেফ

1
আমি পরীক্ষার পদ্ধতি পছন্দ করি। আমি এর মতো কিছু ব্যবহার করেছি:@test -n "$(name)" || (echo 'A name must be defined for the backup. Ex: make backup name=xyz' && exit 1)
সোয়াম্পফক্স 357

6

এখন পর্যন্ত প্রদত্ত উত্তরের সাথে একটি সম্ভাব্য সমস্যা হ'ল মেকের মধ্যে নির্ভরতার আদেশটি সংজ্ঞায়িত করা হয়নি। উদাহরণস্বরূপ, চলমান:

make -j target

যখন targetকয়েকটি নির্ভরতা থাকে তখন গ্যারান্টি দেয় না যে এগুলি কোনও প্রদত্ত ক্রমে চলবে।

এর সমাধান (রেসিপিগুলি নির্বাচনের আগে ENV পরীক্ষা করা হবে কিনা তার নিশ্চয়তা দেওয়ার জন্য) কোনও রেসিপির বাইরে মেকের প্রথম পাসের সময় ENV পরীক্ষা করা উচিত:

## Are any of the user's goals dependent on ENV?
ifneq ($(filter deploy other-thing-that-needs-ENV,$(MAKECMDGOALS)),$())
ifndef ENV 
$(error ENV not defined)
endif
endif

.PHONY: deploy

deploy: foo bar
    ...

other-thing-that-needs-ENV: bar baz bono
    ...

আপনি এখানে ব্যবহৃত বিভিন্ন ফাংশন / ভেরিয়েবলগুলি সম্পর্কে পড়তে পারেন এবং $()এটি স্পষ্টভাবে বোঝানোর একটি উপায় যা আমরা "কিছুই না" এর সাথে তুলনা করছি।


6

আমি খুঁজে পেয়েছি সেরা উত্তরটি প্রয়োজন হিসাবে ব্যবহার করা যাবে না, অন্যান্য PHONY লক্ষ্যগুলি ব্যতীত। একটি আসল ফাইল যে টার্গেটের নির্ভরতা হিসাবে ব্যবহৃত হয়, তা ব্যবহার করে check-envসেই ফাইল টার্গেটটি পুনর্নির্মাণ করতে বাধ্য করা হবে।

অন্যান্য উত্তরগুলি বিশ্বব্যাপী (যেমন মেকফিলের সমস্ত টার্গেটের জন্য ভেরিয়েবলের প্রয়োজন হয় ) বা শেলটি ব্যবহার করুন, যেমন ENV অনুপস্থিত থাকলে লক্ষ্য নির্বিশেষে মেকটি বন্ধ হয়ে যাবে।

আমি উভয় ইস্যুগুলির একটি সমাধান পেয়েছি

ndef = $(if $(value $(1)),,$(error $(1) not set))

.PHONY: deploy
deploy:
    $(call ndef,ENV)
    echo "deploying $(ENV)"

.PHONY: build
build:
    echo "building"

আউটপুট মত দেখাচ্ছে

$ make build
echo "building"
building
$ make deploy
Makefile:5: *** ENV not set.  Stop.
$ make deploy ENV="env"
echo "deploying env"
deploying env
$

value কিছু ভীতিজনক ক্যাভ্যাট রয়েছে, তবে এই সাধারণ ব্যবহারের জন্য আমি বিশ্বাস করি এটি সেরা পছন্দ।


5

যেহেতু আমি দেখতে পাচ্ছি কমান্ডটি নিজেই ENV ভেরিয়েবলের প্রয়োজন তাই আপনি কমান্ডটিতে এটি পরীক্ষা করতে পারেন:

.PHONY: deploy check-env

deploy: check-env
    rsync . $(ENV).example.com:/var/www/myapp/

check-env:
    if test "$(ENV)" = "" ; then \
        echo "ENV not set"; \
        exit 1; \
    fi

এটির সাথে সমস্যাটি deployহ'ল অগত্যা একমাত্র রেসিপি নয় যা এই পরিবর্তনশীল প্রয়োজন needs এই সমাধানের সাথে, আমাকে ENVপ্রত্যেকের অবস্থা পরীক্ষা করতে হবে ... যখন আমি এটির সাথে একক (ধরণের) পূর্বশর্ত হিসাবে কাজ করতে চাই।
abernier

4

আমি জানি এটি পুরানো, তবে আমি ভেবেছিলাম ভবিষ্যতের দর্শনার্থীদের জন্য আমি আমার নিজের অভিজ্ঞতার সাথে চিমে থাকি, কারণ এটি সামান্য পরিষ্কার আইএমএইচও।

সাধারণত, এটির ডিফল্ট শেল হিসাবে makeব্যবহৃত হবে sh( বিশেষ SHELLভেরিয়েবলের মাধ্যমে সেট )। এর shএবং এর ডেরাইভেটিভসগুলিতে, পরিবেশের পরিবর্তনশীলটি সেট না করা বা না করে যদি এটি বাতিল করে থাকে তবে: একটি ত্রুটি বার্তা দিয়ে প্রস্থান করা তুচ্ছ ${VAR?Variable VAR was not set or null}

এটি প্রসারিত করে, আমরা একটি পুনরায় ব্যবহারযোগ্য মেক লক্ষ্য লিখতে পারি যা পরিবেশের পরিবর্তনশীল সেট না করা থাকলে অন্যান্য লক্ষ্যগুলি ব্যর্থ করতে ব্যবহার করা যেতে পারে:

.check-env-vars:
    @test $${ENV?Please set environment variable ENV}


deploy: .check-env-vars
    rsync . $(ENV).example.com:/var/www/myapp/


hello:
    echo "I don't care about ENV, just saying hello!"

নোটের বিষয়গুলি:

  • পালানো ডলার সাইন ( $$) এর মধ্যে শেলের পরিবর্তে বিস্তৃতকরণের প্রয়োজনmake
  • এর ব্যবহারটি কেবল testশেলটির বিষয়বস্তু সম্পাদনের চেষ্টা করা থেকে বিরত রাখা VAR(এটি অন্য কোনও উল্লেখযোগ্য উদ্দেশ্যে কাজ করে না)
  • .check-env-varsআরও পরিবেশের ভেরিয়েবলগুলি পরীক্ষা করার জন্য তুচ্ছভাবে বাড়ানো যেতে পারে, যার প্রত্যেকটিতে কেবল একটি লাইন যুক্ত করা হয় (উদাঃ @test $${NEWENV?Please set environment variable NEWENV})

যদি ENVস্পেস থাকে তবে এটি ব্যর্থ বলে মনে হচ্ছে (কমপক্ষে আমার জন্য)
এডিগ্রোভেস

2

আপনি ifdefএকটি ভিন্ন লক্ষ্য পরিবর্তে ব্যবহার করতে পারেন ।

.PHONY: deploy
deploy:
    ifdef ENV
        rsync . $(ENV).example.com:/var/www/myapp/
    else
        @echo 1>&2 "ENV must be set"
        false                            # Cause deploy to fail
    endif

আরে, আপনার উত্তরের জন্য THX কিন্তু আপনার প্রস্তাবনাটি সদৃশ কোড তৈরি করার কারণে এটি গ্রহণ করতে পারে না ... রাষ্ট্রীয় পরিবর্তনশীল deployযাচাই করার জন্য কেবলমাত্র একমাত্র রেসিপি নয় ENV
abernier

তারপরে শুধুই রিফ্যাক্টর Ifdef ব্লকের আগে .PHONY: deployএবং deploy:বিবৃতি ব্যবহার করুন এবং সদৃশ অপসারণ। (বিটিডব্লিউ আমি সঠিক পদ্ধতিটি প্রতিফলিত করার জন্য উত্তরটি সম্পাদনা করেছি)
ডুইট স্পেন্সার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.