So, I am creating a small testing library for some simple tasks. I use the self-registration method to define the tests, but I am getting a segfault that I don't understand where is coming from. My project looks like this
Lib
|
|__include
| |__lib.hpp
|__src
| |__lib.cpp
|__examples
| |__example.cpp
|__Makefile
This is my .hpp. Please, ignore the public maps, as I am well aware that they should not be public in the final version.
#include <string>
#include <map>
#include <functional>
#define TEST(name, result_var_name, short_result_var_name, explanation_var) \
bool test_##name(std::string result_var_name); \
static bool test_##name##_registered = TestFactory::getInstance()->Register(#name, &test_##name, #result_var_name, #short_result_var_name); \
static bool test_##name##_description = TestFactory::getInstance()->RegisterExplanation(#result_var_name, explanation_var); \
bool test_##name(std::string result_var_name)
#define RESULT_LONG(result_var_name, result) \
TestFactory::getInstance()->RegisterResult(result_var_name, result);
#define RESULT_SHORT(result_var_name, result) \
TestFactory::getInstance()->RegisterResult(TestFactory::getInstance()->short_to_long_param[result_var_name], result);
class TestFactory {
private:
TestFactory();
public:
std::map<std::string, std::function<bool(std::string)>> Tests;
std::map<std::string, std::string> short_to_long_param;
std::map<std::string, std::string> param_to_testName;
std::map<std::string, std::string> testName_to_result;
std::map<std::string, std::string> param_to_explanation;
static TestFactory* getInstance();
bool Register(std::string name, std::function<bool(std::string)> func, std::string long_param, std::string short_param);
bool RegisterResult(std::string result_var_name, std::string result);
bool RegisterExplanation(std::string result_var_name, std::string explanation);
};
And this is my example file:
#include "lib.hpp"
#include <iostream>
TEST(testing_test, foo, f, "This is a description of foo"){
try
{
return foo == "example";
}
catch(const std::exception& e)
{
std::cerr << "Exception thrown in testing_test: " << e.what() << '\n';
return false;
}
};
It was working when I built everything together manually, but then I decided to create the static library and compile the example separately, it started segfaulting.
This is what my Makefile looks like (as you can see, I am not a pro Makefile user, please be gentle)
LIBNAME := libtest.a
CXX := g++
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
LIBRARIES := -ltest
EXECUTABLE := example
LIBRARY_SOURCES := $(SRC)/lib.o
EXECUTABLE_SOURCES := examples/example.o
CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb -I$(INCLUDE)
all: $(BIN)/$(EXECUTABLE)
run: clean all
clear
./$(BIN)/$(EXECUTABLE)
$(LIB)/$(LIBNAME): $(LIBRARY_SOURCES)
ar rcs $# $^
$(BIN)/$(EXECUTABLE): $(LIB)/$(LIBNAME)
$(CXX) $(CXXFLAGS) -I$(INCLUDE) -L$(LIB) $(EXECUTABLE_SOURCES) -o $# $(LIBRARIES)
clean:
-rm -rf $(BIN)/*
-rm -rf $(LIB)/*
Initially, I had all static methods and variables, and I changed them to a singleton to avoid initialisation and memory issues. However, I am getting a segfault in the Register method when it is trying to access the Test map. Any ideas?
EDIT:
So, I reproduced the compilation manually like so:
g++ -Iinclude -std=c++17 -c src/mxIntegration.cpp -o lib/manual_object_file.o
ar rvs lib/manual_library.a lib/manual_object_file.o
g++ -Iinclude examples/main.cpp lib/manual_object_file.o -o bin/manual_test_linking
The resulting executable is running. I'm going to try to catch any difference in the process now.
So, after careful analysis, it seems like the example.o file was not being generated successfully. I basically added them as a requirement for the executable recipe, and updated the clean recipe. I believe the .a file could also be passed as an input to the final g++ command.
LIBNAME := libIntegration.a
CXX := g++
BIN := bin
SRC := src
INCLUDE := include
LIB := lib
LIBRARIES := -l:$(LIBNAME)
EXECUTABLE := main
LIBRARY_SOURCES := $(SRC)/mxIntegration.o
EXECUTABLE_SOURCES := examples/main.o
CXXFLAGS := -Wall -Wextra -std=c++17 -ggdb -I$(INCLUDE)
all: $(BIN)/$(EXECUTABLE)
run: clean all
clear
./$(BIN)/$(EXECUTABLE)
$(LIB)/$(LIBNAME): $(LIBRARY_SOURCES)
ar rvs $# $^
$(BIN)/$(EXECUTABLE): $(LIB)/$(LIBNAME) $(EXECUTABLE_SOURCES)
$(CXX) $(CXXFLAGS) -L$(LIB) $(EXECUTABLE_SOURCES) -o $# $(LIBRARIES)
clean:
-rm -rf $(BIN)/*
-rm -rf $(LIB)/*
-rm -rf **/*.o
Related
I've looked at several posts of the same questions on here and as far as I've figured I've done what they said to do. However, I still get a "undefined reference to `cmb::functionA()'" warning.
I have the header:
//combine.h
#ifndef COMBINE_H
#define COMBINE_H
namespace cmb
{
void functionA();
}
#endif
Function source file:
// combine.cc
#include <iostream>
#include "combine.h"
using namespace std;
namespace cmb
{
void functionA()
{
cout << "print something\n";
}
}
And main:
//main.cc
#include "combine.h"
using namespace std;
using namespace cmd;
int main(int argc, char *argv[])
{
functionA();
}
It is now working when compiling manually (g++ -o Test *.cc -Wall --std=c++17) but using make still gives me the same error. I really don't understand make files so any help would be appreciated.
makefile:
CXX := g++
CXXFLAGS += -Wall -std=c++17
LIBSRCS = $(filter-out main.cc,$(shell find -name \*.cc))
LIBOBJS = $(patsubst %.cc,%.o,$(LIBSRCS))
main: main.o combine.o libproject.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $# $<
$(LIBOBJS): %.o: %.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<
libproject.a: $(LIBOBJS)
ar rcs $# $^
clean:
rm -f libproject.a $(LIBOBJS)
.PHONY: clean
I just use make main in terminal.
You must add combine.o after main: in the makefile.
Since you use a library, you need to tell the linker to use it (LDFLAGS), and it should be after the main in g++ command. As in previous comments, the using namespace cmd needed to be changed to cmb
This one worked for me:
CXX := g++
CXXFLAGS += -Wall -std=c++17
LIBSRCS = $(filter-out ./main.cc,$(shell find -name \*.cc))
LIBOBJS = $(patsubst %.cc,%.o,$(LIBSRCS))
LDFLAGS += -L. -lproject
main: main.o libproject.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# $< $(LDFLAGS)
libproject.a: $(LIBOBJS)
ar rcs $# $^
.PHONY: clean
clean:
rm -f libproject.a $(LIBOBJS) main main.o
I also needed to add ./ in filtering out main.cc
Example run:
jontte#jontte-Latitude-E5420:~/Temp/maketest$ make
g++ -Wall -std=c++17 -c -o main.o main.cc
g++ -Wall -std=c++17 -c -o combine.o combine.cc
ar rcs libproject.a combine.o
g++ -Wall -std=c++17 -o main main.o -L. -lproject
jontte#jontte-Latitude-E5420:~/Temp/maketest$ ./main
print something
jontte#jontte-Latitude-E5420:~/Temp/maketest$ make clean
rm -f libproject.a ./combine.o main main.o
jontte#jontte-Latitude-E5420:~/Temp/maketest$
I execute with debugger this code in codeblocks but the breakpoints are not respected. Why is this? The problem persists if I change the location of the breakpoint. When running the script with the default Codeblocks makefile everything debiggs ok. When changing to the makefile below the debugger sees the breakpoints only when dleting the "typedef unsigned char byte;".
#include <iostream>
using namespace std;
typedef unsigned char byte;
int main(const int argc, const char *const argv[])
{
return 0;
}
I use this makefile:
CXX = g++
CXXFLAGS = -c -Wall -Wextra -Werror
LDFLAGS = -lgmp -lsodium -lssl -lcrypto -lgmpxx
SRC = $(wildcard *.cpp )
HDR = $(wildcard *.h )
OBJ = $(SRC) $(SRC :.cpp =.o )
all : Release
Debug : CXXFLAGS +=-g
Debug : test
Release : test
test : $(OBJ)
$(CXX) -o $# $^ $(LDFLAGS)
%.o : %.cpp $(HDR)
$(CXX) $(CXXFLAGS) $< -o $#
clean :
rm -f $(OBJ) test
The code runs without errors, only that I can't use the debugger.
Should I add in the makefile sth. about typedef command?
My C++ program consists of three files:
two source files 'main.cpp' and 'hellolib.cpp'
a header file 'hellolib.h'
I am creating a makefile for this program. For my assignment I need one target ('hello') that compiles all source files in an executable.
Another target ('obj') should compile all '.cpp' files into objects and link them together in an executable.
When running make I prefer the object files to be created in a seperate folder called 'bin'. The source files are would be in a folder called 'src'. These folders are siblings, the makefile is in it's parent folder.
My makefile works fine but I wish two combine the two targets 'bin/main.o' and 'bin/hellolib.o' into one to reduce the amount of rules, especially for later when I am dealing with more source files.
I imagined the replacement would look something like this, but it doesn't seem to work.
It gives me the error: "*** No rule ot make target 'bin/main.o',
needed by 'obj'. Stop.
bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Working Makefile:
CC = g++
SOURCES = ./src/main.cpp \
./src/hellolib.cpp
OBJECTS = ./bin/main.o \
./bin/hellolib.o
hello : $(SOURCES)
$(CC) -o $# $^
obj : $(OBJECTS)
$(CC) -o $# $^
bin/main.o : src/main.cpp
$(CC) -c $< -o $#
bin/hellolib.o : src/hellolib.cpp
$(CC) -c $< -o $#
clean:
#rm -rf hello obj bin/*.o
main.cpp:
#include "hellolib.h"
int main() {
Hello h("Name");
h.Print();
return 0;
}
hellolib.cpp
#include "hellolib.h"
#include <iostream>
Hello::Hello(std::string name) {
if (name.empty()) {
cout << "Name is not valid!";
return;
}
_name = name;
}
void Hello::Print() {
cout << "Hello " << _name << endl;
}
hellolib.h
#ifndef HELLO_LIB_H
#define HELLO_LIB_H
#include <string>
using namespace std;
class Hello {
std::string _name;
public:
Hello(std::string name);
void Print();
};
#endif
You need to change:
OBJECTS = ./bin/main.o \
./bin/hellolib.o
to:
OBJECTS = bin/main.o \
bin/hellolib.o
(Removing leading "./"). Either that, or change your pattern rule to include the leading "./":
./bin/%.o : src/%.cpp
$(CC) -c $< -o $#
Make rule matching uses text matching. It's not based on filenames, so "./././foo" and "foo" are not the same thing.
Personally I recommend rewriting like this:
SOURCES = src/main.cpp \
src/hellolib.cpp
OBJECTS = $(patsubst src/%.cpp,bin/%.o,$(SOURCES))
so you only need to keep the list of files in one place.
You can make a rule that builds anything conforming to a specific pattern like this:
bin/%.o : src/%.cpp
$(CC) -c -o $# $<
That will compile any bin/%.o dependency from the corresponding source src/%.cpp.
Also it is standard when compiling C++ to use CXX rather than CC (which is for C code).
I am trying to use shared_ptr in c++. I am using MinGw gcc compiler.
My g++ version is 4.8.1.
When I try to use std::shared_ptr, it says it does not name a type.
Is this because it is part of c++ 11, and that is not supported in the compiled I am using?
Or do I need to set a flag to use c++ 11 features?
EDIT: I tried adding the flag to enable c++ to my makefile, and it still gives an error.
My header where shared_ptr is used is as follows
#pragma once
#include <vector>
#include <memory>
namespace WavFileTools
{
class WavFile;
}
class WavFileTools::WavFile
{
public:
typedef std::vector<unsigned char> PCMData8_t;
typedef std::vector<unsigned short int> PCMData16_t;
struct WavFileHeader {
int num_channels;
int sample_rate;
int bits_per_sample;
};
static std::shared_ptr<WavFile> LoadWavFromFile(std::string filename);
private:
WavFile(void);
private:
WavFileHeader m_header;
PCMData16_t m_data16;
PCMData8_t m_data8;
};
And the makefile...
CC := g++
CFLAGS := -g -O2 -std=c++0x
BIN_DIR := bin
BUILD_DIR := build
SRC_DIR := src
MAIN := WavFileTool
TARGET := wavfiletool.exe
SOURCES := $(wildcard src/*.cpp)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.cpp=$(BUILD_DIR)/%.o)
$(BIN_DIR)/$(TARGET): CREATE_DIRS $(BUILD_DIR)/$(MAIN).o $(OBJECTS)
$(CC) $(OBJECTS) $(CFLAGS) -o $#
$(BUILD_DIR)/$(MAIN).o: $(SRC_DIR)/WavFileTool.cpp
$(CC) $(CFLAGS) -c -o $# $<
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h
$(CC) $(CC_FLAGS) -c -o $# $<
CREATE_DIRS:
if not exist $(BIN_DIR) mkdir $(BIN_DIR)
if not exist $(BUILD_DIR) mkdir $(BUILD_DIR)
CLEAN:
if exist $(BIN_DIR) rmdir /Q /S $(BIN_DIR) # /S allows deleting non-empty folder, and /Q prevents confirmation required
if exist $(BUILD_DIR) rmdir /Q /S $(BUILD_DIR)
and the error
In file included from src/WavFile.cpp:1:0:
src/WavFile.h:26:10: error: 'shared_ptr' in namespace 'std' does not name a type
static std::shared_ptr<WavFile> LoadWavFromFile(std::string filename);
I have a static method in class as follows in file Convert.h
class Convert
{
public :
static string convertIntToStr(unsigned int integer);
};
In Convert.cpp
string
Convert::convertIntToStr(unsigned int integer)
{
ostringstream ostr;
ostr << integer;
return ostr.str();
}
I use this in some other class method in another .cpp file as Convert::convertIntToStr, but I get linking error, which says undefined reference to Convert::convertIntToStr(unsigned int). Could you please let me know what could be wrong?
With multiple cpp file, you have to link the compiled object file into executable. In IDE like eclipse CDT or Visual stdio, It has been done for you.
To compile and link by yourself, with gcc for example, write Makefile:
CC=g++
CPPFLAGS=-fPIC -Wall -g -O2
all:executable
executable: convert.o other.o
$(CC) $(CPPFLAGS) -o $# $^
convert.o: convert.cpp
$(RC) $^
other.o: other.cpp
$(CC) -o $# -c $^
.PHONY:clean
clean:
rm *.o executable