Подаруночок від FTDI
Подаруночок від FTDI виявився дуже цікавим.
У повній відповідності до принципу «дивись рисунок 1» вони взяли і замінили типи даних при переході від бібліотек libftd2xx.so версій 0.4.x до libftd2xx.so.1.0.0. Подаруночок впливає лише на роботу з 64-бітними варіантами бібліотек, з 32-бітними проблем нема.
Бібліотека ftd2xx народжувалася в Windows та ще й містить в собі функції FT_W32_ххх()
для роботи з мікросхемами FTDI в стилі функцій роботи з COM-портом у WinAPI. Тому в ній використовуются стандартні для WinAPI типи даних DWORD
, BYTE
тощо. Щоб при написанні Linux-версії бібліотеки не міняти файл ftd2xx.h та всі тексти, в проект було додано файл WinTypes.h з означеннями потрібних типів. Загалом, крок логічний, але…
Ось фрагмент файлу WinTypes.h від libftd2xx версії 0.4.16:
typedef unsigned long ULONG;
typedef long LONG;
Тобто просто взято типи з файлу windef.h компіляторів для Windows.
А ось те ж саме місце з версії 1.0.0:
typedef unsigned int ULONG;
typedef int LONG;
Для Windows, в тому числі 64-бітних, різниці між цими означеннями на практиці нема, бо в Windows-64 використовється так звана модель даних LLP64 (64-бітними є лише типи long long та pointer-types). При цьому sizeof(long) == sizeof(int)
, обидва ці типи є 32-бітними. Так само буде і в 32-бітному Linux. В цих операційних системах стара версія avreal працюваиме з новою бібліотекою.
А от у 64-біт Linux використовується модель LP64, тобто 64-бітним є також тип long.
Отже, для libftd2xx.so 0.4.x та 64-біт Linux типи DWORD
, ULONG
, LONG
64-бітні, тобто займають вдвічі більше місця, ніж в 32-бітній версії. Але, оскільки і бібліотека, і програма компілюються з одним і тим же заголовочним файлом, все працює правильно.
Для libftd2xx 1.0.0 розміри типів в 32- та 64-бітних версіях ОС збігаються, вони скрізь 32-бітні. Теж нічого поганого, якщо бібліотека та програма компілюються з одними й тими ж типами даних.
Але якщо avreal-у, зібраному зі старим заголовочним файлом, підсунути нову бібліотеку, то працювати програма не буде. Розглянемо такий виклик:
char serno[16];
char description[64];
status = FT_GetDeviceInfo(handle, &chip_type, &chip_id, serno, description, 0);
В старій програмі змінні chip_type
, chip_id
64-бітні. Нова бібліотека запише 32-бітні дані в молодші половинки цих змінних. Якби я писав трохи акуратніше (параноїдальніше?) і ініціалізував ці змінні нулями, то стара програма навіть не помітила б, що нова бібліотека вважала ці змінні 32-бітними (подякуємо x86 за те, що він є little-endian процесором). Але користі з того було б мало, бо в бібліотеці є ще такий тип даних:
ULONG Flags;
ULONG Type;
ULONG ID;
DWORD LocId;
char SerialNumber[16];
char Description[64];
FT_HANDLE ftHandle;
} FT_DEVICE_LIST_INFO_NODE;
Ця структура займає 120 байт при роботі старої версії бібліотеки та 104 байти при роботі нової версії. Функція побудови списку підключених пристроїв FT_GetDeviceInfoList()
приймає вказівник на масив таких структур. Зрозуміло, що це місце не працюватиме в будь-якому випадку.
Гірше буде, якщо зібрати нову версію avreal з новим заголовочним файлом, але у користувача на комп’ютері буде стара бібліотека. В усі змінні бібліотека писатиме більше, ніж розмір змінних, затираючи при цьому вміст сусідніх змінних. В кращому випадку просто не працюватиме, в гіршому буде «segmentation fault».
Тому поки-що я не збиратиму avreal з новою бібліотекою і для 64-біт Linux пропоную брати стару версію libftd2xx 0.4.16 у мене на сторінці download, поруч з архівом avreal.
Я подумаю, що я маю робити з цим подарунком від FTDI. Можливо, починаючи з якоїсь версії avreal, перейти на новий варіант бібліотеки і всі, хто оновлює avreal повинні будуть замінити і бібліотеку. Можливо, я спробую зробити вибір одного з двох режимів роботи залежно від версії бібліотеки, яку поверне FT_GetLibraryVersion()
.
…
и для чего существуют uint8_t .. uint64_t ?
А использовать открытую libftdi?
Так про неё smartly уже сказал по соседству.
Можно, и в том направлении я буду двигаться малой скоростью.
Но и с libfd2xx особых проблем нет — когда стало ясно, в чём дело.
В любом случае это будет не «перейти», а «поддерживать и», так как совсем отказываться от libftd2xx я не собираюсь.