ভেরিয়েবল সেট না করা থাকলে মেকফিল বাতিল করুন


151

আমি কীভাবে কোনও মেকফাইলের ভেরিয়েবল সেট / মূল্যবান না হয়ে একটি মেক / মেকফাইল এক্সিকিউশন বাতিল করতে পারি?

আমি এটি নিয়ে এসেছি, তবে কেবল তখনই কাজ করে যদি কলার সুস্পষ্টভাবে লক্ষ্য না চালায় (অর্থাত্ makeকেবল রান )।

ifeq ($(MY_FLAG),)
abort:   ## This MUST be the first target :( ugly
    @echo Variable MY_FLAG not set && false
endif

all:
    @echo MY_FLAG=$(MY_FLAG)

আমি মনে করি এরকম কিছু ভাল ধারণা হবে তবে মেকের ম্যানুয়ালটিতে কিছুই খুঁজে পেল না:

ifndef MY_FLAG
.ABORT
endif

উত্তর:


271

টিএল; ডিআর : errorফাংশনটি ব্যবহার করুন :

ifndef MY_FLAG
$(error MY_FLAG is not set)
endif

নোট করুন যে লাইনগুলি অবশ্যই ইন্টেন্ট করা উচিত নয়। আরও স্পষ্টভাবে, কোনও ট্যাব অবশ্যই এই লাইনগুলির আগে না।


জেনেরিক সমাধান

আপনি যদি অনেকগুলি ভেরিয়েবল পরীক্ষা করতে চলেছেন তবে তার জন্য একটি সহায়ক ফাংশন সংজ্ঞায়িত করার মতো:

# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
#
# Params:
#   1. Variable name(s) to test.
#   2. (optional) Error message to print.
check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
      $(error Undefined $1$(if $2, ($2))))

এটি এখানে কীভাবে ব্যবহার করবেন তা এখানে:

$(call check_defined, MY_FLAG)

$(call check_defined, OUT_DIR, build directory)
$(call check_defined, BIN_DIR, where to put binary artifacts)
$(call check_defined, \
            LIB_INCLUDE_DIR \
            LIB_SOURCE_DIR, \
        library path)


এটি এর মতো একটি ত্রুটি আউটপুট দেবে:

Makefile:17: *** Undefined OUT_DIR (build directory).  Stop.

মন্তব্য:

আসল চেক এখানে করা হয়:

$(if $(value $1),,$(error ...))

এটি ifndefশর্তাধীন আচরণকে প্রতিফলিত করে , যাতে খালি মানকে সংজ্ঞায়িত করা একটি ভেরিয়েবলটিকে "অপরিজ্ঞাত" হিসাবে বিবেচনা করা হয়। তবে এটি কেবল সহজ ভেরিয়েবল এবং স্পষ্টতই খালি পুনরাবৃত্ত ভেরিয়েবলগুলির ক্ষেত্রে সত্য:

# ifndef and check_defined consider these UNDEFINED:
explicitly_empty =
simple_empty := $(explicitly_empty)

# ifndef and check_defined consider it OK (defined):
recursive_empty = $(explicitly_empty)

মন্তব্যগুলিতে @ ভিক্টর সার্জিয়েনকো পরামর্শ অনুসারে, কিছুটা ভিন্ন আচরণ পছন্দ হতে পারে:

$(if $(value $1)মানটি খালি না হলে পরীক্ষা করে। ভেরিয়েবলটি একটি খালি মান দিয়ে সংজ্ঞায়িত করা হয় তবে এটি কখনও কখনও ঠিক থাকে । আমি ব্যবহার করব$(if $(filter undefined,$(origin $1)) ...

এবং:

অধিকন্তু, যদি এটি একটি ডিরেক্টরির এবং এটা থাকা আবশ্যক যখন চেক সঞ্চালন করা হয়, আমি ব্যবহার করতে চাই $(if $(wildcard $1))। তবে অন্য ফাংশন হবে।

লক্ষ্য-নির্দিষ্ট চেক

সমাধানটি প্রসারিত করাও সম্ভব যাতে একটি নির্দিষ্ট টার্গেট করা হয় তবেই কারও একটি পরিবর্তনশীল প্রয়োজন।

$(call check_defined, ...) রেসিপি ভিতরে থেকে

কেবল চেকটিকে রেসিপিটিতে সরিয়ে ফেলুন:

foo :
    @:$(call check_defined, BAR, baz value)

নেতৃস্থানীয় @কমান্ড প্রতিধ্বনি বন্ধ চিহ্ন করিয়া এবং :প্রকৃত কমান্ড, একটি শেল নো অপ শহরের উপর অসম্পূর্ণ নিবন্ধ

লক্ষ্য নাম দেখানো হচ্ছে

check_definedফাংশন এছাড়াও আউটপুট লক্ষ্য নাম (মাধ্যমে প্রদান করা থেকে উন্নত করা যায় $@পরিবর্তনশীল):

check_defined = \
    $(strip $(foreach 1,$1, \
        $(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
    $(if $(value $1),, \
        $(error Undefined $1$(if $2, ($2))$(if $(value @), \
                required by target `$@')))

সুতরাং, এখন একটি ব্যর্থ চেক একটি সুন্দর বিন্যাসিত আউটপুট উত্পাদন করে:

Makefile:7: *** Undefined BAR (baz value) required by target `foo'.  Stop.

check-defined-MY_FLAG বিশেষ লক্ষ্য

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

# Check that a variable specified through the stem is defined and has
# a non-empty value, die with an error otherwise.
#
#   %: The name of the variable to test.
#   
check-defined-% : __check_defined_FORCE
    @:$(call check_defined, $*, target-specific)

# Since pattern rules can't be listed as prerequisites of .PHONY,
# we use the old-school and hackish FORCE workaround.
# You could go without this, but otherwise a check can be missed
# in case a file named like `check-defined-...` exists in the root 
# directory, e.g. left by an accidental `make -t` invocation.
.PHONY : __check_defined_FORCE
__check_defined_FORCE :

ব্যবহার:

foo :|check-defined-BAR

লক্ষ করুন যে, check-defined-BARহিসেবে তালিকাভুক্ত করা হয় অর্ডার কেবল- ( |...) পূর্বশর্ত।

পেশাদাররা:

  • (যুক্তিযুক্তভাবে) আরও পরিষ্কার বাক্য গঠন

কনস:

আমি বিশ্বাস করি, কিছু evalজাদু এবং গৌণ সম্প্রসারণ হ্যাকগুলি ব্যবহার করে এই সীমাবদ্ধতাগুলি অতিক্রম করা যেতে পারে , যদিও আমি নিশ্চিত নই যে এটির পক্ষে এটি উপযুক্ত।


ঠিক কি? কখনই ম্যাক ব্যবহার করা হয়নি, যদিও আমার ধারণা এটিতে মেক ডিফল্টরূপে ইনস্টল হওয়ার আরও একটি বাস্তবায়ন রয়েছে (যেমন জিএনইউ মেকের পরিবর্তে বিএসডি মেক)। আমি আপনাকে make --versionপ্রথম পদক্ষেপ হিসাবে পরীক্ষা করার পরামর্শ দিচ্ছি ।
এলদার আবুসালিমভ

1
এটি 3.81 তৈরিতে কাজ করছে বলে মনে হচ্ছে না। এটি সর্বদা ত্রুটিযুক্ত, এমনকি যদি ভেরিয়েবল সংজ্ঞায়িত হয় (এবং প্রতিধ্বনিত হতে পারে)।
অরেঞ্জডগ

আহ, আপনাকে লিঙ্কযুক্ত নকলের মতোই একেবারে কাঠামো তৈরি করতে হবে।
অরেঞ্জডগ

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

2
আমি নুবিদের জন্য (আমার মতো) একটি স্পেসিফিকেশন যুক্ত করব যে যদি আইফেন্ডেফকে ইনডেন্ট করা উচিত নয় :) আমি সেই টিপটি অন্য কোথাও পেয়েছি এবং হঠাৎ আমার সমস্ত ত্রুটিগুলি বুঝতে পেরেছিল।
হিলিওস

40

শেল ফাংশন ব্যবহার করুন test:

foo:
    test $(something)

ব্যবহার:

$ make foo
test 
Makefile:2: recipe for target 'foo' failed
make: *** [foo] Error 1
$ make foo something=x
test x

3
একই সমস্যার মুখোমুখি হওয়ার সময় আমি এটি ব্যবহার করেছি - ধন্যবাদ মেসা! আমি দুটি হালকা পরিবর্তন করেছি: 1) আমি একটি checkforsomethingলক্ষ্য তৈরি করেছি যা কেবলমাত্র এতে ছিল testএবং এটির fooউপর নির্ভরশীল করে রেখেছি , এবং 2) আমি চেকটি @if test -z "$(something)"; then echo "helpful error here"; exit 1; fiপরিবর্তে পরিবর্তিত করেছি । এটি আমাকে একটি দরকারী ত্রুটি যুক্ত করার ক্ষমতা দিয়েছে এবং আমাকে নতুন টার্গেটের নামটিও কী ভুল হয়েছে সেটিকে আরও কিছুটা সূচক করার অনুমতি দিয়েছে।
ব্রায়ান জেরার্ড

এর সাথে আমি পেয়েছিMakefile:5: *** missing separator. Stop.
সিলগন

7
সংক্ষিপ্ততার জন্য আমি test -n "$(something) || (echo "message" ; exit 1)স্পষ্টতাকে এড়িয়ে চলতাম if
ব্যবহারকারী 295691

@ সিলগন আপনি সম্ভবত কোনও ট্যাবের পরিবর্তে স্পেস ব্যবহার করে ইনডেন্টিং করছেন।
ইবউব

9

আপনি পরীক্ষার জন্য একটি আইএফ ব্যবহার করতে পারেন:

check:
        @[ "${var}" ] || ( echo ">> var is not set"; exit 1 )

ফলাফল:

$ make check
>> var is not set
Makefile:2: recipe for target 'check' failed
make: *** [check] Error 1

[কমান্ডের জন্য একটি উপনাম test, সুতরাং এটি উপরে @ মেসার মতো একই উত্তর। এটি আরও কমপ্যাক্ট, যদিও এবং এতে ত্রুটি বার্তা উত্পন্ন রয়েছে।
ব্যবহারকারী 295691

6

আনসেট ভেরিয়েবলগুলির জন্য শেল ত্রুটি হ্যান্ডলিং ব্যবহার করুন (ডাবল নোট করুন $):

$ cat Makefile
foo:
        echo "something is set to $${something:?}"

$ make foo
echo "something is set to ${something:?}"
/bin/sh: something: parameter null or not set
make: *** [foo] Error 127


$ make foo something=x
echo "something is set to ${something:?}"
something is set to x

আপনার যদি কাস্টম ত্রুটি বার্তা প্রয়োজন হয় তবে এটির পরে যুক্ত করুন ?:

$ cat Makefile
hello:
        echo "hello $${name:?please tell me who you are via \$$name}"

$ make hello
echo "hello ${name:?please tell me who you are via \$name}"
/bin/sh: name: please tell me who you are via $name
make: *** [hello] Error 127

$ make hello name=jesus
echo "hello ${name:?please tell me who you are via \$name}"
hello jesus

2

সরলতা এবং সংকোচনের জন্য:

$ cat Makefile
check-%:
        @: $(if $(value $*),,$(error $* is undefined))

bar:| check-foo
        echo "foo is $$foo"

আউটপুট সহ:

$ make bar
Makefile:2: *** foo is undefined. Stop.
$ make bar foo="something"
echo "foo is $$foo"
foo is something
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.