bakota

Lama Pema Dudul 2015 Kyiv Retreat

Буддизм — это не то, что вы думаете!



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

Но что же на самом деле дает человеку буддизм? Религия ли это, философия, или новомодный способ отношения к жизни? Чему учил Будда и как это можно применять в современных условиях?

Приглашаем всех на лекцию "Буддизм. Развенчание иллюзий". Лама Пема Дудул развеет популярные мифы, ответит на вопросы и расскажет о более чем 20-летнем опыте изучения и практики тибетского буддизма.

Lama Pema Dudul (носящий также имя Пема Тринлей Ринпоче, в миру Сергей Дудко) родился в Украине в 1968 году. Специалист по искусству и культуре стран Гималайского региона, где проживает около 20 лет, путешественник, переводчик, лама ордена Катxок традиции Ньингма тибетского буддизма. После многих лет обучения и практики в Гималаях и Тибете он уполномочен своими Мастерами распространять эту традицию. Этим летом он впервые приедет в Киев для проведения лекций и трехдневного затвора для всех желающих.

Подробная информация: http://5ht.co/dharma/pema.dudul.htm

Дата: 16 июля 2015 (четверг)
Время: 19:00-22:00
Место: Киев, ул.Крещатик, 2, Украинский Дом, зал "Арт-Галлерея", 3 этаж. (метро Майдан Незалежности)
Вход свободный
Рекомендованый взнос на организацию: 50 гривен

Программа в Киеве:

16 июля Открытая лекция: "Буддизм. Развенчание иллюзий"

17-19 июля Затвор «Вступление на Путь Будды Шакьямуни и Гуру Падмасамбхавы»

20 июля Празднование годовщины Первой Проповеди Будды

21-22 - Заключительные встречи, ответы на вопросы.

Будем благодарны за помощь в организации приезда Ламы и любую спонсорскую поддержку
bakota

Киев Катманду Лхаса Кайлаш 2015

Котаны, кому интересно следить за нашей экспедицией, вот фоточки:

http://5ht.co/dharma/tibet.htm

Как вы понимаете, времени у меня ацки мало, так как движемся мы стремительно и быстро. Нет времени даже фотки заресайзить, так что имейте ввиду, что каждая фотка весит мегабайты. Нажимайте на эту ссылку только если вы меня очень любите и готовы простить многое.

Этот журнал я пока фотками закидываю так как не времени писать текст. Надеюсь, что в ближайшее время у меня появится время и я дополню текстами этот журнал. Есть много полезной информации для тех, кто хочет повторить этот тур. В основном редомендации оптимизационного экономического характера, медицинского и духовного. Ну и выебоны конечно тоже будут, куда же без этого :-)

Напоминаю, что спонсор фотографий — Microsoft Lumia 1520.
bakota

Statically typed LLVM-based modern functional language compiler

 main -> repeat 0 1000000 (seq 0 1000).

repeat m m x -> x;
repeat n m x -> repeat (n+1) m (rev x).

seq n m -> seq n m [].

seq n n acc -> acc;
seq n m acc -> seq n (m-1) [m|acc].

rev xs -> rev xs [].

rev [] acc -> acc;
rev [x|xs] acc -> rev xs [x|acc].


      1) Erlang version, timer:tc(heap,main,[]) — 13.040s
      2) L version[1] (llc/gcc), time ./a.out      — 3.456s

         GC: heap size: 4096K
         GC: runs: 3846
         GC: reclaimed: 15624375K

Type Inference: 

      $ lc -t heap.l

zf7_3 = $67 -> int -> $67 -> $67.
tf8_2 = nil + [int|$67] -> $67 -> $67.
rev2 = $67 -> $67 -> $67.
rev1 = $67 -> $67.
gf4_3 = int -> int -> $67 -> $67.
seq3 = int -> int -> $67 -> $67.
seq2 = int -> int -> $67.
gf3_3 = int -> int -> $67 -> $67.
repeat3 = int -> int -> $67 -> $67.
main0 = $67.
$67 = nil + [int|$67].



New, Better Erlang is coming...

________________
[1]. LLVM Output: https://gist.github.com/5HT/401a348636af9acd3a16
buka

Extended Wylie Tibetan Script EWTS UTF-8 Converter

