Makefiles - Compiling to a different target folder - build

I have a list of library folders that I'm specifying in a make file:
LIBRARIES = Ethernet \
SPI \
SD
I also have a number of rules for compiling each one into a local obj folder of my project:
obj/SPI/%.cpp.o: $(LIBS_DIR)/SPI/%.cpp
#echo "Compiling $<"
obj/SD/%.cpp.o: $(LIBS_DIR)/SD/%.cpp
#echo "Compiling $<"
obj/Ethernet/%.cpp.o: $(LIBS_DIR)/Ethernet/%.cpp
#echo "Compiling $<"
(Note that each one uses it's own sub-folder). How can I generate these rules from $(LIBRARIES) automatically so that I don't have to duplicate them like this?

You can just do:
obj/%.cpp.o : $(LIBS_DIR)/%.cpp
g++ -c -o $# ${CPPFLAGS} ${CXXFLAGS} $<
In the above % captures dir/src part.
If you'd like the output directories to be created automatically it can be done with secondary expansion make feature:
.SECONDEXPANSION:
obj/%.cpp.o : $(LIBS_DIR)/%.cpp | $${#D} # object file depends on its directory
g++ -c -o $# ${CPPFLAGS} ${CXXFLAGS} $<
obj/% : # directory creation rule
mkdir -p $#

Sufficiently new versions of GNU make support the eval function. You can use it like this:
define SUBDIR_RULE
obj/$1/%.cpp.o: $(LIBS_DIR)/$1/%.cpp
#echo "Compiling $$<"
enddef
$(foreach D,$(LIBRARIES),$(eval $(call SUBDIR_RULE,$D)))
If you don't want to rely on that you can use auto-generated makefiles, which have been a feature of GNU make for much much longer. But this method is slightly trickier to use.

Related

Simple Makefile using WiringPi

I'm new to Makefiles. I've been making a simple C++ library using WiringPi for my RaspberyPi related projects. So far its very simple with things like an LED class, DuelLED, Motor, Button, etc (both .h and .cpp). I was able to piece together a Makefile but I am getting an error "No rule to make target RumPi.o needed by RumPi". (Note: The name of my library is called RumPi)
Thanks for all the help, Here is the final fix:
CXX = g++
CXXFLAGS = -std=c++11
LDLIBS = -lwiringPi
HEADERS = Components/Headers/RumPi.h ./Common.h Components/Headers/Component.h Components/Headers/Vehicle.h Components/Headers/Motor.h Components/Headers/Receiver.h Components/Headers/DualLED.h Components/Headers/LED.h Components/Headers/RGBLED.h Components/Headers/Relay.h
OBJECTS = RumPi.o Vehicle.o Motor.o Receiver.o DualLED.o LED.o RGBLED.o Relay.o
default: RumPi
RumPi: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $#
%.o: Components/Implementations/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
$(OBJECTS): $(HEADERS)
clean:
-rm -f $(OBJECTS)
-rm -f RumPi
That message means make can't figure out how to build that target (RumPi.o). Do you have a Components/Implementations/RumPi.cpp file? Do all the header files you've listed in the $(HEADERS) variable actually exist? If either of those is not true, then your pattern rule will not match. If your pattern rule doesn't match (and the default rule doesn't match) then make can't figure out how to build the object file.
If you want full details you can run make -d and examine the debug output. You might want to redirect it to a file so you can look at it with less or a text editor since there's a lot of output.
By the way, you should not add the -lwiringPi option to your compile line. Libraries are only used at link time, not compile time.
ETA
Something else you should consider is rewriting your pattern rule so that only the source file is listed as a prerequisite and moving the headers to a separate line:
%.o: Components/Implementations/%.cpp
gcc -c $< -o $# -lwiringPi
$(OBJECTS): $(HEADERS)
The advantage to this is you'll get a clearer error message if one of the headers is not found. When you use a pattern rule, make will try to match all the patterns it can and if none match it tells you it doesn't know how to build the target. Since there are usually many different ways to build a target, make doesn't show an error for every one that doesn't match.
But if you declare a direct explicit prerequisite relationship between two files, rather than using a pattern that may or may not match, then if there is a missing file make will tell you directly.
ETA2
In your original makefile you had a rule like this:
RumPi: $(OBJECTS)
gcc $(OBJECTS) -o $# -lwiringPi
but then later you removed it. Why did you take this out? You need this rule to tell make how to link your executable file RumPi.
Also, you shouldn't be using gcc as the compiler/linker for C++ code; gcc is for C, not C++. You should use g++ for C++ code. And it's best to contain this information in variables so it's easy to find and modify (even from the command line if you like). The standard variable names for the C++ compiler is CXX etc.
Your makefile should look something like this:
CXX = g++
CXXFLAGS = -std=c++11
LDLIBS = -lwiringPi
HEADERS = Components/Headers/RumPi.h ./Common.h Components/Headers/Component.h \
Components/Headers/Vehicle.h Components/Headers/Motor.h Components/Headers/Receiver.h \
Components/Headers/DualLED.h Components/Headers/LED.h Components/Headers/RGBLED.h \
Components/Headers/Relay.h
OBJECTS = RumPi.o Vehicle.o Motor.o Receiver.o DualLED.o LED.o RGBLED.o Relay.o
default: RumPi
RumPi: $(OBJECTS)
$(CXX) $(CXXFLAGS) $^ $(LDLIBS) -o $#
%.o: Components/Implementations/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $<
$(OBJECTS): $(HEADERS)
clean:
-rm -f $(OBJECTS)
-rm -f RumPi

Makefile Confusion

I'm new to makefiles, but I finally managed to get one working for a project I'm working on. The original goal was to search the folder "Source" for any CPP files, then create an Object file in the folder Products/Objs. Instead, it finds the CPP files, but OBJECT_FILES is the same as SOURCE_FILES, and I'm not sure how it's working. It doesn't generate any .o files (that I could see), but still compiles successfully. Super confused but would love some help. Thanks!
##########################################
# Editable options #
##########################################
# Program Name
EXECUTABLE=net
# Compiler options
CC=g++
CFLAGS=
LDFLAGS=
# Folders
SRC=Source
OBJ=Products/Objs
#########################################################
# Do Not Touch This #
#########################################################
SOURCE_FILES := $(shell find $(SRC)/ -type f -name '*.cpp')
## This should not work
OBJECT_FILES := $(SOURCE_FILES: $(SRC)/%.cpp=%.o)
## Like at all --> It's the same as SOURCE_FILES
## But I guess???
build: $(EXECUTABLE)
## Deletes the executable (assumes small compile time)
clean:
#rm -r -f $(shell find $(SRC)/ -type f -name '*.o')
#rm $(EXECUTABLE)
.PHONY: build clean
$(EXECUTABLE): $(OBJECT_FILES)
#$(CC) $(LDFLAGS) -o $# $^
#echo "Build successful!"
$(OBJECTS_FILES): %.o : $(SRC)/%.cpp
#$(CC) $(CFLAGS) -o -c $# $^
Well first you have a typo; you create a variable OBJECT_FILES:
OBJECT_FILES := $(SOURCE_FILES: $(SRC)/%.cpp=%.o)
Also you shouldn't use spaces here (after the :). Then you use a variable named OBJECTS_FILES instead:
$(OBJECTS_FILES): %.o : $(SRC)/%.cpp
That variable is empty so this is essentially a no-op.
Your compiler invocation is wrong. The word after the -o option is the file the output should go to; yours is:
#$(CC) $(CFLAGS) -o -c $# $^
which means that the output of this command is going to the file -c. Then the input is an object file that doesn't exist... most likely you'll get an error. Also you only want to pass the source file to the compiler, not all the other prerequisites (headers etc.) This should be:
#$(CC) $(CFLAGS) -c -o $# $<

Using makefile arguments without foo=

I have a makefile I use to compile a single file. When I need to pass an argument, I use target=targetFile.
The script takes the argument, looks for the file (within the same directory) that has the same value as the argument and compiles it.
I use this for compiling problems from uhunt and uva, which use a single c++ file. So I dont' need multiple makefiles for multiple source files. Single makefile for multiple source files is the reason I made the makefile.
Here's the code I have so far
OBJS = $(target).o
CC = g++
CFLAGS = -Wall -g -std=c++11
INCLUDE = -I./$(target)
#default command to run
all : Main-$(target) clean run
#compile and build
Main-$(target) : $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
%.o : %.cpp
$(CC) -c $(CFLAGS) $<
#remove object and any other garbage files.
clean:
rm -rf -d $(target).o *~ *% *# .#*
#remove the compiled file
clean-all:
$(clean) rm Main-$(target)
#run the compiled file
run:
./Main-$(target)
The command I use to compile is,
make target=sourceFile
Also I don't include the file extension, I have all my source file extensions to be cpp
What I want in the end is:
make sourceFile
Just a side note, for using the command clean and clean-all, I use
make target=sourceFile clean
make target=sourceFile clean-all
I'd prefer if I can use:
make sourceFile clean
make sourceFile clean-all
You may use common Makefile variable MAKECMDGOALS that contains all targets passed to make.
Please try this variant
CC = g++
CFLAGS = -Wall -g
MAKECMDGOALS := $(filter-out clean, $(MAKECMDGOALS))
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
clean:
rm -f *.o
Here the lines
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
will generate separate build targets for each word in MAKECMDGOALS.
Note, we need this Makefile to know that 'clean' is a target for removing stuff, but not to attempt build Main-clean. This why we remove clean from MAKECMDGOALS using filter-out function.
So if we run make a b clean, the build system will generate automatically targets for building Main-a and Main-b and then use already written clean target
Disclaimer -- this is a non-standard use of Make, and will therefore open up all kinds of corner cases, so I don't recommend it. This is better suited for a shell script calling make. That being said... it is an interesting question.
You can't do make xxx clean, and not have it try to build xxx (unless you do some really nasty cludge using recursive make, but I won't go there). You could do something like make clean-xxx though, as follows:
%:Main-%
Main-%:%.cpp
$(CC) $(CFLAGS) $< -o Main-$#
clean-%:
rm Main-$*
Notice that %-clean has a shorter stem, and therefor takes precedence over the % if the make target starts with clean-.

