How to get the binary representation of a module

Let’s say I have a module that is loaded, but not compiled into a beam file (it is defined in a exs file, or directly typed into iex). Is there any way to get the binary representation of that module at runtime?

I’ve tried with :code.get_object_code/1, but it only seems to work when there is a beam file, otherwise it returns :error:

iex(1)> defmodule Foo do
...(1)> end
{:module, Foo,
 <<70, 79, 82, 49, 0, 0, 3, 32, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 117,
   0, 0, 0, 12, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
   105, 110, 102, 111, 95, 95, 7, 99, 111, ...>>, nil}
iex(2)> :code.get_object_code(Foo)
:error

To be clear: what I’d like to get is the third element of the tuple returned by defmodule.

Why do you want to do that?

Maybe you want Code.compile_file/2 or Code.compile_string/2?

iex(46)> Code.compile_string("defmodule Foo do end") |> IO.inspect(limit: :infinity) 
warning: redefining module Foo (current version defined in memory)
  nofile:1

[
  {Foo,
   <<70, 79, 82, 49, 0, 0, 3, 12, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 117,
     0, 0, 0, 12, 10, 69, 108, 105, 120, 105, 114, 46, 70, 111, 111, 8, 95, 95,
     105, 110, 102, 111, 95, 95, 7, 99, 111, 109, 112, 105, 108, 101, 3, 109,
     100, 53, 10, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 6, 109, 111,
     100, 117, 108, 101, 10, 100, 101, 112, 114, 101, 99, 97, 116, 101, 100, 9,
     102, 117, 110, 99, 116, 105, 111, 110, 115, 6, 109, 97, 99, 114, 111, 115,
     6, 101, 114, 108, 97, 110, 103, 15, 103, 101, 116, 95, 109, 111, 100, 117,
     108, 101, 95, 105, 110, 102, 111, 11, 109, 111, 100, 117, 108, 101, 95,
     105, 110, 102, 111, 0, 0, 0, 67, 111, 100, 101, 0, 0, 0, 117, 0, 0, 0, 16,
     0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 10, 0, 0, 0, 3, 1, 16, 153, 0, 2, 18,
     34, 16, 1, 32, 48, 21, 3, 59, 3, 21, 23, 224, 50, 53, 66, 53, 82, 53, 98,
     69, 114, 85, 130, 85, 146, 85, 1, 48, 64, 3, 19, 64, 18, 3, 153, 0, 78, 32,
     0, 1, 64, 64, 18, 3, 19, 1, 80, 64, 2, 3, 19, 1, 96, 153, 0, 2, 18, 194, 0,
     1, 112, 64, 18, 3, 153, 0, 78, 16, 16, 1, 128, 153, 0, 2, 18, 194, 16, 1,
     144, 64, 3, 19, 64, 18, 3, 153, 0, 78, 32, 0, 3, 0, 0, 0, 83, 116, 114, 84,
     0, 0, 0, 0, 73, 109, 112, 84, 0, 0, 0, 28, 0, 0, 0, 2, 0, 0, 0, 10, 0, 0,
     0, 11, 0, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 1, 69, 120, 112, 84,
     0, 0, 0, 40, 0, 0, 0, 3, 0, 0, 0, 12, 0, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0, 12,
     0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 76, 111, 99,
     84, 0, 0, 0, 4, 0, 0, 0, 0, 65, 116, 116, 114, 0, 0, 0, 40, 131, 108, 0, 0,
     0, 1, 104, 2, 100, 0, 3, 118, 115, 110, 108, 0, 0, 0, 1, 110, 16, 0, 172,
     42, 167, 141, 120, 247, 60, 243, 77, 148, 209, 20, 217, 102, 90, 131, 106,
     106, 67, 73, 110, 102, 0, 0, 0, 79, 131, 108, 0, 0, 0, 3, 104, 2, 100, 0,
     7, 118, 101, 114, 115, 105, 111, 110, 107, 0, 5, 55, 46, 50, 46, 53, 104,
     2, 100, 0, 7, 111, 112, 116, 105, 111, 110, 115, 106, 104, 2, 100, 0, 6,
     115, 111, 117, 114, 99, 101, 107, 0, 25, 47, 100, 97, 116, 97, 47, 114,
     101, 112, 111, 115, 47, 116, 117, 114, 114, 101, 116, 47, 110, 111, 102,
     105, 108, 101, 106, 0, 68, 98, 103, 105, 0, 0, 0, 144, 131, 80, 0, 0, 0,
     174, 120, 156, 45, 141, 81, 14, 194, 48, 12, 67, 131, 64, 19, 12, 184, 10,
     210, 14, 1, 215, 168, 186, 37, 99, 153, 218, 166, 234, 210, 137, 227, 147,
     34, 254, 252, 108, 203, 94, 142, 8, 119, 164, 177, 190, 29, 167, 89, 220,
     62, 32, 244, 20, 248, 195, 197, 81, 9, 139, 197, 151, 63, 238, 131, 2, 192,
     217, 114, 175, 90, 120, 172, 74, 219, 138, 112, 155, 36, 102, 14, 228, 36,
     107, 227, 43, 210, 204, 137, 149, 37, 53, 236, 145, 114, 161, 201, 43, 161,
     209, 105, 182, 102, 180, 153, 46, 73, 147, 230, 4, 78, 228, 15, 8, 93, 20,
     172, 205, 233, 159, 191, 191, 199, 75, 196, 214, 106, 42, 228, 167, 197,
     143, 129, 214, 245, 11, 102, 226, 57, 34, 68, 111, 99, 115, 0, 0, 0, 55,
     131, 104, 7, 100, 0, 7, 100, 111, 99, 115, 95, 118, 49, 97, 1, 100, 0, 6,
     101, 108, 105, 120, 105, 114, 109, 0, 0, 0, 13, 116, 101, 120, 116, 47,
     109, 97, 114, 107, 100, 111, 119, 110, 100, 0, 4, 110, 111, 110, 101, 116,
     0, 0, 0, 0, 106, 0, 69, 120, 68, 112, 0, 0, 0, 27, 131, 104, 2, 100, 0, 20,
     101, 108, 105, 120, 105, 114, 95, 100, 101, 112, 114, 101, 99, 97, 116,
     101, 100, 95, 118, 49, 106, 0, 76, 105, 110, 101, 0, 0, 0, 20, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0>>}
]

My goal is to run code defined in my tests on a slave node to perform assertions about how a distributed application is behaving.

Code.compile_file/2 and Code.compile_string/2 return the module being defined in the file or the string, not the one that is already loaded, which is the one I’m looking for.

It’s not possible. You’d have to store the bytecode yourself.

Are you writing tests in .exs files ?

  1. Your best bet might be to place the code performing the assertions in a module and load that.

Is your slave node started using :slave ? By using the proper path on startup or using Code.append_path/1 post startup the slave will load the module automatically for you.

  1. The other option is to grab the information needed for your assertion remotely via :rpc and execute the assertion code locally.
1 Like

I’d like to build it as a library, thus it should work with .ex and .exs tests to provide the best user experience.

Yes, I’m using :slave, but I think Code.append_path/1 won’t work because it receives a path where the .beam files are located, and there is no such path for .exs files.

Yes, that is a viable solution. It doesn’t allow the user to run anonymous functions on the slave, which I think will provide the best experience, but I’ll probably end up doing something like that.