Транлитерация Wylie позволяет двухстороннюю конвертацию транлитерации, в отличии от других тибетских транлитераций с потерями. Нужно ли говорить, что все реализации, которые я видел не укладываются в один экран. Решил исправить это. Так как я не хочу брать perl транслитерацию, написал свою с нуля:

t(0,String,Dictionary,Letters,P) -> t(4,tl(String),Dictionary,[hd(String)|Letters],0);
t(_,[],_,L,_) -> L;
t(N,String,Dictionary,Letters,P) when P > 4 -> t(N,String,Dictionary,Letters,0); % clear stack
t(N,String,Dictionary,Letters,P) ->
    R = lists:keyfind(lists:sublist(String,N),1,Dictionary),
    io:format("R: ~p~n",[R]),
    case R of
        {Key,Value} ->
            Vowel = is_vowel(Key),
            {Letter,Stack} = case Value of
                Value when Value == 16#0f0b -> {Value,5};
                {A,B} -> case P of
                    0 -> {[A],P+1};
                    _ -> {[B],P+1}
                end;
                Value when Vowel andalso is_integer(Value) andalso P == 0 -> {[16#0F68,Value],P+1};
                Value when is_list(Value) -> {Value,P+1};
                Value when is_integer(Value) -> case Key of
                    Value when P == 0 -> {[Value],P+1};
                    "a" -> {[],5};
                    _ -> {[Value],5}
                end
            end,
            case length(String) > N of
                false -> [Letter|Letters];
                true -> t(4,lists:sublist(String,N+1,length(String)),
                            Dictionary,[Letter|Letters],Stack) end;
        false -> t(N-1,String,Dictionary,Letters,P) end.

transcode({wylie,Text}) ->
    Table = lists:flatten([
        constants(),vowels(),sanskrit_vowels(),complex_vowels(),final(),other()]),
    Res = lists:reverse(t(4,Text,Table,[],0)),
    lists:flatten(Res).

tibetan(Wylie) ->
    transcode({wylie,Wylie}).

is_vowel(Char) -> lists:keyfind(Char,1,vowels()) /= false.

tests() ->
    "ཨོཾ་ཨཱཿ་ཧཱུྃ" = tibetan("oM AH hU~M"),
    "ཀློང་ཆེན་སྙིང་ཐིག" = tibetan("klong chen snying thig"),
    "རྣམ་དག་སྟོན་པ" = tibetan("rnam dag ston pa"),
    "ཨོཾ་ཨཨཿ་ཧཱུྃ་བཛྲ་གུ་རུ་པདྨ་སིདྡྷི་ཧཱུྂ༔" = tibetan("oM aH hU~M badz+ra gu ru pad+ma sid+dhi hU~M`:"),
    ok.



_________________
[1]. https://github.com/5HT/wylie/blob/master/src/wylie.erl
buka

Непрерывный рефакторинг и проблема совместимости

Я помню на первой своей работе мы всячески выгрызали рефакторинг. У нас был специально обученый менеджер, который по нашим стонам понимал как важен рефакторинг. Поэтому он планировал все так, чтобы у нас был еще один месяц на рефакторинг до сдачи проекта. Текст, как всегда, сумбурный, провокационный, с ошибками и прочей хуйней, отнеситесь, пожалуйста, к этому снисходительно.

Overview

Почему вообще появляется необходимость рефакторинга? От ошибок проектирования. Представьте себе гипотетического программиста, который как Будда все видит на перед, может он написать код от Hello World до любого проекта не прибегая к рефакторингу? Может, конечно, он же Будда. В реальности тоже так хочется, т.е. сами программисты и хотели бы не писать код по два раза,

NOTE: Утверждение спорное, но спросите себя
хотите вы переписывать свой код?
Нормальный ответ должен быть НЕТ.
поэтому наступает момент, когда ты уже разочарован в своем коде и начинаешь придумывать всякие штуки типа "technical debt" или "code sanity". Начальство с подозрением смотрит на эти штуки, так как какого хуйя писать два раза? С одного что-ли не понял? Но люди совершают ошибки и CMMI производственном процессе это все оговорено явно. Интересно кто читал вообще этот CMMI Level 5? Естественно програмисты совершают ошибки, их нужно фиксать. В этом смысле рефакторинг не отличается от обычной ошибку "тут хуйня". Никаких вроде бы проблем, но переписать 5 строчек и закрыть ошибку это ОК а переписать 5 классов или 5 проектов это уже BAD. Особенно если на них потрачено 5 миллионов долларов. Но тут у меня есть другой пример, как например в крупных инвест банках закрывают (end of life) проекты, которые писали с нуля несколько лет целым этажем программистов, которые получают по $4K. И все это еще делается на ура, потому что стало понятно что направление гиблое, коньюнктура изменилась и нужно быстро двигаться вперед. Все почему-то забывают про опыт. Конечно в больших компаниях все по-другому и опыт там понятие очень размазанное, на маленьких группах понятно, что если ты скажем писал по Java 10 лет, а потом перешел на Haskell то нельзя же сказать, что ты потратил 10 лет зря.

Вроде как хочется избежать рефакторинга. Важно понимать, что отсутвие рефаторинга не означает отсутвие эволюции. У нас же непрерывный процесс изменения кода, код который не изменяется мертв и никому не нужен. Напомню, что наш гипотетический программист абсолютно просветлен, стал ли бы он рефакторить?

Refactoring Prerequisites

После 10 лет непрерывного переписывание ООП лапши на C# я понял, что ООП парадигма не может исключить рефакторинг так как на самом начальном этапе информация структурируется довольно крупными блоками. В простейшем примере это 1 тип данных (поля объекта) + N функции для работы с этим типом. Но что если у нас 3 типа данных и N фунций? Вы ответите, что нужно три объекта. Не все так просто, так как непонятно какие функции к каким объектам "присоединять" или как говорят "инкапсулировать", если функция работает с более чем одним объектом. Так появляются всякие разруливающие менджеры, неуместное наследование и другие промежуточные звенья, которы пограмисты и рефакторят. Инкапсуляция это первое имманентное примордиальное зло программиста. Если вы испольузете инкапсуляцию 1 объект + N функий то — все вам пиздец — вы будете рефакторить пока не прочитаете наконец свою первую книгу по функциональному программированию.

Лисперы говорят, что при построении ООП систем, существует 12 уровней индирекшинов между слоями от базы данных до. Вот пример стектрейса таких систем (стектрейс курильщика):

com.devdaily.sarah.tests.TrySuccessFailure$AlsException: Bummer!
    at com.devdaily.sarah.tests.TrySuccessFailure$$anonfun$badAdder$1.apply$mcI$sp(TrySuccessFailure.scala:31)
    at com.devdaily.sarah.tests.TrySuccessFailure$$anonfun$badAdder$1.apply(TrySuccessFailure.scala:27)
    at com.devdaily.sarah.tests.TrySuccessFailure$$anonfun$badAdder$1.apply(TrySuccessFailure.scala:27)
    at scala.util.Try$.apply(Try.scala:161)
    at com.devdaily.sarah.tests.TrySuccessFailure$.badAdder(TrySuccessFailure.scala:27)
    at com.devdaily.sarah.tests.TrySuccessFailure$delayedInit$body.apply(TrySuccessFailure.scala:8)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
    at scala.App$class.main(App.scala:71)
    at com.devdaily.sarah.tests.TrySuccessFailure$.main(TrySuccessFailure.scala:6)
    at com.devdaily.sarah.tests.TrySuccessFailure.main(TrySuccessFailure.scala)

А вот пример стектрейсов на функциональных языках (стектрейс нормального человека):

[{gen_server,call,2,182},
 {deposits_termination,event,1,84},
 {n2o_nitrogen,info,3,42},
 {n2o_websocket,push,5,39},
 {bullet_handler,websocket_info,3,163},
 {cowboy_websocket,handler_call,7,588},
 {cowboy_protocol,resume,6,457}]


Наследование как известно это вторая хуйня которая заставить вас рефакторить свой код бесконечно. Тот кто писал свой Grid для GUI знает о чем я говорю. Угадать таксономию с первого раза и раскадать все по модели 1:N (объектов:функций) неполучится, а поскольку модель N:M (объектов:функций) нам недоступна мы используем таксономию для оптимизации по сути копипасты которая тянется из-за того что кому-то идиоту захателось чтобы функции цеплялить только к одному объекту.

Полиморфизм впрочем не такая плохая штука, однако почему-то он всегда в классических ООП языках реализован частично. Люди выдумают мультиметоды, дженерик фанкшинс и мультипл диспатч, просто потому, что они не прочитали в свое время про паттер мачинг при разработке своих языков. Вообще говоря эффективный паттерн мачинг это NP полная задача, поэтому тот, кто знает нужные эвристики у того таблицы SDN свичей матчатся очень эффективно. У Erlang довольно эффективный паттерн мачинг.

Breaking Changes

Итак мы определили уже что ООП заставляет делать ошибки в архитектуре, которые приводят к бесконечному рефакторингу. Допустим мы взяли ФП, каждая библиотека у наc имеет N типов-объектов и M функций-методов и мы жаждим непрерывной эволюции кода. У нас могут получится две вещи:

1) Эволюциионая разработка тоже как и рефакторинг может содержать ошибки. Но если ужас рефакторинга — это функториальная перекомпоновка функций и типов, то ужас эволюционной разработки это breaking changes. Тут я тоже могу кое о чем написать. Так как N2O за 2 с половиной года жизни имел всего 1 breaking change:

1. От версии 0.1 к версии 1.4. Ранний N2O.
2. От версии 1.5 к версии 2.5. N2O на протоколах.


Более детальная история N2O описана в History N2O.
потеря совместимости 1 раз за 11 релизов за 2.5 года — по-моему неплохо.

2) Идеально было бы вообще не иметь breaking changes. Программист-Будда именно так бы и делал, я знаю. С ужасом представляю еще одну потерю совместимости в N2O и тут важно не стать заложником эмоций. Возможно breaking changes нужно сделать и нужно признать свои ошибки. Но это не очень большая порблема, так как программисты же охотно признают свою непросветленность и требую рефакторинг, так что и breaking changes должны принимать.