organize project and specify directory for object files in Makefile

Here are my two questions:
I am now learning to manage my code with CVS, and I just want to make a repository for my C++ files, Makefile and bash and python scripts only, not the object files and executables. So I made several subdirectories under my project directory: src, bin, scripts, results and data.
I put C++ files and Makefile under ~/myproject/src, Bash and Python scripts under ~/myproject/scripts and object and executables under ~/myproject/bin. I am hoping only the files under src and scripts will be updated via CVS. I wonder how you organize your projects? Just hope to follow some good habits.
Since I put my C++ files and Makefile into ~/myproject/src and object and executable files into ~/myproject/bin, I have to specify the directories in Makefile. Here is what I am doing
Makefile:
...
BIN_DIR=/home/myproject/bin/
all: $(BIN_DIR)myexecutable TAGS
TAGS: *.cc *.h
etags --members --declarations -l c++ *.cc *.h
$(BIN_DIR)myexecutable: $(BIN_DIR)myobject.o
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
Makefile.depend: *.h *.cc Makefile
$(CXX) -M $(CXXFLAGS) *.cc > Makefile.depend
clean:
\rm -f $(BIN_DIR)myexecutable $(BIN_DIR)*.o Makefile.depend TAGS`
However this will give error
make: *** No rule to make target /home/myproject/bin/myobject.o', needed by /home/myproject/bin/myexecutable'.
How to specify a different directory for object and executable files from C++ files in Makefile?
If you want to learn make, the GNU make manual is very good, both as a reference and a tutorial. You might want to consider using the patsubst command. The following is a chopped down version of one of my own makefiles that uses it:
OUT = bin/csvfix.exe
CC = g++
IDIR = inc
ODIR = obj
SDIR = src
INC = -Iinc -I../alib/inc
LIBS = ../alib/lib/alib.a -lodbc32
_OBJS = csved_atable.o \
csved_case.o \
csved_cli.o \
csved_command.o \
csved_date.o \
OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))
$(ODIR)/%.o: $(SDIR)/%.cpp
$(CC) -c $(INC) -o $# $< $(CFLAGS)
$(OUT): $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
strip $(OUT)
clean:
rm -f $(ODIR)/*.o $(OUT)
You can keep your files in different directories if you like, but that isn't necessary. Add a file or directory to the CVS repository once, and CVS will retain it indefinitely. From then on you can update it, check it in, whatever. If you don't add an object file to the repository, CVS won't touch it. If you want to add a whole directory tree, and you're in the habit of keeping objects there, just make clean before you do it.
Make is a wonderful tool, but it has some glaring faults. What you're describing is one of the classic problems: Make is good at using a source there to make something here, but not the other way around. Here are a couple of ways to do what you're trying to do.
A) Run make in your binary directory:
...
all: myexecutable TAGS
myexecutable: myobject.o
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
VPATH = /home/myproject/src
...
cd ~/myproject/bin
make -f ../src/makefile
B) Put the objects on the bin directory by brute force:
$(BIN_DIR)%.o: %.cc
$(CXX) $(CXXFLAGS) -c -o $# $^
This will give you a problem with Makefile.depend, which you can approach several ways.
C) Learn some more advanced Make techniques. You probably shouldn't try this yet.
Your directory structure seems sensible.
I would make an explicit rule for executing the compiler, like
TARGET_DIR=bin
SRC_DIR=src
CXX=g++
CXXFLAGS=
ETC=
OBJS=$(TARGET_DIR)/test.o
all: $(OBJS)
$(TARGET_DIR)/%.o: $(SRC_DIR)/%.cc
$(CXX) -c -o $# $(CXXFLAGS) $(ETC) $<
Use automake and autoconf for building your project.
As for the structure of files just look at any big open-source C++ application. Any KDE application
will do fine for that matter. If you find an application that uses C++ and Python even better.
Why not go for eclipse, which is quite popular and handy for managing large projects. You can make a new project in eclipse, import-export code into the project from other projects, does version control for you as well etc. No need to write your make files, eclipse does it for you with your mentioned preferences in GUI.
If you are involved in a C++ project, just install the CDT plugin over eclipse and your are done.

Gnu Makefile - Handling dependencies

What approach do C++ programmers on Unix platform use to create and manage Makefiles?
I was using hand made Makefiles for my projects but they don't handle header file changes and other dependencies. I googled around and found a good solution here.
But I ran into a problem here in the sed command -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
The problem is with the 3rd expression "-e 's/ *\$$//'.
It doesn't work. Its supposed to remove trailing backslashes. I understand that there has to be double dollar there since this is part of a Makefile. Can someone tell me what wrong here?
Here's the complete Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $# $< $(CFLAGS)
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
Apart from the solution to this problem, I would also like some tips/pointers to my 1st question.
gcc/g++ can generate dependencies for you with the -M family of options.
The following works by specifying how to generate .depends files given a source file. By doing -include $(DEPS) $(DEPS) is recognized as a target and will be built/rebuilt when the source files change.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cc x.cc foo.cc
OBJS = $(SRCS:.cc=.o)
DEPS = $(SRCS:.cc=.depends)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.depends: %.cc
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
I use that approach too and can't praise it highly enough. And I write my makefiles by hand and reuse them a lot on new projects.
.The expression "s/ *\\$//" will work outside the context of Make. Within a makefile it doesn't work because Make tries to interpret "$/" before handing the result to the shell. So you must use "s/ *\\$$//" (note the extra $) within the makefile, but this won't work outside the context of Make (so testing it is a slight pain).
EDIT:
I've tried your makefile, and that sed statement seems to remove trailing backslashes just fine. Try something simpler, like this:
backslash:
#echo " \\" > $#
test: backslash
#echo without sed:
#cat backslash
#echo with sed:
#sed -e 's/ *\\$$//' &lt backslash
EDIT:
All right, now I'm hooked. Could you try these experiments and tell us the results?
Change the last character to 'z' : s/.$/z/
Change a trailing backslash to 'z' : s/\\$/z/
Change a trailing backslash to 'z' : sm\\$mzm
Delete a trailing backslash : s/\\$//
Delete spaces and a trailing backslash: s/ *\\$//
Try all of these inside and outside of Make, with '$' and '$$'.
In a make file anything you list on the dependency line is a dependency header files or other files included.
BSD tutorial on make Note: you can auto generate header dependency info with the -MM switch of GCC.
I must be missing something. Why doesn't generating dependency files work for you?
I prefer to use CMake, even though it's not strictly the solution to your problem.
It's a project description language that'll generate your Makefiles, Visual Studio Project, Eclipse Project, KDevelop, etc for you. All the dependencies are done for you:
CMakeLists.txt
add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)
In lib/CMakeLists.txt
add_library(my_library file3.c file4.c)
This creates a my_exe from file1.c file2.c linked against my_library. I find this much simpler. It also has things like package discovery:
find_package(Qt4)
The makedepend utility is installed on many systems and can be quite useful for generating dependency information.
Here is an example Makefile that uses the include directive (plus a little Perl magic) to incorporate the output from makedepend:
# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc
# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror
# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable. $^ is a shortcut for $(OBJS). $# is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $^ -o $#
# Use "make clean" to remove all of the support files.
clean:
rm -f $(OBJS) $(TARGET) Makefile.depend *~
# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files. This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
makedepend -f- -Y $(SRCS) 2> /dev/null | \
perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend
If both foo.cc and main.cc depend on foo.h, then the contents of Makefile.depend would be:
Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h
The end result is that the dependency information from makedepend is injected into the Makefile as a series of rules. It's similar to the approach of using a .d file for each .cc file, but keeps the dependency information in one file instead of scattered all over the place.
In Mozilla's build system, we use GCC's -MD switch to generate the dependency files:
http://mxr.mozilla.org/mozilla-central/source/configure.in#7134
and then we use a script called mddepend.pl to check for removed header files, such that
removing a header simply causes a rebuild, not an error:
http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl
That script generates an .all.pp file containing all the dependencies, with extra foo.o: FORCE dependencies stuck in for missing header files. We then simply -include the .all.pp file in rules.mk right below there.
You can use qmake to generate Makefiles for a project even if that project is not using Qt.
I use BSD make (pmake?) which does lot of work for me (my lang is C, but I think no difference here). This is my common 'local.prog.mk', I never change it:
.PHONY: tags .depend
# .depend depends only on $(SRCS) in bsd.dep.mk, so we can't track changes of
# header's own dependencies properly. so .depend is .PHONY target here.
CSTD ?=c99
WARNS ?=9
.if !empty(PC_LIST)
PC_CF !=pkg-config --cflags $(PC_LIST)
PC_LD !=pkg-config --libs $(PC_LIST)
.endif
CFLAGS +=$(PC_CF) -fgnu89-inline
.if !defined(NO_DEBUG)
CFLAGS +=-O0 -ggdb3
.endif
LDFLAGS +=$(PC_LD)
CTAGS =exctags
NO_MAN=
NO_OBJ=
CLEANFILES+=$(PROG).core
.include <bsd.prog.mk>
$(PROG): $(SUBDIR)
build: clean cleandepend depend all
run: $(PROG)
./$(PROG)
Note 'bsd.prog.mk' inclusion -- this handles all, build, depend, clean targets. Project-specific BSDmakefiles are simple:
.SILENT:
PROG =hello
SRCS =hello.c world.c
PC_LIST =gtk+-2.0 gnet-2.0
.include "../local.prog.mk"
proto:
cproto -siv `pkg-config --cflags $(PC_LIST)` $(SRCS) > prototypes
CLEANFILES+=prototypes
I just make depend every time I insert/remove any #include directives.
Instead of the sed scripts, use gcc's -MT option to modify the target of the generated dependency rules. This blog post has more info.
With a more modern version of GCC, you can add the -MP flag to have GCC generate empty rules for the headers itself.
I top tip that I have found useful when building dependency files is to include the dependency file as a target in the generated rule:
file.d file.o : file.c header.h header2.h ...
Thus make will regenerate the dependencies if the source or any of the headers change. Including phony targets for the headers (GCC -MP) should then allow stable builds when headers are removed - the absense of required header remains a compilation error, not a make dependency error.
Assuming that dependency files are generated into the same directory as the object files, the following should work for GCC on Unix:
-include $(OBJ:.o=.d)
$(OBJDIR)/%d : $(SRCDIR)/%.cpp
mkdir -p $(#D)
echo -n "$# " > $#.tmp
$(CXX) $(CPPFLAGS) -MM -MP -MT $(#:.d=.o) $< >> $#.tmp
mv $#.tmp $#
(from memory)