I am on GNU/Linux outputting C code to a shared library bin/libcore.so
and then using the library in the creation of an executable bin/test
. The files are successfully created, but bin/test
gives the following error when it runs:
bin/test: error while loading shared libraries: libcore.so: cannot open shared object file: No such file or directory
Separated this into its own issue because it may be off the right track entirely.
I read my problem can be because I need to set -Wl,-rpath,bin
when building bin/test
(I had to go through something similar to get this to work for Windows, i.e. setting -Wl,-out-implib,bin/libcore.dll.a
).
I pass LDFLAGS
to my Makefile the following way:
make -f build/Makefile PLATFORM="linux" \
TARGET="bin/libcore.so" \
LDFLAGS="-shared" \
... \
and in build/Makefile
, I have the following lines which reference LDFLAGS
:
# 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)
But when I try to run the Makefile, I get:
LDFLAGS += -Wl,-rpath,bin
make[1]: LDFLAGS: No such file or directory
As noted by the accepted answer, my Makefile syntax was incorrect. Furthermore, I updated rpath
to $$ORIGIN
instead of bin
to avoid the issues described in the answer. Here is the working Makefile:
# 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)
First, the error message make[1]: LDFLAGS: No such file or directory:
Mike is correct your makefile is not complete enough to explain this error. However, given the message itself I will make two guesses and I'll bet I'm right: first, before the ifeq
you have another target defined, which you don't show in your makefile. Second, the first character on the line setting the LDFLAGS
variable is a TAB.
In this case, the variable assignment is considered part of the recipe for the previous target. Be aware that in makefiles, blank lines, comments, and preprocessor statements like ifeq
do not end a target recipe.
In general, TAB is a very meaningful character in makefiles and you should never use them anywhere except to introduce recipe command lines. Alternatively if you're willing to require GNU Make 3.82 and above you can consider using the .RECIPEPREFIX
variable to change the special character to something other than TAB.
For your original issue, the way you're doing this cannot work. If you set a variable on the command line it will override all settings in the makefile: using +=
will not append to the value in the makefile. It's not true that an assignment on the command line sets "the default value" of a variable: instead that variable on the command line has a higher "priority" to make than any setting in the makefile.
You have two choices: you can use the override
directive to have your makefile setting override the command line setting. But, my recommendation is that you just use a separate variable:
ifeq ($(PLATFORM),linux)
EXTRA_LDFLAGS += -Wl,-rpath,bin
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)
The coding standards for GNU packages, for example, say that makefile authors should never assume any value for the standard make variables like CFLAGS
, LDFLAGS
, LDLIBS
, etc. and that any custom settings should be added to separate variables: the standard variables are reserved for use by users on the command line.
Finally, your rpath setting is problematic. Using bin
as the rpath means that you can only run your program when your current working directory contains bin/libcore.so
. So, if you change your directory (for example cd bin; ./test
) then it will fail.
You probably want to use the special $ORIGIN
token to represent the directory containing the binary, if you're going to put the shared library in the same directory as the program; something like:
EXTRA_LDFLAGS += -Wl,-rpath,'$$ORIGIN'
See the man page for ld.so
(on GNU/Linux anyway) for more details on how this works.
And finally finally, just as advice: do not name your testing program test
. There's a POSIX standard program test
and by naming your program test
you run a high risk of getting them confused in ways that will cause you to spend a long, frustrating time scratching your head. Just don't do it.