Makefile string substitution in dependency not working - makefile

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 $#

Related

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

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.

Attempt to link objects makes them recompile even if up-to-date

I have a recipe in my makefile that relies on several object files. I would like it to simply link the them, but they are always recompiling.
I've googled around and found information I did not know(marked with #) and changed it a bit, but the problem persisted.
I am led to believe make expects the name of the recipe be the name of the file, and I am failing to accomplish that. The problem is I do not what else to try and fix this. I would appreciate any help
CC = g++
#.PHONY: sfml-app
LIBS = -lsfml-graphics -lsfml-window -lsfml-system
APPLICATION = sfml-app
INCLUDE_DIR = -I include/
SOURCE_DIR = source
OUTPUT_DIR = bin
SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
OBJECTS = $(notdir $(patsubst %.cpp, %.o, $(SOURCES)))
#$(OUTPUT_DIR)/$(APPLICATION): $(OBJECTS)
#bin/sfml-app: $(OBJECTS)
#sfml-app: $(OBJECTS)
#$(APPLICATION): $(OBJECTS)
$(CC) $(OUTPUT_DIR)/*.o $(LIBS) -o $(OUTPUT_DIR)/$(APPLICATION)
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
clean:
rm $(OUTPUT_DIR)/*
print-% : ; #echo $* = $($*)
This rule doesn't create the file it promises to:
%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $(OUTPUT_DIR)/$#
See that -o $(OUTPUT_DIR)/$#? That's instructing the compiler to create a file in $(OUTPUT_DIR) instead of in the working directory.
If you really want your object files to go in $(OUTPUT_DIR), you need to make sure that your rule indicates that:
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CC) -c $< $(INCLUDE_DIR) -o $#
Or better, to act like the standard %.o: %.c rule (which will include CFLAGS etc):
$(OUTPUT_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(COMPILE.c) $(OUTPUT_OPTION) $<
I note your input files are named *.cpp - usually, that convention is for C++ files (i.e. to be compiled with $(COMPILE.cc), which will invoke $(CXX) rather than $(CC)). Check that you've not mixed up your C and C++ sources!

How can I make a Makefile file target depend on a different path?

I apologize for the ambiguous title, I couldn't think of a simple way to phrase it due to my lack of knowledge in GNU make.
I'm writing a simple Makefile for a small project, and I'm trying to enable it to generate individual objects by using their base name (without path) as the target:
$(BASE_OBJS) : %.o : $(SRC_DIR)/%.c $(OBJDIR) $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $(OBJDIR)/$#
The problem is that the 'make' app obviously expects the target object to be present in the current folder, but it's actually found in the $(OBJDIR) subfolder. The causes those targets to unnecessarily rebuild.
Alternatively, this rule does check for the object's existence in the right place:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
But it can't be used for running things like 'make main.o', as $(OBJS) includes the full path of the objects, so it only allows things like 'make output/main.o'.
If it's a duplicate then I'm sorry, I was looking for a while and couldn't find a similar question.
For reference, these are the variable definitions:
BASE_SRC=$(notdir $(SOURCES))
BASE_OBJS = $(BASE_SRC:%.c=%.o)
OBJS = $(BASE_OBJS:%.o=$(OBJDIR)/%.o)
Your main set of targets and prerequisites must use the full path, because that's how make works. So you must have something like:
$(OBJS) : $(OBJDIR)/%.o: $(SRC_DIR)/%.c $(INCLUDES)
#echo $(CC): [$(notdir $<)] '->' [$(notdir $#)]
#$(CC) -c $< $(CFLAGS) -o $#
Now if in addition you want to be able to run a simple make foo.o, then to do that you should define extra "alias" targets for the real targets. These rules only exist for the short-hand, they don't actually do anything. Something like:
$(BASE_OBJS) : %.o : $(OBJDIR)/%.o

GNU make Pattern Rule Fails with 'Main.cpp"

I've got a general-purpose makefile that I've successfully used for small (personal) projects before, as below:
#Makefile to compile a folder's contents into a program.
PROGNAME := MyProgram
LIBRARIES :=
CXX := g++ --std=c++11
INCLUDES := -Isrc -Ihdr
VPATH := src:hdr
CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))
$(PROGNAME): $(OBJ_FILES)
$(CXX) $(INCLUDES) $(LIBRARIES) $^ -o $# $(ROOTFLAGS)
#Automatically generate dependencies (-MM), change the target to be the
# object file (-MT) and output it to the dependency file (-MF).
%.d: src/%.cpp
$(CXX) $(INCLUDES) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $#
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
.PHONY: clean
clean:
rm obj/*.o $(PROGNAME)
This is designed for the following directory structure:
ParentFolder/
Makefile
hdr/
file1.h
...
src/
file1.cpp
...
obj/
I gave the makefile to a colleague and they found it didn't work - after some investigation, the cause of the problem seems to be that they had a source file called main.cpp in src/, which when running make would give the following error:
make: *** No rule to make target `obj/main.o', needed by `MyProgram'. Stop.
If I rename main.cpp to something else (e.g. test.cpp) then the makefile works as expected.
What is the cause of this behaviour? I've looked through the GNU Make Manual but did not find anything regarding special treatment of files called main.* (in fact, some of the examples use it).
While trying to fix the problem, I found that defining an explicit rule for main.o meant that it would be found - therefore, I presume it's an interaction with the main name and pattern-based rules, but I have not been able to find what that may be.
The trouble is that this rule:
obj/%.o: src/%.cpp %.d hdr/%.h
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
requires a corresponding header file. I suspect that there is no hdr/main.h, and Make has no way to build one, so when it is searching for a way to build obj/main.o it considers this rule, rejects it, and finds no other.
I suggest you add another pattern rule (after this one) to handle source files without matching header files:
obj/%.o: src/%.cpp %.d
echo $#
$(CXX) $(INCLUDES) -o $# -c $< $(ROOTFLAGS)
(P.S. Your dependency handling is a little odd and appears to be vestigial -- you generate dependency files and never use them. We can help you with that, once you're building main.o correctly.)

How can I put .o files to different folder and how should I improve this overall?

I've never really wrote any makefiles before and I have little knowledge of its syntax.
I'd like to put .o files into separate folder, obj/ for example. But I'm a bit lost how this should be done since there seem to be lot's of different ways to write makefile.
This is what I have currently and I would like to improve it.
PROGRAM=Project
CC=g++
CFLAGS=-c -g -std=c++0x -Wall -Wextra -pedantic -I $(SFML)/include -I src
LDFLAGS=-lsfml-graphics -lsfml-window -lsfml-system -lsfml-audio -L $(SFML)/lib -Wl,-rpath=$(SFML)/lib -Wl,-rpath-link=$(SFML)/lib
SOURCES=$(wildcard src/*.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=bin/project
all: build $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(OBJECTS) $(LDFLAGS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
build:
#mkdir -p bin
clean:
rm -rf $(EXECUTABLE) $(OBJECTS)
I've tried some different approaches but haven't yet figured out how to put .o files in their own folder.
Replace your OBJECTS line with something like:
OBJECTS=$(patsubst src/%.cpp,obj/%.o,$(SOURCES))
Remove the .ccp.o rule and replace it with something like:
obj/%.o: src/%.cpp
$(CC) $(CFLAGS) $< -o $#
You can probably also remove $(SOURCES) from the prerequisite list of the all target unless you expect make to try to create those files somehow.

Resources