Пишемо багатоплатформовий код з Haxe
Якось я вже писав про цю мову на DOU. Однак, щоб розкрити всі його особливості, однієї статті недостатньо. Більш того, в коментарях було багато цікавих запитань, які спонукали мене продовжити писати про даної технології.
Хто не читав попередню статтю , пропоную ознайомитися. Кому лінь читати, коротенько Haxe — це інструментарій для розробки крос-платформного. Мова Haxe транслюється в безліч інших мов і може бути виконаний на різних платформах.
Це перша практична стаття, з якої можна почати своє знайомство з інструментарієм Haxe в цілому і зрозуміти (я сподіваюся), що він із себе представляє.
Установка і настройка Haxe
- Качаємо інсталятор для своєї ОС.
- Качаємо VSCode :
- Встановлюємо розширення для Haxe: marketplace .
Готово :) Але, щоб повністю оцінити всі можливості, описані в цій статті, вам також не завадить встановлений NodeJS і VisualStudio (для компіляції C#, С++ коду під Windows), встановлена Java 7+ в системі і Python 3.
Якщо ж вам ліньки встановлювати всі ці залежності, то ви можете їх сміливо опустити, просто прочитавши статтю. Однак, я б рекомендував встановити хоча б NodeJS, щоб ви могли експериментувати з мовою особисто.
Практика
Після того, як ви встановили сам Haxe, редактор і плагін до нього, давайте приступимо відразу до практики.
Створіть файл MyApp.hx такого змісту:
package; class MyApp { public static function main():Void { trace("Hello world!"); } }
Відкрийте термінал і виконайте наступну команду:
haxe -main MyApp --interp
У разі успішного виконання ця команда виведе на екран рядок:
MyApp.hx:4: Hello world!
Давайте зупинимося на цьому етапі докладніше.
Як і в багатьох інших об'єктно-орієнтованих мовах, основна одиниця в Haxe — клас. Він же, у свою чергу, оголошується всередині пакету (package, подібно Java), який є свого роду простором імен. Пакет також повинен відповідати шляху до файлу. Тобто якщо ми оголосили пакет package com.cosmething, то наш клас повинен лежати в папці com/something. Ім'я класу оголошується з великої літери.
У нашому прикладі є публічна статична функція main, яка є точкою входу для всіх програм, написаних на мові Haxe (у деяких випадках ця функція не обов'язкова). Всередині цієї точки входу ми викликаємо функцію trace, яка може приймати будь-який об'єкт, який вона спробує перетворити на рядок і вивести на екран. Крім об'єкта, функція виведе ім'я поточного класу і номер рядка, де була викликана дана функція. Як ви зрозуміли, це дуже зручно для налагодження.
Викликавши команду компіляції, ми вказали наш основний клас -main MyApp, який містить функцію main і передали туди прапор --interp, який інтерпретує наш код на льоту без його компіляції.
JavaScript
Тепер спробуємо створити JavaScript-файл з нашого Haxe-класу. Змініть умови компіляції наступним чином:
haxe -main MyApp -js ./myapp.js
Після успішного виконання команди поруч з вашим класом повинен з'явитися згенерований myapp.js файл. Його можна відкрити через редактор і подивитися, що ж нам згенерував Haxe компілятор.
Якщо у вас вже встановлений NodeJS, то ви можете виконати отриманий JS наступним чином:
node ./myapp.js
У разі успішного виконання NodeJS виведе на екран рядок:
MyApp.hx:4: Hello world!
Ми отримали те ж саме, що і в першому прикладі. Різниця лише в тому, що в умовах компіляції ми замінили прапор інтерпретації коду на компіляцію (за фактом трансляцію) під JS, вказавши в якості значення ім'я вихідного файлу.
Тепер скрізь, де вам доступний JavaScript, ви можете виконувати свій код.
Довідка. Коли ви пишете на сучасному JS, вам доводиться використовувати додаткові інструменти на зразок Webpack'a для склеювання ваших JS класів і файлів. Haxe робить це автоматично, і вся програма буде злита в один монолітний JS файл. Варто, однак, згадати, що якщо є така необхідність, то можна генерувати за JS файлу на клас за допомогою сторонньої бібліотеки, опис яких виходить за рамки цієї статті.
Java
Продовжимо. Сила Haxe в тому, що ви можете генерувати код для безлічі мов і виконати його, таким чином, практично під будь платформою. Давайте перевіримо це на практиці і спробуємо зібрати наш код під Java. Для цього нам потрібно встановити відповідну бібліотеку — hxjava .
Довідка. Бібліотека hxjava буде встановлена глобально і буде доступна у всіх Haxe проектах. За її установку відповідає бібліотечний менеджер haxelib. За замовчуванням установка бібліотек проводиться в папку установки Haxe (а там в папку lib). Змінити цю директорію можна викликавши команду haxelib setup.
Отже, виконаємо установку залежності:
haxelib install hxjava
А потім викличемо компіляцію:
haxe -main MyApp -java ./java
Замість -js прапора ми тепер використовуємо -java. На відміну від попереднього прапора, в якості значення цільової мови ми вказали директорію, а не вихідний файл. Таким чином, у нас повинна була з'явитися директорія java, в якій лежить скомпільований MyApp.jar. Перейдіть в цю директорію і запустіть його:
java -jar ./MyApp.jar
І консоль знову видасть вам:
MyApp.hx:4: Hello world!
Тепер скрізь, де вам доступна Java 7+, ви можете виконувати свій код.
C#
Для цього цільової мови, подібно Java, нам потрібно встановити бібліотеку hxcs :
haxelib install hxcs
Далі, як ми вже робили це раніше, скомпилируем наш код під C#:
haxe -main MyApp -cs ./csharp
Перейшовши в директорію csharp/bin, ви зможете виявити ваш MyApp.exe. Запустивши його з консолі, ви побачите вже звичний відповідь:
MyApp.hx:4: Hello world!
Тепер скрізь, де вам доступний C#, ви можете виконувати свій код.
Python
Чергу за Python. Компілюємо:
haxe -main MyApp -python ./myapp.py
Виконуємо:
python ./myapp.py
І отримуємо:
Hello world!
Ви могли помітити, що у отриманого результату відсутнє ім'я класу і рядок виклику функції trace. Для Python таргету це зроблено спеціально в якості оптимізації. Однак, якщо це дійсно необхідно, то можна додати наступний код перед викликом trace:
package; class MyApp { public static function main():Void { haxe.Log.trace = haxe.Log.trace; //змусить Haxe використовувати свою реалізацію виведення налагоджувальної інформації, замість нативного в python print trace("Hello world!"); } }
Тепер ви можете виконувати свій код скрізь, де вам доступний Python3.
Довідка. Дуже часто чую запитання з приводу Python таргету — навіщо він потрібен? Відповідь на поверхні і в цілому застосовний і до інших таргетам. Haxe — це ООП мову, з потужною системою типів і макросів, крос-компіляцією і оптимизациями на рівні генерації коду. Таким чином, якщо вам з якоїсь причини не подобається або не хочеться вчити Python, то Haxe можна розглянути як його заміну. Так само, як і TypeScript є заміною чистого JS. Ви можете взяти будь-яку Python-бібліотеку, наприклад TensorFlow, підключити її до Haxe і писати код на строго типизированном ООП мовою.
C++
Далі для компіляції C++ нам знадобиться встановлений в системі VisualStudio (під лінуксом — GCC, під маком — Xcode). Детальніше про компіляторах — Getting started with Haxe/C++ .
За прикладом з Java і C#, необхідно встановити бібліотеку hxcpp , яка дозволить нам компілювати згенерований код:
haxelib install hxcpp
Після успішної установки ми можемо зібрати наш код:
haxe -main MyApp -cpp ./cpp
У папці cpp повинен був з'явитися файлик MyApp.exe, виконавши який ми вже традиційно отримаємо:
MyApp.hx:4: Hello world!
Тепер ви можете виконувати свій код (майже) скрізь, де вам доступний C++.
Довідка. С++ — дуже багатогранний таргет. Код може бути згенерований З с++11 стандарту, скомпільований під різні архітектури (x86, x64, arm), під різні платформи: Linux, Mac, Windows, WinRT, Android, iOS, QNX, консолі, etc. Hxcpp підтримує статичну і динамічну лінкування, як зовнішніх бібліотек, так і коду, написаного на Haxe (для використання в якості бібліотеки в існуючому проекті, наприклад). Також отриманий код може бути використаний через emscripten.
Файл зборки
Кожен раз писати безліч аргументів (а їх може бути багато) в командному рядку для того, щоб скомпілювати код — напряжно. У Haxe для цього передбачені файли з розширенням hxml, які описують інструкції компілятора.
Видаліть всі, крім MyApp.hx, і створіть файт build.hxml, а файл MyApp.hx перенесіть в папку src так, щоб у вас вийшла наступна ієрархія:
./build.hxml ./src/MyApp.hx
У файлі build.hxml додайте наступні команди:
# This is our build file -cp src -main MyApp.hx -js ./deploy/out.js -dce full -D analyzer-optimize -debug
Тепер натисніть Ctrl+Shift+B, і VSCode відкриє вам в спадаючому списку доступні файли збірки:
Виберете наш build.hxml, і тоді VSCode скомпилирует вам Haxe код в JS з вихідним файлом ./deploy/out.js. Тепер ми можемо перестати використовувати термінал для компіляції коду. Варто сказати, що цей процес можна ще більше спростити, додавши завдання для складання через налаштування VSCode. Докладніше — Build Tasks .
Повернемося до коду. Як ви, напевно, помітили, у нас з'явилися якісь нові, незрозумілі прапори компілятора у файлі build.hxml. Давайте розберемо їх:
- -dce full, — це виняток мертвого, невикористаного коду. Таким чином, всі класи, які не використовуються, не будуть включені в збірку (в тому числі стандартна бібліотека Haxe). Це дозволяє генерувати більш компактний код. Докладніше .
- -D analyzer-optimize, — включає статичний аналізатор коду та намагається оптимізувати те, що ми отримуємо на виході. Докладніше .
- -debug, — включає дебаг-режим і генерує карти коду (source map). Докладніше .
І наостанок давайте зберемо ще один маленький приклад.
Створіть у папці deploy файл index.hxml з наступним змістом:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Hello, Haxe!</title> <script src="out.js"></script> </head> <body> </body> </html>
А MyApp клас змінити наступним чином:
package; import haxe.Json; import js.Browser.console; import js.Browser.document; import js.Browser.window; class MyApp { public static function main():Void { //парсим JSON, типизировав об'єкт (типізувати необов'язково): var a:{my_value:Int} = Json.parse('{"my_value": 100}'); //так що, поле my_value доступно через автодоповнення коду: console.log(o.my_value); //виведемо повідомленням значення my_value: window.alert('my_value is ${o.my_value}'); //почекаємо завантаження сторінки //використовуємо анонімну функцію document.addEventListener. ('DOMContentLoaded', function():Void { //приведемо до рядку распарсенный раніше об'єкт: document.body.innerHTML = Json.stringify(o); throw "Something happened."; }); } }
Скомпілюйте Haxe код (Ctrl+Shift+B) і відкрийте index.html у браузері. Якщо ви зробили все правильно, то браузер повинен показати вам повідомлення із значенням змінної my_value. Якщо ви відкриєте консоль розробника в браузері, то побачите, що console.log також успішно відпрацював. І наостанок, щоб показати інтеграцію з цільовими платформами, ми змінюємо HTML код прямо з Haxe.
Якщо ви звернете увагу на консоль розробника, то побачите, що відпрацювало кинуте нами виключення, яке за допомогою дебаг-режиму відправляє нас прямо в Haxe код (а не в згенерований JS) для налагодження:
Довідка. Варто розуміти, що код з останнього прикладу не може бути скомпільований, наприклад, Java, т. к. там немає HTML об'єктів. Для вирішення таких ситуацій у Haxe є препроцесор, за допомогою якого можна обернути платформо-залежні частини коду, які не будуть включені в збірку там, де не треба. Наприклад:
#js
trace("This code is available on JavaScript target.");
#elseif java
trace("This code is available on Java target.");
#else
trace("This code is available on all (other) targets");
#end
Haxe підтримує і інші мови, наприклад PHP, Lua, ActionScript. Розглядати ми їх вже не станемо, щоб не повторюватися, так як кодогенерация відбувається ідентично вищеописаним мов.
Також у Haxe є добре оптимізована віртуальна машина HashLink, яка може виконувати згенерований байткод aka JIT, або конвертуватися в Сі з подальшою компіляцією і виконанням без віртуальної машини.
Висновки
Спираючись на все вищесказане, підсумую, що Haxe — це потужний засіб для кроссплатформної розробки, яке може бути використаний як самостійний інструментарій для розробки програми, так і як засіб для створення загальної кодової бази між різними платформами і мовами.
Цікаві факти:
- Всі цільові платформи Haxe можуть використовувати нативні бібліотеки.
- Компілювати згенерований код в виконуваний файл необов'язково (Java, C#, C++). Ви можете генерувати тільки код, а компіляцію виробляти своїми інструментами (або включати згенерований код у вже існуючі проекти). У цьому вам допоможе прапор -D no-compilation.
- Генеруючи JavaScript, ви можете використовувати його як самостійний додаток, так і включати його в свої JS проекти і використовувати безпосередньо з JS-коду. Для того, щоб Haxe класи стали доступні з JS-коду, використовуйте для них @:expose мету. Докладніше .
- Згенерований код Haxe може бути використаний безпосередньо в цільових мовах. Так само, як і ці мови можуть бути використані прямо в коді Haxe.
Посилання
Чат: gitter.im/HaxeFoundation/haxe
Форум: community.haxe.org
Мануал:
Порівняння Haxe, TypeScript, Dart і Wasm: github.com/damoebius/HaxeBench
Зв'язок зі мною: [email protected]
У наступній статті ми подивимося на цікаві конструкції мови, його особливості та переваги.
Опубліковано: 12/06/18 @ 07:00
Розділ Різне
Рекомендуємо:
DevOps дайджест #20: Microsoft і GitHub, AWS зарелизил EKS, DevOps Factors
Реактивний підхід до валідації полів введення на Android
DOU Проектор: CleverStaff — сервіс для автоматизації рекрутингу
Не малюванням єдиним: навіщо дизайнеру розуміти бізнес замовника і впливати на продукт
Я, девелопер