मैं SRC, OBJ, और BIN उपनिर्देशिकाओं के साथ C परियोजनाओं के लिए एक मेकफाइल कैसे बना सकता हूं?


95

कुछ महीने पहले, मैं Makefileस्कूल के कामों के लिए निम्नलिखित जेनेरिक के साथ आया :

# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon@gmail.com
# Date  : 2010-11-05
#
# Changelog :
#   0.01 - first version
# ------------------------------------------------

# project name (generate executable with this name)
TARGET   = projectname

CC       = gcc -std=c99 -c
# compiling flags here
CFLAGS   = -Wall -I.

LINKER   = gcc -o
# linking flags here
LFLAGS   = -Wall

SOURCES  := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS  := $(SOURCES:.c=*.o)
rm       = rm -f

$(TARGET): obj
    @$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

obj: $(SOURCES) $(INCLUDES)
    @$(CC) $(CFLAGS) $(SOURCES)
    @echo "Compilation complete!"

clean:
    @$(rm) $(TARGET) $(OBJECTS)
    @echo "Cleanup complete!"

यह मूल रूप से हर संकलित कर देगा .cऔर .hफ़ाइल उत्पन्न करने के लिए .oफ़ाइलों और निष्पादन योग्य projectnameएक ही फ़ोल्डर में सभी।

