Комментарии 22
Halt пытался реализовать идиоматичные байндинги, но его запал слегка угас.Не то что угас, я по-прежнему не знаю, как это сделать и возможно ли это в принципе. Все подробности я описал на форуме.
К сожалению да, авторы BWAPI написали его на C++ и это доставило массу головной боли всем, кто не на MSVC++ и Windows. Хотя их можно понять, когда они начинали (а это было аж в 2009м), решиться писать на C было сложно, поскольку сам проект был связан с реверс инжинирингом бинарников Starcraft, а он написан на C++. Вдобавок, они считали, что их разработка будет продуктивнее, если они будут делать на C++.
Но теперь, когда так много различных платформ, с которыми можно интегрироваться (Rust, Go, Node, JVM, Python, .Net) выбор C++ кажется архитектурным просчётом.
Но повторюсь, ребята проделали огромную работу, и они большие молодцы, пусть уж лучше законченная библиотека на C++, чем гипотетическая на C.
Но теперь, когда так много различных платформ, с которыми можно интегрироваться (Rust, Go, Node, JVM, Python, .Net) выбор C++ кажется архитектурным просчётом.А вы считаете что лучше было бы на С?
Отличная статья! Я бы даже сказал: о наболевшем, а именно о мучениях с ABI C++.
Однако, я не смог понять, как Вам удалось справиться с соглашениями о вызовах. Если речь идёт о 32-битном коде, то просто объявления статических функций и заполнения ими таблицы виртуальных методов недостаточно, поскольку виртуальные методы используют соглашение о вызовах thiscall
, тогда как функции обычно используют stdcall
.
С 64-битным кодом всё несколько проще. Насколько я понял, там спасает ключ компилятора -mabi=ms
. Тем не менее, мне очень интересно, что за магия происходит в wrap_handler
и как Rust понимает, что нужно использовать соглашения о вызовах MSVC вместо System V без -mabi=ms
.
Дело в том, что я избавился от виртуальных функций членов в публичном API с помощью opaque pointers. BWAPI-C скрывает C++ ABI внутри себя и правильно выбирает соглашение о вызовах благодаря нативному компилятору, а наружу торчит обычный C.
Например, для Windows BWAPI-C собирается cl.exe & link.exe, на выходе получаем 2 библиотеки — BWAPIC.lib и BWAPIC.dll (в CMake за это отвечает флаг CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS). GNU toolchain умеет работать с .lib, а динамическая линковка с .dll уже происходит во время запуска игры. Таким образом у нас нет головной боли с соглашением о вызовах.
Ну а с 64-битным кодом всё еще проще, его просто нет. Игра писалась 20 лет назад =)
Чуть подкорректирую: оригинальный Старкрафт, он да, 32-битный, но OpenBW может в x64.
Логику ботов вполне можно писать под OpenBW, а потом компилировать в Win32 таргет, запустить под оригинальным Старкрафтом, убрать шероховатости, если есть.
Это неплохой вариант, если кому-то некомфортно под виндой (например, мне :-))
Чтобы понять, что происходит в wrap_handler
надо понять, что происходит в сишной обертке createAIModuleWrapper
: https://github.com/RnDome/bwapi-c/blob/master/src/AIModule.cpp. Я обернул C структуру в C++ класс, вернув сырой указатель. Чтобы создать Rust модуль, надо его обернуть в C, чтобы потом обернуть в C++, читайте https://github.com/RnDome/bwapi-rs/blob/master/src/aimodule.rs .
Если будут вопросы, я отвечу подробнее.
Уже в процессе
Перевод: https://habr.com/en/post/436254/
Извини, заняло много времени на раскачку.
Бот для Starcraft на Rust, C и на любом другом языке