123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- -module(mad_ling).
- -author('Maxim Sokhatsky').
- -description("LING Erlang Virtual Machine Bundle Packaging").
- -copyright('Cloudozer, LLP').
- -compile(export_all).
- -define(ARCH, list_to_atom( case os:getenv("ARCH") of false -> "posix"; A -> A end)).
- main(_App) ->
- io:format("ARCH: ~p~n", [?ARCH]),
- io:format("Bundle Name: ~p~n", [mad_repl:local_app()]),
- io:format("System: ~p~n", [mad_repl:system()]),
- io:format("Apps: ~p~n", [mad_repl:applist()]),
- % io:format("Overlay: ~p~n", [[{filename:basename(N),size(B)}||{N,B} <- mad_bundle:overlay()]]),
- % io:format("Files: ~p~n", [[{filename:basename(N),size(B)}||{N,B} <- bundle()]]),
- io:format("Overlay: ~p~n", [[filename:basename(N)||{N,_B} <- mad_bundle:overlay()]]),
- add_apps(),
- false.
- cache_dir() -> ".madaline/".
- local_map(Bucks) -> list_to_binary(lists:map(fun({B,M,_}) -> io_lib:format("~s /~s\n",[M,B]) end,Bucks)).
- bundle() -> lists:flatten([ mad_bundle:X() || X <- [beams,privs,system_files,overlay] ]).
- library(Filename) -> case filename:split(Filename) of
- ["deps","ling","apps",Lib|_] -> list_to_atom(Lib);
- ["ebin"|_] -> mad_repl:local_app();
- ["priv"|_] -> mad_repl:local_app();
- A when length(A) >= 3 -> list_to_atom(hd(string:tokens(lists:nth(3,lists:reverse(A)),"-")));
- ["apps",Lib|_] -> list_to_atom(Lib);
- ["deps",Lib|_] -> list_to_atom(Lib);
- _ -> mad_repl:local_app() end.
- apps(Ordered) ->
- Overlay = [ {filename:basename(N),B} || {N,B} <- mad_bundle:overlay() ],
- lists:foldl(fun({N,B},Acc) ->
- A = library(N),
- Base = filename:basename(N),
- Body = case lists:keyfind(Base,1,Overlay) of
- false -> B;
- {Base,Bin} -> 'overlay', Bin end,
- case lists:keyfind(A,1,Acc) of
- false -> [{A,[{A,Base,Body}]}|Acc];
- {A,Files} -> lists:keyreplace(A,1,Acc,{A,[{A,Base,Body}|Files]}) end
- end,lists:zip(Ordered,lists:duplicate(length(Ordered),[])),bundle()).
- lib({App,Files}) ->
- { App, lists:concat(["/erlang/lib/",App,"/ebin"]), Files }.
- boot(Ordered) ->
- BootCode = element(2,file:read_file(lists:concat([code:root_dir(),"/bin/start.boot"]))),
- { script, Erlang, Boot } = binary_to_term(BootCode),
- AutoLaunch = {script,Erlang,Boot++[{apply,{application,start,[App]}} || App <- Ordered]},
- io:format("Boot Code: ~p~n",[AutoLaunch]),
- { boot, "start.boot", term_to_binary(AutoLaunch) }.
- add_apps() ->
- {ok,Ordered} = mad_plan:orderapps(),
- Bucks = [{boot,"/boot",[local_map, boot(Ordered)]}] ++ [ lib(E) || E <- apps(Ordered) ],
- %io:format("Bucks: ~p~n",[[{App,Mount,[{filename:basename(F),size(Bin)}||{_,F,Bin}<-Files]}||{App,Mount,Files}<-Bucks]]),
- io:format("Bucks: ~p~n",[[{App,Mount,length(Files)}||{App,Mount,Files}<-Bucks]]),
- filelib:ensure_dir(cache_dir()),
- EmbedFsPath = lists:concat([cache_dir(),"/embed.fs"]),
- io:format("Initializing EMBED.FS:"),
- Res = embed_fs(EmbedFsPath,Bucks),
- {ok, EmbedFsObject} = embedfs_object(EmbedFsPath),
- Oneliner = ld() ++
- ["../deps/ling/core/vmling.o"] ++
- ["-lm", "-lpthread", "-ldl"] ++
- [EmbedFsObject, "-o", "../" ++ atom_to_list(mad_repl:local_app()) ++ ".img"],
- io:format("LD: ~p~n",[Oneliner]),
- Res = case sh:oneliner(Oneliner,cache_dir()) of
- {_,0,_} -> ok;
- {_,_,M} -> binary_to_list(M) end,
- io:format("Linking Image: ~p~n",[Res]).
- embed_fs(EmbedFsPath,Bucks) ->
- {ok, EmbedFs} = file:open(EmbedFsPath, [write]),
- BuckCount = length(Bucks),
- BinCount = lists:foldl(fun({_,_,Bins},Count) -> Count + length(Bins) end,0,Bucks),
- file:write(EmbedFs, <<BuckCount:32>>),
- file:write(EmbedFs, <<BinCount:32>>),
- lists:foreach(fun({Buck,_,Bins}) ->
- BuckName = binary:list_to_bin(atom_to_list(Buck)),
- BuckNameSize = size(BuckName),
- BuckBinCount = length(Bins),
- file:write(EmbedFs, <<BuckNameSize, BuckName/binary, BuckBinCount:32>>),
- lists:foreach(fun
- (local_map) -> LocalMap = local_map(Bucks),
- io:format("~nMount View:~n ~s",[LocalMap]),
- write_bin(EmbedFs, "local.map", LocalMap);
- ({_App,F,Bin}) -> write_bin(EmbedFs, filename:basename(F), Bin)
- end,Bins)
- end,Bucks),
- file:close(EmbedFs),
- ok.
- embedfs_object(EmbedFsPath) ->
- EmbedCPath = filename:join(filename:absname(cache_dir()), "embedfs.c"),
- OutPath = filename:join(filename:absname(cache_dir()), "embedfs.o"),
- {ok, Embed} = file:read_file(EmbedFsPath),
- io:format("Creating EMBED.FS C file: ..."),
- Res = bfd_objcopy:blob_to_src(EmbedCPath, "_binary_embed_fs", Embed),
- io:format("~p~n",[Res]),
- io:format("Compilation of Filesystem object: ..."),
- Res = case sh:oneliner(cc() ++ ["-o", OutPath, "-c", EmbedCPath]) of
- {_,0,_} -> ok;
- {_,_,M} -> binary_to_list(M) end,
- io:format("~p~n",[Res]),
- io:format("Out Path: ~p~n",[OutPath]),
- {ok, OutPath}.
- write_bin(Dev, F, Bin) ->
- {ListName,Data} = case filename:extension(F) of
- ".beam" -> { filename:rootname(F) ++ ".ling", beam_to_ling(Bin) };
- _ -> { F, Bin } end,
- Name = binary:list_to_bin(ListName),
- NameSize = size(Name),
- DataSize = size(Data),
- file:write(Dev, <<NameSize, Name/binary, DataSize:32, Data/binary>>).
- beam_to_ling(B) ->
- ling_lib:specs_to_binary(element(2,ling_code:ling_to_specs(element(2,ling_code:beam_to_ling(B))))).
- gold() -> gold("ld").
- gold(Prog) -> [Prog, "-T", "ling.lds", "-nostdlib"].
- ld() -> ld(?ARCH).
- ld(arm) -> gold("arm-none-eabi-ld");
- ld(xen_x86) -> case os:type() of {unix, darwin} -> ["x86_64-pc-linux-ld"]; _ -> gold() end;
- ld(posix) -> case os:type() of {unix, darwin} ->
- ["clang","-image_base","0x8000","-pagezero_size","0x8000","-arch","x86_64"];
- _ -> gold() end;
- ld(_) -> gold().
- cc() -> cc(?ARCH).
- cc(arm) -> ["arm-none-eabi-gcc", "-mfpu=vfp", "-mfloat-abi=hard"];
- cc(xen_x86) -> case os:type() of {unix, darwin} -> ["x86_64-pc-linux-gcc"]; _ -> ["cc"] end;
- cc(_) -> ["cc"].
|