अब, मैं इसे थोड़ा आगे बढ़ाना चाहूंगा। निम्नलिखित निर्देशिका संरचना के साथ एक सी परियोजना को संकलित करने के लिए मैं एक मेकफिल कैसे लिख सकता हूं?

 ./
 ./Makefile
 ./src/*.c;*.h
 ./obj/*.o
 ./bin/<executable>

दूसरे शब्दों में, मैं एक ऐसा मेकफाइल रखना चाहूंगा जिसमें C स्रोतों को संकलित ./src/किया जाए ./obj/और फिर निष्पादन योग्य बनाने के लिए सब कुछ लिंक किया जाए ./bin/

मैंने अलग-अलग मेकफाइल्स को पढ़ने की कोशिश की है, लेकिन मैं केवल उन्हें प्रोजेक्ट संरचना के लिए काम नहीं कर सकता; इसके बजाय, परियोजना सभी प्रकार की त्रुटियों के साथ संकलन करने में विफल रहती है। निश्चित रूप से, मैं पूर्ण विकसित आईडीई (मोनोडेवलप, अंजुता, आदि) का उपयोग कर सकता था, लेकिन मैं ईमानदारी से जीडिट और अच्छे ओल 'टर्मिनल के साथ रहना पसंद करता हूं।

क्या कोई गुरु है जो मुझे एक काम करने वाला समाधान दे सकता है, या इस बारे में स्पष्ट जानकारी दे सकता है कि यह कैसे किया जा सकता है? धन्यवाद!

** अद्यतन (v4) **

अंतिम समाधान :

# ------------------------------------------------
# Generic Makefile
#
# Author: yanick.rochon@gmail.com
# Date  : 2011-08-10
#
# Changelog :
#   2010-11-05 - first version
#   2011-08-10 - added structure : sources, objects, binaries
#                thanks to http://stackoverflow.com/users/128940/beta
#   2017-04-24 - changed order of linker params
# ------------------------------------------------

# project name (generate executable with this name)
TARGET   = projectname

CC       = gcc
# compiling flags here
CFLAGS   = -std=c99 -Wall -I.

LINKER   = gcc
# linking flags here
LFLAGS   = -Wall -I. -lm

# change these to proper directories where each file should be
SRCDIR   = src
OBJDIR   = obj
BINDIR   = bin

SOURCES  := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS  := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm       = rm -f


$(BINDIR)/$(TARGET): $(OBJECTS)
    @$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
    @echo "Linking complete!"

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
    @$(CC) $(CFLAGS) -c $< -o $@
    @echo "Compiled "$<" successfully!"

.PHONY: clean
clean:
    @$(rm) $(OBJECTS)
    @echo "Cleanup complete!"

.PHONY: remove
remove: clean
    @$(rm) $(BINDIR)/$(TARGET)
    @echo "Executable removed!"

यहाँ विशिष्ट प्रश्न क्या है?
ओलिवर चार्ल्सवर्थ

मुझे यकीन नहीं है कि मैं समझता हूं कि आप क्या करना चाहते हैं।
टॉम

अपडेट किया गया Makefile। मैं पास हो रहा हूं, लेकिन मुझे स्वचालित चर के साथ परेशानी है, इसलिए यह वैसे भी लगता है
यानिक रोचॉन

मुझे बस एक उपाय मिला। अगर किसी को कुछ बेहतर खोजने की परवाह है, तो मेकफाइल को अभी भी बेहतर बनाया जा सकता है।
यानिक रोचॉन

2
@YanickRochon का मतलब आपके अंग्रेजी कौशल की आलोचना करना नहीं था। लेकिन जाली लक्ष्य कोई मतलब आप सबसे निश्चित रूप से केले नहीं लिख सकते हैं बनाने के लिए;) gnu.org/software/make/manual/html_node/Phony-Targets.html
Joni

जवाबों:


34

सबसे पहले, आपका $(OBJECTS)नियम समस्याग्रस्त है, क्योंकि:

  1. यह अंधाधुंध की तरह है, सभी स्रोतों को हर वस्तु के पूर्वापेक्षाएँ बनाते हुए ,
  2. यह अक्सर गलत स्रोत का उपयोग करता है (जैसा कि आपने के साथ खोजा file1.oऔर file2.o)
  3. यह वस्तुओं पर रुकने के बजाय निष्पादन योग्य बनाने की कोशिश करता है, और
  4. लक्ष्य का नाम ( foo.o) वह नहीं है जो नियम वास्तव में उत्पन्न करेगा ( obj/foo.o)।

मैं निम्नलिखित सुझाव देता हूं:

OBJECTS  := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)

$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@
    @echo "Compiled "$<" successfully!"

$(TARGET)नियम एक ही समस्या है कि लक्ष्य नाम वास्तव में वर्णन नहीं है क्या नियम बनाता है। इस कारण से, यदि आप makeकई बार टाइप करते हैं, तो मेक हर बार लक्ष्य का पुनर्निर्माण करेगा, भले ही इसका कोई कारण न हो। एक छोटा सा परिवर्तन ठीक करता है:

$(BINDIR)/$(TARGET): $(OBJECTS)
    $(LINKER) $@ $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

एक बार यह सब क्रम में, आप अधिक परिष्कृत निर्भरता से निपटने पर विचार कर सकते हैं; यदि आप हेडर फ़ाइलों में से एक को संशोधित करते हैं, तो इस मेकफाइल को पता नहीं चलेगा कि किन वस्तुओं / निष्पादनयोग्य को फिर से बनाया जाना चाहिए। लेकिन वह एक और दिन इंतजार कर सकता है।

संपादित करें:
क्षमा करें, मैंने $(OBJECTS)ऊपर दिए गए नियम का हिस्सा छोड़ दिया है; मैंने इसे सुधारा है। (काश मैं कोड नमूने के अंदर "स्ट्राइक" का उपयोग कर सकता।)


आपके सुझाए गए परिवर्तनों के साथ, मुझे मिल गया:obj/file1.o: In function 'main': \n main.c:(.text+0x0): multiple definition of 'main' \n obj/main.o:main.c:(.text+0x0): first defined here
यानिक रोचॉन

@ यानिक रूचोन: क्या आपके पास कई mainकार्य हैं? शायद एक में file1.cऔर एक में main.c? यदि ऐसा है तो आप इन वस्तुओं को लिंक नहीं कर पाएंगे; mainएक निष्पादन में केवल एक ही हो सकता है ।
बीटा

नहीं मैं नहीं। प्रश्न में पोस्ट किए गए अंतिम संस्करण के साथ सब कुछ ठीक काम करता है। जब मैं अपने मेकफाइल को आपके सुझाव के अनुसार बदल देता हूं (और आप जो कह रहे हैं उसके लाभों को समझते हैं) तो मुझे यही मिलता है। मैं बस चिपकाया गया, file1.cलेकिन यह परियोजना की हर एक फाइल को एक ही संदेश देता है। और main.cहै केवल एक मुख्य कार्य के साथ एक ... और main.cआयात file1.hऔर file2.h(वहाँ के बीच कोई संबंध नहीं है file1.cऔर file2.c), लेकिन मुझे शक है समस्या से आता है।
यानिक रोचॉन

@ यानिक रूचोन: मैंने अपने $(OBJECTS)शासन की पहली पंक्ति को चिपकाने में गलती की ; मैंने इसे संपादित किया है। खराब लाइन के साथ मुझे एक त्रुटि मिली, लेकिन आपको जो नहीं मिली ...
बीटा

6

आप -Iसंकलक झंडे (CFLAGS) में ध्वज को जोड़ने के लिए संकेत कर सकते हैं कि संकलक को स्रोत फ़ाइलों के लिए कहाँ दिखना चाहिए, और -o झंडे को इंगित करना चाहिए कि बाइनरी को कहाँ छोड़ा जाना चाहिए:

CFLAGS   = -Wall -I./src
TARGETPATH = ./bin

$(TARGET): obj
    @$(LINKER) $(TARGETPATH)/$(TARGET) $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

objनिर्देशिका में ऑब्जेक्ट फ़ाइलों को छोड़ने के लिए , -oसंकलन करते समय विकल्प का उपयोग करें । इसके अलावा, देखो $@और $< स्वत: चर

उदाहरण के लिए, इस सरल मेकफाइल पर विचार करें

CFLAGS= -g -Wall -O3                                                            
OBJDIR= ./obj

SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o )
all:$(OBJS)

%.o: %.c 
   $(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$@

अद्यतन>

आपके मेकफाइल को देखकर, मुझे लगता है कि आप -oध्वज का उपयोग कर रहे हैं । अच्छा। इसका उपयोग जारी रखें, लेकिन आउटपुट फ़ाइल कहाँ लिखा जाना चाहिए यह इंगित करने के लिए एक लक्ष्य निर्देशिका चर जोड़ें।


क्या आप अधिक विस्तार से बताएंगे? क्या आपको जोड़ने -l ...का मतलब है CFLAGSऔर ... -oलिंकर ( LINKER) का तर्क पहले से ही है
यानिक रोचॉन

हां, CFLAGS, और हां, -o का उपयोग करते रहें, बस TARGETPATH ​​चर जोड़ें।
टॉम

धन्यवाद, मैंने संशोधन किए हैं, लेकिन ऐसा लगता है कि मैं अभी भी याद कर रहा हूँ (प्रश्न पर अद्यतन देखें)
यानिक रोचॉन

बस make, जहां से मेकफाइल बैठता है
यानिक रोचॉन

क्या आप निष्पादित की जा रही कमांड को नहीं पढ़ सकते हैं? उदाहरण के लिए gcc -c yadayada। बहुत यकीन है कि एक चर है जिसमें वह नहीं है जो आप उम्मीद करते हैं
टॉम

-1

मैंने इन दिनों मेकफाइल्स लिखना बंद कर दिया है, अगर आपका इरादा आगे बढ़ने का है, तो आपके पास अच्छा मेकफाइल जनरेटर है जो ग्रहण सीडीटी के साथ आता है। यदि आप अपने निर्माण के पेड़ के साथ कुछ रख-रखाव / कई परियोजना का समर्थन चाहते हैं, तो निम्नलिखित पर एक नज़र डालें -

https://github.com/dmoulding/boilermake मुझे यह बहुत अच्छा लगा ..!


3
राय आधारित। ओपी के सवाल का जवाब नहीं देता। ग्रहण का वातावरण ग्रहण करता है।
नाथनियल जॉनसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.