अपने Makefile की वर्तमान सापेक्ष निर्देशिका कैसे प्राप्त करें?


202

मेरे पास ऐप विशिष्ट निर्देशिकाओं में कई मेकफाइल्स हैं:

/project1/apps/app_typeA/Makefile
/project1/apps/app_typeB/Makefile
/project1/apps/app_typeC/Makefile

प्रत्येक मेकफाइल में एक .inc फ़ाइल होती है जिसमें एक स्तर ऊपर होता है:

/project1/apps/app_rules.inc

App_rules.inc के अंदर, मैं चाहता हूं कि जहां मैं चाहता हूं कि बायनेरिज़ को जब बनाया जाए तो मैं उस स्थान को निर्धारित करूं। मैं चाहता हूं कि सभी बायनेरिज़ अपने-अपने app_typeरास्ते में हों:

/project1/bin/app_typeA/

मैंने$(CURDIR) इस तरह का उपयोग करने की कोशिश की :

OUTPUT_PATH = /project1/bin/$(CURDIR)

लेकिन इसके बजाय मैं इस तरह से पूरे रास्ते के नाम पर दफन किए गए बायनेरिज़ मिला: (अतिरेक नोटिस)

/project1/bin/projects/users/bob/project1/apps/app_typeA

मैं निष्पादन की "वर्तमान निर्देशिका" प्राप्त करने के लिए क्या कर सकता हूं ताकि मैं app_typeXअपने संबंधित प्रकार के फ़ोल्डर में बायनेरिज़ डालने के लिए बस पता कर सकूं?

जवाबों:


271

खोल समारोह।

आप shellफ़ंक्शन का उपयोग कर सकते हैं current_dir = $(shell pwd):। या shellसंयोजन में notdir, यदि आपको पूर्ण पथ की आवश्यकता नहीं है current_dir = $(notdir $(shell pwd)):।

अपडेट करें।

दिए गए समाधान केवल तभी काम करते हैं जब आप makeMakefile की वर्तमान निर्देशिका से चल रहे हों ।
जैसा कि @ नोटम ने उल्लेख किया है:

ध्यान दें कि यह वर्तमान कार्यशील निर्देशिका को लौटाता है, मेकफाइल की मूल निर्देशिका को नहीं।
उदाहरण के लिए, यदि आप चलाते हैं cd /; make -f /home/username/project/Makefile, तो current_dirचर होगा /, नहीं /home/username/project/

नीचे दिया गया कोड किसी भी निर्देशिका से निर्मित मेकफाइल्स के लिए काम करेगा:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))

5
वह काम नहीं करता। यह एक ही समस्या है। pwd पूर्ण पथ के नाम को प्रिंट करता है, मैं सिर्फ उस वास्तविक वर्तमान फ़ोल्डर का नाम चाहता हूं जिसमें मैं हूं।
boltup_im_coding

6
इसके लिए मूल्य का तुरंत विस्तार होना आवश्यक है: = ऑपरेटर का उपयोग किया जाना चाहिए। जैसा कि mkfile_path में: = और current_dir = (अन्यथा राइट साइड वैल्यू का मूल्यांकन बाद में किया जा सकता है जब अन्य Makefiles शामिल किए जाने के बाद MAKEFILE_LIST बदल गया है
टॉम ग्रूनर

10
मुझे पता है कि यह एक पुराना प्रश्न है लेकिन मैं अभी भाग गया और सोचा कि यह उपयोगी हो सकता है। यह भी तब काम नहीं करेगा जब मेकफाइल के सापेक्ष पथ में एक स्थान हो। विशेष रूप से, $(lastword "$(MAKEFILE_LIST)")पथ पर एक मेकफाइल "Sub Directory/Makefile"आपको देगा "Directory/Makefile"। मुझे नहीं लगता है कि वहाँ के बाद से इस के आसपास किसी भी तरह से है $(MAKEFILE_LIST)दो makefiles साथ आप एक ही स्ट्रिंग देता है "Makefile One Makefile Two, जो रिक्त स्थान नहीं संभाल कर सकते हैं
mrosales

2
यह current_dirमेरे लिए काम नहीं करता है। $(PWD)करता है और यह बहुत सरल है।
सीएटीएक्स

3
"solution only works when you are running make from the Makefile's current directory""वास्तव में काम नहीं" कहने का एक हल्का तरीका है। मैं उत्तर के शीर्ष पर नवीनतम टुकड़ा रखूंगा।
विक्टर सर्जेनको

138

जैसा कि यहाँ से लिया गया है ;

ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))