Minimal Viable Product

Единственная штука к которой можно свести эволюционную разработку без рефакторинга — это попытаться написать суть приложения в одном файле. Тот кто хорошо и быстро прототипирует находится на пути безрефакторного программирования.

>

Без скромности могу сказать, что тут тоже есть чем похвастаться, распределенная CP база данных с chain replication, RAFT-оракулом (paxos optional), была написана за 2 недели и 2000 LOC. Почитать про CR можно тут. Тут важно очень хорошо понимать суть задачи. А то может быть так что если вы не знаете сути задачи, то вам придется построить 3-4 прототипа, прежде чем взять последний прототип как основу для дальнейшей эволюции проекта. Для прототипирования, когда незнакома предметная область рулят диматические языки Clojure или Erlang, если вы хороше разбираетесь в предметной области возможно быстро прототипировать и на Scala или Haskell.

Point Break

Что можно сказать о факте, что Erlang не менялся 20 лет, а Haskell меняется каждый год? Не хочется делать каких-то выводов, просто напишу мысли. Haskell ведь не стал хуже, от того, что там не боятся делать breaking changes, наоборот! А то что Erlang до сих пор остается актуальным, говорит о просветленности Джо Армстронга и принимаемых им решений. Erlang нашел свою мелодию одной струны, в то время как на Хаскеле мы имеем conduit, pipes, machines, iteratee. Ищут блядь архитекторы. Вообще в Хаскеле мало просветления. SPJ просветлен конечно, но Haskell сообщетво — это питонисты и джависты. Оно конечно немного лучше чем так называемое Erlang сообщество, тут немного дела похуже, тут уровень PHP. Проблема в том, что люди не знают чего они хотят, а это всегда хорошая почва для будущего рефакторинга.

Желаю вам никогда не рефакторить и никогда не выкатывать breaking changes!
buka

LING Bootstrap

Попробовать LING с приложениями SYNRC лучше всего с помощью MAD.

Например вы хотите чтобы ваше приложение и его зависимости было скомпилировано с вшитой виртуальной машиной и чтобы все было в виде исполняемого Mach-O DWARF-3 имаджа. Нет ничего проще! В rebar.config вам нужно указать зависимость от LING. Например вот rebar.config от нашего приложения MAD:

{deps_dir,"deps"}.
{deps, [{ling, ".*", {git, "git://github.com/proger/ling", {tag, "osx-again"}}},
        {sh, ".*",   {git, "git://github.com/synrc/sh",       {tag, "1.4"}}}]}.


Пока Влад не смержился с master нужно указывать его ветку и tag osx-again.

С LING идут два приложения ling (конветация байткода и другие внутренние функции ling) и et (шаблонизатор написанный Yariv Sadan). Шаблоны нужны при компилялции, для mad плагина нам понадобится только ling_code, ling_disasm, ling_bifs и ling_lib модули.
Как выглядят инструкции виртуальной машины LING (сконвертированный BEAM байткод в байткод LING):


5> element(2,ling_code:beam_to_ling(element(2,mad_repl:load_file("mad.beam")))).

