LINUX.ORG.RU

Сращивание двух проектов. Попадают ли дефайны в пространство имен и другие вопросы.


0

0

Здравствуйте!

Никогда активно не работал с пространствами имен, а тут, видимо, придется. В ближайшее время нужно будет мне срастить два проекта (~25Mb кода в каждом). То есть, было две программы, а теперь надыть, чтобы были они были обе в одном бинарнике. Программы написаны в смешанном структорно-объектном стиле.

Проблема в том, что программы используют одинаковые библиотеки (15 штук в виде исходников), но библиотеки дефайнами в разных программах настраиваются немного по-разному.

Проекты пока разделены, и библиотеки пока имеют такую структуру

some_library.h

#ifndef _SOME_LIBRARY_H_
#define _SOME_LIBRARY_H_

include "prog1_config.h" // Чтобы были известны define-настройки и типы 1-й проги

... прототипы ....

#endif // _SOME_LIBRARY_H_

some_library.cpp

#include "some_library.h"

extern int a;
extern char b[];

... реализация ...

Пока проекты разделены, и чтобы использовать библиотеку из 1-го проекта во втором, копируется её h и cpp файлы, в h-файле меняется

include "prog1_config.h"
на
include "prog2_config.h"
и библиотека работает.

А при сращивании имеем проблемы...

Первая проблема - extern переменные. Её можно было бы решить, если в сращиваемой версии библиотеки задать нужный namespace. Но тогда нужно, чтобы код библиотеки включался два раза - первый раз с namespace для программы 1, второй раз с namespace для программы 2.

Вторая проблема - разные настройки prog1_config.h и prog2_config.h. Настройки там задаются дефайнами. Дефайны имеют, само собой, одинаковые имена в prog1_config.h и в prog2_config.h. Я туплю в документацию, и немогу понять будут ли дефайны разные для разных пространств имен? Что-то мне подсказывает, что дефайны от пространства имен никак не зависят, так как это отдельный «язык разметки». А значит, нужно как-то гарантировать, чтобы дефайн-настройки 1-й программы применились к 1-й программе, а настройки 2-й ко 2-й. Как это сделать?

Третья проблема - общая для первых двух. Надо каким-то образом включить namespace1 и подключить prog1_config.h и скомпилить библиотеку, а затем включить namespace2 и подключить prog2_config.h и скомпилить библиотеку. Как это сделать?

Все это желательно сделать средствами синтаксиса C/C++, внешние скрипты очень нежелательны.

Вопрос - какие могут быть решения, чтоб срастить две подобные программы?


напейсать всё с нуля же!

zh
()

Еще варианты?

xintrea
() автор топика

как вариант: собрать два проекта в два объектника (с помощью инкрементальной линковки, например), потом в каждом через objcopy сделать конфликтующие глобальные символы локальными. а потом уже линковать окончательно. при этом не придётся править исходники, но от проблемы дублирующихся дефайнов это не спасёт.

arsi ★★★★★
()

Пока что на ум приходит такая конструкция в заголовках библиотек

Предположим, что есть дефиниция CURRENT_PROG, которая принимает значение 1 или 2.

Заголовок либы:

#if CURRENT_PROG==1

 #ifndef _SOME_LIBRARY_P1_H_
 #define _SOME_LIBRARY_P1_H_

 include "prog1_config.h"

 namespace P1
 {

#elif CURRENT_PROG==2

 #ifndef _SOME_LIBRARY_P2_H_
 #define _SOME_LIBRARY_P2_H_

 include "prog2_config.h"

 namespace P2
 {
#endif


... прототипы ...


} // Закрылось namespace

#endif // Закрылось _SOME_LIBRARY_P1/P2_H_

Проблема в том, что #elif и первый #endif будут закрывать не условие #if CURRENT_PROG==X, а #elif закроет #ifndef _SOME_LIBRARY_P1_H_... В общем конструкция неправильная.

xintrea
() автор топика

Знатное извращение однако тут получается:

Библиотеки, компилируясь с разными макроопределениями, представляют из себя разные двоичные функции. Следовательно каждая функция из библиотеки должна находиться в 2 двоичных вариантах: одна откомпилирована для одной части проекта, другая откомпилирована для другой части проекта. Это означает, что в общем проекте существуют 2 двоичных функции F. Они должны откомпилироваться в объектные модули, имея разные имена. Для этого надо иметь двойной исходный код, размещённый в разные пространства имён, тогда они будут иметь разные имена. Каждый модуль из двух имеющихся должен быть исправлен во всех своих исходниках на применение соответствующего ему пространства имён. А каждый из двух исходных текстов модулей должен быть не только изменён на пространство имён, но и там же должны быть заданы нужные этой копии макроопределения.

было

lib_source.h
//#define BALLMER_SUCKS
#define LINUX_FOREVER

void f();

должно стать

lib_source_1.h
#define BALLMER_SUCKS
namespace NM1
{
void f();
}

lib_source_2.h
#define LINUX_FOREVER
namespace NM2
{
void f();
}

Ну или вместо 2 файлов *_1.h *_2.h два варианта кода поместить копипастом в один файл и разделять макроопределениями #if defined (LIB_1) #elsif defined(LIB_2)




anonumus
()
Ответ на: комментарий от anonumus

Хм, напрашивается еще и такой вариант. Каждая прога, само собой, помещается в свой namespace. Все исходники каждой проги обрамляются своим namespace. Остается разрулить общие библиотеки.

Для каждой библиотеки нужно будет иметь 3 файла

some_library.cpp
some_library.h
some_library_prototype.h

В some_library.cpp весь код обрамляется просто

#if CURRENT_PROG==1
 namespace P1 {
#elif CURRENT_PROG==2
 namespace P2 {
#endif

... код ...

}

Весь существующий код some_library.h переносится в some_library_prototype.h. А в some_library.h размещаем такой код

#if CURRENT_PROG==1

#ifndef _SOME_LIBRARY_P1_H_
#define _SOME_LIBRARY_P1_H_

include "prog1_config.h"

namespace P1
{
 include "some_library_prototype.h"
}

#endif
#endif


#if CURRENT_PROG==2

#ifndef _SOME_LIBRARY_P2_H_
#define _SOME_LIBRARY_P2_H_

include "prog2_config.h"

namespace P2
{
 include "some_library_prototype.h"
}

#endif
#endif

Вроде бы так должно работать?

Остается тольео проблема, в каких местах разместить определения CURRENT_PROG=1 и CURRENT_PROG=2.

xintrea
() автор топика
Ответ на: комментарий от xintrea

Каждый файл с исходным кодом в 1 проекте компилируется только один раз, преобразуясь в объектный файл для последующей компоновки.

Поэтому каждый файл надо откомпилировать 2 раза, задавая каждый раз нужные параметры макроопределений и поместить каждый результат в отдельный объектный файл.

Поэтому такой исходник библиотеки в одном проекте работать не будет

#if CURRENT_PROG==1
namespace P1 {
#elif CURRENT_PROG==2
namespace P2 {
#endif

... код ...

}
anonumus
()

Два пути - костыли и рефакторинг. Все зависит от целей, ресурсов и сроков, которыми ты располагаешь. Если есть возможность сделать рефакторинг, лучше выбери его. Потом самому будет не стыдно смотреть на _П_родукт.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.