के रूप में दिखाता है;

$ cd /home/user/

$ make -f test/Makefile 
/home/user/test

$ cd test; make Makefile 
/home/user/test

उम्मीद है की यह मदद करेगा


3
IMHO के dirबजाय आंतरिक मेक-फंक्शन का उपयोग करना बेहतर होगा , shell dirnameहालांकि यह अनुगामी /चरित्र के साथ पाथनाम हो जाता है ।
सर्ज रोसक

3
बाहरी उपकरणों पर निर्भरता में कमी के कारण। Ie क्या होगा अगर किसी सिस्टम पर dirname कमांड का उपनाम होगा? ..
सर्ज रोसक

6
यह लगभग मेरे लिए काम करता है, लेकिन डीआईआर में एक प्रमुख व्हाट्सएप था, इसलिए एक मामूली बदलाव ने पूरी तरह से काम किया:DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
थोरस्टन लॉरेंज

9
वर्तमान मेकफाइल को संदर्भित करने के लिए , $MAKEFILE_LISTकिसी भी includeऑपरेशन ( डॉक्स ) से पहले का उपयोग करना होगा ।
नोबार

2
उद्धरण का उपयोग करना चाहिए - कम से कम तर्क के आसपास dirname- अगर मामले में मार्ग में रिक्त स्थान हैं।
नोबार

46

यदि आप GNU मेक, $ (CURDIR) का उपयोग कर रहे हैं, तो वास्तव में एक अंतर्निहित वैरिएबल है। यह वह स्थान है जहाँ मेकफाइल वर्तमान कार्यशील निर्देशिका में रहता है, जो संभवतः मेकफाइल है, लेकिन हमेशा नहीं

OUTPUT_PATH = /project1/bin/$(notdir $(CURDIR))

Http://www.endu.org/software/make/manual/make.html में एक त्वरित संदर्भ देखें


18
जीएनयू मेक मैनुअल (पेज 51) से: "जब जीएनयू मेक शुरू होता है (इसके बाद किसी भी -सी विकल्प को संसाधित किया जाता है) तो यह वेरिएबल CURDIR को वर्तमान वर्किंग डायरेक्टरी के पथनाम पर सेट करता है।" वह स्थान जहां मेकफाइल स्थित है - हालांकि, वे समान हो सकते हैं।
साइमन पेवरेट

4
डाउनवोट किया गया क्योंकि उत्तर तकनीकी रूप से सही नहीं है, जैसा कि पिछली टिप्पणी में साइमन पेवेरेट ने नोट किया था।
सबफ्यूज़न

5
@SimonPeverett: कोष्ठक में अभिव्यक्ति का अर्थ है "वर्तमान कार्यशील निर्देशिका AFTER -C opts"। नाम मात्र $ (CURDIR) "मेक-सी xxx" और "cd मेक" के लिए समान परिणाम देता है। साथ ही यह ट्रेलिंग को हटाता है /। मैंने gmakev3.81 के साथ बंधे की कोशिश की । लेकिन आप सही हैं यदि makeइसे कहा जाता है make -f xxx/Makefile
ट्रू य

CURDIRमेरे लिए काम करता है जहाँ PWDनहीं किया। मैंने mkdir -p a/s/dतब प्रत्येक फोल्डर में एक मेकफाइल रखा था, जो मुद्रित PWDऔर CURDIRपहले था +$(MAKE) <subdir>
मार्क के कोवन

27
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))

12
... जब तक आपके पास किसी भी पथ में स्थान नहीं है।
क्रेग रिंगर

9
... जब तक आपने पिछली पंक्ति में कुछ अन्य
मेकफाइल

1
@ बरबस हां। यही मेरा सामना है। यह बहुत अच्छा काम करता है अगर आपके पास केवल दो मेकफाइल्स (मुख्य एक प्लस एक शामिल है)।
sherrellbc

6

मैंने इनमें से कई उत्तरों की कोशिश की, लेकिन मेरे AIX सिस्टम पर ग्नू 3.80 के साथ मुझे कुछ चीजें पुरानी स्कूल करने की आवश्यकता थी।

यह पता चला है कि lastword, abspathऔर realpath3.81 तक नहीं जोड़े गए थे। :(

mkfile_path := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
mkfile_dir:=$(shell cd $(shell dirname $(mkfile_path)); pwd)
current_dir:=$(notdir $(mkfile_dir))

जैसा कि दूसरों ने कहा है, सबसे सुरुचिपूर्ण नहीं क्योंकि यह एक शेल को दो बार आमंत्रित करता है, और इसमें अभी भी रिक्त स्थान के मुद्दे हैं।

लेकिन जैसा कि मेरे रास्तों में मेरा कोई स्थान नहीं है, यह मेरे लिए काम करता है चाहे मैं कैसे भी शुरू करूँ make:

  • make -f ../wherever/makefile
  • make -C ../verver
  • मेक -C ~ / जहाँ भी
  • cd ../verver; बनाना

सभी मुझे दे whereverके लिए current_dirऔर का निरपेक्ष पथ whereverके लिए mkfile_dir


मैंने, एक के लिए, बिना किसी समस्या के ऐक्स (5-6-7) पर गन्न-मेक 3.82 का संकलन किया है।
ज़िग्समंड लोंसिएज़ी

हां, 3.81 तक पहले के समाधानों के लिए आवश्यक कार्यों को लागू किया गया था। मेरा जवाब 3.80 या उससे पहले के पुराने सिस्टम के लिए है। अफसोस की बात है, काम पर मुझे AIX सिस्टम में टूल जोड़ने या अपग्रेड करने की अनुमति नहीं है। :(
जेसी चिशोल्म

5

मुझे चुना गया उत्तर पसंद है, लेकिन मुझे लगता है कि यह वास्तव में इसे समझाने की तुलना में काम करना अधिक उपयोगी होगा।

/tmp/makefile_path_test.sh

#!/bin/bash -eu

# Create a testing dir
temp_dir=/tmp/makefile_path_test
proj_dir=$temp_dir/dir1/dir2/dir3
mkdir -p $proj_dir

# Create the Makefile in $proj_dir
# (Because of this, $proj_dir is what $(path) should evaluate to.)
cat > $proj_dir/Makefile <<'EOF'
path := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
cwd  := $(shell pwd)

all:
    @echo "MAKEFILE_LIST: $(MAKEFILE_LIST)"
    @echo "         path: $(path)"
    @echo "          cwd: $(cwd)"
    @echo ""
EOF

# See/debug each command
set -x

# Test using the Makefile in the current directory
cd $proj_dir
make

# Test passing a Makefile
cd $temp_dir
make -f $proj_dir/Makefile

# Cleanup
rm -rf $temp_dir

आउटपुट:

+ cd /tmp/makefile_path_test/dir1/dir2/dir3
+ make
MAKEFILE_LIST:  Makefile
         path: /private/tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test/dir1/dir2/dir3

+ cd /tmp/makefile_path_test
+ make -f /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
MAKEFILE_LIST:  /tmp/makefile_path_test/dir1/dir2/dir3/Makefile
         path: /tmp/makefile_path_test/dir1/dir2/dir3
          cwd: /tmp/makefile_path_test

+ rm -rf /tmp/makefile_path_test

नोट: फ़ंक्शन $(patsubst %/,%,[path/goes/here/])का उपयोग ट्रेलिंग स्लैश को स्ट्रिप करने के लिए किया जाता है।


2

Makefileशेल सिंटैक्स का उपयोग करके आपकी फ़ाइल को पूर्ण पथ प्राप्त करने के लिए यहां एक-लाइनर है :

SHELL := /bin/bash
CWD := $(shell cd -P -- '$(shell dirname -- "$0")' && pwd -P)

और यहाँ @ 0xff उत्तर के आधार पर शेल के बिना संस्करण है :

CWD := $(abspath $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST))))))

