makefile objects in subdirectory - makefile

I was asked to make my VC++ code compile on gcc, and was given a makefile which should compile my code in a subdirectory of the directory of this make file. The problem is that the object files are looked for in the subdirectory, but output into the makefile dir. I assume I need to add something to "-o", but I am out of my depth here.
include ../makefile.common
CCFLAGS += -I. -I../general -L../general
HEADERS := $(wildcard *.h) $(wildcard */*.h)
SRCS := $(wildcard *.cpp) $(wildcard */*.cpp)
OBJS=$(SRCS:.cpp=.o)
DEPS=$(SRCS:.cpp=.d)
EXE=k2csv
default: $(EXE)
all: $(EXE)
$(EXE): $(OBJS) ../general/lib2csgeneral.a
# ( cd ../general ; make ; )
$(CPP) $(CCFLAGS) -o $(EXE) $(OBJS) -l2csgeneral -lmh -lm -pthread $(LDEFS)
clean:
rm -f $(OBJS) $(DEPS) $(EXE)
ifneq "$(MAKECMDGOALS)" "clean"
sinclude $(DEPS)
endif
The code compiles if I copy the object files, but this still irks me. Thanks for any help!

It seems I needed to add a rule for my outputs. This resolved my issue:
%.o: %.cpp
$(CPP) $(CCFLAGS) -c $< -o $#
$< replaces the input, $# replaces the output.

Related

Makefile ignoring included rules

