Makefile'nizin şu anki göreli dizinini nasıl edinebilirsiniz?


203

Bunun gibi app belirli dizinlerde birkaç Makefiles var:

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

Her Makefile bir üst düzey bu yolda bir .inc dosyası içerir:

/project1/apps/app_rules.inc

İçinde app_rules.inc İkili dosyaları inşa ederken yerleştirilmesini istediğim yeri belirliyorum. Tüm ikili dosyaların kendi app_typeyollarında olmasını istiyorum :

/project1/bin/app_typeA/

Kullanmayı denedim$(CURDIR) , şöyle:

OUTPUT_PATH = /project1/bin/$(CURDIR)

ancak bunun yerine tüm yol adına gömülü ikili dosyaları aldım: (artıklığa dikkat edin)

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

app_typeXİkili kodları ilgili tipler klasörüne koymak için sadece "geçerli dizin" i almak için ne yapabilirim ?

Yanıtlar:


273

Kabuk işlevi.

Sen kullanabilirsiniz shellişlevi: current_dir = $(shell pwd). Veya shellbirlikte notdir, eğer mutlak yol gerekmez: current_dir = $(notdir $(shell pwd)).

Güncelleme.

Verilen çözüm yalnızca makeMakefile'in geçerli dizininden çalıştırdığınızda çalışır .
@Flimm'in belirttiği gibi:

Bunun Makefile öğesinin üst dizinini değil, geçerli çalışma dizinini döndürdüğünü unutmayın.
Örneğin, çalıştırırsanız cd /; make -f /home/username/project/Makefile, current_dirdeğişken /olmaz /home/username/project/.

Aşağıdaki kod, herhangi bir dizinden çağrılan Makefiles için çalışacaktır:

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

5
Bu çalışmıyor. Aynı sorun. pwd tam yol adını yazdırır, sadece içinde bulunduğum gerçek klasörün adını istiyorum.
boltup_im_coding

6
Değerin hemen genişletilmesi gerekir, bu nedenle: = operatörü kullanılmalıdır. Mkfile_path: = ve current_dir = 'de olduğu gibi (aksi takdirde sağ taraf değerleri MAKEFILE_LIST değiştikten sonra diğer Makefiles'ler eklendikten sonra değerlendirilebilir
Tom Gruner

10
Bunun eski bir soru olduğunu biliyorum ama bununla karşılaştım ve bunun yararlı olabileceğini düşündüm. Bu, marka dosyasının göreli yolunda bir boşluk olduğunda da çalışmaz. Özellikle, $(lastword "$(MAKEFILE_LIST)")yoldaki bir makefile "Sub Directory/Makefile"size verecektir "Directory/Makefile". Ben $(MAKEFILE_LIST)iki makefiles ile size "Makefile One Makefile Twoboşluk işleyemez tek bir dize verir, çünkü bu konuda herhangi bir yolu olduğunu sanmıyorum
mrosales

2
Bu current_dirbenim için işe yaramıyor. $(PWD)ve çok daha basit.
CaTx

3
"solution only works when you are running make from the Makefile's current directory""gerçekten çalışmıyor" demenin hafif bir yoludur. En son parçayı cevabın üstüne koyardım.
Victor Sergienko

138

Buradan alındığı gibi ;

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

Olarak görünür;

$ cd /home/user/

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

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

Bu yardımcı olur umarım


3
IMHO iç makyaj işlevini kullanmak daha iyi olacaktır diryerine shell dirnamesondaki ile yol adı alır gerçi /karakter.
Serge Roussak

3
dış aletlerdeki bağımlılıkların azalması nedeniyle. Yani bazı sistemlerde dirname komutunun takma adı olacak mı? ..
Serge Roussak

6
Bu neredeyse benim için çalıştı, ancak DIR önde gelen bir boşluğa sahipti, bu yüzden küçük bir değişiklik mükemmel çalıştı:DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
Thorsten Lorenz

9
Başvurmak için geçerli makefile, kullanımı $MAKEFILE_LISTzorunluluk herhangi önce includeişlemleri ( dokümanlar ).
Brent Bradburn

2
Yolda dirnameboşluk olması durumunda - en azından argüman etrafında - tırnak işaretleri kullanılmalıdır .
Brent Bradburn

46

