2010-07-27 16 views
6

मेरे प्रश्न को स्पष्ट करने के लिए एक उदाहरण:एक मेकफ़ाइल में, रिश्तेदार पथ को एक पूर्ण पथ से दूसरे तक कैसे प्राप्त करें?

शीर्ष स्तर मेकफ़ाइल

rootdir = $(realpath .) 
export includedir = $(rootdir)/include 
default: 
    @$(MAKE) --directory=$(rootdir)/src/libs/libfoo 

src/libfoo

currentdir = $(realpath .) 
includedir = $(function or magic to make a relative path 
       from $(currentdir) to $(includedir), 
       which in this example would be ../../../include) 

currentdir = $(realpath .) 
includedir = $(function or magic to make a relative path 
       from $(currentdir) to $(includedir), 
       which in this example would be ../../../include) 

के लिए मेकफ़ाइल एक और उदाहरण:

current dir = /home/username/projects/app/trunk/src/libs/libfoo/ 
destination = /home/username/projects/app/build/libfoo/ 
relative = ../../../../build/libfoo 

यह कैसे किया जा सकता है, यथासंभव पोर्टेबल होने की कोशिश करते समय?

उत्तर

6

जो भी आप चाहते हैं वह करना आसान नहीं दिखता है। मेकफ़ाइल में बहुत सारे $(if का उपयोग करके संभव हो सकता है लेकिन पोर्टेबल नहीं (केवल gmake) और बोझिल।

आईएमएचओ, आप अपनी समस्या को हल करने की कोशिश कर रहे हैं। आप शीर्ष स्तर के मेकफ़ाइल से includedir का सापेक्ष पथ क्यों नहीं भेजते हैं?

rootdir = $(realpath .) 
default: 
    @$(MAKE) --directory=$(rootdir)/src/libs/libfoo includedir=../../../include 

तो फिर तुम सब-makefiles में $(includedir) उपयोग कर सकते हैं: यह बहुत आसानी से इस प्रकार किया जा सकता है। यह पहले ही रिश्तेदार के रूप में परिभाषित किया गया है।

+0

इस मेटा-जवाब सबसे अच्छा एक है:

यहाँ एक उदाहरण है! ध्यान दें कि '- निर्देशिका' पोर्टेबल नहीं है: 'cd $ (rootdir)/src/libs/libfoo; $ (मेक) ... 'अधिक विश्वसनीय होगा। –

+1

@ नॉर्मन ग्रे: '$ (मेक) -सी ... के साथ क्या गलत है? – Beta

+0

मुझे नहीं लगता कि मैं _wrong_ तक जाऊंगा, लेकिन सभी 'मेक' कमांड इसका समर्थन नहीं करते हैं (और यह [posix] में नहीं है (http://www.opengroup.org/onlinepubs/009695399/utilities/make .html), उदाहरण के लिए), इसलिए यदि यह मेकफ़ाइल वितरण के लिए है, तो यह समस्याएं पैदा कर सकता है। किसी भी मामले में, मुझे लगता है कि 'सीडी फू; $ (मेक) ... 'इरादे को और स्पष्ट रूप से व्यक्त करता है। –

4

पायथन पोर्टेबल है! तो, मैं आप अपने submakefile

current_dir और destination_dir रास्तों os.path.relpath() आप के लिए काम करता है के साथ इस सरल उदाहरण सुझाव है तो आप पहिया फिर से आविष्कार करने की जरूरत नहीं है जाएगा।

submakefile.mk

current_dir=$(CURDIR) 
makefile_target: 
    (echo "import os"; echo "print os.path.relpath('$(destination_dir)', '$(current_dir)')")| python 
+2

पहला: महान समाधान! मुझे पायथन की भयानक ओएस लाइब्रेरी का उपयोग करना याद रखना होगा .... दूसरा: आपने os.path.relpath() के तर्कों को स्विच किया है। यह होना चाहिए: os.path.relpath ('$ (destination_dir)', '$ (current_dir)') – jvriesem

+0

मैंने एक पायथन स्क्रिप्ट लिखी है जो 1-2 पैरामीटर और प्रिंट परिणाम लेती है। फिर इसे $ $ (खोल पायथन relpath.py $ (destination_dir)) द्वारा कॉल करें। कमाल की नोक! –

2

डिडिएर के जवाब सबसे अच्छा एक है, लेकिन निम्न आप कुछ विचार दे सकता है:

includedir=/a/b/c/d 
currentdir=/a/b/e/f/g 
up=; while ! expr $includedir : $currentdir >/dev/null; do up=../$up; currentdir=`dirname $currentdir`; done; relative=$up`expr $includedir : $currentdir'/*\(.*\)'` 
echo "up=$up currentdir=$currentdir, relative=$relative" 

छाँटे गए!

(कोई ने कहा कि यह बहुत होने के लिए ... था)

1

यहाँ एक समाधान है कि केवल का उपयोग करता है जीएनयू कार्यों बनाते हैं। भले ही यह पुनरावर्ती है, यह बाहरी कार्यक्रम को कॉल करने से अधिक कुशल होना चाहिए। विचार बहुत सीधे आगे है: सापेक्ष पथ शून्य या अधिक होगा .. सबसे आम पूर्वजों तक जाने के लिए, फिर दूसरी निर्देशिका में जाने के लिए एक प्रत्यय। कठिन हिस्सा दोनों पथों में सबसे लंबा आम उपसर्ग ढूंढ रहा है।

# DOES not work if path has spaces 
OneDirectoryUp=$(patsubst %/$(lastword $(subst /, ,$(1))),%,$(1)) 

# FindParentDir2(dir0, dir1, prefix) returns prefix if dir0 and dir1 
# start with prefix, otherwise returns 
# FindParentDir2(dir0, dir1, OneDirectoryUp(prefix)) 
FindParentDir2= 
$(if 
    $(or 
    $(patsubst $(3)/%,,$(1)), 
    $(patsubst $(3)/%,,$(2)) 
    ), 
    $(call FindParentDir2,$(1),$(2),$(call OneDirectoryUp,$(3))), 
    $(3) 
) 

FindParentDir=$(call FindParentDir2,$(1),$(2),$(1)) 

# how to make a variable with a space, courtesy of John Graham-Cumming 
# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html 
space:= 
space+= 

# dir1 relative to dir2 (dir1 and dir2 must be absolute paths) 
RelativePath=$(subst 
       $(space), 
       , 
       $(patsubst 
       %, 
       ../, 
       $(subst 
        /, 
        , 
        $(patsubst 
        $(call FindParentDir,$(1),$(2))/%, 
        %, 
        $(2) 
        ) 
       ) 
       ) 
      ) 
      $(patsubst 
       $(call FindParentDir,$(1),$(2))/%, 
       %, 
       $(1) 
      ) 

# example of how to use (will give ..) 
$(call RelativePath,/home/yale,/home/yale/workspace) 

मैं हाल ही में एक पूरी परियोजना में पुनरावर्ती makefiles के एक बड़े सेट अनुवाद के रूप में यह अच्छी तरह से जाना जाता है पुनरावर्ती मेकअप की वजह से पूरे निर्भरता ग्राफ (http://aegis.sourceforge.net/auug97.pdf) को उजागर नहीं करने के लिए बुरा है कि सुनिश्चित करें। सभी स्रोत कोड और लाइब्रेरी पथ वर्तमान मेकफ़ाइल निर्देशिका के सापेक्ष परिभाषित किए गए हैं। जेनेरिक% बिल्ड नियमों की एक निश्चित संख्या को परिभाषित करने के बजाय, मैं प्रत्येक (स्रोत कोड निर्देशिका, आउटपुट निर्देशिका) जोड़ी के लिए नियमों का एक सेट बना देता हूं, जो vpath का उपयोग करने की अस्पष्टता से बचाता है। निर्माण नियम बनाते समय, मुझे प्रत्येक स्रोत कोड निर्देशिका के लिए एक कैननिकल पथ की आवश्यकता होती है। यद्यपि पूर्ण पथ का उपयोग किया जा सकता है, यह आमतौर पर बहुत लंबा और कम पोर्टेबल होता है (मैं सिग्विन जीएनयू का उपयोग करने के लिए हुआ जहां पूर्ण पथों में एक/साइग्राइड उपसर्ग है और विंडोज प्रोग्राम द्वारा मान्यता प्राप्त नहीं है)।इसलिए, मैं इस कार्य का उपयोग कैनोलिक पथ उत्पन्न करने के लिए भारी रूप से करता हूं।

4

खोल इस सुविधा realpath (1) और --relative करने ध्वज का उपयोग, इसलिए आप बस खोल आह्वान सकता है।

यहाँ एक उदाहरण है:

RELATIVE_FILE1_FILE2:=$(shell realpath --relative-to $(FILE1) $(FILE2))

तुम भी realpath (1) के बाद से यह जानता है कि कैसे कई फ़ाइल नाम पर कार्रवाई करने के में से एक मंगलाचरण के साथ फ़ाइलों की एक पूरी सूची पर कार्रवाई कर सकते हैं। - समस्या से बचने के

RELATIVES:=$(shell realpath --relative-to $(RELATIVE) $(FILES))
+0

रीयलपाथ मेरे खोल में मौजूद नहीं है। (बीएसडी) मुझे नहीं लगता कि यह सिग्विन के तहत मौजूद है, या तो। – dbn

+1

रीयलपाथ (1) जीएनयू कोर्यूटिल्स का एक हिस्सा है, इसलिए यह लिनक्स पर मानक है। –

संबंधित मुद्दे