I'm trying to create a makefile for a very basic c++ program. I'm trying to implement the automatic generation of dependencies by running g++ with the -M flag, storing this output in a .d file, and then including those .d files in my main makefile. The makefile content is below
CC=g++
CPPFLAGS=-Wall -Wextra -g -std=c++11
SOURCEDIR=src
SOURCES = $(wildcard $(SOURCEDIR)/*.cpp)
BUILDDIR=build
OBJDIR=$(BUILDDIR)/objs
OBJS=$(SOURCES:$(SOURCEDIR)/%.cpp=$(OBJDIR)/%.o)
DEP_FILES = $(OBJS:.o=.d)
OUTFILE=hello.out
$(OUTFILE) : $(OBJS)
$(CC) -o $# $^ $(CPPFLAGS)
include $(DEP_FILES)
$(OBJDIR)/%.d : $(SOURCEDIR)/%.cpp
$(CC) $(CPPFLAGS) $< -MM -MT $(#:.d=.o) > $#
$(DEP_FILES) : | $(OBJDIR)
$(OBJS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
.PHONY: clean
clean:
rm -f $(BUILDDIR) -r
rm -f *~
rm -f $(OUTFILE)
When I run make, the directory build/objs/ is generated and a .d file is generated with rules in it. Here's main.d file:
build/objs/main.o: src/main.cpp src/main.h
And here's the myfunc.d file:
build/objs/myfunc.o: src/myfunc.cpp src/main.h
Here's the issue
Since I'm calling include on these .d files, I'd expect the .o files which they specify to then be created, and then the main outfile to be created as the main rule. However, make creates the .d files, and then skips directly to the main compilation step without creating any .o files:
g++ -o hello.out build/objs/myfunc.o build/objs/main.o -Wall -Wextra -g -std=c++11
This fails with the following error, since the .o files are never created:
g++: error: build/objs/myfunc.o: No such file or directory
g++: error: build/objs/main.o: No such file or directory
g++: fatal error: no input files
How can I use this makefile to generate the .o files necessary for g++? Thank you for any help in advance!
I saw you got your makefile working but I just wanted to add a few things you might want to consider for future projects. I recommend using the vpath variable rather than specifying $(OBJDIR)/%.o in your makefile recipes. I actually read somewhere that it's not "cannon" to build object files in a separate directory, but in the cursory search I conducted before posting, I couldn't find the document.
That being said, I wrote a makefile that does what you wanted; it builds the output folder, generates the dependencies, and compiles the program. I specifically included the $(COMPILE.cpp) definition so you could see what it's composed of. $(CC) is specifically the C compiler, and $(CFLAGS) is specifically flags for the C compiler. They're just variables, obviously, so you can change them like you did and it will work fine, but the main think to keep in mind is that whoever uses your programs will expect to be able to configure the compilation as they see fit. This means they will set the $(CXX) and $(CXXFLAGS) expecting to set the C++ compiler and flags. $(CPPFLAGS) stands for C/C++ Preprocessor flags.
It's not the cleanest makefile, and if I was to change something, I would just compile the object files in place and save myself that headache. That cuts down on unnecessary make hacking, but for the purposes of answering your question, here it is. Anyways I hope this helps you somewhat, let me know if you have any questions.
Oh yea, I almost forgot; notice I changed your make clean script. I used $(RM) instead of simply rm -f. When you use utilities in your makefiles, you want to use them as variables. Again, this is to allow your users as much freedom and flexibility as possible when they're compiling your program.
vpath %.cpp src
vpath %.hpp include
vpath %.o build/objs
vpath %.d build/objs
.SUFFIXES:
.SUFFIXES: .cpp .hpp .o .d
SRCDIR = src
INCLUDESDIR = include
BUILDDIR = build
OBJDIR = $(BUILDDIR)/objs
SRCS = $(wildcard $(SRCDIR)/*.cpp)
OBJS = $(patsubst %.cpp, %.o, $(notdir $(SRCS)))
DEP_FILES = $(patsubst %.o, %.d, $(OBJS))
INCLUDE_DIRS = -I $(INCLUDESDIR)
CXX = g++
CPPFLAGS =
CXXFLAGS = -Wall -Wextra -g -std=c++11
PROGRAM = hello.out
COMPILE.cpp = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(INCLUDE_DIRS) $(TARGET_ARCH)
all: $(PROGRAM)
$(PROGRAM): %: $(OBJS)
$(LINK.cpp) $(INCLUDE_DIRS) $(addprefix $(OBJDIR)/, $^) $(LOADLIBES) $(LDLIBS) -o $#
%.o: %.cpp
$(COMPILE.cpp) -c -o $(OBJDIR)/$# $<
%.d: %.cpp
mkdir -p $(OBJDIR)
$(COMPILE.cpp) $^ -MM -MT $(addprefix $(OBJDIR)/, $(#:.d=.o)) > $(OBJDIR)/$#
include $(DEP_FILES)
.PHONY: clean
clean:
#echo $(RM)
$(RM) $(BUILDDIR) -r
$(RM) *~
$(RM) $(PROGRAM)
For anyone having a similar issue, here's the correct solution is in the comments. Here for convenience: The included .d files generate dependencies but not a recipe for making the .o files, and since I'm putting things in various directories the default rule doesn't work here, so the .o files aren't created. The solution was to add in the following rule to my main makefile.
$(OBJDIR)/%.o :
$(CC) -c -o $# $< $(CPPFLAGS)
Thanks Matt and Renaud for your answers!

Make: Compiling only one .c file though i modify the header file which is included in two .c files [duplicate]

This question already has answers here:
'make' does not recompile when source file has been edited
(3 answers)
Closed 4 years ago.
I have two .c files and one .h file which is included in both .c files.
I have make file :
CC=gcc
CFLAGS=-I.
OBJ = hellofunc.o hellomake.o
DEPS := $(OBJ:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $(patsubst %.o,%.d,$#) $<
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o $# $^
I modified hellomake.h header file and then ran above make file. It is compiling only the first file which is assigned to DEPS variable, Which is hellofunc.c
FYI, When i change the order of DEPS variable it is compiling hellomake.o , Seems like make is only picking first file assigned to DEPS variable.
Is there anything wrong in my makefile.. Please help.
As #tripleee noted in the comments, make will by default build the first target it encounters. Since the include files are included directly, as if they were cut-and-pasted in place, the first target in the first .d file (which I'm guessing you'll find to be hellofunc.c) is the first target that make encounters, so that's what make aims to build.
If you move the include line to the end of the file, then the first target in the file will be hellomake, and so that's the target make will attempt to build by default.
Meta remark: if you can, I'd say it's better to avoid this pattern of depending on .d files, and instead aim to express sufficiently many of the dependencies ‘by hand’ directly in the makefile. Doing it this .d way does work (ie, I'm not saying what you're doing is wrong) and appears to be labour-saving, but in my experience it tends to be a little brittle, partly because if you don't have the .d files to hand then you suddenly have zero dependencies. In order to have the .d files to hand, you'll have to check them in to your code repository (you are using a repository, aren't you?), but that will mean they'll frequently be trivially out of date, and... it can turn into a bit of a mess.
EDIT: considered MadScientist's comment and blog post about separate recipe for .d files.
You could tell make how to generate the .d files with a separate rule instead of putting this in another recipe (but see the above mentioned blog post for several reasons for not doing so).
And you should probably tell make that your default goal is hellomake:
.DEFAULT_GOAL := hellomake
CC=gcc
CFLAGS=-I.
OBJ = hellofunc.o hellomake.o
DEPS := $(OBJ:.o=.d)
-include $(DEPS)
%.d: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $# $<
%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
hellomake: hellomake.o hellofunc.o
$(CC) -o $# $^
And it would probably be even better if you were letting make find the source files and deduce the rest:
.DEFAULT_GOAL := hellomake
CC := gcc
CFLAGS := -I.
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SRC))
DEPS := $(patsubst %.c,%.d,$(SRC))
-include $(DEPS)
%.d: %.c
$(CC) $(CFLAGS) -MM -MT $# -MF $# $<
%.o: %.c
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJS)
$(CC) -o $# $^
Finally, following MadScientist's advices, a better, more efficient, less prone to failures solution could be:
.DEFAULT_GOAL := hellomake
CC := gcc
CFLAGS := -I.
SRCS := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SRC))
DEPS := $(wildcard $(patsubst %.c,%.d,$(SRC)))
include $(DEPS)
%.o: %.c %.d
$(CC) -MT $# -MMD -MP -MF $*.Td $(CFLAGS) -c -o $# $<
mv -f $*.Td $*.d && touch $#
hellomake: $(OBJS)
$(CC) -o $# $^
%.d: ;
.PRECIOUS: %.d

No rule to make target (make project in different directories)

Excuse me for asking simple questions, but I can't find where the problem is.
I have an src directory, contains makefile and obj folder. An include folder and a lib one. The codes have provided here.
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~
it gives me the following error:
gcc -c -o obj/hellomake.o hellomake.c -I../include
make: *** No rule to make target 'obj/hellofunc.o', needed by 'hellomake'. Stop.
It uses the same rule for creating .o files and hellomake file. but the last one does not work.
Thanks for any comment or guide.
You have a src directory, but you don't tell Make about it. Make is complaining that there is no hellofunc.c. (There is asrc/hellofunc.c, but Make didn't know to look there.) Try this:
SRC := src
$(ODIR)/%.o: $(SRC)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)

Why is makefile recompiling entire set of files if I only change one?

Here is my makefile... Why does it recompile all sources even if only one changes??
CC = g++
CFLAGS = -w -g -c
LIBS = -lm
EXEC = DFMS_PDS_L2_to_L3
.PHONY : clean tgz wdtgz
HOMEDIR = ../
BIN = bin
SRC = src
OBJ = obj
SRCFILES := $(wildcard $(SRC)/*.cc)
OBJFILES := $(patsubst %.cc, $(OBJ)/%.o, $(notdir $(SRCFILES)))
OBJS := $(patsubst %.cc, %.o, $(notdir $(SRCFILES)))
# Executable Targets
all: $(EXEC)
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
# Dependencies
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
# Miscellaneous Targets
clean:
rm -rf $(BIN)/$(EXEC) obj/*.o *~
tgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild --exclude=data
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
wdtgz:
tar cvzf $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild
cp $(HOMEDIR)cppbuild.tgz $(HOMEDIR)cppbuild.tgz.allow
I'm running on Linux 3.0 with gnu make
Is it in the $(EXEC) definition?
My guess is that this recompiles all of the sources even if none changes.
Look at these two rules:
$(EXEC) : $(OBJS)
$(CC) $(LIBS) $(OBJFILES) -o $(BIN)/$(EXEC)
%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $(OBJ)/$#
Suppose foo.cc is the only source file. The first rule says that the target depends on foo.o, but actually builds it from obj/foo.o. The second can be invoked to build foo.o (which the first rule demands), but it actually builds obj/foo.o. So the first time you run Make it will build the executable correctly (and obj/foo.o). But every time thereafter, Make sees that foo.o does not exist and attempts to build it and rebuild the executable.
The solution is to rewrite the rules so that they build -- and depend on -- what they claim:
all: $(BIN)/$(EXEC)
$(BIN)/$(EXEC) : $(OBJFILES)
$(CC) $(LIBS) $^ -o $#
$(OBJ)/%.o: $(SRC)/%.cc
$(CC) $< $(CFLAGS) -o $#

Makefile rebuilds everything every time, why?

I have simple makefile here:
SOURCES= $(wildcard *.c)
OBJECTS= $(patsubst %.c, %.o, $(SOURCES))
NAMES= $(patsubst %.c, %, $(SOURCES))
CC=gcc
CFLAGS= -Wall -c -o
TASKS_IN_DIRS= $(addprefix obj/,$(OBJECTS)) $(addprefix bin/,$(NAMES))
all: $(NAMES)
$(NAMES): %: %.o $(OBJECTS)
$(CC) -o bin/$# obj/$^
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) obj/$# $<
clean:
rm -rf $(TASKS_IN_DIRS)
Getting all the c files names.
Making from them simple names(without extension) and object names.
Doing things
And what matters - all works, but works every time i print make(compiling and linking all the files). even if i don't changed anything and i do it few times in row, is something wrong with dependencies?
I expected something like "blabla is up to date" instead.
$(OBJECTS): %.o: %.c
$(CC) $(CFLAGS) obj/$# $<
is looking in your current directory for your .o files. Since they're not there it's rebuilding them.
The following does what you want.
SOURCES= $(wildcard *.c)
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
OBJECTS:= $(addprefix obj/,$(OBJECTS))
NAMES:= $(patsubst %.c, %, $(SOURCES))
NAMES:= $(addprefix bin/,$(NAMES))
CC=gcc
CFLAGS= -Wall -c -o
TASKS_IN_DIRS=$(OBJECTS) $(NAMES)
all: $(NAMES)
$(NAMES): $(OBJECTS)
$(CC) -o $# $<
obj/%.o: %.c
$(CC) $(CFLAGS) $# $<
clean:
rm -rf $(TASKS_IN_DIRS)
You lied to make. You promised that each of the$(NAMES) targets creates its object file in the current directory, but due to $(CC) -o bin/$# obj/$^ it is created in the bin directory.
At the next make invocation, it can't find the object files and runs each command again.
Hard and Fast Rule for Makefiles: each non-PHONY target must use a plain $# somewhere in its commands to indicate the file it creates.

Resources