Wie erhalte ich das aktuelle relative Verzeichnis Ihres Makefiles?

202

Ich habe mehrere Makefiles in app-spezifischen Verzeichnissen wie diesem:

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

Jedes Makefile enthält eine .inc-Datei in diesem Pfad eine Ebene höher:

/project1/apps/app_rules.inc

In app_rules.inc lege ich das Ziel fest, an dem die Binärdateien beim Erstellen platziert werden sollen. Ich möchte, dass sich alle Binärdateien auf ihrem jeweiligen app_typePfad befinden:

/project1/bin/app_typeA/

Ich habe versucht$(CURDIR) , wie folgt zu verwenden:

OUTPUT_PATH = /project1/bin/$(CURDIR)

Stattdessen habe ich die Binärdateien wie folgt im gesamten Pfadnamen vergraben: (Beachten Sie die Redundanz)

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

Was kann ich tun, um das "aktuelle Verzeichnis" der Ausführung abzurufen, damit ich nur das wissen kann, app_typeXum die Binärdateien in ihrem jeweiligen Typordner abzulegen?

Boltup_im_Coding
quelle

Antworten:

271

Die Shell-Funktion.

Sie können die shellFunktion verwenden : current_dir = $(shell pwd). Oder shellin Kombination mit notdir, wenn Sie keinen absoluten Pfad benötigen : current_dir = $(notdir $(shell pwd)).

Aktualisieren.

Die angegebene Lösung funktioniert nur, wenn Sie makeaus dem aktuellen Verzeichnis des Makefiles ausgeführt werden.
Wie @Flimm feststellte:

Beachten Sie, dass dies das aktuelle Arbeitsverzeichnis zurückgibt, nicht das übergeordnete Verzeichnis des Makefiles.
Wenn Sie beispielsweise ausführen cd /; make -f /home/username/project/Makefile, ist die current_dirVariable /nicht /home/username/project/.

Der folgende Code funktioniert für Makefiles, die aus einem beliebigen Verzeichnis aufgerufen werden:

mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
Nikolai Popov
quelle
5
Das funktioniert nicht. Es ist das gleiche Problem. pwd druckt den vollständigen Pfadnamen, ich möchte nur den Namen des aktuellen Ordners, in dem ich mich
befinde
6
Der Wert muss sofort erweitert werden, damit der Operator: = verwendet werden kann. Wie in mkfile_path: = und current_dir = (andernfalls könnten die Werte auf der rechten Seite später ausgewertet werden, wenn sich die MAKEFILE_LIST geändert hat, nachdem andere Makefiles aufgenommen wurden
Tom Gruner
10
Ich weiß, dass dies eine alte Frage ist, aber ich bin gerade darauf gestoßen und dachte, dass dies nützlich sein könnte. Dies funktioniert auch nicht, wenn im relativen Pfad des Makefiles ein Leerzeichen vorhanden ist. Insbesondere $(lastword "$(MAKEFILE_LIST)")von einem Makefile am Pfad erhalten "Sub Directory/Makefile"Sie "Directory/Makefile". Ich glaube nicht, dass es einen Ausweg gibt, da Sie $(MAKEFILE_LIST)mit zwei Makefiles eine einzige Zeichenfolge erhalten "Makefile One Makefile Two, die keine Leerzeichen verarbeiten kann
mrosales
2
Das current_dirfunktioniert bei mir nicht. $(PWD)tut und es ist viel einfacher.
CaTx
3
"solution only works when you are running make from the Makefile's current directory"ist eine milde Art zu sagen "nicht wirklich funktioniert". Ich würde das neueste Stück ganz oben auf die Antwort setzen.
Victor Sergienko
137

Wie von hier genommen ;

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

Erscheint als;

$ cd /home/user/

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

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

Hoffe das hilft

schläfrig
quelle
3
IMHO , es wäre eine bessere interne Make-Funktion zu verwenden , dirstatt , shell dirnameobwohl es Pfadname bekommt mit Hinter /Charakter.
Serge Roussak
3
wegen der Verringerung der Abhängigkeit von externen Werkzeugen. Dh was ist, wenn es auf einem System einen Alias ​​des Befehls dirname gibt? ..
Serge Roussak
6
Das hat fast für mich funktioniert, aber DIR hatte ein führendes Leerzeichen, so dass eine kleine Änderung die Arbeit perfekt machte:DIR:=$(strip $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))))
Thorsten Lorenz
9
Um auf das aktuelle Makefile zu verweisen , muss die Verwendung von $MAKEFILE_LISTvor allen includeVorgängen ( Dokumenten ) stehen.
Nobar
2
Sollte Anführungszeichen verwenden - zumindest um das Argument herum dirname-, falls der Pfad Leerzeichen enthält.
Nobar
46

