Questão principal
Estou usando GNU/Linux, enviando código C para uma biblioteca compartilhada bin/libcore.so
e, em seguida, usando a biblioteca na criação de um executável bin/test
. Os arquivos são criados com sucesso, mas bin/test
ocorre o seguinte erro ao executar:
bin/test: error while loading shared libraries: libcore.so: cannot open shared object file: No such file or directory
Subquestão
Separei isso em uma questão própria porque pode estar completamente fora do caminho certo.
Li que meu problema pode ser porque preciso definir -Wl,-rpath,bin
ao compilar bin/test
(tive que passar por algo parecido para fazer isso funcionar no Windows, ou seja, definir -Wl,-out-implib,bin/libcore.dll.a
).
Eu passo LDFLAGS
para meu Makefile da seguinte maneira:
make -f build/Makefile PLATFORM="linux" \
TARGET="bin/libcore.so" \
LDFLAGS="-shared" \
... \
e em build/Makefile
, tenho as seguintes linhas que fazem referência LDFLAGS
a:
# Linker flags.
ifeq ($(PLATFORM),linux)
LDFLAGS += -Wl,-rpath,bin
endif
ifeq ($(suffix $(TARGET)),.dll)
LDFLAGS += -Wl,--out-implib,$(dir $(TARGET))lib$(basename $(notdir $(TARGET))).dll.a
endif
# Build target.
$(TARGET): $(OBJ_FILES)
$(CC) -o $@ $^ $(LDFLAGS)
Mas quando tento executar o Makefile, recebo:
LDFLAGS += -Wl,-rpath,bin
make[1]: LDFLAGS: No such file or directory
Solução
Conforme observado na resposta aceita, a sintaxe do meu Makefile estava incorreta. Além disso, atualizei rpath
para $$ORIGIN
em vez de bin
para evitar os problemas descritos na resposta. Aqui está o Makefile funcionando:
# Additional linker flags.
EXTRA_LDFLAGS :=
ifeq ($(PLATFORM),linux)
EXTRA_LDFLAGS := -Wl,-rpath,'$$ORIGIN'
endif
ifeq ($(suffix $(TARGET)),.dll)
EXTRA_LDFLAGS := -Wl,--out-implib,$(dir $(TARGET))lib$(basename $(notdir $(TARGET))).dll.a
endif
# Build target.
$(TARGET): $(OBJ_FILES)
$(CC) -o $@ $^ $(LDFLAGS) $(EXTRA_LDFLAGS)
Primeiro, a mensagem de erro make[1]: LDFLAGS: Nenhum arquivo ou diretório :
Mike está certo, seu makefile não está completo o suficiente para explicar esse erro. No entanto, dada a mensagem em si, vou dar dois palpites e aposto que estou certo: primeiro, antes do comando,
ifeq
você tem outro alvo definido, que não aparece no seu makefile. Segundo, o primeiro caractere na linha que define aLDFLAGS
variável é um TAB.Nesse caso, a atribuição de variáveis é considerada parte da receita para o destino anterior. Esteja ciente de que, em makefiles, linhas em branco, comentários e instruções de pré-processador como essa não
ifeq
encerram uma receita de destino.Em geral, TAB é um caractere muito significativo em makefiles e você nunca deve usá-lo em lugar nenhum, exceto para introduzir linhas de comando de receitas. Alternativamente, se você estiver disposto a usar o GNU Make 3.82 ou superior, pode considerar usar a
.RECIPEPREFIX
variável para alterar o caractere especial para algo diferente de TAB.Para o seu problema original, a maneira como você está fazendo isso não funciona. Se você definir uma variável na linha de comando, ela substituirá todas as configurações no makefile: usar
+=
não adicionará valor ao makefile. Não é verdade que uma atribuição na linha de comando define "o valor padrão" de uma variável: em vez disso, essa variável na linha de comando tem uma "prioridade" maior para ser executada do que qualquer configuração no makefile.Você tem duas opções: usar a
override
diretiva para que a configuração do seu makefile substitua a configuração da linha de comando. Mas minha recomendação é que você use uma variável separada:Os padrões de codificação para pacotes GNU, por exemplo, dizem que os autores do makefile nunca devem assumir nenhum valor para as variáveis make padrão como
CFLAGS
,LDFLAGS
,LDLIBS
, etc. e que quaisquer configurações personalizadas devem ser adicionadas a variáveis separadas: as variáveis padrão são reservadas para uso por usuários na linha de comando.Por fim, a configuração do rpath é problemática. Usar
bin
rpath significa que você só pode executar o programa quando o diretório de trabalho atual contiverbin/libcore.so
. Portanto, se você alterar o diretório (por exemplocd bin; ./test
), o programa falhará.Você provavelmente vai querer usar o
$ORIGIN
token especial para representar o diretório que contém o binário, se for colocar a biblioteca compartilhada no mesmo diretório que o programa; algo como:Veja a página de manual
ld.so
(pelo menos no GNU/Linux) para mais detalhes sobre como isso funciona.E, finalmente, apenas como conselho: não dê nome ao seu programa de teste
test
. Existe um programa padrão POSIXtest
e, ao nomeá-lo,test
você corre o risco de confundi-lo de uma forma que fará com que você passe um tempo longo e frustrante coçando a cabeça. Simplesmente não faça isso.