Комментарии 11
Тема не раскрыта. Зачем это всё, когда есть dynamic linker, который это делает автоматически?

Но даже если и надо зачем-то, то новый дом здорового человека создаётся не вызовом «library_func» каждый раз, а
typedef const char *(*mysql_stat_t)(MYSQL * mysql);
mysql_stat_t mysql_stat;
...
void init_new_homes()
{
  mysql_stat= (mysql_stat_t)library_func(library, "mysql_stat");
}

и теперь mysql_stat() можно использовать как обычно. Это прекрасно работает и с variadic, тут никакой разницы.

Если же обязательно надо вызвать variadic функцию из variadic враппера — например, в gcc для этого есть __builtin_va_arg*, может и у VS что-то найдется. Используется так:
          extern int myprintf (FILE *f, const char *format, ...);
          extern inline __attribute__ ((__gnu_inline__)) int
          myprintf (FILE *f, const char *format, ...)
          {
            int r = fprintf (f, "myprintf: ");
            if (r < 0)
              return r;
            int s = fprintf (f, format, __builtin_va_arg_pack ());
            if (s < 0)
              return s;
            return r + s;
          }
Если же обязательно надо вызвать variadic функцию из variadic враппера — например, в gcc для этого есть __builtin_va_arg*, может и у VS что-то найдется.

__builtin_va_arg не являются частью стандартной библиотеке. Решение в статье основано на стандартных функциях.
то новый дом здорового человека создаётся не вызовом «library_func» каждый раз, а

Это требует хранения всех этих переменных, создания их экземпляров. При автоматической генерации файла гораздо проще при проходе генератора в цикле сгенерировать файл за один проход.
Тем более, что при этом способе, если подгружается статическая библиотека-загрузчик, то вам всё равно нужно прокидывать наружу библиотеки функции, которые вызывают «оригинальные»:
int func(int a) {
    direct_func(a);
}
конечно __builtin_va_arg не является. но если (я не проверял) у VS есть что-то похожее, то оно все ifdef-ится. Так же как и LoadLibrary с HMODULE.

А переменные — ну тут или переменные или функции, что-то создавать надо. Только каждый раз дёргать dlsym и искать функцию по имени при каждом вызове — это жуткий перебор.

А что значит «прокидывать наружу» и зачем это делать?
А что значит «прокидывать наружу» и зачем это делать?

Основная идея в том, чтобы не менять исходный код всех проектов, но при этом обеспечить не статическую, а динамическую линковку с целевой библиотекой. Для этого:
Создается отдельная библиотека в дереве проектов, с которой происходит статическая линковка. Которая динамически загружает нужную нам и производит экспорт символов. Таким образом не меняя код по всем проектам можно отвязать их от линковки установленными в системе библиотеками при компиляции.
ну да, это смысл любого dlopen/dlsym. А функции-врапперы зачем? Искать функцию по имени при каждом вызове — это дикий overhead, такое надо делать только если есть уважительная причина не кешировать.

С указателями на функции, как я выше показал, точно так же «не меняя код по всем проектам можно отвязать их от линковки». Это быстрее и никаких проблем с variadic.
С указателями на функции, как я выше показал, точно так же «не меняя код по всем проектам можно отвязать их от линковки». Это быстрее и никаких проблем с variadic.

Как вы собрались не меняя код экспортировать ваши переменные за пределы библиотеки? Это как минимум требует декларации extern в вызывающем коде, иначе переменные не видны.
ну да. static_library.h:
typedef const char *(*mysql_stat_t)(MYSQL * mysql);
extern mysql_stat_t mysql_stat;

typedef int (*mysql_optionsv_t)(MYSQL * mysql,
                   enum mysql_option,
                   const void * arg,
                   ...);
extern mysql_optionsv_t mysql_optionsv;

static_library.c
mysql_stat_t mysql_stat;
mysql_optionsv_t mysql_optionsv;

void init_static_library()
{
  mysql_stat= (mysql_stat_t)library_func(library, "mysql_stat");
  mysql_optionsv= (mysql_optionsv_t)library_func(library, "mysql_options");
}

вызывающий код должен сделать #include <static_library.h>, это по-любому надо, хоть с функциями, хоть с указателями
вызывающий код должен сделать #include <static_library.h>, это по-любому надо, хоть с функциями, хоть с указателями

Ну то есть вызывающий код надо модифицировать.
А в случае с библиотекой-враппером этого делать не нужно, потому что исходный условный #include <mysql/mysql.h> уже включен и содержит декларации экспортированных из враппера функций.
Всё что нужно поменять для такой замены — поменять в сборщике линковку с оригинальной mysql на библиотеку-враппер.

А проблема с «оверхед» решается проще через экземпляр статик-переменной с типом функции внутри функции обертки, которая инициализируется при первом вызове.
А-а, совсем не модифицировать. Тогда да. Хотя я бы всё равно подсунул бы свой mysql.h впереди в пути include-ов, а в нём бы include-ил системный mysql.h

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

Решение в статье работает только для variadic функций, которые берут не более чем 8 void* параметров. А например mysql_optionsv может брать size_t. Хотя практически это может и работать, если всегда sizeof(size_t) == sizeof(void *).

Врапперы хороши для другого. Если можно грузить разные реализации библиотеки, где функции берут слегка отличающиеся параметры. Тогда врапперами это можно унифицировать.
потому что врапперами проблемы с variadic не решить.

Решена выше с припиской:
Если по каким-то причинам нам не будет хватать 9 параметров мы всегда сможем поместить v-переменные в массив нужного нам размера и воспользоваться циклом.

void * на x86 и x86_64 будет размером с машинное слово, следовательно по размеру регистра. Что бы не принимала variadic — этой ширины хватит для регистровой передачи, а что не влезает будет как обычно передано на стеке.
Хотя я бы всё равно подсунул бы свой mysql.h впереди в пути include-ов, а в нём бы include-ил системный mysql.h

Автоматикой проходиться по нескольким сотням тысяч строк опасно — это раз. Подключаться может не той строкой что вы ожидаете — два (например libxml по инструкции подключается макросом).
Если можно грузить разные реализации библиотеки, где функции берут слегка отличающиеся параметры.

И это тоже. После автогенерации кода для всех функций это можно поправить внутри враппера руками.
И да, в VS нет подобного механизма: coderoad.ru/13972329/%D0%95%D1%81%D1%82%D1%8C-%D0%BB%D0%B8-%D1%83-MSVC-%D1%87%D1%82%D0%BE-%D1%82%D0%BE-%D0%B2%D1%80%D0%BE%D0%B4%D0%B5-__builtin_va_arg_pack
И мало того, этот механизм можно использовать только на встроенных функциях там, где компилятор заранее видит количество аргументов. На экспортируемые функции это не работает.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.