Отладка lua в visual studio code
Реализация плагина позволила подключить следующий функционал отладчика Visual Studio для LUA-программ:
* Возможность подключения и отключения от выполняемого процесса из Visual Studio (Attach и Detach).
* Контроль выполнения программы (StepIn/StepOut, Continue, прерывание по break).
* Назначение точек остановка (Breakpoints)
* Просмотр значения переменных (окно Watch и значений под курсором)
* Синхронизация с исходным кодом, при которой автоматически открывается нужны исходный файл на текущей строке при срабатывании BreakPoint или другой команды, при которой передаётся управление в программе.
* Вывод окна с диагностической информацией об ошибках выполнения.
Что требуется для реализации
После установки SDK необходимо ознакомиться с разделом, посвящённым архитектуре отладчика, который называется ”Visual Studio Debugging Extensibility”.
SDK содержит исчерпывающий пример отладчика скриптового языка ”Text Interpreter”, в котором последовательно изложен процесс подключения отладчика.
В данной статье я поясню основные этапы подключения отладчика к игровому движку для отладки LUA-приложений.
Подробнее о подключении отладчика
В первую очередь для подключения библиотек Visual Studio 2005 SDK необходимо включить в файлы исходного кода заголовочный файл dbgmetric.h, для чего придётся прописать путь к каталогу VS2005SDK.
Например, "C:\Program Files\Visual Studio 2005 SDK\2006.09\VisualStudioIntegration\Common\Inc"
Также необходимо прописать путь к каталогу с библиотеками, например,
"C:\Program Files\Visual Studio 2005 SDK\2006.09\VisualStudioIntegration\Common\Lib\x86"
Состав необходимых для подключения заголовочных и библиотечных файлов можно найти в справке по используемым функциям в MSDN.
Для подключения отладчика к вашему приложению потребуется создать следующие объекты:
Регистратор Debug-метрик Visual Studio, который необходим для информирования Visual Studio о существовании LUA Debug Engine. Информация о Debug Engine вносится в реестр, чтобы Visual Studio узнала про новый тип отладчика и могла его отобразить в окне ”Processes”:
В результате отладчик LUA станет доступен:
Затем необходимо зарегистрировать LUA-программу в системе:
Также необходима COM-фабрика, чтобы Visual Studio могла создавать Debug Engine посредством вызова CoCreateInstance.
Наиболее эффективна реализация, при которой Debug Engine находится в одном процессе с виртуальной машиной LUA, в этом случае значительно упрощается доступ к памяти LUA-программы.
Отладчик реализуется посредством предоставления предоставлять набора COM-объектов:
* IDebugEngine2 – обеспечивает контроль над сеансом отладки
* IDebugProgramNode2 – обеспечивает регистрацию процесса в системе
* IDebugProgram2 – представление отлаживаемого процесса
* IDebugStackFrame2 – представление информации о состоянии стека
* IDebugThread2 – представление информации о свойствах каждой LUA машины
* IDebugExpressionContext2, IDebugProperty2, IDebugExpression2 – информация о значении переменных
* IDebugPendingBreakpoint2 – представление точки останова
При всём пугающем объёме интерфейсов и реализуемых ими методов в большинстве случаев достаточно использовать функции-заглушки, не выполняющие реальной работы.
Безусловно, в этом случае необходимо возвращать E_NOTIMPL как результат работы.
Пример реализации метода-заглушки:
Другие методы играют роль обёрток, возвращающих необходимые значения:
Наиболее эффективным способом реализации интерфейсов является последовательный просмотр описания методов в SDK и их реализация. В любом случае, заглушки должны быть предоставлены для всех методов. Какие из них заменять реальным кодом – будет зависеть от ваших потребностей.
В любом случае имеет смысл расставить строки с выводом в протокол информации о вызове того или иного метода. Так вы сможете получить больше информации, в какой ситуации какие методы вызываются и по какой причине какой-то функционал может не работать.
Оставшаяся часть методов составляет обёртки для соответствующих функций LUA Debug API. Последний представлен в файле lua.h и представляет собой хороший пример удобного и чётко сформулированного программного интерфейса.
Показать реализацию всех интерфейсов и методов в статье не представляется возможным, поэтому я ограничусь лишь фрагментами реализации интерфейса IDebugPendingBreakpoint2, поскольку он достаточно компактен.
Интерфейс IDebugPendingBreakpoint2 представляет собой точку останова, которая готова к связыванию с конкретным участком программы. Как вы знаете, точка останова может существовать в нескольких состояниях – два из них – «готовая к связыванию» и «связанная». Готовая к связыванию точка останова определяет имя файла и номер строки исходного кода. Однако она не привязана к конкретной точке в программе. Такое состояние возможно, когда программа не загружена или не инициализирована. В отладчике такая точка останова отображается пустой окружностью в поле точек останова.
После загрузки программы (или её трансляции/компиляции) происходит «связывание». После этого точка останова в отладчике отображается «залитой» окружностью.
Создание точки останова производится из интерфейса IDebugEngine2:
Класс, реализующий интерфейс IDebugPendingBreakpoint2, будет выглядеть следующим образом:
You can use the Lua Debugger extension to debug Lua programs with Visual Studio Code.
- You should be able to use luasocket in a Lua program to be debugged.
- You should be able to use a JSON library in a Lua program to be debugged.
cjson and dkjson are recommended, but you can use other JSON libraries whose interfaces are compatible. - Your code or third party library should not call debug.sethook .
In order to debug Lua programs with Lua Debugger, you have to put vscode-debuggee.lua in the program to be debugged.
If you have used mobdebug, you are familiar with it.
Debugger Connection
Download vscode-debuggee.lua and put it in your project.
Paste the following code into your program to run after all the Lua source code is loaded.
Depending on which JSON library you are using, you may need to modify your code accordingly.
Open the folder that contains the program you want to debug in Visual Studio Code, open the Debug window with Ctrl-Shift-D , and edit the debugging settings accordingly.
Set the breakpoint by pressing F9 at the appropriate location in the program to be debugged.
Press the F5 key to start debugging.
Setting to Enter the Debugger When an Error Occurs
Paste the following code at the location where you want to handle the error.
Enabling Debug Commands to be Processed During Execution
To enable the Lua program to respond to commands from the debugger, such as setting a pause or a breakpoint, while running, set the following code to be called at appropriate intervals.
If your project is a game client, you can call it every frame.
You can run Gideros Player directly from Visual Studio Code.
Please refer to the 'launch-gideros' section of the debugging settings.
If you set the debugging setting to wait and start debugging, Visual Studio Code will wait for a debuggee without executing one.
This is useful if you want to see the string that the debugging target leaves on the console, or if the debugger and the debugging target must be running on different machines.
Basically Vscode-debuggee.lua drops the speed of running Lua programs because it implements the breakpoint mechanism using debug.sethook .
This performance degradation can be overcome by applying a simple patch to the Lua VM.
The OP_HALT patch relies heavily on the work mentioned in the Lua mailing list. Thanks to Dan Tull.
We got an idea from mobdebug about how to connect the debuggee to the debugger. Thanks to Paul Kulchenko.
Thanks to Google Translator for translating this article!
debuggee.start(jsonLib, config)
Connect with the debugger. jsonLib is a JSON library containing .encode and .decode functions.
Config.onError is a callback to receive when an error occurs in the vscode-debuggee module.
Config.connectTimeout , config.controllerHost , and config.controllerPort are settings for remote debugging. If config.redirectPrint is true, the print call is intercepted and displayed in the Visual Studio Code output window. Use this item if you want Gideros to print the results of a print called just before the breakpoint.
debuggee.start returns two values. The first return value is true if it is normally connected to the debugger, otherwise it is false . If the OP_HALT patch is applied in the current Lua VM, the second return value is 'halt' , otherwise it is 'pure' .
debuggee.poll()
Processes queued debugging commands and returns immediately.
debuggee.enterDebugLoop(depth[, what])
Stops running the Lua program and start debugging from the current location.
depth specifies the relative depth of the stack to indicate where the debugger is currently running. 0 means the place to call debuggee.enterDebugLoop , and 1 means a step shallow.
what is the message you want to pass to the Visual Studio Code as you start debugging.
debuggee.print(category, . )
Prints text on vscode debug console. category colorize print text, you can choose log , warning , or error .
Local Lua Debugger for Visual Studio Code
A simple Lua debugger which requires no additional dependencies.
Notice of Breaking Change
Beginning in version 0.3.0, projects which use sourcemaps to debug code transpiled from another language (such as TypescriptToLua), must specify the scriptFiles launch configuration option in order to use breakpoints in the original source files. This allows these to be resolved at startup instead of at runtime which allows for a significant performance increase.
- Debug Lua using stand-alone interpretor or a custom executable
- Supports Lua versions 5.1, 5.2, 5.3 and LuaJIT
- Basic debugging features (stepping, inspecting, breakpoints, etc. )
- Conditional breakpoints
- Debug coroutines as separate threads
- Basic support for source maps, such as those generated by TypescriptToLua
Lua Stand-Alone Interpreter
To debug a Lua program using a stand-alone interpreter, set lua-local.interpreter in your user or workspace settings:
Alternatively, you can set the interpreter and file to run in launch.json :
Custom Lua Environment
To debug using a custom Lua executable, you must set up your launch.json with the name/path of the executable and any additional arguments that may be needed.
You must then manually start the debugger in your Lua code:
Note that the path to lldebugger will automatically be appended to the LUA_PATH environment variable, so it can be found by Lua.
- For convenience, a global reference to the debugger is always stored as lldebugger .
- You can detect that the debugger extension is attached by inspecting the environment variable LOCAL_LUA_DEBUGGER_VSCODE . This is useful for conditionally starting the debugger in custom environments.
Additional Configuration Options
A list of alternate paths to find Lua scripts. This is useful for environments like LÖVE, which use custom resolvers to find scripts in other locations than what is in package.config .
A list of glob patterns identifying where to find Lua scripts in the workspace when debugging. This is required for placing breakpoints in sourcemapped files (ex. 'ts' scripts when using TypescriptToLua), as the source files must be looked up ahead of time so that breakpoints can be resolved.
Example: scriptFiles: ["**/*.lua"]
A list of Lua patterns that specifies files to skip when stepping through code.
Example: ignorePatterns: ["^/usr"]
Step into Lua when stepping through source-mapped code and no mapping is available for the current line.
Break into the debugger when errors occur inside coroutines.
- Coroutines created with coroutine.wrap will always break, regardless of this option.
- In Lua 5.1, this will break where the coroutine was resumed and the message will contain the actual location of the error.
Automatically break on first line after debug hook is set.
Specify working directory to launch executable in. Default is the project directory.
List of arguments to pass to Lua script or custom environment when launching.
Specify environment variables to set when launching executable.
Specifies how the extension communicates with the debugger.
- stdio (default): Messages are embeded in stdin and stdout.
- pipe : Pipes are created for passing messages (named pipes on Windows, fifos on Linux). Use this if your environment has issues with stdio communication.
Enable verbose output from debugger. Only useful when trying to identify problems with the debugger itself.
Custom Environment Examples
Note that console must be set to false (the default value) in conf.lua , or the debugger will not be able to communicate with the running program.
game/conf.lua
Note that even when using busted via a lua interpreter, it must be set up as a custom environment to work correctly.
Lua for Visual Studio Code
Provides Intellisense and Linting for Lua in VSCode
- Autocompletion
- Go to Symbol
- Error checking
- Linting
- Formatting
- Code Snippets
- Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter:
- ext install vscode-lua
Alternatively, you can download the extension from the marketplace.
lua.luacheckPath (Default: null )
Specifies the path to luacheck binary (if not found on PATH ).
lua.preferLuaCheckErrors (Default: false )
Specifies whether to prefer luacheck errors over the standard luaparse errors if luacheck is available.
lua.targetVersion (Default: 5.1 )
Specifies the target version of Lua. Valid options:
Can also be changed using the version selector in the bottom right of the IDE.
lua.format.enabled (Default: true )
Specifies whether to use the Lua formatter
lua.format.lineWidth (Default: 120 )
Maximum length of a line before it will be wrapped.
lua.format.indentCount (Default: 4 )
Number of characters to indent.
lua.format.singleQuote (Default: false )
Whether to use single or double quotes on strings. Defaults to double quotes.
lua.linting.enabled (Default: true )
Specifies whether to enable linting of source files
lua.linting.luaCheckConfig (Default: null )
Path to a .luacheckrc to be used for linting, instead of the default luacheck search path
Additional arguments to pass to luacheck
Support for linting is provided via luacheck. Installation instructions can be found on the luacheck repository.
Once installed, luacheck support can be activated by assigning the lua.luacheckPath setting to the path of the luacheck executable. Additionally, since luacheck provides vastly more detailed and contextually aware errors that may sometimes duplicate those created by luaparse , the setting lua.preferLuaCheckErrors can be set to true to suppress luaparse errors.
This project is licensed under the MIT License - see the LICENSE file for details.
В статье рассказывается об опыте использования отладчика Microsoft Visual Studio для отладки скриптов, написанных с использованием языка Lua. Отладчик был интегрирован в игровой движок Riposte компании Parallax Arts Studio.
Роль скриптов в игровом проекте
Преимущества использования скриптов:
1. Предоставляют возможность описания логики игровых уровней дизайнерам.
По сути скрипты в данном случае могут рассматриваться как дизайнерские данные в силу следующих причин: изменения не требуют компиляции; для работы не требуется хорошего знания языка программирования; среда выполнения полностью контролируется игровым движком, вследствие чего сложно допустить трудноуловимые ошибки.
2. Возможность быстро пробовать и настраивать алгоритмические блоки без перекомпиляции кода и даже без перезапуска движка и игровых уровней. То есть скрипты идеальны для прототипирования, ведения исследовательских работ и ситуаций, когда требуется вносить большое количество мелких изменений. Таким образом, скрипты подходят для разработки игровой логики, моделей поведения персонажей, пользовательских интерфейсов.
3. Возможность не компилировать код и не строить билд движка, передавая его заказчику.
4. Для небольших проектов скрипты могут играть роль единственной среды разработки проекта при стабильном ярде игрового движка. В этом случае дополнительным аргументом в пользу использования скриптов будет возможность значительного упрощения кросс-платформенной разработки.
Также проявляются некоторые положительные аспекты использования скриптов, которые можно реализовать и без скриптов (например, на уровне С++ кода), но использование скриптов делает их более естественными и явными:
1. Возможность создавать предметно-ориентированный программный интерфейс высокого уровня (DSL – Domain-Specific Language), поднимая уровень абстрагирования до уровня, используемого дизайнерами.
2. Между скриптами и движком естественным образом формируется интерфейс, который обычно стабилен и хорошо документирован.
Всё это в сумме позволяет значительно упростить, ускорить и удешевить разработку.
Особенности работы со скриптами
1. Скрипты часто используются пользователями, не имеющими специальной подготовки.
2. Скрипты часто используются при прототипировании и других видах работ, когда отсутствуют формальные спецификации на программную систему.
3. Часто вносится много мелких изменений
Всё вышеуказанное приводит к тому, что в скриптах достаточно часто появляются логические ошибки, которые требуется локализировать и исправлять. Этим обуславливается необходимость в инструменте, позволяющем быстро проводить отладку скриптового кода.
Возможные альтернативы
Существует большое число способов отладки кода.
1. Визуальный просмотр текста программы, анализа текста и проверка правильности «силой ума».
2. Использование средств протоколирования для вывода интересующих значений.
3. Использование модульных тестов при разработке кода
Однако ни одно из вышеперечисленных средств не обладает той оперативностью в расследовании ошибочной ситуации, какой обладает отладчик.
Отладчик позволяет рассмотреть конкретную ситуацию и её контекст. В отладчике можно выяснить значение конкретных, необходимых нам переменных, стека вызовов в нужный нам момент и даже модифицировать переменные для анализа работы алгоритма в разных условиях.
Какой отладчик лучше?
Зафиксировав наш выбор на необходимости иметь отладчик для используемого языка программирования, рассмотрим вариант создания отладчика.
Самый простой вариант – использование готового отладчика, который поставляется вместе с языком программирования. Как мы видим это, например, в случае с С++. Однако, отладчики поставляются в основном только для промышленных языков программирования, таких как С++. Найти хороший отладчик для скриптового языка достаточно сложно.
Например, для скриптового языка Lua есть несколько достаточно простых IDE, которые содержат в себе отладчик. Но интегрировать их в движок не представляется возможным и, вследствие этого, такая среда годится только для проверки небольших самостоятельных программ на Lua.
Можно написать свой собственный отладчик, но при этом придётся решить большое число задач, связанных с разработкой пользовательского интерфейса, интеграции с движком, получения доступа к необходимым данным, управления выполнением и т.д.
В данном случае наиболее эффективным является использованием комбинированного варианта: разработка плагина для существующих интегрированных средств разработки.
Мы использовали интеграцию в Visual Studio. NET, поскольку это привычная для нас среда разработки, в которой уже реализованы текстовый редактор, управление проектами из многих файлов, система контроля версий, дополнительные средства (например, система расцвечивания исходного текста).
Читайте также: