8.22.2019

Как скомпилить C&C++ код в Web Assembly на Windows 10 / Вектор поиска

Вектор поиска - это небольшая заметка дающая правильный вектор для того или иного вопроса на основе опыта автора.

Быстрый ответ используйте docker контейнер, но нужно иметь windows pro и устранить несколько багов из статьи. Каких именно и как читайте ниже :) 

Ах да и прочтение статьи все еще не позволит вам компилить код с подключенной библиотекой, например какие-то либы. Конечно если вы не разбираетесь в тех ошибках которые будут выскакивать при компиляции.

Если вы хотите запустить С/С++ код в браузере либо в node.js то можно использовать Web Assembly.

WA - это такой формат байт кода который понимает браузер. Берешь байт код (его можно загрузить так же как загружаются картинки), пихаешь его в массив байтов как-то так new Uint8Array дальше компилишь в модуль WebAssembly.compile(new Uint8Array) и из полученного модуля создаешь экземпляр класса в котором и будут доступны функции из C/C++ программы new WebAssembly.Instance(WebAssembly.compile(new Uint8Array)).

В общем почитайте тут. В статье используется онлайн компилер.

Возможные варианты компиляции


Для компиляции кода C/C++ в web assembly байт код существует аналог gpp. Называется Emscripten. И тут есть три варианта как его использовать:
  1. Установить на Windows и попробовать избежать ошибок :)
  2. Установить на Linux используя Virtual Box.
  3. Рабочий. О нем чуть ниже.
Установка на Windows конечно вариант не плохой, но всегда найдется ситуация когда возникнет ошибка и ответы будут под linux.

Установка на linux идеальный вариант, но лично мне не нравится вариант с Virtual Box потому что он не удобный. Для меня этот подход оказался очень медленным в разработке.

И тут на помощь приходит третий вариант который я счел оптимальным.

3. Docker контейнер.


Понадобится контейнер в котором уже все настроено /https://hub.docker.com/r/trzeci/emscripten/
Взять за основу статью Emscripten and npm. А так же устранить пару ошибок.

Ошибка с путями


На винде может возникнуть ошибка с монтированием директории из-за путей. Помогает использование полного пути. Например так вместо $(pwd)
docker run --rm -v d:/_projects/web-assembly:/src trzeci/emscripten./build.sh
В статье так
docker run --rm -v $(pwd):/src trzeci/emscripten./build.sh 

Ошибка при чтении build.sh из-за текстовой кодировки


Для устанения символов понадобится програмка doc2unix.

Ошибка с путем к директории src


src/my-module.cpp из build.sh заменяем на my-module.cpp

Ошибка с командой npm run build:app

 

У меня скрипт "build:app": "cp index.html dist/index.html", просто не запустился. Оно и понятно так как cp не указан как зависимость.

Я предпочел использовать copyfiles npm i copyfiles --save-dev.

А в секции команды build:app написать так "build:app": "copyfiles index.html dist/

8.11.2019

TypeScript паттерн проектирования стратегия / Короткие заметки

Источником материала является данная книга: Head First. Паттерны проектирования. Обновленное юбилейное издание

Все примеры из книги можно найти в гит репозитории Head-First-Design-Patterns

Реализация паттерна на TypeScript.
Реализация паттерна на Java.

Обычно в книгах по паттарнам проектирования все примеры приводятся на Java или C++, C#, или что-то вроде этого. А JavaScript программисту хочется видеть эти же примеры но на понятном ему языке. Поэтому я решил, что будет совсем не плохо если в процессе чтения книги я буду переписывать примеры реализации разных паттернов проектирования на понятный мне TypeScript и изучаемый мною Golang.

Коротко о паттерне


Существует не мало паттернов и все они классифицированы. Когда я начал задумываться, что бы я хотел сказать от себя о паттерне стратегия в голову пришло словосочетания "Стратегия выбора поведения". После этого до  меня сразу дошло по чему стратегия является поведенческим паттерном.

Как почувствовать, что нужно применить стратегию?