GNU make kullanıyorsanız, $ (CURDIR) aslında yerleşik bir değişkendir. Öyle Makefile bulunduğu konum her zaman olmasa da Makefile nerede muhtemelen Geçerli çalışma dizini .

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

Http://www.gnu.org/software/make/manual/make.html adresindeki Ek Hızlı Referans'a bakın.


18
GNU Make manual'dan (sayfa 51): "GNU make başladığında (herhangi bir -C seçeneğini işledikten sonra) CURDIR değişkenini geçerli çalışma dizininin yol adına ayarlar." Makefile'nin bulunduğu yer değil - aynı olsalar da.
Simon Peverett

4
Önceki yorumda Simon Peverett tarafından belirtildiği gibi cevap teknik olarak doğru olmadığı için indirildi.
Subfuzion

5
@SimonPeverett: Köşeli parantez içindeki ifade "" AFTER -C opts uygulandı "geçerli çalışma dizini" anlamına gelir. Yani $ (CURDIR) "make -C xxx" ve "cd xxx; make" için aynı sonuçları verir. Ayrıca izleri kaldırır /. gmakeV3.81 ile bağlı denedim . Ama haklı makeolarak adlandırılırsanız haklısınız make -f xxx/Makefile.
TrueY

CURDIRPWDdeğil benim için çalışıyor . Yaptığım mkdir -p a/s/dher klasörde basılmış bir makefile vardı sonra PWDve CURDIRönce +$(MAKE) <subdir>.
Mark K Cowan

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

12
... yollarda boşluk yoksa.
Craig Ringer

9
... önceki satıra başka bir makefile
eklemediyseniz

1
@robal Yep. Ben de yeni karşılaştım. Bu sadece iki Makefiles (ana bir artı bir dahil) varsa harika çalışıyor .
sherrellbc

Bu benim için iyi çalışıyor (dir alanlarda boşluk test etmedim, ancak bununla karşılaşmayı beklemiyorum). Bu kod ile vardı ana sorun $(dir)son yol ayırıcı koruyor olmasıdır. $(realpath)Bu sorunu çözmeden önce eklemek .
Guss

6

Bu cevapların çoğunu denedim, ancak gnu make A80 sistemimde 3.80 eski okuldan bazı şeyler yapmam gerekiyordu.

Çıkıyor lastword, abspathve realpath3.81 kadar eklenmedi. :(

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

Diğerlerinin söylediği gibi, iki kez bir kabuk çağırdığı için en zarif değil ve hala uzay sorunları var.

Ama yollarımda hiç boşluk olmadığından, nasıl başladığımdan bağımsız olarak benim için çalışıyor make:

  • -f ../wherever/makefile yap
  • -C ../her yerde yap
  • -C ~ / yapın
  • cd ../her yerde; Yapmak

Tüm bana vermek whereveriçin current_dirve mutlak yol whereveriçin mkfile_dir.


Ben, bir tanesi için, aix (5-6-7) üzerinde gnu-make-3.82'yi sorunsuz derledim.
Zsigmond Lőrinczy

Evet, 3.81'e kadar önceki çözümler için gerekli fonksiyonlar uygulandı. Cevabım 3.80 veya daha eski sistemlere yönelik. Ne yazık ki, işyerinde AIX sistemine araç eklememe veya yükseltme işlemine izin verilmiyor. :(
Jesse Chisholm

5

Seçilen cevabı beğendim, ama aslında çalıştığını göstermenin açıklamaktan daha yararlı olacağını düşünüyorum.

/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

Çıktı:

+ 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

NOT: Bu fonksiyon $(patsubst %/,%,[path/goes/here/]), sondaki eğik çizgiyi çıkarmak için kullanılır.


3

Burada bulunan çözüm: https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/

Çözüm : $ (CURDIR)

Bu şekilde kullanabilirsiniz:

CUR_DIR = $(CURDIR)

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

3
Stack Overflow'a hoş geldiniz. Cevabınıza daha fazla ayrıntı ekleyebilir misiniz? Soru $(CURDIR), zaten başarısız bir şekilde denendiğini belirtir .
Sean

4
, Çabuk Google'cılara UYARI: Bu değil makefile olan dizin, ancak mevcut çalışma dizini (burada makebaşlatıldı). Gerçekten OP'nin gerçekten istediği şey, ama soru başlığı sahte, bu yüzden sorunun kendisi tutarsız. Yani, bu yanlış bir soruya doğru bir cevaptır. ;)
Sz.

