[erlang-questions] Installing a module from code?

John Haugeland <>
Tue Mar 24 02:12:25 CET 2009


I've got a problem I don't fully understand.  I keep wanting to call it a
bug, but it may be that I'm handling this wrongly.

During my attempt to compile and install a module from code, it seems I've
managed to break the Erlang VMs I'm installing into.  My gut instinct is
that my namespaced module sc.file is somehow conflicting with the real
module file.  This is frustrating, because after my compile process it
appears to work as expected; sc.file is treated differently than file, all
package calls are resolved appropriately, etc.  But, on next start, one gets
the following error:

Erlang (BEAM) emulator version 5.6.4 [smp:2] [async-threads:0]

{"init terminating in do_boot",{undef,
  [{file,path_eval,[[".","C:\Users\John Haugeland"],".erlang"]},
  {c,f_p_e,2},{init,eval_script,7},{init,do_boot,3}]}}

Crash dump was written to: erl_crash.dump
init terminating in do_boot ()

Abnormal termination

(Formatted that a little to make it fit email)

And I mean, that kind of looks like that's the Erlang VM saying "I have no
function path_eval in module file", and as stupid as it sounds, the back of
my mind is screaming "it's because sc.file overrides real .file".

I have replicated this on Windows Vista HP-32 5.6.4, Windows Vista HP-32
5.5.5 and Centos4-32 5.6.4.  All I have to do is run my install process,
where everything appears to go kosher, then restart the Erlang VM.

So, my method of "installing" is to take the source root directory and call
.compile:file() progressively on each source file.  Then I use
.code:get_object_code() to get the binary and the filename, which I pass
with the module name as an atom to .code:load_binary() to load the actual
code (since :load.module() doesn't seem to understand package names).  I'm
actually going to show my install process twice, because there's a much
shorter version and a much longer version.  The shorter version is used to
compile my string module, which contains utilities that the installer uses,
so that it can turn around and install everything else.  As such, it's a
single special case and shows my expectation of The Right Way to do this in
a very short space; that way if I'm just taking a numbskulled approach
someone can point out my fool fault with little effort.  Then I'm posting
the long version, in case it's somehow importantly different than the string
special case.

But frankly, here's how this seems to me: I think the packaged modules are
conflicting at boot time with the real thing.  I can't imagine any other
reason for do_boot to complain that a function that's part of the standard
library is unavailable.

If for whatever reason this code is unreadable, it can be gotten at
http://scutil.com/ from /src/sc/installer.erl .  I would recommend
installing it on an isolated VM; calling the installer will prevent that VM
from booting again.

The short one (note that get_object_code seems only to work with the
"un-packaged" name, which I worry is part of the problem):

.compile:file(From++"/src/sc/string.erl"),
{_, Bin, FileName} = .code:get_object_code(string),
.code:load_binary('sc.string', FileName, Bin),

The long one:

compile_all(From, Options) ->

    ReportOnCompile = fun
        ( Module, error)                                 -> { error, Module
};
        ( Module, {error, ErrorList, WarningList})       -> { error, Module,
ErrorList, WarningList };
        (_Module, {ok,AtomName})                         -> AtomName;
        (_Module, {ok,AtomName, Warnings})               -> { AtomName,
Warnings }
    end,

    IsFailureCase = fun
        ({ error,_Module })                         -> true;
        ({ error,_Module,_ErrorList,_WarningList }) -> true;
        (_)                                         -> false
    end,

    IsWarningCase = fun
        ({_ModuleAtom, [] })       -> false;
        ({_ModuleAtom,_Warnings }) -> true
    end,

    ToFilename = fun
        (List) when is_list(List) -> .sc.string:implode("/", [
atom_to_list(Item) || Item <- List ]) ++ ".erl";
        (Atom) when is_atom(Atom) -> atom_to_list(Atom) ++ ".erl"
    end,

    Report = [ ReportOnCompile(From ++ ToFilename(File), .compile:file(From
++ ToFilename(File), Options)) ||
        File <- contained_modules()
    ],

    { Fail, PassWarn } = .lists:partition(IsFailureCase, Report),
    { Warn, Pass     } = .lists:partition(IsWarningCase, PassWarn),

    LoadFile = fun(Passed) ->
        [LastPiece|_]      = .lists:reverse(.sc.string:explode(".",
atom_to_list(Passed))),
        {_, Bin, FileName} = .code:get_object_code(list_to_atom(LastPiece)),
        .code:load_binary(Passed, FileName, Bin)
    end,

    [ LoadFile(Passed) || {Passed,[]} <- Pass ],

    { { pass, Pass }, { warn, Warn }, { fail, Fail } }.

I know it's a lot to ask, but I could use some help sorting this out; these
parts of the standard library aren't well documented, and I wouldn't want to
think one could break an erlang install by compiling and loading modules
containing correct code under a name which should not but does conflict.  I
really want there to be a stupid mistake on my part here.

Any help would be greatly appreciated.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20090323/e74d1f5e/attachment.html>


More information about the erlang-questions mailing list