I have read other questions asking similar things, alas I am still confused.
This is my current Makefile:
CC = g++
EXEFILE = template
IFLAGS= -I/usr/include/freetype2 -I../Camera
LFLAGS= -L/usr/lib/nvidia-375 -L/usr/local/lib -L/usr/include/GL -L/usr/local/include/freetype2 -L/usr/local/lib/
LIBS = -lglfw -lGL -lGLU -lOpenGL -lGLEW -pthread -lfreetype
SRC=*.cpp
DEPS=*.h
$(EXEFILE):
$(CC) -std=c++11 -o $(EXEFILE) -Wall -Wno-comment $(SRC) $(IFLAGS) $(LFLAGS) $(LIBS)
all: run clean
run: $(EXEFILE)
./$(EXEFILE)
clean:
rm $(EXEFILE)
Right now all of my .h files and .cpp files are on the working directory, and everything compiles and runs just fine. My issue is that I have already a large number of files, and it is getting quite messy. I want to create multiple directories (and maybe even directories inside these directories) to organize my files. But as soon as I move a header file and it's corresponding cpp file(s) to a directory inside of the current directory the compiler doesn't know how to link them anymore.
How do I tell my make file to compile and link everything under the current root?
Alternatively, is there a ELI5 guide to makefile syntax?
The quickest way to solve your problem is to add SRC and DEPS the files contains in all your sub-directories, something like:
SRC=*.cpp src/*.cpp
DEPS=*.h inc/*.h
Now you may consider writing a rule to first compile every file in a separate directory:
# Group compilation option
CXXFLAGS := -std=c++11 -Wall -Wno-comment $(IFLAGS)
# A directory to store object files (.o)
ODIR := ./objects
# Read this ugly line from the end:
# - grep all the .cpp files in SRC with wildcard
# - add the prefix $(ODIR) to all the file names with addprefix
# - replace .cpp in .o with patsubst
OBJS := $(patsubst %.cpp,%.o,$(addprefix $(ODIR)/,$(wildcard $(SRC)/*.cpp)))
# Compile all the files in object files
# $# refers to the rule name, here $(ODIR)/the_current_file.o
# $< refers to first prerequisite, here $(SRC)/the_current_file.cpp
$(ODIR)/%.o:$(SRC)/%.cpp $(DEPS)/%.h
$(CXX) $(CXXFLAGS) -c -o $# $<
# Finally link everything in the executable
# $^ refers to ALL the prerequisites
$(EXEFILE): $(OBJS)
$(CXX) $(CXXFLAGS) -o $# $^ $(LFLAGS) $(LIBS)
I found a solution, that, to my tastes seems elegant, or at least easy to trace using the wildcard operator. Here is my current makefile:
EXEFILE := $(shell basename $(CURDIR))
DIRECTORIES = $(filter-out ./ ./.%, $(shell find ./ -maxdepth 10 -type d))
IFLAGS= -I/usr/include/freetype2
LOCAL_I_DIRS =$(addprefix -I./, $(DIRECTORIES))
LFLAGS= -L/usr/lib/nvidia-375 -L/usr/local/lib -L/usr/include/GL -L/usr/local/include/freetype2 -L/usr/local/lib/
LIBS = -lglfw -lGL -lGLU -lOpenGL -lGLEW -pthread -lfreetype
SRC := $(wildcard *.cpp) $(wildcard **/*.cpp)
$(EXEFILE): $(EXEFILE).cpp
g++ -std=c++11 -o $(EXEFILE) -Wall -Wno-comment $(SRC) $(IFLAGS) $(LOCAL_I_DIRS) $(LFLAGS) $(LIBS)
all: run clean
run: $(EXEFILE)
./$(EXEFILE)
clean:
rm $(EXEFILE)
print-%: ; #echo $* = $($*)
So I get all directories up to depth 10. I then take out the current root (./) and any hidden directory (./.) leaving me with standard subdirectories stored under "DIRECTORIES", I then add -I to every directory to make it an include directory and store them in LOCAL_I_DIRS
So I can now create as many subdirectories as needed (up to 10 levels) and the compiler will be happy.
Related
I am quite new to Make. I am attempting to write a Makefile to build a medium-sized Linux C/C++ application as below.
Making a simple Makefile by having all source files in one location and explicitly listing the source files works ok for me but I would like it to be more generic.
I have all my source files (C and C++) in the src folder in different subdirectories. I have header files inside an inc and inc/common folder, and then libs inside a lib folder.
The Makefile is run on the same level :
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
CXX := /bin/arm-linux-gnueabi-g++
EXE := $(BIN_DIR)/runfile
SRC := $(shell find $(SRC_DIR) -name *.cpp -or -name *.c)
OBJ := $(patsubst $(SRC_DIR)/%,$(OBJ_DIR)/%,$(addsuffix .o,$(basename $(SRC))))
CPPFLAGS := -Iinc -Iinc/common -MMD -MP
CXXFLAGS := -std=c++11 -Wall
LDFLAGS := -Llib
LDLIBS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
I get lots of errors such as below when I run it, including problems opening dependency files. I think i'm almost there, but can't see my error exactly :
compilation terminated.
/bin/arm-linux-gnueabi-g++ -Iinc -Iinc/common -MMD -MP -std=c++11 -Wall -c -o obj/main.d.o
cc -Llib obj/main.d.o -o obj/main.d
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: error adding symbols: file in wrong format
I don't see how the output you show can be generated from the makefile you show here but anyway.
This is not right:
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
A pattern rule is a template that tells make "if you want to build a target that matches this pattern, then you can build it from the prerequisites that match this pattern".
Here you are listing ALL your source files as a prerequisite for EVERY object file. Suppose SRC is set to foo.c bar.c biz.c baz.c, then this expands to:
obj/%.o : foo.c bar.c biz.c baz.c | obj
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
You're telling make that every single .o target depends on ALL the source files, not just the one for that object file. Further, the automatic variable $< always expands to the first prerequisite, which here will always be foo.c. So, you're compiling foo.c four times, creating each of the object files.
The very first important rule when debugging makefiles is to look carefully at the output (command lines) that make prints. If they are not right, then your makefile is not right. If you do that you'll see all the compile lines are compiling the same source, like:
g++ -c foo.c -o obj/foo.o
g++ -c foo.c -o obj/bar.o
g++ -c foo.c -o obj/biz.o
g++ -c foo.c -o obj/baz.o
That clearly cannot work and it's why you get link errors trying to link together all these object files: they all have the same content.
You need this:
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
which tells make how to build an object file from a single source file.
You also need to create the actual output directory that the object file will go into. Just creating $(OBJ_DIR) is not enough, if the object file appears in a subdirectory.
# Compiler to use
CC = g++
# flags to pass compiler
CFLAGS = -ggdb3 -O0 -std=c99 -Wall -Werror
# Name for the executable
EXE = test
# space-separated list of header files
HDRS = simplegui.h globals.h timer.h tile.h gamesprites.h
# space-separated list of libraries, if any,
# each of which should be prefixed with -l
LIBS = -lSDLmain -lSDL -lSDL_image -lSDL_mixer -lSDL_ttf
# space-separated list of source files
SRCS = main.cpp gamesprites.cpp simplegui.cpp tile.cpp timer.cpp
# automatically generated list of object files
OBJS = $(SRCS:.cpp=.o)
# default target
$(EXE): $(OBJS) $(HDRS) Makefile
$(CC) -IC:\SDL-1.2.15\include -LC:\SDL-1.2.15\lib $(CFLAGS) -o $# $(OBJS) $(LIBS)
# dependencies
$(OBJS): $(HDRS) Makefile
It does not work with the makefile. My other approach was:
g++ -IC:\SDL-1.2.15\include -o test main.cpp -LC:\SDL-1.2.15\lib -lSDLmain -lSDL -lSDL_image -lSDL_ttf -lSDL_mixer
It worked initially, I don't know what I changed, no it doesn't work, it keeps telling that it does not find the directory. Previously it did find the directory, but yelled at me about dependencies. I am frustrated cannot find an answer. How do I compile a program that has many .h .cpp files, and that has .h files in other directories? Neither approach I showed, worked... (However I CAN compile the code using my IDE that is configured, but I don't remember how, and I will format my pc soon.
EDIT:
EDIT: Changed \ to /, now I have this:
Not the best solution, but I was a fool. I had "redundant" code, it got fixed when I wrote the following Makefile:
# Compilador a utilizar
CC = g++
# Libraries
LIBS = -lmingw32 -lSDLmain -lSDL -lSDL_image -lSDL_ttf -lSDL_mixer
# Codigo
SRC = main.cpp timer.cpp simplegui.cpp gamesprites.cpp
# Object files
OBJS = $(SRC:.cpp=.o)
# Nombre del ejecutable
EXE = juego_naves
all: $(SRC) $(EXE)
$(OBJS):
g++ -IC:/SDL-1.2.15/include -c $(SRC)
$(EXE): $(OBJS)
g++ -LC:/SDL-1.2.15/lib -o $# $(OBJS) $(LIBS)
clean:
rm -rf *.o $(EXE).exe
I am trying to work through the following http://www.cs.columbia.edu/~keenan/Projects/DGPDEC/paper.pdf. The following source files are used to illustrate what is going on https://github.com/dgpdec/course. Now I cannot get it to work. Here is what I tried:
First I went into the folder 'basecode', edited the Makefile to have the right include and library paths. Then I want to make but it gives me the error
'ostream’ in namespace ‘std’ does not name a type
I looked for this error online but I could not find a solution to the problem. In the included file libddg_userguide.pdf it says that I should edit the Makefile in root libddg folder but I don't know which folder that is. I am sorry for the kind of nooby question but I am really stuck and have been trying for a long time. Here is the Makefile I used (in the Basecode folder) for reference:
##########################################################################################
# Specify library locations here (add or remove "#" marks to comment/uncomment lines for your platform)
# Linux
DDG_INCLUDE_PATH = -I/usr/include/ -I/usr/local/include -I/usr/include/suitesparse
DDG_LIBRARY_PATH = -L/usr/lib -L/usr/local/lib
DDG_BLAS_LIBS = -llapack -lblas -lgfortran
DDG_SUITESPARSE_LIBS = -lspqr -lcholmod -lmetis -lcolamd -lccolamd -lcamd -lamd -lm
DDG_OPENGL_LIBS = -lglut -lGL -lGLU -lX11
########################################################################################
TARGET = ddg
CC = g++
LD = g++
CFLAGS = -O3 -Wall -Werror -ansi -pedantic $(DDG_INCLUDE_PATH) -I./include -I./src
LFLAGS = -O3 -Wall -Werror -ansi -pedantic $(DDG_LIBRARY_PATH)
LIBS = $(DDG_OPENGL_LIBS) $(DDG_SUITESPARSE_LIBS) $(DDG_BLAS_LIBS)
########################################################################################
## !! Do not edit below this line
HEADERS := $(wildcard include/*.h)
SOURCES := $(wildcard src/*.cpp)
OBJECTS := $(addprefix obj/,$(notdir $(SOURCES:.cpp=.o)))
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LD) $(OBJECTS) -o $(TARGET) $(CFLAGS) $(LFLAGS) $(LIBS)
obj/%.o: src/%.cpp ${HEADERS}
$(CC) -c $< -o $# $(CFLAGS)
clean:
rm -f $(OBJECTS)
rm -f $(TARGET)
rm -f $(TARGET).exe
Thanks in advance for any help!
It means there is a bug in the code: a header's missing because someone made an assumption.
Your particular toolchain does not satisfy that assumption.
Find the problematic file (you didn't say which it is) and add #include <ostream> to it.
(course/Connection/include/DenseMatrix.h appears to be one such file; there may be others.)
N.B. I must say that, despite the bug, overall this is incredibly good C++ code for a University course. I'm impressed.
I have been creating a library. When I compile it as a static library, it works fine. Now I want to turn it into a shared library. The library is created and in the proper place, but when I try to compile the client code, the linking phase says that it can't find the library.
I already tried to rename it to al or dylib but that doesn't help either. When I put the -v flag on the linking, I can see that my library path is there. I also tried different paths. I used a relative path, but even with a full path it doesn't find it.
The Makefile from the library:
.SUFFIXES:
.SUFFIXES: .o .cpp
.SUFFIXES: .o .d
CC := g++
LNK:= g++
CXXFLAGS_RELEASE = -fPIC -shared -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -fPIC -shared -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
HDIR:= include
INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
CPP_FILES := propertyfile/propertyfile.cpp \
propertyfile/propertyitem.cpp \
propertyfile/propertyfactory.cpp \
helper/string_helper.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
LIBS:=
TARGET:= libsupport.so
all: $(TARGET)
$(TARGET): $(OBJ)
$(LNK) -o $(TARGET) $(OBJ) -shared
#cp $(TARGET) ../lib
#cp -r include ..
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
And here is the Makefile for the application:
.SUFFIXES:
.SUFFIXES: .o .cpp
CC := g++
LD := g++
CXXFLAGS_RELEASE = -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
INCLUDE_PATHS:= -Iinclude -I../include
LIBS:= -L /cygdrive/d/src/c/lib -lsupport
CPP_FILES := nohupshd.cpp \
daemon.cpp \
task.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
TARGET:= nohupshd
all: $(TARGET)
$(TARGET): $(OBJ)
$(LD) -o $(TARGET) $(OBJ) $(LIBS)
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
After some experimenting I found a solution on how to compile a shared library under cygwin.
Apparently the compiler is looking for a DLL file even though it is inside cygwin. so the first step is to add your path, where the library is going to be to the PATH variable.
export PATH=$PATH:/cygdrive/d/src/c/lib
Apparently when linking against a shared library, the linker seems to look for a DLL file by default. I don't know why, because inside cygwin I would expect it to look for a .so file just like on other UNIX systems.
However, there are two solutions to this, which both work.
First, you can create a link to your .so library with the name .dll
ln -s /cygdrive/d/src/lib/libsupport.so libsupport.dll
In this case the makefile doesn't have to be changed and -lsupport will find the library while linking. I prefer this solution.
Second, you can specify the linker option with the full name.
LIBS:= -L /cygdrive/d/src/c/lib -l:libsupport.so
then you don't have to create a link.
So the crucial thing seems to be that the shared library must be in the PATH under cygwin. Using LD_LIBRARY_PATH doesn't help in that case as you can link the executable, but when trying to run it, it will not find it.
ldd nohupshd.exe
libsupport.so => not found
UPDATE: For some reason when I checked with ldd, my library was suddenly gone from the list. I found out that cygwin uses the name to differentiate between MS Windows and Unix shared libraries. So in order to make it work, the name of the library must be cyg.so to make it work, otherwise the exectuable seems to be some Windows build. In this case you don't need to create the link named x.dll as the shared library stays inside the Unix environment.
$(LNK) -o cyg$(TARGET).so $(OBJ) -shared
When using eclipse for debugging, the path to the shared library must also be in the windows path environment variable. Otherwise the debug session immediately terminates without an error.
I have looked, and found a few answers that look like they're related to this question, but none seem to help.
It is the usual story - I have a folder of .hpp and .cpp files which I'd like to compile to .o files, and then only have files recompiled when files they depend on have been changed.
My current makefile is:
SRCS = $(shell find ../Includes/ -name "*.cpp")
DEPS = $(SRCS:.cpp=.d)
OBJS = $(SRCS:.cpp=.o)
all: $(DEPS) $(OBJS)
# Create the dependency files
%.d : %.cpp
clang++ -MM $< -o $# -c -std=c++11
# Include the dependency files
include $(DEPS)
# Compile the source files
%.o : %.cpp
clang++ -c -Wall -std=c++11 $< -o $#
I've run this a few times (so the dependency files exist before I run make, and should definitely exist when I include them). I've also tried adding %.d to the dependancies of %.o.
Basically all that happens at the moment is that 'touch'ing a .cpp causes the .o and .d files to be regenerated, and touching a .hpp file (that is listed in the .d files for other files) does nothing.
Example Dependency File:
SomeFile.o : ../Includes/SomeFile.cpp \
../Includes/SomeFile.hpp ../Includes/SomeOtherFile.hpp
Apart from the path issue, I find it more natural to create the dependencies along the way, i.e. with the -MD or -MMD flags. That way you don't need a rule to update the dependency file.
CPPFLAGS += -MMD
TARGET := hello
.DEFAULT: all
all: $(TARGET)
SRCS := $(shell find . -type f -name "*.cpp")
OBJS := $(SRCS:.cpp=.o)
DEPS := $(SRCS:.cpp=.d)
hello: $(OBJS)
$(LINK.cc) -o $# $^
-include $(DEPS)
It turns out that I was creating rules for:
SomeFile.o : ...
Whereas I needed a rule for:
../Includes/SomeFile.o : ...
Thanks to NovaDenizen who set me on the right path.