I am familiar with Gtkmm and C++, but new to Makefiles and am having issues getting mine to actually produce an executable. I know a full Makefile is overkill for the current simplicity of my project, but I am trying to put together a basic template for use in larger projects. I am on Ubuntu 17.10 and running the make command from my "build" folder. Any help would be greatly appreciated!
Terminal Output
pearscol#UBUNTU-1710:~/projects/testprogram/build$ make
g++ -o testprogram `pkg-config --libs gtkmm-3.0`
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In
function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Makefile:19: recipe for target 'testprogram' failed
make: *** [testprogram] Error 1
Source File Structure
- /build
- /build/Makefile
- /src
- /src/main.cpp
/build/Makefile
CXX = g++
CXXFLAGS = `pkg-config gtkmm-3.0 --cflags` -std=c++14 -g -Wall
INCLUDES = -I../include
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
PROGRAM = testprogram
DEPDIR = ../src/
LIBS = `pkg-config --libs gtkmm-3.0`
all: $(PROGRAM)
-include $(OBJS:%.o=$(DEPDIR)/%.Po)
%.o: %.cpp
$(CXX) -MT $# -MD -MP -MF $*.Tpo -c -o $# $(CXXFLAGS) $<
$(PROGRAM): $(OBJS)
$(CXX) -o $(PROGRAM) $(OBJS) $(LIBS)
# DO NOT DELETE THIS LINE -- make depend needs it
/src/main.cpp
#include <gtkmm.h>
int main(int argc, char *argv[]) {
Glib::RefPtr<Gtk::Application> app =
Gtk::Application::create(argc, argv, "testprogram");
Gtk::Window window;
window.set_default_size(400, 200);
window.set_title("Tutorial");
return app->run(window);
}
If you want to specify the source files using a $(wildcard ...) function,
then replace:
SRCS = $(wildcard *.cpp)
with:
SRCS = $(wildcard src/*.cpp)
because src is where the *.cpp files are, with respect to the build directory.
To place the object files in the build directory, then replace:
OBJS = $(SRCS:.cpp=.o)
with:
$(notdir $(SRCS:.cpp=.o))
Finally do one of the following:
Either replace the pattern rule:
%.o: %.cpp
with:
%.o: src/%.cpp
Or, leave the pattern rule as it is and add:
VPATH := src
to the variable settings at the top of your makefile. See
VPATH.
Asides
You default target all is a phony target: you are never going to make
a file called all, and you assume no such file will ever exist. Better specify it as a .PHONY target.
For defining variables, use simple expansion - VAR := val - rather than
recursive expansion - VAR = val - unless recursive expansion is needed, which it isn't in your makefile.
Your makefile lacks a clean target for
deleting all make-prodicts and restoring the build directory to its pristine
state. It is standard to provide this phony target.
As far as I can tell,
$(CXX) -o $(PROGRAM) $(OBJS) $(LIBS)
results in
g++ -o testprogram `pkg-config --libs gtkmm-3.0`
because $(OBJS) is empty, because $(SRCS) is empty, because *.cpp matches no files, because your build directory contains no .cpp files.
Related
I can compile the project just fine if I run the project by hand with g++ source/* -lSDL2 -o bin/fly_fishing. When I do run make, I get
mkdir -p bin
g++ -lSDL2 -o bin/fly_fishing
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x17): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [Makefile:20: bin/fly_fishing] Error 1
Which tells me that it's not populating from $^ for linking. So what have I missed here? Here's the makefile for reference.
SRC_DIR := source
OBJ_DIR := objects
BIN_DIR := bin
EXE := $(BIN_DIR)/fly_fishing
SRC := $(wildcard $(SRC_DIR)/*.c)
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
CXXFLAGS := -Wall
#CFLAGS := -Wall
LDLIBS := -lSDL2a
LDFLAGS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CXX) -c $(CXXFLAGS) $(CFLAGS) $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
Which tells me that it's not populating from $^ for linking.
That seems unlikely. Much more likely would be that $^ expands to nothing. Which would be the case if $(OBJ) expands to nothing. Which seems plausible because I don't see any corresponding objects being built (though perhaps you've omitted that, or they were built on a previous run). And $(OBJ) expanding to nothing implies that $(SRC) expands to nothing.
So what have I missed here?
That $(SRC) expands to nothing is not inconsistent with the data presented. I observe that the manual compilation command you present is
g++ source/* -lSDL2 -o bin/fly_fishing
That does seem to suggest that there are indeed source files in source/, but do they match the pattern source/*.c? Since you're compiling with g++, I bet not. It would be highly unconventional to name C++ source files to end with .c, and surely you would not attempt to compile C source files with a C++ compiler. I infer, then, that your source files are all named with .cpp, or maybe .cc or .C, all of which forms are conventions for C++ source names.
If all your source names follow one or another of those patterns then indeed, this ...
SRC := $(wildcard $(SRC_DIR)/*.c)
... will result in $(SRC) being empty.
I have created simple C++ Makefile Eclipse project in Ubuntu. Eclipse has created default Makefile:
PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
OBJS = cpp_makefile.o
ifeq ($(BUILD_MODE),debug)
CFLAGS += -g
else ifeq ($(BUILD_MODE),run)
CFLAGS += -O2
else ifeq ($(BUILD_MODE),linuxtools)
CFLAGS += -g -pg -fprofile-arcs -ftest-coverage
LDFLAGS += -pg -fprofile-arcs -ftest-coverage
else
$(error Build mode $(BUILD_MODE) not supported by this Makefile)
endif
all: cpp_makefile
cpp_makefile: $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
%.o: $(PROJECT_ROOT)%.cpp
$(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) -o $# $<
%.o: $(PROJECT_ROOT)%.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
clean:
rm -fr cpp_makefile $(OBJS)
Everything goes fine in case I have only one source file. In case I create class TestMe with it's header and cpp file and add include header to main cpp file build fails. Looks like system can't find TestMe.cpp.
Error:
Building in: /home/a/cpp-workspace2/cpp_makefile/build/default
make -f ../../Makefile
g++ -c -O2 -o cpp_makefile.o /home/a/cpp-workspace2/cpp_makefile/cpp_makefile.cpp
g++ -o cpp_makefile cpp_makefile.o
/usr/bin/ld: cpp_makefile.o: in function `main':
cpp_makefile.cpp:(.text.startup+0x1c): undefined reference to `TestMe::TestMe()'
collect2: error: ld returned 1 exit status
make: *** [../../Makefile:19: cpp_makefile] Error 1
Build complete (3 errors, 0 warnings): /home/a/cpp-workspace2/cpp_makefile/build/default
In case I use same source in Eclipse C++ Managed build project everything goes fine. How to solve this problem in right way In Eclipse Makefile project?
cpp_makefile.cpp
#include "TestMe.h"
int main(int argc, char **argv)
{
TestMe testMe = TestMe();
return 0;
}
TestMe.h:
class TestMe {
public:
TestMe();
virtual ~TestMe(){};
};
TestMe.cpp:
#include "TestMe.h"
TestMe::TestMe() {
}
Eclipse will create a default Makefile for you, but it does not manage the Makefile(s) in a makefile-based project. It cannot really do so while also allowing you to make your own makefile changes or supporting makefiles it did not generate itself. If you want the build configuration to be completely managed by Eclipse then you should choose a different project type.
With a makefile-based project, then, you need to make appropriate changes to the Makefile yourself when you add sources to the project. In this particular case, it looks like you should change
OBJS = cpp_makefile.o
to
OBJS = cpp_makefile.o TestMe.o
I have a file ./src/test.cpp:
#include "test.h"
void Hi() {
std::cout << "Hi, indeed..." << std::endl;
}
test.h is located in ./include folder.
This is my makefile:
CC = g++
CFLAGS = -Wall
INCLUDES = -I./include
SRCS = $(shell find ./src/ -name '*.cpp')
.PHONY: clean depend
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
release: $(OBJS)
$(CC) $(CFLAGS) -o app_name $(OBJS)
VPATH = ./src
../%.o: %.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c $*.cpp
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ > ./.depend;
include .depend
As a result I get an error:
g++ -c -o test.o ./src/test.cpp
./src/test.cpp:1:18: fatal error: test.h: No such file or directory
compilation terminated.
<builtin>: recipe for target 'test.o' failed
make: *** [test.o] Error 1
Also the file .depend is completely empty.
How to resolve the issue? The makefile is in root directory:
./
makefile
./src/
test.cpp
main.cpp
./include/
test.h
What G.M. is trying to say is that you have defined a pattern rule that knows how to build a target matching a pattern ../%.o. But, when you ask make to build objects, they are of the form ./xxx.o; e.g., after:
SRCS = $(shell find ./src/ -name '*.cpp')
suppose SRCS contains ./src/foo.cpp. Now after this:
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
OBJS will contain the value ./foo.o (by the way, a simpler way to get this behavior is to use the patsubst function: $(patsubst ./src/%.cpp,./%.o,$(SRCS))).
So, make will try to build the file ./foo.o. Since there's no explicit rule for this it will look for an implicit rule.
It sees your pattern rule, but that says how to build ../%.o which does not match the object file make wants to build ./foo.o, so your rule is ignored.
Then make will go look for some other implicit rules and it will find the built-in rule that knows how to build a .o file from a .cpp file, and it will use that. That rule doesn't use your variable $(INCLUDES), so your compile fails.
You need to either fix your OBJS settings to create filenames like ../foo.o instead of ./foo.o, if you really want your object files to appear in the parent directory, or else change your pattern rule to build %.o not ../%.o.
I have the makefile given below. When I do make I get the following error
cc -c -o timing.o timing.c
test_c.c:5:17: fatal error: test.h: No such file or directory
#include "test.h"
I have manually verfied that test.h is present in ../include path. I am not sure why this is not finding the header file.It would be great if someone could help.Also I would expect g++ instead of cc
# Makefile template for shared library
CXX = g++ # C++ compiler
CXXFLAGS = -fPIC -Wall -Wextra -O2 -g -I../include #CXX flags
LDFLAGS = -lboost_system -shared # linking flags
RM = rm -f # rm command
TARGET_LIB = libtest.a # target lib
C_SRCS := test_a.c test_b.c
CPP_SRCS := test_c.cpp test_d.cpp
OBJS := $(C_SRCS:.c=.o) $(CPP_SRCS:.cpp=.o)
.PHONY: all
all: ${TARGET_LIB}
$(TARGET_LIB): $(OBJS)
$(CXX) $(CXXFLAGS) ${LDFLAGS} -o $# $^
.PHONY: clean
clean:
-${RM} ${TARGET_LIB} ${OBJS}
~
You have not written a rule for building timing.o from timing.c, so Make uses the default rule it has for that.
But that rule uses CFLAGS, not CXXFLAGS. The CXXFLAGS variable appears in the rule for building object files from C++ sources.
So modify CFLAGS instead of CXXFLAGS, and it should work.
How can I link jsoncpp with a C++ program using g++? I tried:
g++ -o program program.cpp -L/path/to/library/files -ljsoncpp, -ljson, -llibjsoncpp
but g++ keeps saying:
/usr/bin/ld: cannot find -lsomething
You could also try using the new Amalgamated version of jsoncpp, which is new as of version 0.6.0.
The Amalgamated version allows you to use jsoncpp by adding just one directory with a couple of header files and one .cpp file to your project. You then can directly compile jsoncpp into your program with no worries about having to link to any jsoncpp libraries.
Look in /path/to/library/files to see what your *.a file is really named. On my system, I link with:
-ljson_linux-gcc-4.4.3_libmt
Some libraries will create a link from lib<name>.a to lib<name>-<version>.a for you, but I don't think that jsoncpp does this automatically. Therefore, you need to specify the complete name when linking.
You basically need to tell the path and the library.
jsoncpp library has pkg-config and you can use the command
`pkg-config --cflags path/to/jsoncpp/build/pkg-config/jsoncpp.pc`
for the include path and
`pkg-config --libs ../jsoncpp/build/pkg-config/jsoncpp.pc`
for linking (when running the command with g++ use the ). To see the single commands which is -L/libraryPath -ljsoncpp) run the commands above in the terminal without the ``.
It is easier to use this commands in a Makefile. As example my Makefile is:
CXX = g++
CXXFLAGS = -std=c++11
INC_PATH = `pkg-config --cflags ../jsoncpp/build/pkg-config/jsoncpp.pc`
LIBS = `pkg-config --libs ../jsoncpp/build/pkg-config/jsoncpp.pc`
SOURCES := $(wildcard *.cpp)
OBJDIR=obj
OBJECTS := $(patsubst %.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,$(OBJDIR)/%.d,$(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: yourProjectExecutableName
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
yourProjectExecutableName: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $# $(LIBS)
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.cpp Makefile $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) -MMD -MP -c $< -o $#
and then in the directory of the file I run make. The final command(s) will be printed out in the Terminal