Makefile, শিরোনাম নির্ভরতা


98

ধরা যাক নিয়মটি সহ আমার একটি মেকফিল রয়েছে

%.o: %.c
 gcc -Wall -Iinclude ...

আমি চাই যখনই একটি শিরোনাম ফাইল পরিবর্তন হয় * .o পুনর্নির্মাণ করা। নির্ভরতার একটি তালিকা তৈরির পরিবর্তে, যখনই কোনও শিরোনাম ফাইল /includeপরিবর্তিত হয়, তখন দির সমস্ত বস্তু পুনর্নির্মাণ করতে হবে।

আমি এটিকে স্থিতিশীল করার নিয়মটি পরিবর্তন করার কোনও দুর্দান্ত উপায় সম্পর্কে ভাবতে পারি না, আমি পরামর্শের জন্য উন্মুক্ত। বোনাস পয়েন্টগুলি যদি শিরোনামগুলির তালিকাটি হার্ড-কোডেড না হয়


আমার উত্তরটি নীচে লিখে রেখে আমি সম্পর্কিত তালিকায় সন্ধান করেছি এবং পেয়েছি: stackoverflow.com/questions/297514/… যা সদৃশ বলে মনে হচ্ছে। ক্রিস ডডের উত্তর আমার সমতুল্য, যদিও এটি একটি পৃথক নামকরণ কনভেনশন ব্যবহার করে।
dmckee --- প্রাক্তন-মডারেটর বিড়ালছানা

উত্তর:


117

আপনি যদি কোনও জিএনইউ সংকলক ব্যবহার করছেন তবে সংকলকটি আপনার জন্য নির্ভরতার একটি তালিকা একত্রিত করতে পারে। মেকফিল টুকরা:

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ -MF  ./.depend;

include .depend

বা

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ > ./.depend;

include .depend

যেখানে SRCSএকটি পরিবর্তনশীল উৎস ফাইল আপনার সমগ্র লিস্টে নির্দেশ করা হয়।

হাতিয়ারটিও রয়েছে makedependতবে আমি এটির মতো পছন্দ করি নাgcc -MM


4
আমি এই কৌশলটি পছন্দ করি, তবে dependউত্স ফাইলগুলি পরিবর্তিত হলে আমি কীভাবে চালাতে পারি ? এটি নির্বিশেষে প্রতিবারই চলবে বলে মনে হচ্ছে ...
তাড়া করুন

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

4
এটি কি অন্য ফাইলের আগে কিছু উপসর্গ যুক্ত করার উপায় এটি দেখানোর জন্য এটি অন্য ডিরেক্টরিতে রয়েছে build/file.o?
রিয়াদ

আমি এসআরসিএসকে ওবিজেইটিএসে পরিবর্তন করেছি, যেখানে ওবিজেইসিটিস আমার * .o ফাইলের একটি তালিকা। এটি প্রতিবার চালানো থেকে নির্ভর করে এবং কেবলমাত্র শিরোলেখের ফাইলগুলিতে পরিবর্তন এনেছে বলে মনে হয়েছিল। এটি পূর্ববর্তী মন্তব্যের বিপরীতে মনে হচ্ছে..আমি কিছু মিস করছি?
বিগব্রাউনবিয়ার 00

4
সেমিকোলন কেন প্রয়োজনীয়? যদি আমি এটি ছাড়াই চেষ্টা করি বা -এমএফ ./. নির্ভর করে শেষ যুক্তি না হয়ে থাকি তবে এটি file (এসআরসিএস) এ কেবলমাত্র শেষ ফাইলটির নির্ভরতা সংরক্ষণ করে।
হামডজ

75

বেশিরভাগ উত্তরগুলি আশ্চর্যজনকভাবে জটিল বা ভুল। তবে সহজ এবং দৃ examples় উদাহরণ অন্য কোথাও পোস্ট করা হয়েছে [ কোডরিভিউ ]। স্বীকার করা যে gnu প্রিপ্রোসেসর দ্বারা প্রদত্ত বিকল্পগুলি কিছুটা বিভ্রান্তিকর। তবে বিল্ড টার্গেট থেকে সমস্ত ডিরেক্টরি মুছে ফেলা দলিলযুক্ত-MM এবং কোনও বাগ [ জিপিপি ] নয়:

ডিফল্টরূপে সিপিপি মূল ইনপুট ফাইলের নাম নেয়, যে কোনও ডিরেক্টরি উপাদান এবং যে কোনও ফাইল প্রত্যয় যেমন '। সি' মুছে ফেলে এবং প্ল্যাটফর্মের স্বাভাবিক অবজেক্ট প্রত্যয় যুক্ত করে।

(কিছুটা নতুন) -MMDবিকল্পটি সম্ভবত আপনি চান। সম্পূর্ণতার জন্য এমন একটি মেকফিলের উদাহরণ যা একাধিক এসআরসি ডায়ারকে সমর্থন করে এবং কিছু মন্তব্য দিয়ে ডায়ার তৈরি করে। বিল্ড ডায়ার ছাড়াই সাধারণ সংস্করণের জন্য [ কোডরিভিউ ] দেখুন।

CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow

# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build

# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)

# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)

# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)

# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
    # Create build directories - same structure as sources.
    mkdir -p $(@D)
    # Just link all the object files.
    $(CXX) $(CXX_FLAGS) $^ -o $@

# Include all .d files
-include $(DEP)

# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
    mkdir -p $(@D)
    # The -MMD flags additionaly creates a .d file with
    # the same name as the .o file.
    $(CXX) $(CXX_FLAGS) -MMD -c $< -o $@

.PHONY : clean
clean :
    # This should remove all generated files.
    -rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)

এই পদ্ধতিটি কাজ করে কারণ যদি একক লক্ষের জন্য একাধিক নির্ভরতা লাইন থাকে তবে নির্ভরতাগুলি কেবল যুক্ত হয়, যেমন:

a.o: a.h
a.o: a.c
    ./cmd

সমান:

a.o: a.c a.h
    ./cmd

যেমনটি উল্লেখ করা হয়েছে: একক লক্ষ্যের জন্য মেকফিল একাধিক নির্ভরতা লাইন?


4
আমি এই সমাধানটি পছন্দ করি। আমি মেক ডিপেন্ড কমান্ড টাইপ করতে চাই না। দরকারী !!
রবার্ট

4
CPPCPPS
OBJ

4
এটি আমার পছন্দসই উত্তর; আপনার জন্য +1 এটি কেবলমাত্র এই পৃষ্ঠার যা (আমি কি দেখতে পাচ্ছ? জন্য) ইন্দ্রিয়, এবং কভার তোলে যেখানে কম্পায়লেশান প্রয়োজনীয় সব পরিস্থিতিতে এক (অপ্রয়োজনীয় সংকলন এড়ানো এখনো যথেষ্ট,) হয়
জুস্ট

4
বাক্সের বাইরে, এটি আমার জন্য শিরোনামগুলি সনাক্ত করতে ব্যর্থ হয়েছে যদিও এইচপি এবং সিপিপি উভয়ই একই ডিয়ারে রয়েছে।
ভিলাভস

4
যদি আপনার উত্স ফাইলগুলি ( a.cpp, b.cpp) এতে থাকে ./src/তবে কী সেই বিকল্পটি তৈরি করতে পারে না $(OBJ)=./build/src/a.o ./build/src/b.o?
গ্যালোইস

26

আমি এখানে যেমন পোস্ট করেছি জিসিসি নির্ভরতা তৈরি করতে এবং একই সাথে সংকলন করতে পারে:

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

'-MF' প্যারামিটারটি নির্ভরতাগুলি সংরক্ষণ করতে কোনও ফাইল নির্দিষ্ট করে।

'অন্তর্ভুক্ত' এর শুরুতে ড্যাশ .d ফাইল উপস্থিত না থাকায় মেক অব্যাহত রাখতে বলে (যেমন প্রথম সংকলনের উপরে)।

নোট করুন -o বিকল্পের সাথে জিসিসিতে একটি বাগ রয়েছে বলে মনে হচ্ছে। যদি আপনি অবজেক্ট ফাইলের নামটি অজেক্ট / _ফিল__c.o বলতে সেট করেন তবে উত্পন্ন ফাইল .d এ এখনও ফাইল থাকবে ণ না obj / _file__c.o।