इसे प्रिंट करके परीक्षण करें, जैसे:

cwd:
        @echo $(CWD)

1
विशिष्ट महत्व! ऊपर दिए गए दूसरे उदाहरण की जरूरत है: = असाइनमेंट ऑपरेटर या फिर कुछ बहुत ही अजीब और गुस्से वाली चीजें जटिल
मेकफाइल्स के

1
पहले एक दोहराया त्रुटि है और आउट-ऑफ-ट्री-बिल्ड के लिए काम नहीं करता है।
जोहान बोले

2

समाधान यहाँ पाया गया: https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/

उपाय है : $ (CURDIR)

आप इसे इस तरह से उपयोग कर सकते हैं:

CUR_DIR = $(CURDIR)

## Start :
start:
    cd $(CUR_DIR)/path_to_folder

3
ढेर अतिप्रवाह में आपका स्वागत है। क्या आप अपने उत्तर में अधिक विवरण जोड़ सकते हैं? प्रश्न में कहा $(CURDIR)गया है कि पहले से ही असफल प्रयास किया गया था।
शॉन

4
चेतावनी, त्वरित-googlers: यह निर्देशिका नहीं है, जहां मेकफाइल है, लेकिन वर्तमान कार्यशील निर्देशिका (जहां makeलॉन्च किया गया था)। यह वास्तव में है, ओपी वास्तव में क्या चाहता था, लेकिन प्रश्न का शीर्षक फर्जी है, इसलिए प्रश्न ही असंगत है। तो, यह एक गलत प्रश्न का सही उत्तर है। ;)
एसजे।

यह गलत है और एक गलत गलत जवाब है
अपेंडम

0

जहाँ तक मुझे पता है यह यहाँ एकमात्र उत्तर है जो रिक्त स्थान के साथ सही ढंग से काम करता है:

space:= 
space+=

CURRENT_PATH := $(subst $(lastword $(notdir $(MAKEFILE_LIST))),,$(subst $(space),\$(space),$(shell realpath '$(strip $(MAKEFILE_LIST))')))

यह अनिवार्य रूप से स्थान पात्रों से बचकर काम करता है ' ', '\ 'जिसके लिए मेक को सही तरीके से पार्स करने की अनुमति देता है, और फिर यह MAKEFILE_LISTएक और प्रतिस्थापन करके मेकफाइल के फ़ाइलनाम को हटा देता है ताकि आप उस निर्देशिका के साथ रह जाएं जो मेकफाइल में नहीं है। सबसे कॉम्पैक्ट नहीं है। दुनिया में काम करता है लेकिन यह काम करता है।

आप कुछ इस तरह से समाप्त करेंगे जहां सभी स्थान बच गए हैं:

$(info CURRENT_PATH = $(CURRENT_PATH))

CURRENT_PATH = /mnt/c/Users/foobar/gDrive/P\ roje\ cts/we\ b/sitecompiler/

-2

आपके संदर्भ के लिए उदाहरण, नीचे के रूप में:

फ़ोल्डर संरचना इस प्रकार हो सकती है:

यहां छवि विवरण दर्ज करें

जहां दो मेकफाइल्स हैं, प्रत्येक नीचे के रूप में;

sample/Makefile
test/Makefile

अब, हम मेकफाइल्स की सामग्री देखते हैं।

नमूना / Makefile

export ROOT_DIR=${PWD}

all:
    echo ${ROOT_DIR}
    $(MAKE) -C test

परीक्षा / Makefile

all:
    echo ${ROOT_DIR}
    echo "make test ends here !"

अब, नमूना / मेकफाइल को निष्पादित करें, जैसा कि;

cd sample
make

उत्पादन:

echo /home/symphony/sample
/home/symphony/sample
make -C test
make[1]: Entering directory `/home/symphony/sample/test'
echo /home/symphony/sample
/home/symphony/sample
echo "make test ends here !"
make test ends here !
make[1]: Leaving directory `/home/symphony/sample/test'

