i'm trying to build a debug and release version of a library with a Makefile and copy those libraries to the relevant build directories, e.g.
.PHONY: all clean distclean
all: $(program_NAME_DEBUG)
$(CP) $(program_NAME_DEBUG) $(BUILD_DIR)/debug/$(program_NAME_DEBUG)
$(RM) $(program_NAME_DEBUG)
$(RM) $(program_OBJS)
$(program_NAME_RELEASE)
$(CP) $(program_NAME_RELEASE) $(BUILD_DIR)/release/$(program_NAME_RELEASE)
$(RM) $(program_NAME_RELEASE)
$(RM) $(program_OBJS)
$(program_NAME_DEBUG): $(program_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$(program_NAME_DEBUG) $(program_OBJS) -o $(program_NAME_DEBUG)
$(program_NAME_RELEASE): $(program_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$(program_NAME_RELEASE) $(program_OBJS) -o $(program_NAME_RELEASE)
The 1st target in all (program_NAME_DEBUG) compiles OK but the 2nd, (program_NAME_RELEASE) produces the following error:
libGlam_rel.so
make: libGlam_rel.so: Command not found
make: *** [all] Error 127
libGlam_rel.so is the value of program_NAME_RELEASE
It doesn't seem to be recognising the 2nd target as it does the 1st?
EDIT
finally got this working.
one issue was having src files in multiple dirs, used VPATH to sort this, e.g.
# specify dirs other then current dir to search for src files
VPATH = ../../pulse_IO/src ../../../g2/src
Added in additional library targets into the platform conditional stuff, e.g.
# Platform specific conditional compilation
UNAME := $(shell uname)
TARGET := Glam
ifeq ($(UNAME), Linux)
# LINUX version
program_NAME := lib$(TARGET).so
program_DEBUG_NAME := lib$(TARGET)_dbg.so
program_RELEASE_NAME := lib$(TARGET)_rel.so
BUILD_DIR = ../build/linux
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS version
program_NAME := lib$(TARGET).dll
program_DEBUG_NAME := lib$(TARGET)_dbg.dll
program_RELEASE_NAME := lib$(TARGET)_rel.dll
BUILD_DIR = ../build/windows
endif
added the new debug and release object files:
DEBUG_OBJS := $(addprefix $(BUILD_DIR)/debug/,${program_OBJS})
RELEASE_OBJS := $(addprefix $(BUILD_DIR)/release/,${program_OBJS})
set my debug and release CFLAGS:
DEBUG_CFLAGS := -fPIC -g -Wall -DDEBUG=1
RELEASE_CFLAGS := -fPIC -O2 -Wall -DDEBUG=0
collated all the debug and release compiler options:
DEBUG_LINK.c := $(CC) $(DEBUG_CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
RELEASE_LINK.c := $(CC) $(RELEASE_CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
added my new rules to the 'all' target:
.PHONY: all clean
all: $(program_DEBUG_NAME) $(program_RELEASE_NAME)
the rule set looks like this (inc. a replacement for the implicit object file generation):
$(program_DEBUG_NAME): $(DEBUG_OBJS)
$(DEBUG_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_RELEASE_NAME): $(RELEASE_OBJS)
$(RELEASE_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
# rule to build object files (replaces implicit rule)
$(BUILD_DIR)/debug/%.o: %.c
$(DEBUG_LINK.c) $< -c -o $#
$(BUILD_DIR)/release/%.o: %.c
$(RELEASE_LINK.c) $< -c -o $#
and to finish off I modified clean to deal with all the new files:
clean:
#- $(RM) $(BUILD_DIR)/debug/$(program_DEBUG_NAME)
#- $(RM) $(DEBUG_OBJS)
#- $(RM) $(BUILD_DIR)/release/$(program_RELEASE_NAME)
#- $(RM) $(RELEASE_OBJS)
This works allowing me to produce debug and release versions of my library across linux and windows platforms with a single Makefile, e.g. $ make -k
First things first. You seem to want different versions of the object files for the two libraries, but there is nothing in this makefile that will provide that.
There are several ways to do it. The cleanest is probably to have two directories:
debug_objs/
ang.o
naur.o
gul.o
release_objs/
ang.o
naur.o
gul.o
The second-cleanest is to have different file names:
ang_debug.o
naur_debug.o
gul_debug.o
ang_rel.o
naur_rel.o
gul_rel.o
Either way, you can write rules for RELEASE_OBJS and DEBUG_OBJS (we can help with that, if need be).
Now look at the library rules:
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$(program_NAME_DEBUG) $(DEBUG_OBJS) -o $(program_NAME_DEBUG)
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$(program_NAME_RELEASE) $(RELEASE_OBJS) -o $(program_NAME_RELEASE)
We can use Automatic Variables to make them more concise:
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$# $^ -o $#
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$# $^ -o $#
(We could go a little farther, but let's not push it.)
Now for all. We move $(program_NAME_RELEASE) into the prerequisite list where it belongs:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
$(CP) $(program_NAME_DEBUG) $(BUILD_DIR)/debug/$(program_NAME_DEBUG)
$(RM) $(program_NAME_DEBUG)
$(RM) $(DEBUG_OBJS)
$(CP) $(program_NAME_RELEASE) $(BUILD_DIR)/release/$(program_NAME_RELEASE)
$(RM) $(program_NAME_RELEASE)
$(RM) $(RELEASE_OBJS)
But there's no reason to remove the object files, since they can't collide, and Make will delete them anyway if they're intermediate files. And there's no need to $(CP) and then $(RM) when we can just mv. And there's no need to mv; if that's where the libraries belong, we can build them there in the first place:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
EDIT:
To build the object files (I'll guess that you're using C):
OBJS:= ang.o naur.o gul.o
DEBUG_OBJS := $(addprefix debug_objs/,$(OBJS))
RELEASE_OBJS := $(addprefix release_objs/,$(OBJS))
debug_objs/%.o: $(SOURCE_DIR)/%.c
$(CC) $(DEBUG_FLAGS) $< -o $#
release_objs/%.o: $(SOURCE_DIR)/%.c
$(CC) $(RELEASE_FLAGS) $< -o $#
(Just make sure that those directories exist-- you can automate that too, but you're making enough changes for one day.)
This change should do it:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
Otherwise, make all fails to make $(program_NAME_RELEASE), which is what the error message is telling you.
Related
Following this question and my answer and its comments I have a doubt.
What is the proper way to reference dependencies in a Makefile?
Let me give an example considering this file:
CXX = g++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
I can do DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES)) but also DEPENDS := $(wildcard $(OBJDIR)/*.d): can't I?
If I delete a source file before running make clean the correspondent dependency file remains. In the second case it will be removed with the next make clean while in the first it will not. However if I do not run make clean dependencies not related to the sources might be included.
What is the best way to reference dependencies in a Makefile? Should I use two variables, one to run clean and the other for include?
I'm on my path to study the wonderful world of Makefiles and this was my first attempt on my own makefile. However I have hit my small brains at a wall with errors and I can not figure the cause, I only know the issue is in the Makefile, I am doing something wrong, because when I compile my "project" manually, it compiles.
cxx := g++
dirs := obj bld_win32 bld_linux
cpp := $(wildcard src/*.cpp)
obj := $(addprefix obj/,$(notdir $(cpp:.cpp=.o)))
ifeq ($(OS), Windows_NT)
target := bld_win32/engine.exe
flags := -mwindows -lopengl32 -openal32 -lgdi32
else
target := bld_linux/engine
flags := -lX11 -lGL -lopenal -lalut
endif
all: precheck $(target)
precheck:
mkdir -p $(dirs)
$(target): $(obj)
$(cxx) -std=c++11 -Wall -o $# $^ $(flags)
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
Your pattern rule is wrong, as you would have noticed if you'd tried to build object files one by one using this makefile. This rule:
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
lists all source files as prerequisites of every object file, and when you try to build any object file, it compiles only the first source file in the list (src/aardvark.cpp, or whatever), so that all of your object files are the same, even though they have different names.
Change it to this:
obj/%.o: src/%.cpp
$(cxx) -c -o $# $<
I've this folder structure
project
|_src
| |_test
| |_main.cpp
|_Makefile
This is my makefile (trying to adapt from this link):
CC = g++
RM = rm
WFLAGS = -c -Wall -W
LDFLAGS =
SRCTESTD = src/test
EXECUTABLE = test
OBJD = .obj
DEPD = .dep
SRCSTEST = $(SRCTESTD)/main.cpp
OBJECTSTEST = $(patsubst %.cpp, $(OBJD)/test/%.o, $(notdir $(SRCSTEST)))
DEPDSTEST = $(patsubst %.cpp, $(DEPD)/test/%.d, $(notdir $(SRCSTEST)))
all: $(SRCSTEST) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTSTEST)
$(CC) $(LDFLAGS) $(OBJECTSTEST) -o $#
.cpp.o:
$(CC) $(WFLAGS) $< -o $#
It does not work, and I've this error
make: *** No rule to make target `.obj/test/main.o', needed by `test'. Stop.
What I'm doing wrong? Sorry for trivial question, but I'm a make newbie.
The link shows outdated methods, such as suffix rules. Making dependencies can also be done during compilation by gcc/g++.
As for the rest, here is it :
EXE := test
SRCDIR := src
OBJDIR := .obj
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
LDLIBS := # -l flags
LDFLAGS := # -L flags
CPPFLAGS := -MMD -MP # -I flags also
CXXFLAGS := -W -Wall # no -c flag here
.PHONY: all clean fclean re
all: $(EXE)
clean:
$(RM) -r $(OBJDIR)
fclean: clean
$(RM) $(EXE)
re: fclean all
-include $(DEP)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
No redefinition of internally defined variables, no suffix rules, correct linking step and dependencies generation.
Update: To avoid calling mkdir for every source file, one should use order-only prerequisites and the special target .SECONDEXPANSION.
Change this block:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
To this:
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir $*
The error means make can't find a correct rule to build your object files. Your tree structure lacks some informations: only one file ? Where are the others ? Anyway, here are some hints:
In the last two lines, you are using an obsolete feature of make: suffix rules. I suggest you switch to a pattern rule, which is functionaly equivalent.
Say something like:
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
Another thing (that shouldn't be a problem here): you are using the variable CC which is internally defined as the default C compiler. It's okay because you redefine it, but as your sources seem to be C++ files, why not use the variable CXX, that is internally defined as the C++ compiler ?
Lastly, to make sure your set of files are correctly defined, you can print them with a dummy show target, see here.
show:
#echo "OBJECTSTEST=$(OBJECTSTEST)"
...
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 $#
so I learned what a Makefile was some time ago, created a template Makefile and all I do is copy and alter the same file for every program I'm doing. I changed it a few times, but it's still a very crude Makefile. How should I improve it? This is an example of my current version:
CC = g++
CFLAGS = -std=gnu++0x -m64 -O3 -Wall
IFLAGS = -I/usr/include/igraph
LFLAGS = -ligraph -lgsl -lgslcblas -lm
DFLAGS = -g -pg
# make all
all: run test
# make a fresh compilation from scratch
fresh: clean test
#makes the final executable binary
run: main.o foo1.o foo2.o
$(CC) $(CFLAGS) $(LFLAGS) $^ -o $#
#makes the test executable with debugging and profiling tags
test: test.o foo1.o foo2.o
$(CC) $(DFLAGS) $(CFLAGS) $(LFLAGS) $^ -o $#
#makes teste.o
teste.o: teste.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#makes main.o
main.o: main.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#file foo1
foo1.o: foo1.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
#file foo2
foo2.o: foo2.cpp
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -o $#
clean: clean-test clean-o clean-annoying
clean-test:
rm test-rfv
clean-o:
rm *.o -rfv
clean-annoying:
rm *~ -rfv
Just by visually comparing with other makefiles I saw around in the web, this seems to be not a very bright Makefile. I don't know how they work, but I can see there's significantly less boilerplate and more generic code in them.
Can this can be made better, safer, and easier to particularize for each project?
You don't want to name specific files in a makefile if you can get away with it, and 99% of the time you can. This page shows how to develop a very general makefile. The following is my own makefile, based on that page's info:
SHELL := bash
PROG := pathed.exe
OUTDIRS := bin/debug bin/rel obj/debug obj/rel
PROG_REL := bin/rel/$(PROG)
PROG_DEBUG := bin/debug/$(PROG)
SRCFILES := $(wildcard src/*.cpp)
OBJFILES_REL := $(patsubst src/%.cpp,obj/rel/%.o,$(SRCFILES))
OBJFILES_DEBUG := $(patsubst src/%.cpp,obj/debug/%.o,$(SRCFILES))
DEPFILES := $(patsubst src/%.cpp,obj/%.d,$(SRCFILES))
CFLAGS := -Iinc -Wall -Wextra -MMD -MP
DBFLAGS := -g
RELFLAGS :=
CC := g++
.PHONY: default all testmake debug release clean dirs
default: debug
all: dirs clean debug release
dirs:
#mkdir -p $(OUTDIRS)
debug: $(PROG_DEBUG)
release: $(PROG_REL)
testmake:
#echo OBJFILES_REL = $(OBJFILES_REL)
#echo OBJFILES_DEBUG = $(OBJFILES_DEBUG)
#echo SRCFILES = $(SRCFILES)
#echo DEPFILES = $(DEPFILES)
clean:
rm -f $(OBJFILES_REL) $(OBJFILES_DEBUG) $(DEPFILES) $(PROG)
$(PROG_REL): $(OBJFILES_REL)
$(CC) $(OBJFILES_REL) -o $(PROG_REL)
strip $(PROG_REL)
#echo "---- created release binary ----"
$(PROG_DEBUG): $(OBJFILES_DEBUG)
$(CC) $(OBJFILES_DEBUG) -o $(PROG_DEBUG)
#echo "---- created debug binary ----"
-include $(DEPFILES)
obj/rel/%.o: src/%.cpp
$(CC) $(RELFLAGS) $(CFLAGS) -MF $(patsubst obj/rel/%.o, obj/%.d,$#) -c $< -o $#
obj/debug/%.o: src/%.cpp
$(CC) $(DBFLAGS) $(CFLAGS) -MF $(patsubst obj/debug/%.o, obj/%.d,$#) -c $< -o $#
Do NOT use CC for the C++ compiler. The standard convention is that CC is the C compiler, CXX is the C++ compiler. CFLAGS are flags for the C compiler, CXXFLAGS are flags for the C++ compiler, and CPPFLAGS are flags for the pre-processor (eg, -I or -D flags). Use LDFLAGS for -L flags to the linker, and LDLIBS (or LOADLIBES) for -l flags.
Using the standard conventions is good not just because it makes things easier for others to understand, but also because it allows you to take advantage of implicit rules. If make needs to make a .o file from a .c file and you have not provided a rule, it will use a standard rule and honor the settings of CC, CFLAGS, and CPPFLAGS. If CC is a C++ compiler, things will probably not work.