GNU Make reports no rule when dealing with a target under subdirectory with source from another directory - makefile

My project's directory is mounted via NFS. From the directory under which it is mounted, I call make -f msh/Makefile cd=msh. (msh is my mount.) cd is a variable in the Makefile that is prepended to source files. This works fine with source files directly under cd. However, if the source files are under a subdirectory within cd, Make fails, saying that there is no rule to make that target. It does not fail if I call Make from within my mount.
This is my Makefile.
CC?=gcc
CFLAGS:=-Wall -Werror -D_POSIX_C_SOURCE=200112L $(CFLAGS)
cd?=.
objects_nix=if/tty.o
objects:=sub.o if.o $(objects_nix)
ifdef SO
CFLAGS+=-fPIC
bin=libmsh.so
else
bin=libmsh.a
endif
.PHONY : clean
$(bin) :
libmsh.a : $(objects)
$(AR) -r -c -s $# $(objects)
libmsh.so : $(objects)
#echo
#echo If you have resumed compilation after not having used the SO flag,
#echo you should run make clean.
#echo
$(LD) $(LDFLAGS) -shared -o $# $(objects)
test : $(cd)/test.c $(bin)
ifdef SO
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -L. -lmsh -Wl,-rpath,. -o $# $(cd)/test.c
else
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -o $# $(cd)/test.c $(bin)
endif
%.o : $(cd)/%.c
$(CC) $(CFLAGS) -c -o $# $<
clean :
rm -f libmsh.so libmsh.a
rm -f $(objects)
rm -f test.o test
I have tried creating another rule for the subdirectory, and this works. But I'd like it to work with only the one rule.

You have told Make how to make a .o file from .c file in $(cd). It does not know how to make a .o file if the .c file in some other directory. You can solve this in various ways, such as:
Add an explicit rule for all directories. You have already done that.
Use VPATH.
Create a Makefile for each directory.

Related

Makefile - link input file from folder

I try to compile a project with generated object stored in a sub directory :
myproject:
|
src: .cpp, .cpp ...
|
release: .o, .o ...
Here's a part of Makefile:
SRC ?= src
OBJ_PATH = $(SRC)/Release
vpath %.o $(OBJ_PATH)
...
OBJS := $(addprefix $(OBJ_PATH)/,obj1.o obj2.o )
all: build
obj1.o: $(SRC)/Manager.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
obj2.o: $(SRC)/Synth.cpp
$(EXEC) $(CC) $(INCLUDES) $(CCFLAGS) $(GNCD_FLGS) $(DEFS) -c $(<) -o $(OBJ_PATH)/$# #-o $# -c $<
myApp: obj1.o obj2.o
$(EXEC) $(CC) $(LDFLAGS) $(GNCD_FLGS) -o $# $(OBJS) $+ $(LIBS)
$(EXEC) mkdir -p $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(EXEC) cp $# $(OBJ_PATH)/$(TRGT_ARCH)/$(TRGT_OS)/$(BLD_TP)
$(OBJECTS) : Stt.h
build: myApp
run: build
$(EXEC) ./myApp
..but i got an error link:
Could not open input file 'obj1.o'
Makefile:86: recipe for target 'myApp' failed
So it seems couldn't find object in src/Release dir;
any ideas ?
thank's
Your recipe for myApp use $+, which list the prerequisites. It expands in obj1.o obj2.o. But you build obj1.o and obj2.o in $(OBJ_PATH). So the linker try to find the objects in the root directory, but cannot find them, since they are in $(OBJ_PATH).
Since your recipe explicitely lists them (with $(OBJS)), you do not need the automatic variable.
Sidenote
According to Paul's Second rule of Makefiles, it is best that every rule updates a file corresponding exactly to the target name (including the path part) (in other words, always use $# in the recipe), in order to always know which is the exact file updated.
In your case, if you want to build the objects files in OBJ_PATH, you could use a rule of the form $(OBJ_PATH)/obj.o for each.
You could also replace the dependency of myApp by $(OBJS), and use the automatic variable (btw, is there a reason why you prefer $+ over $^ (does the same thing but do not conserv duplicates in the prerequisites list) ?).