Wenn Sie GNU make verwenden, ist $ (CURDIR) tatsächlich eine integrierte Variable. Dies ist der Speicherort, an dem sich das Makefile im aktuellen Arbeitsverzeichnis befindet. Dort befindet sich wahrscheinlich das Makefile, aber nicht immer .

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

Siehe Anhang A Kurzreferenz unter http://www.gnu.org/software/make/manual/make.html

Tzunghsing David Wong
quelle
18
Aus dem GNU Make-Handbuch (Seite 51): "Wenn GNU make startet (nachdem es alle -C-Optionen verarbeitet hat), setzt es die Variable CURDIR auf den Pfadnamen des aktuellen Arbeitsverzeichnisses." Nicht der Ort, an dem sich das Makefile befindet - obwohl sie möglicherweise identisch sind.
Simon Peverett
4
Abgestimmt, weil die Antwort technisch nicht korrekt ist, wie von Simon Peverett im vorherigen Kommentar festgestellt.
Subfuzion
5
@SimonPeverett: Der Ausdruck in Klammern bedeutet das "aktuelle Arbeitsverzeichnis NACH -C wählt angewendet". $ (CURDIR) liefert nämlich genau die gleichen Ergebnisse für "make -C xxx" und "cd xxx; make". Außerdem wird das Nachlaufen entfernt /. Ich habe versucht, mit gmakev3.81 gebunden . Aber Sie haben Recht, wenn makees heißt make -f xxx/Makefile.
TrueY
CURDIRarbeitet für mich wo PWDnicht. Ich hatte mkdir -p a/s/ddann in jedem Ordner ein Makefile, das gedruckt wurde PWDund CURDIRvorher +$(MAKE) <subdir>.
Mark K Cowan
27
THIS_DIR := $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
Momo
quelle
12
... es sei denn, Sie haben Leerzeichen in Pfaden.
Craig Ringer
9
... es sei denn, Sie haben ein anderes Makefile in die vorherige Zeile aufgenommen
Robal
1
@robal Ja. Das ist mir gerade begegnet. Dies funktioniert hervorragend, wenn Sie nur zwei Makefiles haben (das Haupt-Plus plus ein enthaltenes).
Sherellbc
6

Ich habe viele dieser Antworten ausprobiert, aber auf meinem AIX-System mit gnu make 3.80 musste ich einige Dinge der alten Schule erledigen.

Stellt sich heraus , dass lastword, abspathund realpathwurden bis 3,81 hinzugefügt. :((

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

Wie andere gesagt haben, nicht das eleganteste, da es eine Shell zweimal aufruft, und es hat immer noch die Platzprobleme.

Da ich jedoch keine Leerzeichen auf meinen Pfaden habe, funktioniert dies für mich unabhängig davon, wie ich angefangen habe make:

  • make -f ../wherever/makefile
  • mache -C ../wie auch immer
  • mache -C ~ / wo auch immer
  • cd ../wie auch immer; machen

Alle geben mir whereverfür current_dirund den absoluten Weg zu whereverfür mkfile_dir.

Jesse Chisholm
quelle
Zum einen habe ich gnu-make-3.82 auf aix (5-6-7) ohne Probleme kompiliert.
Zsigmond Lőrinczy
Ja, bis 3.81 wurden die erforderlichen Funktionen für die früheren Lösungen implementiert. Meine Antwort ist für ältere Systeme mit 3.80 oder früher. Leider darf ich bei der Arbeit keine Tools zum AIX-System hinzufügen oder aktualisieren. :(
Jesse Chisholm
5

Ich mag die gewählte Antwort, aber ich denke, es wäre hilfreicher, sie tatsächlich als funktionierend zu zeigen, als sie zu erklären.

/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

Ausgabe:

+ 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

HINWEIS: Mit dieser Funktion $(patsubst %/,%,[path/goes/here/])wird der nachgestellte Schrägstrich entfernt.

Bruno Bronosky
quelle
2

Hier ist ein Einzeiler, um Makefilemithilfe der Shell-Syntax den absoluten Pfad zu Ihrer Datei zu erhalten :

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

Und hier ist eine Version ohne Shell basierend auf @ 0xff Antwort :

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

Testen Sie es, indem Sie es ausdrucken, wie:

cwd:
        @echo $(CWD)
Kenorb
quelle
1
Kritische Wichtigkeit! Das zweite Beispiel oben benötigt den: = Zuweisungsoperator oder einige sehr seltsame und wütende Dinge können mit komplexen Makefiles passieren (vertrau mir)
EMon
1
Der erste ist ein wiederholter Fehler und funktioniert nicht für Builds außerhalb des Baums.
Johan Boulé
2

Hier gefundene Lösung: https://sourceforge.net/p/ipt-netflow/bugs-requests-patches/53/

Die Lösung ist : $ (CURDIR)

Sie können es so verwenden:

CUR_DIR = $(CURDIR)

## Start :
start:
    cd $(CUR_DIR)/path_to_folder
Soma Bini
quelle
3
Willkommen bei Stack Overflow. Können Sie Ihrer Antwort weitere Details hinzufügen? Die Frage besagt, dass $(CURDIR)bereits erfolglos versucht wurde.
Sean
4
WARNUNG, Quick-Googler: Dies ist nicht das Verzeichnis, in dem sich das Makefile befindet, sondern das aktuelle Arbeitsverzeichnis (in dem makees gestartet wurde). Es ist in der Tat das, was OP wirklich wollte, aber der Titel der Frage ist falsch, so dass die Frage selbst inkonsistent ist. Dies ist also eine richtige Antwort auf eine falsche Frage. ;)
Gr.
Dies ist
absolut
0

Soweit mir bekannt ist, ist dies hier die einzige Antwort, die mit Leerzeichen richtig funktioniert:

space:= 
space+=

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

Es funktioniert im Wesentlichen durch Leerzeichen entweicht durch Substitution ' 'für '\ 'welche Marke ermöglicht es richtig zu analysieren, und dann entfernt er die Dateinamen der Make - Datei inMAKEFILE_LIST einem anderen Substitution zu tun , so dass Sie mit dem Verzeichnis links sind , dass Make - Datei ist in . Nicht gerade die kompakteste Sache in der Welt, aber es funktioniert.

Sie werden mit so etwas enden, wo alle Leerzeichen maskiert werden:

$(info CURRENT_PATH = $(CURRENT_PATH))

CURRENT_PATH = /mnt/c/Users/foobar/gDrive/P\ roje\ cts/we\ b/sitecompiler/
Peter Frost
quelle
-2

Beispiel für Ihre Referenz wie folgt:

Die Ordnerstruktur könnte wie folgt sein:

Geben Sie hier die Bildbeschreibung ein

Wo es zwei Makefiles gibt, jeweils wie unten;

sample/Makefile
test/Makefile

Lassen Sie uns nun den Inhalt der Makefiles sehen.

Beispiel / Makefile

export ROOT_DIR=${PWD}

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

Test / Makefile

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

Führen Sie nun das Beispiel / Makefile aus als;

cd sample
make

AUSGABE:

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'

Erläuterung: Das übergeordnete / Home-Verzeichnis kann im Umgebungsflag gespeichert und exportiert werden, sodass es in allen Makefiles des Unterverzeichnisses verwendet werden kann.

Parasrish
quelle
2
Dadurch wird das aktuelle Arbeitsverzeichnis abgerufen, nicht das Ausgangsverzeichnis des Makefiles.
Jesse Chisholm
Dies sind die Zeilen im Makefile. Wenn der Makefile-Befehl ausgeführt wird, wird der Pfad abgerufen, unter dem sich das Makefile befindet. Ich verstehe, dass "makefile home directory" sich auf dasselbe bezieht, dh auf den Verzeichnispfad, in dem Makefile ausgeführt wird.
Parasrish
@ Jesse Chisholm bitte noch einmal besuchen. Ich habe mit Gebrauch erklärt.
Parasrish
Ein wiederholter Fehler: Es funktioniert nicht für Out-of-Tree-Builds. Außerdem bietet Ihr Gnome-Terminal eine einfache Möglichkeit, Text zu kopieren: Wählen Sie ihn einfach aus. Das Gerücht besagt, dass Imgur brankrupt ist.
Johan Boulé
-2

update 2018/03/05 finnaly Ich benutze dies:


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

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

Es kann korrekt im relativen oder absoluten Pfad ausgeführt werden. Wird korrekt ausgeführt und von crontab aufgerufen. In einer anderen Shell korrekt ausgeführt.

Beispiel zeigen, a.sh Selbstpfad drucken.

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

alt: Ich benutze das:

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

Es kann korrekt angezeigt werden, wenn es in einer anderen Shell und einem anderen Verzeichnis ausgeführt wird.

zhukunqian
quelle
1
"Es kann korrekt angezeigt werden, wenn es ausgeführt wird, wenn eine andere Shell und ein anderes Verzeichnis" auf Englisch keinen Sinn ergibt. Können Sie es noch einmal versuchen?
Keith M
Entschuldigung für mein schlechtes Englisch
Zhukunqian
Vielen Dank für die Bearbeitung, ich sehe, Sie meinten jetzt IN. Können Sie erklären, was dies bewirkt, bevor ich es versuche? Ich bin mir nicht sicher, wie ich es verwenden soll. Wie, was meinst du mit "andere Muschel"
Keith M
1
Diese Antwort hat so viele falsche Dinge, dass sie unmöglich behoben werden kann. Ich schlage eine einfache Entfernung vor.
Johan Boulé
-2

Eine Zeile im Makefile sollte ausreichen:

DIR := $(notdir $(CURDIR))

Thach Van
quelle