स्पष्टीकरण, यह होगा कि माता-पिता / घर की निर्देशिका को पर्यावरण-ध्वज में संग्रहीत किया जा सकता है, और निर्यात किया जा सकता है, ताकि इसका उपयोग सभी उप-निर्देशिका मेकफाइल्स में किया जा सके।


2
इसे करंट वर्किंग डायरेक्टरी मिलती है, न कि मेकफाइल की होम डायरेक्टरी।
जेसी चिशोल्म

मेकफाइल में ये लाइनें हैं। अब, जैसा कि Makefile कमांड निष्पादित करता है, इससे पथ को वह स्थान मिल जाएगा, जिस पर Makefile है। मैं समझता हूं कि "मेकफाइल होम डाइरेक्टरी" उसी का संदर्भ दे रही है, यानी निर्देशिका-पथ जिसमें मेकफाइल निष्पादित हो रहा है।

@ जेसे चिसोलम कृपया फिर से देखें। मैंने उपयोग के साथ समझाया है।

एक बार-बार त्रुटि: यह आउट-ऑफ-ट्री-बिल्ड के लिए काम नहीं करता है। इसके अलावा, आपका सूक्ति टर्मिनल पाठ की प्रतिलिपि बनाने का एक सरल तरीका प्रदान करता है: बस इसे चुनें। अफवाह है कि Imgur शाखायुक्त है।
जोहान बोले

-2

अपडेट 2018/03/05 फ़ाइनली मैं इसका उपयोग करता हूं:


shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

यह सापेक्ष पथ या पूर्ण पथ में सही निष्पादित किया जा सकता है। क्रेस्टैब द्वारा लगाए गए सही सही। अन्य शेल में निष्पादित सही।

उदाहरण दिखाएं, a.sh प्रिंट सेल्फ पाथ।

[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/test/a.sh
shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

echo $shellPath
[root@izbp1a7wyzv7b5hitowq2yz /]# more /root/b.sh
shellPath=`echo $PWD/``echo ${0%/*}`

# process absolute path
shellPath1=`echo $PWD/`
shellPath2=`echo ${0%/*}`
if [ ${shellPath2:0:1} == '/' ] ; then
    shellPath=${shellPath2}
fi

$shellPath/test/a.sh
[root@izbp1a7wyzv7b5hitowq2yz /]# ~/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/b.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# cd ~
[root@izbp1a7wyzv7b5hitowq2yz ~]# ./b.sh
/root/./test
[root@izbp1a7wyzv7b5hitowq2yz ~]# test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz ~]# cd test
[root@izbp1a7wyzv7b5hitowq2yz test]# ./a.sh
/root/test/.
[root@izbp1a7wyzv7b5hitowq2yz test]# cd /
[root@izbp1a7wyzv7b5hitowq2yz /]# /root/test/a.sh
/root/test
[root@izbp1a7wyzv7b5hitowq2yz /]# 

पुराना: मैं इसका उपयोग करता हूं:

MAKEFILE_PATH := $(PWD)/$({0%/*})

अन्य शेल और अन्य निर्देशिका में निष्पादित होने पर यह सही दिखा सकता है।


1
"अगर अन्य शेल और अन्य निर्देशिका को निष्पादित किया जाता है तो यह सही दिखा सकता है" अंग्रेजी में समझ में नहीं आता है। क्या आप फिर से समझाने की कोशिश कर सकते हैं?
कीथ एम

मेरे गरीब अंग्रेजी के लिए खेद है
zhukunqian

संपादन के लिए धन्यवाद, मैं देख रहा हूँ कि आप अभी मतलब है। क्या आप बता सकते हैं कि इससे पहले कि मैं इसे आज़माता हूँ क्या करता है? मुझे यकीन नहीं है कि इसका उपयोग कैसे करना है। जैसे "अन्य खोल" से आपका क्या मतलब है
कीथ एम

1
इस उत्तर में बहुत सारी गलत चीजें हैं जो संभवतः तय नहीं की जा सकती हैं। मैं एक सरल हटाने का सुझाव देता हूं।
जोहान बोले

-2

Makefile में एक पंक्ति पर्याप्त होनी चाहिए:

DIR := $(notdir $(CURDIR))

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