Je prépare une application c ++ sur Linux (Ubuntu 16.04) en utilisant quelques bibliothèques poco que j’ai liées dynamicment. J’ai un dossier de projet qui comprend: les dossiers include, bin, lib, src et build et le fichier Makefile correspondant. Jusqu’ici, j’ai utilisé le Makefile suivant qui récupère les bibliothèques de / usr / local / lib
CC := g++ # Folders SRCDIR := src BUILDDIR := build TARGETDIR := bin # Targets EXECUTABLE := C++_APP TARGET := $(TARGETDIR)/$(EXECUTABLE) SRCEXT := cpp SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT)) OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o)) CFLAGS := -c -Wall INC := -I include -I /usr/local/include LIB := -L /usr/local/lib -lPocoFoundation -lPocoNet -lPocoUtil $(TARGET): $(OBJECTS) @echo " Linking..." @echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB) $(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) @mkdir -p $(BUILDDIR) @echo " $(CC) $(CFLAGS) $(INC) -c -o $@ $<"; $(CC) $(CFLAGS) $(INC) -c -o $@ $< clean: @echo " Cleaning..."; @echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET) .PHONY: clean
Maintenant, lors de l’exécution de l’éditeur de liens, j’aimerais rechercher des bibliothèques uniquement dans le dossier project lib sans changer LD_LIBRARY_PATH ni modifier ld.so.conf. J’ai donc cherché et j’ai trouvé que cela pouvait être obtenu avec l’argument de l’éditeur de liens -Wl, rpath, $ ORIGIN. Donc, je suppose que je dois append la déclaration suivante
LDFLAGS := -Wl,-rpath,$ORIGIN/../lib
et changez la déclaration LIB comme suit:
LIB := -L $ORIGIN/../lib -lPocoFoundation -lPocoNet -lPocoUtil
Cependant, il récupère toujours les bibliothèques du répertoire par défaut (usr / local / lib), car je l’ai testé sans bibliothèque sur le dossier project lib. Qu’est ce que j’ai mal fait?
Non, vous vous trompez. Vous devez passer la chaîne littérale $ORIGIN/../lib
en tant qu’argument à votre éditeur de liens. Le jeton $ORIGIN
est conservé dans votre programme après sa création et lorsque l’éditeur de liens du runtime commence à exécuter votre programme, il remplacera $ORIGIN
par le chemin actuel à partir duquel votre programme a été appelé. Cela est vrai même si vous avez copié votre programme ailleurs. Donc, si vous exécutez votre programme en tant que /usr/local/bin/myprogram
l’éditeur de liens au moment de l’exécution remplacera $ORIGIN
par /usr/local/bin
. Si vous le copiez dans /opt/mystuff/libexec/myprogram
l’éditeur de liens au moment de l’exécution remplacera $ORIGIN
par /opt/mystuff/libexec
.
Pour passer un $
littéral à la commande invoquée par une recette make, vous devez vous échapper du $
en le doublant: $$
. Sinon, make verra que $
introduit une variable ou une fonction make. Rappelez-vous qu’il est parfaitement légal pour une variable make d’éviter les parenthèses, etc., s’il s’agit d’un seul caractère (note, $@
, $<
, etc.)
Ainsi, lorsque vous écrivez -Wl,-rpath,$ORIGIN/../lib
make interprétera le $O
dans $ORIGIN
comme développant une variable nommée O
, qui est vide, vous donnant ainsi -Wl,-rpath,RIGIN/../lib
.
De plus, vous devez échapper le $
du shell, sinon il essaiera de développer $ORIGIN
tant que variable du shell que vous ne voulez pas.
Vous voulez faire quelque chose comme ça:
LDFLAGS = '-Wl,-rpath,$$ORIGIN/../lib' -L/usr/local/lib LDLIBS = -lPocoFoundation -lPocoNet -lPocoUtil $(TARGET): $(OBJECTS) @echo " Linking..." $(CC) $^ -o $@ $(LDFLAGS) $(LDLIBS)
(Je ne sais pas pourquoi vous utilisez @
pour masquer la commande, puis l'écho de la commande ... pourquoi ne pas simplement supprimer le @
et l' echo
et laisser make vous montrer la commande?)