{m,mad,
   [{label,[1],[]},
    {line,[1],[]},
    {func_info,[{a,mad},{a,main},1],[]},
    {label,[2],[]},
    {is_nil,[{f,3},{x,0}],[]},
    {l_call_only,[{f,57}],[]},
    {label,[3],[]},
    {l_allocate_zero,[3],[]},
    {line,[2],[]},
    {l_call_ext,[{e,{mad_utils,fold_params,1}}],[]},
    {is_tuple_of_arity,[{f,5},{x,0},2],[]},
    {extract_next_element,[{x,1}],[]},
    {get_tuple_element,[{x,0},1,{y,2}],[]},
    {l_is_ne_exact_immed,[{f,4},{x,1},nil],[]},
    {test_heap,[2,2],[]},
    {put_list,[{x,1},nil,{x,1}],[]},
    {line,[3],[]},
    {l_move_call_ext,[{literal,"Unknown Command or Parameter ~p~n\r"},
                      {e,{io,format,...}}],
                     []},
    ...


Также в LING идут оверлеи некоторых OTP модулей для приложений kernel, stdlib, crypto и os_mon. Они собираются автоматически при сборке LING. Не забывайте указывать ARCH=posix_x86. Сборку LING нужно осуществить после того как вы вытащили зависимости с помощью mad.

    $ git clone https://github.com/synrc/mad
    $ ./mad dep
    $ cd deps/ling
    $ ARCH=posix_x86 make


Так у нас появится собраный LING, его оверлеи для некоторых OTP приложений а так же ling и et приложения которые пока робко прячут свои бинарники в kernel приложении, чтобы не плодить приложений.

Теперь можно собвстенно попытаться собрать MAD'ом ваше приложение (в нашем случае мы будем собирать LING версию MAD :).

$ mad lin
Ling Params: []
ARCH: posix_x86
Bundle Name: mad
System: [compiler,syntax_tools,sasl,tools,mnesia,reltool,xmerl,crypto,kernel,
         stdlib,wx,webtool,ssl,runtime_tools,public_key,observer,inets,asn1,
         et,eunit,hipe,os_mon]
Apps: [kernel,stdlib,sh,mad]
Overlay: ["crypto.beam","9p.beam","9p_auth.beam","9p_info.beam",
          "9p_mounter.beam","9p_server.beam","9p_tcp.beam","9p_zero.beam",
          "disk.beam","disk_server.beam","embedded_export.beam",
          "goo_export.beam","goofs.beam","hipe_unified_loader.beam",
          "inet_config.beam","kernel.beam","ling_bifs.beam","ling_code.beam",
          "ling_disasm.beam","ling_iops.beam","ling_iopvars.beam",
          "ling_lib.beam","net_vif.beam","os.beam","prim_file.beam",
          "user_drv.beam","os_mon.beam","dets.beam","filename.beam",
          "maps.beam","unicode.beam","zlib.beam"]
Bucks: [{boot,"/boot",2},
        {os_mon,"/erlang/lib/os_mon/ebin",1},
        {crypto,"/erlang/lib/crypto/ebin",1},
        {kernel,"/erlang/lib/kernel/ebin",90},
        {stdlib,"/erlang/lib/stdlib/ebin",85},
        {sh,"/erlang/lib/sh/ebin",6},
        {mad,"/erlang/lib/mad/ebin",43}]
Initializing EMBED.FS:
Mount View:
 /boot /boot
/erlang/lib/os_mon/ebin /os_mon
/erlang/lib/crypto/ebin /crypto
/erlang/lib/kernel/ebin /kernel
/erlang/lib/stdlib/ebin /stdlib
/erlang/lib/sh/ebin /sh
/erlang/lib/mad/ebin /mad
Creating EMBED.FS C file: ...ok
Compilation of Filesystem object: ...ok
Linking Image: ok


Mount View показывает таблицу mount для приложений которые прилинкованы внутри EMBED.FS вшитой в образ. Получить ее можно запустив LING на маке и выполнив следующие команды:

$ rlwrap ./mad.img
Erlang [ling-0.3.2]

Eshell V6.3  (abort with ^G)
1> io:format("~s",[binary_to_list(element(2,file:read_file("/boot/local.map")))]).
/boot /boot
/erlang/lib/os_mon/ebin /os_mon
/erlang/lib/crypto/ebin /crypto
/erlang/lib/kernel/ebin /kernel
/erlang/lib/stdlib/ebin /stdlib
/erlang/lib/sh/ebin /sh
/erlang/lib/mad/ebin /mad
ok


Также можно посмотреть на загрузчик:

Boot Code: {script,
               {"Erlang/OTP","17"},
               [{preLoaded,[...]},
                {progress,preloaded},
                {path,["$ROOT/lib/kernel-3.0.3/ebin","$ROOT/lib/stdlib-2.2/ebin"]},
                {primLoad,[error_handler]},
                {kernel_load_completed},
                {progress,kernel_load_completed},
                {path,["$ROOT/lib/kernel-3.0.3/ebin"]},
                {primLoad,[...]},
                {path,["$ROOT/lib/stdlib-2.2/ebin"]},
                {primLoad,[...]},
                {progress,modules_loaded},
                {path,["$ROOT/lib/kernel-3.0.3/ebin","$ROOT/lib/stdlib-2.2/ebin"]},
                {kernelProcess,heart,{heart,start,[]}},
                {kernelProcess,error_logger,{error_logger,start_link,[]}},
                {kernelProcess,application_controller,{application_controller,start,[...]}},
                {progress,init_kernel_started},
                {apply,{application,load,[...]}},
                {progress,applications_loaded},
                {apply,{application,start_boot,[kernel,permanent]}},
                {apply,{application,start_boot,[stdlib,permanent]}},
                {apply,{c,erlangrc,[]}},
                {progress,started},
                {apply,{application,start,[kernel]}},
                {apply,{application,start,[stdlib]}},
                {apply,{application,start,[sh]}},
                {apply,{application,start,[mad]}}]}



Как видите в бутлоадер MAD вставил определенные приложения на файловой системе. Все эти приложения появились из rebar.config когда вы вытащили приложения. MAD LING плагин тесно интегрирован в MAD, поэтому занимает меньше чем оригинальный сборщик LING образов, который называется railing. По крайней мере я уже престал собирать им образы, полностью перешел на MAD. Ведь весь MAD вместе с поддержкой LING занимает всего 890 LOC, в то время как railing 990 LOC.

Парсер этого Boot Loader находится в preload/init.erl, именно он и выполняет инструкции Erlang OTP Boot Loader'а и запускает приложения при запуске виртуальнрй машины LING:

$ ./mad.img
Erlang [ling-0.3.2]

Eshell V6.3  (abort with ^G)
1> application:which_applications().
[{mad,"MAD VXZ Build Tool","2.2"},
 {sh,"VXZ SH Executor","0.9"},
 {stdlib,"ERTS  CXC 138 10","2.2"},
 {kernel,"ERTS  CXC 138 10","3.0.3"}]


OM A HUM
buka

LING: MIPS and POSIX ports

Решил на майских поиграться с LING. Как оказалось это проще чем предполагалось. Как вы уже знаете LING может работать с недавнего времени на arm, xen_x86 и posix_x86. Чтобы скомпилировать LING на Mac OS X не нужно ничего кроме clang идущего с системой.

   $ git clone https://github.com/proger/ling & cd ling
   $ make ARCH=posix_x86
   $ cd railing 
   $ make ARCH=posix_x86
   $ ./raling image
   $ ./raling.img
Erlang [ling-0.3.2]

Eshell V6.3  (abort with ^G)
1>


LING идет вместе с railing — это штука типа rebar или mad, но которая может создавать только образы LING с vmling.o и встроенной файловой системой. По умолчанию LING включает только два приложения stdlib и kernel. И то без priv каталогов. Карта маунтов виртуальной файловой системы на 9p протоколе выглядит при этом так:

1> '9p_mounter':show_map().
--------------------------------------------------------------------
Prio | Point                              | Conn       |  Fid | Type
--------------------------------------------------------------------
  11 | /boot                              |   <0.25.0> |    0 | dir
  12 | /erlang/lib/kernel-3.0.3/ebin      |   <0.25.0> |    1 | dir
  13 | /erlang/lib/stdlib-2.2/ebin        |   <0.25.0> |    2 | dir
--------------------------------------------------------------------
ok

1> ls("/boot").
local.map      start.boot
ok

2> io:format("~s~n",[binary_to_list(element(2,file:read_file("/boot/local.map")))]).
/boot /boot
/erlang/lib/kernel-3.0.3/ebin /kernel
/erlang/lib/stdlib-2.2/ebin /stdlib
/erlang/lib/kvs/ebin /kvs
/erlang/lib/db/ebin /db
/erlang/lib/mad/ebin /mad
/erlang/lib/sh/ebin /sh
/erlang/lib/mnesia-4.12.3/ebin /mnesia



Проблема в том, что в start.boot который берется из поставки Erlang/OTP умеет загружать только kernel и stdlib и чтобы писать загрузчик приложений во внутреннем формате Erlang/OTP нужнро самими генерировать эти структуры. Выглядит она вот так:

6> element(3,binary_to_term(element(2,file:read_file("/boot/start.boot")))).
[{preLoaded,
     [erl_prim_loader,erlang,erts_internal,init,otp_ring0,
      prim_eval,prim_file,prim_inet,prim_zip,zlib]},
 {progress,preloaded},
 {path,["$ROOT/lib/kernel/ebin","$ROOT/lib/stdlib/ebin"]},
 {primLoad,[error_handler]},
 {kernel_load_completed},
 {progress,kernel_load_completed},
 {path,["$ROOT/lib/kernel/ebin"]},
 {primLoad,
     [application,application_controller,application_master,
      application_starter,auth,code,code_server,disk_log,
      disk_log_1,disk_log_server,disk_log_sup,dist_ac,dist_util,
      erl_boot_server,erl_ddll,erl_distribution,erl_epmd,
      erl_reply,error_logger|...]},
 {path,["$ROOT/lib/stdlib/ebin"]},
 {primLoad,
     [array,base64,beam_lib,binary,c,calendar,dets,dets_server,
      dets_sup,dets_utils,dets_v8,dets_v9,dict,digraph,
      digraph_utils,edlin,edlin_expand|...]},
 {progress,modules_loaded},
 {path,["$ROOT/lib/kernel/ebin","$ROOT/lib/stdlib/ebin"]},
 {kernelProcess,heart,{heart,start,[]}},
 {kernelProcess,error_logger,{error_logger,start_link,[]}},
 {kernelProcess,application_controller,
     {application_controller,start,
         [{application,kernel,
              [{description,"ERTS  CXC 138 10"},
               {vsn,[...]},
               {id,...},
               {...}|...]}]}},
 {progress,init_kernel_started},
 {apply,
     {application,load,
         [{application,stdlib,
              [{description,[...]},{vsn,...},{...}|...]}]}},
 {progress,applications_loaded},
 {apply,{application,start_boot,[kernel,permanent]}},
 {apply,{application,start_boot,[stdlib,permanent]}},
 {apply,{c,erlangrc,[]}},
 {progress,started}]

7> [P||{path,[P]} <- element(3,binary_to_term(element(2,file:read_file("/boot/start.boot")))) ].
["$ROOT/lib/kernel/ebin",
 "$ROOT/lib/stdlib/ebin"]



Как видно здесь происходит вызов приложений, похоже мы можем просто вписывать операции запуска приложений как описанов в apply операциях:

 {apply,{application,start_boot,[kernel,permanent]}},
 {apply,{application,start_boot,[stdlib,permanent]}},
 {apply,{c,erlangrc,[]}},


Кстати здесь видно backdoor эрланговый, при запуске виртуальной машины BEAM, всегда вызывается c:erlangrc(). Я думаю что в LING это можно пофиксать, и не включать в start.boot этот вызов, а наоборот, вставить вызовы наших приложений. Чтобы заставить формировать файловую систему с проивольными приложениями, пришлось немного изменить railing, при этом я запустил основные свои приложения.

1> '9p_mounter':show_map().
--------------------------------------------------------------------
Prio | Point                              | Conn       |  Fid | Type
--------------------------------------------------------------------
  11 | /boot                              |   <0.25.0> |    0 | dir
  12 | /erlang/lib/kernel-3.0.3/ebin      |   <0.25.0> |    1 | dir
  13 | /erlang/lib/stdlib-2.2/ebin        |   <0.25.0> |    2 | dir
  14 | /erlang/lib/kvs/ebin               |   <0.25.0> |    3 | dir
  15 | /erlang/lib/db/ebin                |   <0.25.0> |    4 | dir
  16 | /erlang/lib/mad/ebin               |   <0.25.0> |    5 | dir
  17 | /erlang/lib/sh/ebin                |   <0.25.0> |    6 | dir
  18 | /erlang/lib/mnesia-4.12.3/ebin     |   <0.25.0> |    7 | dir
--------------------------------------------------------------------

2> application:which_applications().
[{sh,"VXZ SH Executor","0.9"},
 {mad,"MAD VXZ Build Tool","2.2"},
 {db,"Bank Database","1"},
 {kvs,"KVS Abstract Term Database","1"},
 {mnesia,"MNESIA  CXC 138 12","4.12.3"},
 {stdlib,"ERTS  CXC 138 10","2.2"},
 {kernel,"ERTS  CXC 138 10","3.0.3"}]

3> os:type().
{xen,ling}


Пишет {xen,ling} но должно писать {posix,ling}. Пока буду заниматься формированием файловой системы для LING бандла. Итого mad в скором времени будет поддерживать два вида файлов: 1) это BEAM escript бандл со своей файловой системой которая распаковывается в ETS при запуске, и которая может затенятся локальными файлаим 2) Образ виртуальной машины LING слинкованый с файловой системой с erlang приложениями, при этом для posix порта, этот образ представляет собой исполняемый образ хост операционной системы.