Bu düz dışarı yanlış ve gereksiz bir yanlış cevap
UpAndAdam

2

MakefileKabuk sözdizimini kullanarak dosyanızın mutlak yolunu elde etmek için bir astar :

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

Ve @ 0xff cevabına dayanan kabuksuz versiyon :

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

Aşağıdaki gibi yazdırarak test edin:

cwd:
        @echo $(CWD)

1
Kritik önem! Yukarıdaki ikinci örnek: = atama operatörüne ihtiyaç duyar, aksi takdirde karmaşık makefiles'lerde çok garip ve öfkeli şeyler olabilir (bana güven)
EMon

1
Birincisi tekrarlanan bir hatadır ve ağaç dışı yapılarda çalışmaz.
Johan Boulé

0

Bildiğim kadarıyla burada boşluklarla doğru çalışan tek cevap bu:

space:= 
space+=

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

Esas olarak ' ', '\ 'doğru karakterleri ayrıştırmaya izin veren Make yerine boşluk karakterlerinden kaçarak çalışır ve daha sonra makefile'ın MAKEFILE_LISTbulunduğu dizinde kalmanız için başka bir ikame yaparak makefile'ın dosya adını kaldırır . dünyada bir şey ama işe yarıyor.

Tüm boşluklardan kaçan böyle bir şeyle sonuçlanacaksınız:

$(info CURRENT_PATH = $(CURRENT_PATH))

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

-2

Referans için örnek, aşağıdaki gibi:

Klasör yapısı şöyle olabilir:

resim açıklamasını buraya girin

Her biri aşağıdaki gibi iki Makefile olduğunda;

sample/Makefile
test/Makefile

Şimdi Makefiles'in içeriğini görelim.

örnek / Makefile'ında

export ROOT_DIR=${PWD}

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

Test / Makefile'ında

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

Şimdi, / Makefile örneğini şu şekilde yürütün;

cd sample
make

ÇIKTI:

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'

Açıklama, üst / giriş dizininin ortam bayrağında depolanabilmesi ve dışa aktarılabilmesi, böylece tüm alt dizin marka dosyalarında kullanılabilmesidir.


2
Bu, makefile'ın ana dizinini değil, geçerli çalışma dizinini alır.
Jesse Chisholm

Bunlar Makefile'deki çizgiler. Şimdi, Makefile komutu yürütülürken, bu Makefile'nin bulunduğu yolu alacaktır. Anlamak "makefile ana dizini" aynı, yani Makefile yürütme dizin yolu anlamına geliyor.
parasrish

@Jesse Chisholm lütfen tekrar ziyaret edin. Kullanımla açıkladım.
paraşüt

Tekrarlanan bir hata: Ağaç dışı yapılarda çalışmaz. Ayrıca, gnome terminaliniz metni kopyalamak için basit bir yol sağlar: sadece seçin. Söylentiye göre Imgur Brankrupt.
Johan Boulé

-2

güncelleme 2018/03/05 finnaly Bunu kullan:


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

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

Göreli yolda veya mutlak yolda doğru yürütülebilir. Crontab tarafından çağrılan doğru yürütüldü. Diğer kabukta doğru yürütüldü.

örnek göster, a.sh yazdırma öz yolu.

[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 /]# 

eski: Bunu kullanıyorum:

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

Diğer kabukta ve diğer dizinde yürütüldüğünde doğru gösterilebilir.


1
"Diğer kabuk ve diğer dizinler yürütüldüğünde doğru gösteriliyor" İngilizce anlam ifade etmiyor. Tekrar açıklamayı deneyebilir misin?
Keith M

benim fakir ingilizce için üzgünüm
zhukunqian

Düzenleme için teşekkürler, şimdi demek istediğini anlıyorum. Bunu denemeden önce ne yaptığını açıklayabilir misiniz? Nasıl kullanılacağından emin değilim. "Diğer deniz
Keith M

1
Bu cevabın düzeltilemeyecek kadar çok yanlış yanı var. Basit bir kaldırmayı öneririm.
Johan Boulé

-2

Makefile'deki bir satır yeterli olmalıdır:

DIR := $(notdir $(CURDIR))

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.