Module unavailable during compilation, but not at runtime

Reproducible example:

I have an app where there is an auto-generated (protobuf) module Protocol.Account which for some reason is unavailable during compilation:

warning: function Procotol.Account.new/1 is undefined (module Procotol.Account is not available)
  lib/example.ex:15

but available at runtime:

iex(1)> Protocol.Account.new([])
%Protocol.Account{
  account_id: "",
  account_name: "",
  account_resource: nil,
  address: "",
  allowance: 0,
  asset: %{},
  asset_issued_name: "",
  balance: 0,
  code: "",
  codeHash: "",
  create_time: 0,
  free_asset_net_usage: %{},
  free_net_usage: 0,
  frozen: [],
  frozen_supply: [],
  is_committee: false,
  is_witness: false,
  latest_asset_operation_time: %{},
  latest_consume_free_time: 0,
  latest_consume_time: 0,
  latest_opration_time: 0,
  latest_withdraw_time: 0,
  net_usage: 0,
  type: 0,
  votes: []
}

What could be the reason?

deps/tron include source files for Procotol.Account module, and _build/dev/ebin/lib/tron/ebin/Elixir.Protocol.Account.beam exists as well.


example.app

{application,example,
             [{applications,[kernel,stdlib,elixir,logger,tron]},
              {description,"example"},
              {modules,['Elixir.Example']},
              {registered,[]},
              {vsn,"0.1.0"}]}.

tron/app

{application,tron,
             [{applications,[kernel,stdlib,elixir,logger,protobuf,
                             libsecp256k1,keccakf1600,google_protos,grpc]},
              {description,"TRON protocol implementation in elixir.\n"},
              {modules,['Elixir.Protocol.Account',
                        'Elixir.Protocol.Account.AccountResource',
                        'Elixir.Protocol.Account.AssetEntry',
                        'Elixir.Protocol.Account.FreeAssetNetUsageEntry',
                        'Elixir.Protocol.Account.Frozen',
                        'Elixir.Protocol.Account.LatestAssetOperationTimeEntry',
                        'Elixir.Protocol.AccountCreateContract',
                        'Elixir.Protocol.AccountId',
                        'Elixir.Protocol.AccountNetMessage',
                        'Elixir.Protocol.AccountNetMessage.AssetNetLimitEntry',
                        'Elixir.Protocol.AccountNetMessage.AssetNetUsedEntry',
                        'Elixir.Protocol.AccountPaginated',
                        'Elixir.Protocol.AccountResourceMessage',
                        'Elixir.Protocol.AccountResourceMessage.AssetNetLimitEntry',
                        'Elixir.Protocol.AccountResourceMessage.AssetNetUsedEntry',
                        'Elixir.Protocol.AccountType',
                        % ...
                        'Elixir.Protocol.WitnessUpdateContract','Elixir.Tron',
                        'Elixir.Tron.Client']},
              {registered,[]},
              {vsn,"0.1.0-rc"}]}.

Seems like a module name clash where Elixir.Protocol wins during compilation and loses at runtime? Still don’t understand why Elixir.Protocol.Account cannot be used. Can it be due to a protocol consolidation mix option?

Fixed in :tron by using a protobuf prefix different from Protocol.* (Tron.*).

2 Likes

Ah, so is Protocol.* treated in a special manner by the compiler?

¯_(ツ)_/¯