Я использую довольно сложный подход к распределению объектов, используя «каталогный» подход. Код генерирует объект каталога (глобальную статическую карту), который заполняется базовыми указателями, которые указывают на производные объекты. Это все кощунственно, но не в этом суть. После выполнения программы каталог заполняется всеми производными объектами, и мы можем выделить все, что было зарегистрировано в каталоге, без необходимости вести список производных классов-кандидатов. Отлично. Однако когда один из производных классов запускается через архиватор (ar), а архив используется вместо объектного файла для компоновщика, код завершается ошибкой. Может кто-нибудь сказать мне, почему это происходит? Пример кода:
//Base.h
#include<unordered_map>
#include<string>
#include<map>
#include<iostream>
#include<memory>
class Base
{
public:
Base( std::string name ):m_name(name){}
virtual ~Base() {}
std::string m_name;
};
class ObjectCatalogueEntryBase
{
public:
typedef std::map< std::string, ObjectCatalogueEntryBase* > CatalogueType;
ObjectCatalogueEntryBase(){}
virtual std::unique_ptr<Base> Allocate( std::string const & ) = 0;
virtual ~ObjectCatalogueEntryBase(){}
static CatalogueType& GetCatalogue()
{
static CatalogueType catalogue;
return catalogue;
}
static std::unique_ptr<Base> Factory( const std::string& objectTypeName, std::string const & name )
{
std::cout<<"Creating solver of type: "<<objectTypeName<<" name "<<name<<std::endl;
ObjectCatalogueEntryBase* const entry = GetCatalogue().at(objectTypeName);
return entry->Allocate(name);
}
};template< typename TYPE >
class ObjectCatalogueEntry : public ObjectCatalogueEntryBase
{
public:
ObjectCatalogueEntry():
ObjectCatalogueEntryBase()
{
std::string name = TYPE::CatalogueName();
(ObjectCatalogueEntryBase::GetCatalogue())[name] = this;
std::cout<<"Registered Solver: "<<name<<std::endl;
}
~ObjectCatalogueEntry() final{}
virtual std::unique_ptr<Base> Allocate( std::string const & name) final
{
return std::unique_ptr<Base>(new TYPE(name));
}
};
/// Compiler directive to simplify autoregistration
#define REGISTER_FACTORY( ClassName) namespace{ ObjectCatalogueEntry<ClassName> reg_; }
следующий файл:
// Derived.h
#include "Base.h"class Derived : public Base
{
public:
Derived( std::string name );
~Derived();
static std::string CatalogueName() {return "Derived";}
};
следующий файл:
// Derived.cpp
#include "Derived.h"
Derived::Derived( std::string name):Base(name)
{}
Derived::~Derived()
{}
REGISTER_FACTORY(Derived)
следующий файл:
// main.cpp
#include "Derived.h"
int main()
{
std::string newName("Foo");
auto solver = ObjectCatalogueEntryBase::Factory(Derived::CatalogueName(),newName);
return 0;
}
И Makefile:
CPP=g++-mp-6
test: main.o Derived.o
${CPP} -std=c++14 -o test main.o Derived.o
testlib: main.o Derived.a
${CPP} -std=c++14 -o testlib main.o Derived.a
main.o: main.cpp Base.h Derived.h
${CPP} -std=c++14 -c main.cpp
Derived.o: Derived.cpp Derived.h
${CPP} -std=c++14 -c Derived.cpp
Derived.a:
ar qcsv Derived.a Derived.o
clean:
rm *.o *.a test testlib
all: test testily
Таким образом, два исполняемых файла связаны между собой. Первый (тест) связан с объектными файлами и дает «правильный» результат:
$ ./test
Registered Solver: Derived
Creating solver of type: Derived name Foo
Второй (testlib) связан с файлом Derived.o, замененным на Derived.a, который был создан с помощью «ar» с использованием только Derived.o. Результат:
./testlib
Creating solver of type: Derived name Foo
terminate called after throwing an instance of 'std::out_of_range'
what(): map::at
Abort trap: 6
Очевидно, что регистрация здесь не произошла, и карта пуста. Тот же результат с gcc6 и apple clang7. Я подозреваю, что это как-то связано с глобальной статической картой, но я не понимаю «ar» достаточно, чтобы знать, что он извлекает из объектного файла. Итак, есть два вопроса:
Проблема не в архиваторе, а в компоновщике. Компоновщик берет каждый объектный файл, а также то, что нужно из архивов. Члены вашего архива не разрешают неразрешенные ссылки и поэтому не нужны.
Линкер GNU понимает --whole-archive
Это то, что вы намеревались здесь.
Других решений пока нет …