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.