Моя плата MIPS Creator CI20 уже куплена, но еще не приехала:



Поэтому пока ее нет, самое время собрать cross тулзы. Что касается MIPS порта, то я только собрал mipsel-ling-elf-gcc-5.1.0 компилятор используя crosstool-ng, который используется при сборке ARM порта LING. Чтобы использовать один тулчейн для всех платформ, на MIPS тоже будем использовать crosstool-ng. Для этого надо создать в Disk Utility новый диск используя чувствительную к регистру журналируемую файловую систему. crosstool-ng имеет menuconfig



В котором нужно выставить Little Endian для платы CI20 а также выставить tuple mipsel-ling-elf. Для создания raw U-Boot образов, проверить что статическая линковка отключена, и выбрать нужную libc: uLibc, musl, newlib. Поддержка libc у crosstool-ng просто шикарная.

brew install crosstool-ng
ct-ng mips-unknown-elf
ct-ng menuconfig
ct-ng build

mipsel-ling-elf-gcc-5.1.0 --version
mipsel-ling-elf-gcc-5.1.0 (crosstool-NG 1.20.0) 5.1.0

mipsel-ling-elf-objcopy --info
...
               elf32-littlemips elf32-bigmips elf64-bigmips elf64-littlemips
          mips elf32-littlemips elf32-bigmips elf64-bigmips elf64-littlemips
        plugin ---------------- ------------- ------------- ----------------

               elf64-little elf64-big elf32-little elf32-big plugin srec
          mips elf64-little elf64-big elf32-little elf32-big ------ srec
        plugin elf64-little elf64-big elf32-little elf32-big ------ srec

               symbolsrec verilog tekhex binary ihex
          mips symbolsrec verilog tekhex binary ihex
        plugin symbolsrec verilog tekhex binary ihex



gcc-5.1 прекрасно собирается clang, так что думаю можно еще xen_86 сборку перевести на crosstool-ng. Что касается драйвера последовтельного порта и startup.s, то придется понатыкивать с SDK примеров к CI20, тав вроде в arm ничего особенного, не думаю что с MIPS будут проблемы, божественная архитектура. Сейчас каталог arch в LING выглядит так:

$ tree arch -L 1
arch
├── arm
├── mips
├── posix_x86
└── xen_x86