The Makefile below throws the following error when compiled.
Error:
make: *** No rule to make target 'libfoo.so.0.1', needed by 'all'. Stop.
Makefile:
LIBNAME = libfoo
SOLIBNAME = $(LIBNAME).so.0.1
BINNAME = bar
SRC_DIR := exe/src
SRCS := $(shell find $(SRC_DIR) -name '*.cpp')
OBJS := $(SRCS:.cpp=.o)
CXXFLAGS += $(INCLUDES) -std=c++17 -Wall -Wextra -fPIC
LIB_LDFLAGS += \
-L../dir1 \
-lads
all: foobuild barbuild
.PHONY: foobuild barbuild all clean
$(LIBNAME).a: lib/src/abc.o
$(AR) -crs $@ $^
foobuild: lib/src/abc.o
g++ -shared -o $(SOLIBNAME) $^ $(LIB_LDFLAGS)
ln -srf $(SOLIBNAME) $(LIBNAME).so
ln -srf $(SOLIBNAME) $(LIBNAME).so.0
BIN_LDFLAGS += \
-L. \
-lfoo
barbuild: $(OBJS) foobuild
g++ -o $(BINNAME) $(OBJS) $(BIN_LDFLAGS)
clean:
rm -f $(LIBNAME)* $(BINNAME) exe/src/*.o lib/src/*.o
If I replace .PHONY with $(SOLIBNAME) $(BINNAME) all clean, it builds without any error, which I do not understand.
1 Answer 1
In typical use, the Make target on the left-hand side of a rule should be the name of the file the rule generates. Don't use a .PHONY: target if you're building a file; use the name of the file as the target name. In your setup you're creating three file targets (one shared library and two symlinks) and so this can usefully be three rules.
$(SOLIBNAME): lib/src/abc.o
g++ -shared -o $(SOLIBNAME) $^ $(LIB_LDFLAGS)
$(LIBNAME).so: $(SOLIBNAME)
ln -srf $(SOLIBNAME) $(LIBNAME).so
$(LIBNAME).so.0: $(SOLIBNAME)
ln -srf $(SOLIBNAME) $(LIBNAME).so.0
In a comment you ask about still having a consistent name for the command line, even if the library version changes. Here a .PHONY target makes sense.
.PHONY: foobuild
foobuild: $(LIBNAME).so $(LIBNAME).so.0
Now even if you change the build metadata, you'll have a fixed name you can use at the command line.
LIBNAME := libfoo
LIBFOO_MAJOR := 0
LIBFOO_MINOR := 0
LIBFOO_PATCH := 1
LIBFOO_SO_SHORT := $(LIBNAME).so.$(LIBFOO_MAJOR)
LIBFOO_SO_FULL := $(LIBNAME).so.$(LIBFOO_MAJOR).$(LIBFOO_MINOR).$(LIBFOO_PATCH)
.PHONY: foobuild
foobuild: $(LIBFOO_SO_SHORT) $(LIBFOO_SO_FULL)
make foobuild LIBFOO_MAJOR=1 LIBFOO_MINOR=0 LIBFOO_PATCH=0
# same as
# make libfoo.so.1 libfoo.so.1.0.0 LIBFOO_MAJOR=1 LIBFOO_MINOR=0 LIBFOO_PATCH=0
foobuildshould be named$(SOLIBNAME)– the name of the file the rule generates – and it shouldn't be phony. Maybe break this up into three separate targets to build the library itself and the related symlinks.lib/src/abc.cppandexe/src/main.cpp, each containing exactly one function, the latter's being amain(). I used your makefile unmodified except for changing the value ofLIB_LDFLAGSto empty to avoid dealing with whatever yourlibadsis.makesuccessfully built a workingbarexecutable, issuing the usual echo of the commands it was running but no diagnostic messages.LIB_LDFLAGSis not relevant to your particular diagnostic, which is about dependencies between rules, becauseLIB_LDFLAGSis used only in recipes, not in the target or prerequisite list of any rule.all: $(SOLIBNAME) $(BINNAME)and.PHONY: all clean, the build is successful. In case, I only want to build the shared library I need to issue the commandmake libfoo.so.0.1right? Or Is there a more idiomatic way since library version keeps changing.