Если логика поведения становится сложной и при этом появляется много условий когда поведение должно изменяться то я задумываюсь о применении паттерна стратегия. На пример, существует контент (в интерфейсе) который нужно частично скрывать. Это может быть картинка разделенная на 4 части половина из которых скрыта. Если у нас один тип контента то не нужно не каких проверок на тип контента т.е. у нас нет условий когда логика скрытия контента меняется. Как только начинает увеличиваться число типов контента, и мы понимаем что нужно не только определять тип контента но и менять логику скрытия для каждого типа, можно применить паттерн стратегия.

Абстрактную идею понять сложнее чем конкретную реализацию, поэтому я переписал один из вариантов реализации паттерна из книги Head First. Паттерны проектирования. Обновленное юбилейное издание на TypeScript.

Реализация Паттерна Стратегия на TypeScript


ссылка на репозиторий с кодом: Паттерн Проектирования Стратегия.
См. Книгу, Первая глава, стр. 38 приложение SimUDuck

Основная идея заключается в том, что мы не реализуем метод fly внутри класса Duck. Мы создаем отдельный класс для каждого типа полета, а затем создаем различные типы уток и помещаем экземпляр типа полета в свойство типа утки.


interface FlyBehaviorI {
  fly: () => void;
}

class FlyWithWings implements FlyBehaviorI {
  public fly(): void {
    alert("I'm flying!!");
  }
}

interface QuackBehaviorI {
  quack: () => void;
}

class Quack implements QuackBehaviorI {
  public quack(): void {
    alert("Quack");
  }
}

class MuteQuack implements QuackBehaviorI {
  public quack(): void {
    alert("<< Silence >>");
  }
}

class FlyNoWay implements FlyBehaviorI {
  public fly(): void {
    alert("I can't fly.");
  }
}

class FlyRocketPowered implements FlyBehaviorI {
  public fly(): void {
    alert("I'm flying with a rocket!");
  }
}

interface DuckI {
  flyBehavior: FlyBehaviorI;
  quackBehavior: QuackBehaviorI;

  swim: () => void;
  display: () => void;
  performFly: () => void;
  performQuack: () => void;
  setFlyBehavior: (fb: FlyBehaviorI) => void;
  setFlyBehavior: (qb: QuackBehaviorI) => void;
}

abstract class Duck implements DuckI {
  abstract flyBehavior: FlyBehaviorI;
  abstract quackBehavior: QuackBehaviorI;

  public swim(): void {
    alert('Duck swim!');
  }

  abstract display(): void;

  public performFly(): void {
    this.flyBehavior.fly();
  }

  public performQuack(): void {
    this.quackBehavior.quack();
  }

  public setFlyBehavior(fb: FlyBehaviorI): void {
    this.flyBehavior = fb;
  }

  public setQuackBehavior(qb: QuackBehaviorI): void {
    this.quackBehavior = qb;
  }
}

class ModelDuck extends Duck {
  // first way to define instance props  flyBehavior: FlyBehaviorI = new FlyNoWay();
  quackBehavior: QuackBehaviorI = new MuteQuack();

  constructor() {
    super();

    // or second way to define instance props    // this.flyBehavior = new FlyNoWay();    // this.quackBehavior = new MuteQuack();  }

  public display(): void {
    alert("I'm a model duck");
  }
}

class MallardDuck extends Duck {
  // first way to define instance props  flyBehavior: FlyBehaviorI = new FlyWithWings();
  quackBehavior: QuackBehaviorI = new Quack();

  constructor() {
    super();

    // or second way to define instance props    // this.quackBehavior = new Quack();    // this.flyBehavior = new FlyNoWay();  }

  public display(): void {
    alert("I'm a real Mallard duck");
  }
}

const mallard: Duck = new MallardDuck();
mallard.performQuack(); // Quackmallard.performFly(); // I'm flying!!
const model: Duck = new ModelDuck();
model.performFly(); // I can't flymodel.setFlyBehavior(new FlyRocketPowered());
model.performFly(); // I'm flying with a rocket