4
আমি যখন এটি চেষ্টা করি তখন ফলাফল হয় আমার সমস্ত .o ফাইল খালি ফাইল হিসাবে তৈরি হচ্ছে। আমার বিল্ড সাবফোল্ডারে আমার জিনিসগুলি রয়েছে (সুতরাং $ ওবিজেইসিটিসে বিল্ড / মেইন.ও বিল্ড / এসএমএস.ও বিল্ড / ইত্যাদি রয়েছে ...) এবং এটি অবশ্যই আপাত বাগের সাথে বর্ণিত হিসাবে .d ফাইলগুলি তৈরি করে, তবে এটি অবশ্যই মোটে .o ফাইলগুলি তৈরি করছে না, আমি-এমএম এবং-এমএফ সরিয়ে দিলে এটি হয়।
ববপল

4
-এমটি ব্যবহার করা আপনার উত্তরের শেষ পংক্তিতে নোটটি সমাধান করবে যা প্রতিটি নির্ভরতা তালিকার লক্ষ্য আপডেট করে।
গড্রিক সিয়ার

4
@ বোবপল কারণ man gccবলেছেন এর দ্বারা -MMবোঝা যাচ্ছে -Eযা " প্রিপ্রোসেসিংয়ের পরে থামে"। আপনি প্রয়োজন -MMDপরিবর্তে: stackoverflow.com/a/30142139/895245
সিরো Santilli郝海东冠状病六四事件法轮功

23

যেমন কিছু সম্পর্কে:

includes = $(wildcard include/*.h)

%.o: %.c ${includes}
    gcc -Wall -Iinclude ...

আপনি সরাসরি ওয়াইল্ডকার্ডও ব্যবহার করতে পারতেন তবে আমি একাধিক জায়গায় তাদের প্রয়োজন বলে মনে করি।

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


ধন্যবাদ, আমি এটি প্রয়োজনের চেয়ে অনেক জটিল হওয়ার জন্য তৈরি করেছিলাম
মাইকে

15
এটি কাজ করে তবে এর সাথে সমস্যাটি হ'ল প্রতিটি বস্তু ফাইলটি পুনরায় সংযুক্ত হয়ে যায়, প্রতিবার একটি ছোট পরিবর্তন করা হয়, অর্থাত্ আপনার যদি 100 টি উত্স / শিরোনাম ফাইল থাকে এবং আপনি কেবল একটিতে ছোট পরিবর্তন করেন তবে সমস্ত 100 পুনরায় সংযুক্ত হয়ে যায় ।
নিকোলাস হ্যামিল্টন

4
আপনার উত্তরটি আপডেট করতে হবে এটি বলার জন্য এটি একটি খুব অকার্যকর উপায় কারণ এটি যখনই কোনও শিরোনাম ফাইল পরিবর্তিত হয় তখন সমস্ত ফাইল পুনর্নির্মাণ করে। অন্য উত্তরগুলি আরও ভাল।
xaxxon

4
এটি একটি খুব খারাপ সমাধান। নিশ্চিত যে এটি একটি ছোট প্রকল্পে কাজ করবে, তবে যে কোনও উত্পাদন আকারের টিম এবং বিল্ডিংয়ের জন্য এটি ভয়ানক সংকলনের সময় নিয়ে যাবে এবং make clean allপ্রতিবার চলার সমতুল্য হয়ে উঠবে ।
জুলিয়েন গের্টল্ট

আমার পরীক্ষায়, এটি মোটেও কার্যকর হয় না। gccলাইন এ সব মৃত্যুদন্ড কার্যকর করা হয় না, কিন্তু বিল্ট-ইন শাসন ( %o: %.cনিয়ম) পরিবর্তে মৃত্যুদন্ড কার্যকর করা হয়।
পেঙ্গে গেঞ্জ

4

উপরের মার্টিনের সমাধানটি দুর্দান্ত কাজ করে তবে সাব-ডিরেক্টরিতে থাকা কোনও .o ফাইলগুলি হ্যান্ডেল করে না। গর্ড্রিক উল্লেখ করেছেন যে-এমটি পতাকাটি সেই সমস্যার যত্ন নেয় তবে এটি একই সাথে .o ফাইলটিকে সঠিকভাবে লেখা থেকে বাধা দেয়। নিম্নলিখিত উভয় সমস্যার যত্ন নেবে:

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) -o $@ $<

3

এটি কাজটি ঠিকঠাক করবে, এবং এমনকি সাবডিয়ারগুলি নির্দিষ্ট করা হ্যান্ডেল করবে:

    $(CC) $(CFLAGS) -MD -o $@ $<

এটি জিসিসি ৪.৮.৩ দিয়ে পরীক্ষা করেছে


3

এখানে একটি দ্বি-রেখা রয়েছে:

CPPFLAGS = -MMD
-include $(OBJS:.c=.d)

এটি আপনার ডিফল্ট মেক রেসিপিটির সাথে কাজ করে, আপনার যতক্ষণ না আপনার সমস্ত অবজেক্ট ফাইলের একটি তালিকা থাকে OBJS


1

আমি এই সমাধানটিকে অগ্রাধিকার দিচ্ছি, মাইকেল উইলিয়ামসনের গৃহীত উত্তরের চেয়ে এটি উত্স + ইনলাইন ফাইল, পরে উত্স + শিরোনাম এবং অবশেষে কেবল উত্সগুলিতে পরিবর্তন আনে। এখানে সুবিধা হ'ল কেবলমাত্র কয়েকটি পরিবর্তন করা গেলে পুরো গ্রন্থাগারটি পুনরায় সংকলিত হয় না। কয়েকটি ফাইল সহ একটি প্রকল্পের জন্য বিশাল বিবেচনা নয়, আপনার যদি 10 বা 100 টি উত্স থাকে তবে আপনি পার্থক্যটি লক্ষ্য করবেন।

COMMAND= gcc -Wall -Iinclude ...

%.o: %.cpp %.inl
    $(COMMAND)

%.o: %.cpp %.hpp
    $(COMMAND)

%.o: %.cpp
    $(COMMAND)

4
এটি কেবল তখনই কাজ করে যদি আপনার শিরোনামের ফাইলগুলিতে এমন কোনও কিছু না থাকে যার জন্য অন্য কোনও সিপিপি-ফাইলগুলির সংশোধন প্রয়োজন হয় তবে সংশ্লিষ্ট বাস্তবায়ন ফাইল।
matec


0

সোফির উত্তরের একটি সামান্য পরিবর্তিত সংস্করণ যা *। ডি ফাইলগুলিকে আলাদা ফোল্ডারে আউটপুট করতে দেয় (আমি কেবল আকর্ষণীয় অংশটি আটকিয়ে দেব যা নির্ভরতা ফাইলগুলি তৈরি করে):

$(OBJDIR)/%.o: %.cpp
# Generate dependency file
    mkdir -p $(@D:$(OBJDIR)%=$(DEPDIR)%)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM -MT $@ $< -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
# Generate object file
    mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@

পরামিতি নোট করুন

-MT $@

উত্পাদিত * .d ফাইলগুলিতে লক্ষ্যমাত্রা (যেমন বস্তুর ফাইলের নামগুলি) কেবলমাত্র ফাইলের নাম নয়, * .o ফাইলের পুরো পথ রয়েছে তা নিশ্চিত করতে ব্যবহার করা হয়।

আমি জানি না কেন-সি এর সাথে মিশ্রণ হিসাবে এমএমডি ব্যবহার করার সময় এই পরামিতিটির প্রয়োজন হয় না (যেমন সোফির সংস্করণে )। এই সংমিশ্রণে মনে হয় * * .o ফাইলের পুরো পথটি * .ডি ফাইলগুলিতে লেখা আছে। এই সংমিশ্রণ ব্যতীত, -এমএমডি * .d ফাইলগুলিতে কোনও ডিরেক্টরি উপাদান ছাড়াই কেবল খাঁটি ফাইলের নাম লিখে। -সি-এর সাথে একত্রিত হওয়ার পরে কেন কেউ এমএমডি পুরো পথটি লেখেন জানেন। আমি g ++ ম্যান পৃষ্ঠাতে কোনও ইঙ্গিত পাই না।

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