How to move .o on project folder?

I wrote this Makefile to move all .o of the project inside a directory 'obj' in the main folder.
Directories
.:
actor/ lib/ Controller.cpp Controller.h Controller.o doc.txt main.cpp main.o Makefile uno VRP*
./actor:
Customer.cpp Customer.h Customer.o Depot.cpp Depot.h Depot.o Route.cpp Route.h Route.o Vehicle.cpp Vehicle.h Vehicle.o
./lib:
Search.cpp Search.h Search.o Utils.cpp Utils.h Utils.o VRP.cpp VRP.h VRP.o
Makefile
CXX=g++
RM=rm -rf
BIN_NAME=VRP
CPPFLAGS=-s -O2 -std=gnu++11 -Wall
SRCS=$(wildcard *.cpp actor/*.cpp lib/*.cpp)
OBJS=$(subst .cpp,.o,$(SRCS))
all: $(OBJS_DIR) $(BIN_NAME)
$(OBJS_DIR):
mkdir $(OBJS_DIR)
$OBJS_DIR)/%.o : $(SRCS)
$(CXX) $(CPPFLAGS) -c $< -o $#
$(BIN_NAME) : $(OBJS)
$(CXX) -o $# $^
debug:
$(CXX) -g $(CPPFLAGS) -o $(BIN_NAME) $(OBJS)
.PHONY : all clean
clean:
$(RM) $(OBJS) $(OBJS_DIR)
dist-clean: clean
$(RM) $(BIN_NAME)
How can I make it works?
This line $OBJS_DIR)/%.o : $(SRCS) sets the prerequisites of every file that matches $OBJS_DIR)/%.o to all the files in $(SRCS) that's not even close to what you want. (It is also a typo. You are missing the opening ().
You can't write a single rule for what you are trying to do here you need three pattern rules (or one with a vpath/VPATH setup).
$(OBJS_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: actor/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: lib/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
That being said you don't actually have any targets that match $(OBJS_DIR)/%.o since the value of $(OBJS) is Controller.o ... actor/Customer.o ... lib/Search.o. To fix that you also need:
OBJS=$(addprefix $(OBJS_DIR)/,$(patsubst %.cpp,%.o,$(notdir $(SRCS))))
$(notdir) to get just the filename from the source files.
$(patsubst) instead of $(subst) just for correctness (subst would have modified a Bar.cpp.cpp file to Bar.o.o).
$(addprefix) to add the $(OBJS_DIR) prefix to the bare object file names.

Make rebuilding without any modifications

I've started writing a couple of simple tests for a library. I am currently trying to write a make target called btests that is supposed to compile them all.
The tests reside in the tests/ directory in the form of simple .cpp files which #include the library.
The makefile's task is simple: compile each tests/name.cpp into an executable tests/name file which has been linked with the library.
And it works fine, except one thing: each time I run make btests, tests get recompiled. However, they should recompile only if they have been changed or the library itself has been changed.
This is the relevant code:
CC=g++
CFLAGS=-Wall
SRCPATH=source
OBJPATH=object
TESTPATH=tests
OBJ=$(OBJPATH)/nameb.o $(OBJPATH)/hebbann.o
INF=$(SRCPATH)/nameb.hpp $(SRCPATH)/hebbann.hpp
TESTS=$(TESTPATH)/test_api $(TESTPATH)/test_speed
all : libname.a
libname.a : $(OBJ)
ar rvs libname.a $(OBJ)
$(OBJ) : $(OBJPATH)/%.o : $(SRCPATH)/%.cpp $(SRCPATH)/%.hpp
$(CC) $(CFLAGS) -c $< -o $#
btests : $(TESTS)
$(TESTS) : % : %.cpp all
$(CC) $(CFLAGS) $< -L. -lname -o $#
install : all
mkdir -p /usr/include/name
cp $(INF) /usr/include/name
cp libname.a /usr/lib
pack : all
mkdir -p name/
cp $(INF) name/
tar -cvf libname.tar name/ libname.a doc/ source/
clean :
rm -f $(OBJPATH)/* libname.a libname.tar $(TESTS)
How can I force make to recompile only when something has changed?
Your tests depend on all. Since there is no file called "all", Make concludes that it must be rebuilt, and so must the tests that depend on it.
The fix is simple. The rule for all does nothing but require libname.a, so just cut out the middleman:
$(TESTS) : % : %.cpp libname.a
$(CC) $(CFLAGS) $< -L. -lname -o $#

Makefile string substitution in dependency not working

I have a folder structure where all my source files are in ./src/, and all my object files are in ./obj/ (with the same internal directory structure, mirrored using path substitutions). I've created the following makefile:
$(EXECUTABLE): $(OBJECTS)
#echo Linking $(EXECUTABLE)...
$(CXX) $(LDLIBS) $(OBJECTS) -o $(EXECUTABLE)
%.o: $(subst o,cpp,$(subst obj/,src/,$#))
#echo Building $#...
$(CXX) $(CPPFLAGS) -c $(subst o,cpp,$(subst obj/,src/,$#)) -o $#
Which doesn't work! Make keeps claiming that the object files are up to date, even when the source file is actually older than the object file. On the other hand, if I do this:
obj/main.o: src/main.cpp
#echo Building $#...
$(CXX) $(CPPFLAGS) -c src/main.cpp -o $#
For every source file, it works perfectly. I checked, and the two subst give the same result (obj/main.o becomes src/main.cpp as expected). Yet Make doesn't accept the dependency for some reason.
This is giving me a lot of grief, can somebody explain where I am going wrong? I don't understand what is going on, I thought my substitution would work the same since it gives the same output. Am I not allowed to use subst, or $# in the dependencies or something?
You can't use $# in the prerequisites, only in the commands.
But you can do this:
$(OBJECTS): obj/%.o : src/%.cpp
#echo Building $# from $<...
$(CXX) $(CPPFLAGS) -c $< -o $#

How to depend on targets of a previous make invocation

I have a lib (say mylib) and two executables and one of these (say exe1) depends on lib. In file system i have:
src
Makefile
...
lib
mylib
Makefile
...
exe1
Makefile
...
exe2
Makefile
...
and by launching make in src dir all is builded.
Makefile in src:
EXE=exe1 exe2
LIB=mylib
all: $(LIB) $(EXE)
.PHONY: $(LIB) $(EXE)
$(LIB):
$(MAKE) -C lib/$#
$(EXE): $(LIB)
$(MAKE) -C $#
and, for example, Makefile for exe1 is:
...
all: exe1 copy
exe1: exe1.o
$(CC) $(CFLAGS) $(OBJ) $(LDFLAGS) -o $#
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
...
My problem is that if i change a file in mylib dir the library is correctly rebuilded but exe1 obsiously no...is there a way to teel make that exe1 target depends on a target (mylib) that is specified in a previous invocation of make without specifing dependencies on mylib's files in exe1 Makefile?
Thank you all.
#tripleee and #JackKelly (curse his name) are right, this is not a healthy makefile system.
You can get something like what you want by changing src/Makefile:
EXE=exe1 exe2
LIB=lib/mylib/mylib
all: $(LIB) $(EXE)
.PHONY: $(EXE)
$(LIB):
$(MAKE) -C lib/mylib
exe1: $(LIB)
$(EXE):
$(MAKE) -C $#
and changing exe1/makefile so that it will always rebuild exe1:
.PHONY: exe1
This still has many problems, but at least it will correctly rebuild lib/mylib/mylib and src/exe1/exe1 when you run Make in src. (It will not work if you run Make in src/exe1/.)

Resources