2010-06-07 2 views
20

У меня есть проект на C++, который из-за его структуры каталогов настроен как статическая библиотека A, которая связана с общей библиотекой B, которая связана с исполняемым файлом C. (Это кроссплатформенный проект с использованием CMake, так и на Windows, мы получаем A.lib, B.dll и C.exe, и на Linux мы получаем libA.a, libB.so и C.) Библиотека A имеет функцию инициализации (A_init, определенную в A/initA.cpp), , который вызывается из библиотеки функции инициализации B (B_init, определенный в B/initB.cpp), который вызывается от основного номера C. Таким образом, при связывании B, A_init (и все символы, определенные в initA.cpp), связаны с B (что является нашим желаемым поведением).Как принудительно включить объектный файл в статическую библиотеку при связывании с исполняемым файлом?

Проблема возникает в том, что библиотека A также определяет функцию (Af, определенный в A/Afort.f), который предназначен для динамически загружаемых с помощью (то есть LoadLibrary/GetProcAddress на окнах и dlopen/dlsym на Linux). Поскольку ссылки на Af отсутствуют в библиотеке B, символы от A/Afort.o не включены в B. В Windows, мы можем искусственно создать ссылку с помощью прагму:

#pragma comment (linker, "/export:_Af") 

Поскольку это прагма, он работает только в ОС Windows (с помощью Visual Studio 2008). Для того, чтобы получить это работает на Linux, мы пытались добавить следующее A/initA.cpp:

extern void Af(void); 
static void (*Af_fp)(void) = &Af; 

Это не вызывает символ Af быть включены в конечном звене B. Как мы можем связать символ Af с номером B?

ответ

12

Оказывается, моя первоначальная попытка была в основном там. Следующие работы:

extern "C" void Af(void); 
void (*Af_fp)(void) = &Af; 

Для тех, кто хочет самодостаточной макрос препроцессора инкапсулировать это:

#if defined(_WIN32) 
# if defined(_WIN64) 
# define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:" #x)) 
# else 
# define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:_" #x)) 
# endif 
#else 
# define FORCE_UNDEFINED_SYMBOL(x) extern "C" void x(void); void (*__ ## x ## _fp)(void)=&x; 
#endif 

Который используется таким образом:

FORCE_UNDEFINED_SYMBOL(Af) 
3

Вы можете использовать опцию --undefined при создании B:

g++ -Wl,--undefined,Af -o libB.so ... 
0

Попробуйте поместить эти строки в B/initB.cpp так, что они (мы надеемся) нагнетается в libB.so библиотеку во время ссылки.

Но почему вы должны делать это таким образом вообще? Не можете ли вы настроить его так, чтобы исполняемые ссылки, которые функционируют (или вызывающий его), заставляют компоновщик делать правильную вещь автоматически?

+0

C на самом деле является интерфейсом языка сценариев, B - движком языка, а A - набором собственных методов кода для использования движком. Мы реализуем уже существующий язык с хорошо определенным интерфейсом внешних функций. А и В производятся отдельными командами; мы предпочли бы сохранить все, что A-команда пишет в каталоге A. –

0

Если вы можете использовать C++ 0x функции НКИ (-std = C++ 0x), то аргументы шаблона по умолчанию в функции может сделать трюк. Начиная с текущего стандарта C++ аргументы по умолчанию для шаблонов функций не допускаются. С этим включено в C++ 0x, вы можете сделать что-то вроде: -

В каком-то заголовке файл статической библиотеки ...

template< class T = int > 
void Af() 
{ 
} 

Тогда в соответствующем использовании CPP файл явного шаблон экземпляре ...

template void Af(); 

Это будет генерировать символы для функции Af, хотя она еще не называется/ссылка. Это не повлияет на вызывающих абонентов из-за того, что из-за аргумента шаблона по умолчанию вам не нужно указывать тип. Просто добавьте template <class T = int > перед объявлением функции и явно создайте экземпляр в файле реализации.

НТН,

+1

К сожалению, это не сработает, потому что Af фактически является процедурой Fortran. –

+0

Ну, тогда создайте оболочку «C», которая вызывает Af _ (...) [u может вызывать функции fortran из имени функции «C», т.е. имя функции, добавленное подчеркиванием; google nitty gritty details для аргументов, я donno abt C++, вызывающий fortran]. Вызов этой оболочки C из C++. BTW, вот как одна из ведущих финансовых компаний, над которой я работал, управляла своим антикварным/дерьмовым кодом :-) – Abhay

+0

Это очень неочевидный код, который, вероятно, будет удален сторонником новичков через 2 года. По крайней мере, макрос достаточно ясен, чтобы понять. – xryl669

2

Существует лучший способ написать макрос FORCE_UNDEFINED_SYMBOL. Просто нарисуйте эту функцию указателем на void *. Затем он работает с любой функцией - или данными в этом отношении. Кроме того, зачем беспокоиться с праймами MSVC, когда часть gcc вашего макроса будет работать и для MSVC. Так что моя упрощенная версия будет:

#define FORCE_UNDEFINED_SYMBOL(x) void* __ ## x ## _fp =(void*)&x; 

Который используется таким образом:

FORCE_UNDEFINED_SYMBOL(Af) 

Но он должен быть использован в программе, которая включает в себя библиотеку, которая имеет свои символы раздели.

Смежные вопросы