code(3)
πΈ NAME πΈ
code β the interface to the Erlang code server process. that's the whole vibe, bestie. she's the one who actually puts your compiled code into a running Erlang runtime system π
β¨ DESCRIPTION β¨
so. this module is literally the group chat between you and the Erlang code server, and the code server is the one whose entire job is loading compiled code into a live Erlang runtime system. iconic behaviour, no notes π«Ά
your runtime system can boot up in interactive mode or embedded mode, and which one you get is decided by the command-line flag -mode:
% erl -mode embedded
the two modes, bestie, are:
- interactive mode β this is the default, if you didn't clock it. only the modules the runtime system needs get loaded while it's starting up. everything else gets dynamically loaded the moment something first references it. so when somebody calls a function in a module, and that module isn't loaded yet? the code server goes searching for it and tries to load it. queen behaviour π
- embedded mode β nobody auto-loads here. modules do not get pulled in by themselves. try to use a module that hasn't been loaded and you get an error, periodt. this mode is the recommended one when the boot script loads up all the modules, which is how it's typically done in OTP releases. (you can still load code later, you just have to explicitly order the code server to do it. she's not gonna guess. π)
now β to stop you from accidentally reloading modules that the Erlang runtime system itself depends on, the directories kernel, stdlib, and compiler are considered sticky. what that means in practice: if a user tries to reload a module living in any of those, the system throws a warning and rejects the request. you can turn that whole feature off with the command-line flag -nostick.
π¦ Code Path π¦
in interactive mode, the code server keeps a code path β a whole list of directories β and she walks it sequentially when she's trying to load a module. like scrolling through the chat until she finds the message. π
at the very start, the code path is made of the current working directory plus every Erlang object code directory under the library directory $OTPROOT/lib, where $OTPROOT is the installation directory of Erlang/OTP, aka code:root_dir(). directories can be named Name[-Vsn] and the code server, by default, picks the directory with the highest version number among all the ones sharing the same Name. the suffix -Vsn is optional. and if there's an ebin directory sitting under Name[-Vsn], that directory is the one that gets added to the code path.
the environment variable ERL_LIBS (defined by your operating system, not by Erlang) is how you add more library directories to be handled exactly the same way as the standard OTP library directory above β with one exception: directories that don't have an ebin directory get ignored. sorry, no ebin, no entry. π
every application directory found in those extra directories shows up before the standard OTP applications. except for the Kernel and STDLIB applications, which get placed before any additional applications. so, in other words: modules found in any of the additional library directories override modules with the same name in OTP β except modules in Kernel and STDLIB, they're protected. main character immunity, fr fr. π
ERL_LIBS (if it's defined at all) is supposed to contain a colon-separated list (that's for Unix-like systems) or a semicolon-separated list (that's for Windows) of additional libraries.
Example:
on a Unix-like system, ERL_LIBS can be set to this:
/usr/local/jungerl:/home/some_user/my_erlang_lib
okay so the code paths given by $OTPROOT, ERL_LIBS, and boot scripts have their listings cached by default (everything except "."). what that means: the code server looks up the contents of those directories once and then avoids future file system traversals entirely. which also means β and this is the part that gets people β modules you drop into those directories after the Erlang VM has already booted will not be picked up. π
you can disable this behaviour by setting -cache_boot_paths false or by calling code:set_path(code:get_path()).
CHANGE: the support for caching directories in the code path was added in Erlang/OTP 26.
directories you give via the command line options -pa and -pz are not cached by default. and lots of the functions that manipulate the code path accept the atom cache as an optional argument, so you can switch caching on selectively. very choose-your-own-adventure of her. β¨
π Loading of Code From Archive Files π
CHANGE: the existing experimental support for archive files will be changed in a future release. as of Erlang/OTP 27, the functioncode:lib_dir/2, the-code_path_choiceflag, and usingerl_prim_loaderfor reading files from an archive are deprecated.escriptscripts that use archive files should useescript:extract/2to read data files from their archive instead of usingcode:lib_dir/2anderl_prim_loader.
the Erlang archives are ZIP files with the extension .ez. Erlang archives can also be enclosed in escript files whose file extension is arbitrary β she's flexible like that. π
Erlang archive files can contain entire Erlang applications, or just parts of applications. the structure inside an archive file is the same as the directory structure for an application. so if you, for example, create an archive of mnesia-4.4.7, the archive file has to be named mnesia-4.4.7.ez and it has to contain a top directory named mnesia-4.4.7. if you drop the version part of the name, you have to drop it in the archive too. meaning: a mnesia.ez archive must contain a mnesia top directory. consistency is the vibe. π
an archive file for an application can, for example, be created like this:
zip:create("mnesia-4.4.7.ez",
["mnesia-4.4.7"],
[{cwd, code:lib_dir()},
{compress, all},
{uncompress,[".beam",".app"]}]).
any file in the archive can be compressed, but to speed up access to files you read all the time, it can be a good idea to store beam and app files uncompressed in the archive. little optimization moment. π§
normally, the top directory of an application lives in the library directory $OTPROOT/lib, or in a directory referred to by the environment variable ERL_LIBS. at startup, when the initial code path is being computed, the code server also goes looking for archive files in those directories and possibly adds ebin directories inside archives to the code path. so the code path then contains paths that look like $OTPROOT/lib/mnesia.ez/mnesia/ebin or $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin.
the code server uses the module erl_prim_loader in ERTS (possibly through erl_boot_server) to read code files out of archives. however β the functions in erl_prim_loader can also be used by other applications to read files from archives. for example, this call:
erl_prim_loader:list_dir("/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench")
would list the contents of a directory inside an archive. see erl_prim_loader. π
an application archive file and a regular application directory can coexist. this is genuinely useful when you need parts of the application to be regular files. the classic case is the priv directory, which has to sit there as a regular directory so you can link in drivers dynamically and start port programs. for other applications that don't need that, the priv directory can live inside the archive and the files under it can be read through erl_prim_loader. best of both worlds, slay. π
when a directory is added to the code path, and when the entire code path is (re)set, the code server decides which subdirectories in an application get read from the archive and which get read as regular files. so heads up: if directories are added or removed afterwards, the file access can fail if the code path isn't updated β and yes, updating it to the same path as before counts, because it triggers the directory resolution update. you're basically poking her so she re-reads the room. π
for each directory on the second level in the application archive (ebin, priv, src, and so on), the code server first chooses the regular directory if it exists, and second from the archive. function code:lib_dir/2 returns the path to the subdirectory. for example, code:lib_dir(megaco, ebin) can return /otp/root/lib/megaco-3.9.1.1.ez/megaco-3.9.1.1/ebin, while code:lib_dir(megaco, priv) can return /otp/root/lib/megaco-3.9.1.1/priv. β¨
when an escript file contains an archive, there are no restrictions on the name of the escript and no restrictions on how many applications can be stored in the embedded archive. single Beam files can also live on the top level in the archive. at startup, the top directory in the embedded archive and all (second level) ebin directories in the embedded archive get added to the code path. see escript.
a future-proof way for escript scripts to read data files from the archive is to use the escript:extract/2 function.
when the choice of directories in the code path is strict β which is the default as of Erlang/OTP 27 β the directory that ends up in the code path is exactly the stated one. so if, for example, the directory $OTPROOT/lib/mnesia-4.4.7/ebin is explicitly added to the code path, the code server does not load files from $OTPROOT/lib/mnesia-4.4.7.ez/mnesia-4.4.7/ebin. no sneaky substitutions. π«
this behaviour can be controlled through the command-line flag -code_path_choice Choice. if the flag is set to relaxed, the code server instead chooses a suitable directory depending on the actual file structure. if a regular application ebin directory exists, that one is chosen. otherwise, the ebin directory in the archive is chosen if it exists. if neither of them exists, the original directory is chosen.
the command-line flag -code_path_choice Choice also affects how the module init interprets the boot script. the interpretation of the explicit code paths in the boot script can be strict or relaxed. setting the flag to relaxed is especially useful when you're experimenting with code loading from archives without editing the boot script. the default changed to strict in OTP 27 and the option is scheduled for removal in OTP 28. see module init in the Erts application.
π Current and Old Code π
the code for a module can exist in two variants in a system: current code and old code. when a module is loaded into the system for the first time, that module code becomes current, and the global export table gets updated with references to all the functions exported from the module. glow-up complete. π₯
when a new instance of the module is loaded, the code of the previous instance becomes old, and all export entries referring to the previous instance are removed. after that, the new instance is loaded just like it was the first time, and it becomes current.
both the old and the current code for a module are valid, and they can even be executed concurrently. the difference? exported functions in old code are unavailable. hence, a global call cannot be made to an exported function in old code β but the old code can still be executed, because of processes lingering in it. they're just still there. living their best life. π
if a third instance of the module is loaded, the code server removes (purges) the old code, and any processes lingering in it are terminated. π after that, the third instance becomes current and the previously current code becomes old.
for more info about old and current code, and how to make a process switch from old to current code, see section Compilation and Code Loading in the Erlang Reference Manual.
π«Ά Native Coverage Support π«Ά
ok bestie so native coverage β if your runtime system is one of the ones riding the JIT β is a light-weight lil way to find out which functions or lines got executed, or how many times each function or line ran. it's giving "tell me everything but make it cheap" π
CHANGE: The support for native coverage was added in Erlang/OTP 27.
Here's the β¨sitchβ¨: native coverage works by instrumenting code at load-time. so once a module has been instrumented for native coverage collection, you literally can't turn the collection off later β the only escape is reloading the module. no cap. but honestly? the overhead of just leaving coverage collection running is often neligible (basically nothing), especially when you're in coverage mode function, which only keeps track of which functions ran, nothing more.
and here's the cute part π β the cover tool over in the Tools application will automatically use the native coverage support if the runtime system supports it. it just knows. main character behavior tbh.
you only need to touch the functionality described next if cover isn't enough for you. like, for example:
- If one wants to collect coverage information for the code that runs when the runtime system is starting (module
initand so on).covercan only be used when the Erlang system has already started, and it will reload every module that is to be analyzed. so yeah,initis off-limits to plain oldcoverπ - If it is necessary to collect coverage information with the absolute minimum disturbance of the test system.
coveralways counts how many times each line is executed (coverage modeline_counters), but by using native coverage one can use a less expensive coverage mode such asfunction, which has almost negligible overhead. slay π₯
πΈ Short summary of using native coverage πΈ
- If the
lineorline_counterscoverage mode is to be used, the code to be tested must be compiled with optionline_coverage. - Use
set_coverage_mode(Mode)to set a coverage mode for all code subsequently loaded, or set it with option+JPcoverforerl. - Optionally reset coverage information for all modules that are to be tested by calling
reset_coverage(Module). - Run the code whose coverage information is to be collected.
- Read out the counters for all interesting modules by calling
get_coverage(Level, Module), where Level is eitherfunctionorline.
π The other native coverage BIFs π
The following BIFs are sometimes useful, for example to fail gracefully if the runtime system does not support native coverage:
coverage_support()- check whether the runtime system supports native coverageget_coverage_mode()- get the current coverage modeget_coverage_mode(Module)- get the coverage mode for module Module
π Argument Types and Invalid Arguments π
ok so the type rules, lowkey important:
Module and application names are atoms, while file and directory names are strings. for backward compatibility reasons, some functions accept both strings and atoms, but a future release will probably only allow the arguments that are documented. so likeβ¦ don't get attached to the loose behavior okay π
Functions in this module generally fail with an exception if they are passed an incorrect type (for example, an integer or a tuple where an atom is expected). But an error tuple is returned if the argument type is correct and there's just some other error β for example, a non-existing directory is specified to set_path/1.
π Error Reasons for Code-Loading Functions π
Functions that load code (such as load_file/1) will return {error,Reason} if the load operation fails. Here follows a description of the common reasons:
badfileβ The object code has an incorrect format, or the module name in the object code is not the expected module name.nofileβ No file with object code was found.not_purgedβ The object code could not be loaded because an old version of the code already existed.on_load_failureβ The module has an-on_loadfunction that failed when it was called.sticky_directoryβ The object code resides in a sticky directory.
β¨ DATA TYPES β¨
add_path_ret()
add_path_ret() :: true | {error, bad_directory}.
cache()
cache() :: cache | nocache.
coverage_mode()
coverage_mode() ::
none | function | function_counters | line | line_counters.
debug_atom_or_var()debug_call()debug_frame()debug_info()debug_line()debug_name()debug_source()debug_value()debug_var()load_error_rsn()
load_error_rsn() ::
badfile | nofile | not_purged | on_load_failure |
sticky_directory.
load_ret()
load_ret() ::
{error, What :: load_error_rsn()} |
{module, Module :: module()}.
loaded_filename()
loaded_filename() ::
(Filename :: file:filename()) | loaded_ret_atoms().
loaded_ret_atoms()
loaded_ret_atoms() :: cover_compiled | preloaded.
module_status()
module_status() :: not_loaded | loaded | modified | removed.
-opaque prepared_code()β An opaque term holding prepared code. π«§replace_path_ret()
replace_path_ret() ::
true | {error, bad_directory | bad_name | {badarg, _}}.
set_path_ret()
set_path_ret() :: true | {error, bad_directory}.
π FUNCTIONS π
add_patha(Dir, cache()) -> add_path_ret()
add_patha(Dir, cache()) -> add_path_ret()
when Dir :: file:filename().
Adds Dir to the beginning of the code path. front of the line, main character energy π
If Dir exists, it is removed from the old position in the code path. no duplicates allowed bestie.
Argument Cache controls whether the content of the directory should be cached on first traversal. If Cache is cache the directory contents will be cached; if Cache is nocache it will not be cached.
Returns true if successful, or {error, bad_directory} if Dir is not the name of a directory.
add_pathsa(Dirs, cache()) -> ok
add_pathsa(Dirs, cache()) -> ok
when Dirs :: [Dir :: file:filename()].
Traverses Dirs and adds each Dir to the beginning of the code path.
β οΈ heads up bestie: this means that the order of Dirs is reversed in the resulting code path. so if Dirs is [Dir1,Dir2], the resulting path will be [Dir2,Dir1|OldCodePath]. the way that it just flips on you π
If a Dir already exists in the code path, it is removed from the old position.
Argument Cache controls whether the content of the directory should be cached on first traversal. If Cache is cache the directory contents will be cached; if Cache is nocache it will not be cached.
Always returns ok, regardless of the validity of each individual Dir. it's unbothered fr fr β¨
add_pathsz(Dirs, cache()) -> ok
add_pathsz(Dirs, cache()) -> ok
when Dirs :: [Dir :: file:filename()].
Adds the directories in Dirs to the end of the code path.
Directories that are already present in the path will not be added.
Argument Cache controls whether the content of the directory should be cached on first traversal. If Cache is cache the directory contents will be cached; if Cache is nocache it will not be cached.
Always returns ok, regardless of the validity of each individual Dir.
add_pathz(Dir, cache()) -> add_path_ret()
add_pathz(Dir, cache()) -> add_path_ret()
when Dir :: file:filename().
Adds Dir as the directory last in the code path.
If Dir already exists in the path, it is not added.
Argument Cache controls whether the content of the directory should be cached on first traversal. If Cache is cache the directory contents will be cached; if Cache is nocache it will not be cached.
Returns true if successful, or {error, bad_directory} if Dir is not the name of a directory.
all_available() -> [{Module, Filename, Loaded}]
all_available() -> [{Module, Filename, Loaded}]
when
Module :: string(),
Filename :: loaded_filename(),
Loaded :: boolean().
Returns a list of tuples {Module, Filename, Loaded} for all available modules. the whole roster πΈ
A module is considered to be available if it either is loaded or would be loaded if called. Filename is normally the absolute filename, as described for is_loaded/1.
all_loaded() -> [{Module, Loaded}]
all_loaded() -> [{Module, Loaded}]
when Module :: module(), Loaded ::
loaded_filename().
Returns a list of tuples {Module, Loaded} for all loaded modules.
Loaded is normally the absolute filename, as described for is_loaded/1.
atomic_load(Modules) -> ok | {error, [{Module, What}]}
atomic_load(Modules) -> ok | {error, [{Module, What}]}
when
Modules ::
[Module | {Module, Filename, Binary}],
Module :: module(),
Filename :: file:filename(),
Binary :: binary(),
What ::
badfile | nofile | on_load_not_allowed |
duplicated | not_purged |
sticky_directory | pending_on_load.
Tries to load all of the modules in the list Modules atomically. all or nothing, no half-sends π
That means that either all modules are loaded at the same time, or none of the modules are loaded if there is a problem with any of the modules.
Loading can fail for one the following reasons:
badfileβ The object code has an incorrect format, or the module name in the object code is not the expected module name.nofileβ No file with object code exists.on_load_not_allowedβ A module contains an-on_loadfunction.duplicatedβ A module is included more than once in Modules.not_purgedβ The object code cannot be loaded because an old version of the code already exists.sticky_directoryβ The object code resides in a sticky directory.pending_on_loadβ A previously loaded module contains an-on_loadfunction that never finished.
If it is important to minimize the time that an application is inactive while changing code, use prepare_loading/1 and finish_loading/1 instead of atomic_load/1. here's an example, take notes π:
{ok,Prepared} = code:prepare_loading(Modules),
%% Put the application into an inactive state or do any
%% other preparation needed before changing the code.
ok = code:finish_loading(Prepared),
%% Resume the application.
clash() -> ok.
Searches all directories in the code path for module names with identical names and writes a report to stdout. drama detection mode activated πβ¨
clear_cache() -> ok.
Clears the code path cache. bye bye cache π
If a directory is cached, its cache is cleared once and then it will be recalculated and cached once more in a future traversal. it comes back, it always comes back π
To clear the cache for a single path, either re-add it to the code path (with add_path/2) or replace it (with replace_path/3). To disable all caching, reset the code path with code:set_path(code:get_path()).
Always returns ok.
compiler_dir() π
compiler_dir() -> file:filename().
bestie this one just hands you the compiler library directory, that's the whole gig. It's literally the same thing as code:lib_dir(compiler).
coverage_support() β¨
coverage_support() -> Supported when Supported :: boolean().
returns true if the system actually supports coverage, and false if it doesn't. that's it, no notes.
See also: Native Coverage Support
del_path(NameOrDir) π
del_path(NameOrDir) -> boolean() | {error, What}
when
NameOrDir :: Name | Dir,
Name :: atom(),
Dir :: file:filename(),
What :: bad_name.
yeets a directory off the code path. the argument can be an atom Name, and in that case the directory named .../Name-Vsn gets deleted from the code path. you can also just pass the whole directory name Dir as the argument instead.
here's what it gives back:
trueβ it worked, slay πfalseβ the directory was not found{error, bad_name}β the argument was invalid
del_paths(NamesOrDirs) π¦
del_paths(NamesOrDirs) -> ok
when
NamesOrDirs :: [Name | Dir],
Name :: atom(),
Dir :: file:filename().
same vibe as above but for a whole list β deletes directories from the code path. you pass a list of either atoms or complete directory names. if Name is an atom, the directory named .../Name-Vsn gets deleted from the code path.
and here's the thing: it always returns ok, no matter how valid or invalid each individual NamesOrDirs entry is. it does not care. it does not check. periodt.
delete(Module) π₯
delete(Module) -> boolean() when Module :: module().
removes the current code for Module, which basically means the current code for Module gets made into old code.
what that actually means: processes can keep executing the code in the module, but you can't make any external function calls to it anymore. iykyk.
returns true if it worked, or false if there's old code for Module that has to be purged first, or if Module isn't a (loaded) module.
ensure_loaded(Module) πΈ
ensure_loaded(Module) -> {module, Module} | {error, What}
when
Module :: module(),
What ::
embedded | badfile | nofile |
on_load_failure.
tries to load a module the same way load_file/1 does β unless the module is already loaded, in which case it's already giving, no further action needed.
if a bunch of processes call this at the same time, this function makes sure only one process attempts to load the module at any given time. teamwork, but make it structured π«Ά.
in embedded mode, it does not load a module that isn't already loaded β instead it returns {error, embedded}. for a breakdown of the other possible error reasons, go peep Error Reasons for Code-Loading Functions.
ensure_modules_loaded([Module]) π
ensure_modules_loaded([Module]) -> ok | {error, [{Module, What}]}
when
Module :: module(),
What ::
badfile | nofile |
on_load_failure.
tries to load any modules in the list Modules that aren't already loaded, same way load_file/1 does.
but here's the plot twist: unlike ensure_loaded/1, modules get loaded even in embedded mode. okayyy π
returns ok if it all worked out, or {error,[{Module,Reason}]} if loading some modules fails. again, peep Error Reasons for Code-Loading Functions for the other possible error reasons.
finish_loading(Prepared) β
finish_loading(Prepared) -> ok | {error, [{Module, What}]}
when
Prepared :: prepared_code(),
Module :: module(),
What ::
not_purged | sticky_directory |
pending_on_load.
tries to load the code for every module that was previously prepared by prepare_loading/1.
the loading happens atomically, meaning either all the modules get loaded at the same time, or none of them do. all or nothing, main character energy.
this function can fail with any of these error reasons:
not_purgedβ the object code can't be loaded because an old version of the code already exists.sticky_directoryβ the object code lives in a sticky directory.pending_on_loadβ a previously loaded module has an-on_loadfunction that never finished.
get_coverage(Level, module()) π
get_coverage(Level, module()) -> Result
when
Level :: function | line | cover_id_line,
Result :: [{Entity, CoverageInfo}],
Entity :: {Function, Arity} | Line | CoverId,
CoverageInfo :: Covered | Counter,
Function :: atom(),
Arity :: arity(),
Line :: non_neg_integer(),
CoverId :: pos_integer(),
Covered :: boolean(),
Counter :: non_neg_integer().
returns either function or line coverage data for module Module.
if Level is function, it returns function coverage for the given module according to its coverage mode:
functionβ for each function in moduleModule, you get a boolean saying whether that function has been executed at least once.function_countersβ for each function in moduleModule, you get an integer giving the number of times that line has been executed.lineβ for each function in moduleModule, you get a boolean saying whether that function has been executed at least once.line_countersβ for each function in moduleModule, you get a boolean saying whether that function has been executed at least once (note that in this mode, counters for the number of times each function has been executed cannot be retrieved).
if Level is line, it returns line coverage for the given module according to its coverage mode:
lineβ for each executable line in the module, you get a boolean saying whether that line has been executed at least once.line_countersβ for each executable line in the module, you get an integer giving the number of times that line was executed.
Level cover_id_line is used by the cover tool.
failures:
badargβ ifLevelis notfunctionorline.badargβ ifModuleis not an atom.badargβ ifModuledoes not refer to a loaded module.badargβ ifModulewas not loaded in another coverage mode thannone.badargβ ifLevelislineandModulehas not been loaded with eitherlineorline_countersenabled.badargβ if the runtime system does not support coverage.
See also: Native Coverage Support
get_coverage_mode() π§
get_coverage_mode() -> Mode when Mode :: coverage_mode().
returns the coverage mode exactly as it was set by option +JPcover for erl, or by set_coverage_mode/1.
failure:
badargβ if the runtime system does not support coverage.
See also: Native Coverage Support
get_coverage_mode(Module) π
get_coverage_mode(Module) -> Mode
when
Module :: module(),
Mode :: coverage_mode().
gives you the coverage mode for the given module.
failures:
badargβ ifModuleis not an atom.badargβ ifModuledoes not refer to a loaded module.badargβ if the runtime system does not support coverage.
See also: Native Coverage Support
get_doc(Mod) π
get_doc(Mod) -> {ok, Res} | {error, Reason}
when
Mod :: module(),
Res :: #docs_v1{},
Reason :: non_existing | missing | file:posix().
returns EEP 48 style documentation for Module if it's available.
if Module can't be found in the code path, this function returns {error,non_existing}.
if no documentation can be found, this function attempts to generate documentation from the debug information in the module. if no debug information is available, this function returns {error,missing}.
for more tea about the documentation chunk, peep Documentation Storage and Format in Kernel's User's Guide.
get_mode() π
get_mode() -> embedded | interactive.
returns an atom describing the mode of the code server: interactive or embedded.
this info is lowkey useful when an external entity (like an IDE) is providing extra code for a running node. if the code server is in interactive mode, it only has to add the path to the code. if the code server is in embedded mode, the code has to be loaded with load_binary/3.
get_object_code(Module) π₯
get_object_code(Module) -> {Module, Binary, Filename} | error
when
Module :: module(),
Binary :: binary(),
Filename :: file:filename().
returns the object code for module Module if it's found in the code path.
returns {Module, Binary, Filename} if it worked, otherwise error. Binary is a binary data object holding the object code for the module. this is super useful if code needs to be loaded on a remote node in a distributed system. for example, loading module Module on a node Node goes like this:
{_Module, Binary, Filename} = code:get_object_code(Module),
erpc:call(Node, code, load_binary, [Module, Filename, Binary]),
get_path() π
get_path() -> Path when Path :: [Dir :: file:filename()].
returns the code path. that's it, iconic.
is_loaded(Module) πΈ
is_loaded(Module) -> {file, Loaded} | false
when Module :: module(), Loaded :: loaded_filename().
checks whether Module is loaded.
if it is, you get {file, Loaded} back, otherwise false.
normally, Loaded is the absolute filename Filename that the code was obtained from. if the module is preloaded (peep script(4)), then Loaded =:= preloaded. if the module is Cover-compiled (peep cover), then Loaded =:= cover_compiled.
is_sticky(Module) π¦
is_sticky(Module) -> boolean() when Module :: module().
Okay so this one's giving straight yes/no energy: you get back true if Module is the name of a module that was loaded from a sticky directory β which lowkey means any attempt to reload it is gonna flop β or false if Module isn't a loaded module at all, or is loaded but just... not sticky. That's it, that's the whole vibe. π€·ββοΈ
πΈ lib_dir/0
lib_dir() -> file:filename().
Hands you the library directory, $OTPROOT/lib, where $OTPROOT is the root directory of Erlang/OTP. The mothership path, basically. π
Example, bestie:
1> code:lib_dir().
"/usr/local/otp/lib"
π¦ lib_dir/1
lib_dir(Name) -> file:filename() | {error, bad_name}
when Name :: atom().
Gives you the path for the library directory β the top directory β for an application Name that lives under $OTPROOT/lib or in a directory that the environment variable ERL_LIBS points at. It's giving "where does this app actually live" energy. π
If a regular directory called Name or Name-Vsn sits in the code path with an ebin subdirectory, then the path to that directory is what you get back (not the ebin directory itself, bestie β read it carefully).
If the directory refers to a directory inside an archive, the archive name gets stripped off before the path comes back to you. For example, if the directory /usr/local/otp/lib/mnesia-4.2.2.ez/mnesia-4.2.2/ebin is in the path, then /usr/local/otp/lib/mnesia-4.2.2/ebin is what's returned. So the library directory for an application is the same, whether the app lives in an archive or not. Consistency ate, fr fr.
β οΈ WARNING: Archives are experimental. In a future release, they can be removed or their behavior can change. So like... don't build your whole personality around them. π
Example:
> code:lib_dir(mnesia).
"/usr/local/otp/lib/mnesia-4.23"
You get {error, bad_name} if Name is not the name of an application under $OTPROOT/lib or on a directory referred to through the environment variable ERL_LIBS. And it fails with an exception if Name has the wrong type β so type your atoms correctly, queen. π
β οΈ WARNING: For backward compatibility, Name is also allowed to be a string. That will probably change in a future release.
π lib_dir/2
lib_dir(Name, SubDir) -> file:filename() | {error, bad_name}
when Name :: atom(), SubDir :: atom().
π« Deprecated: code:lib_dir/2 is deprecated; this functionality will be removed in a future release. It's giving legacy, and not in the cute vintage way.
Returns the path to a subdirectory directly under the top directory of an application.
CHANGE: This function is part of the archive support, which is an experimental feature that will be changed or removed in a future release. Unstable era, honestly.
Normally the subdirectories live under the top directory of the application, but when applications at least partly reside in an archive, the situation is different. Some of the subdirectories can hang out as regular directories while others live inside an archive file. And no, it does not check whether this directory even exists. It's not your mom, it doesn't verify anything. π
Instead of using this function, use code:lib_dir/1 and filename:join/2. The glow-up path, periodt.
Example:
1> filename:join(code:lib_dir(megaco), "priv").
"/usr/local/otp/lib/megaco-3.9.1.1/priv"
Fails with an exception if Name or SubDir has the wrong type.
π§ load_abs/1
load_abs(Filename) -> load_ret() when Filename :: file:filename().
Equivalent to load_file(Module), except that Filename is an absolute or relative filename. Sneaky twins, basically. π―ββοΈ
The code path is not searched β it does not go looking around for you. It returns a value in the same way as load_file/1. And heads up: Filename must not contain the extension (for example, .beam), because load_abs/1 adds the correct extension itself. Let it do its thing. π
π load_binary/3
load_binary(Module, Filename, Binary) ->
{module, Module} | {error, What}
when
Module :: module(),
Filename :: loaded_filename(),
Binary :: binary(),
What :: badarg | load_error_rsn().
Loads object code straight from a binary. Raw bytes moment. β¨
This one is iconic because you can use it to load object code on remote Erlang nodes. Argument Binary must contain object code for Module. Filename is only used by the code server to keep a record of from which file the object code for Module originates. So like β Filename is not opened and not read by the code server. It's purely for the receipts. π
Returns {module, Module} if it slays, or {error, Reason} if loading fails. See Error Reasons for Code-Loading Functions for a description of the possible error reasons.
π load_file/1
load_file(Module) -> load_ret() when Module :: module().
Tries to load the Erlang module Module using the code path.
It looks for the object code file with an extension corresponding to the Erlang machine being used, for example, Module.beam. The loading fails if the module name found in the object code differs from the name Module β mismatch detected, bestie, no cap. Use load_binary/3 to load object code with a module name that's different from the file name.
Returns {module, Module} if successful, or {error, Reason} if loading fails. See Error Reasons for Code-Loading Functions for a description of the possible error reasons.
β modified_modules/0
modified_modules() -> [module()].
Returns the list of all currently loaded modules for which module_status/1 returns modified. The "these changed on me" list, lowkey stressful.
See also all_loaded/0.
π¦ module_status/0
module_status() -> [{module(), module_status()}].
See module_status/1 and all_loaded/0 for details. Yeah that's the whole thing, it's a lil shortcut. π«Ά
π module_status/1
module_status(Module :: module() | [module()]) ->
module_status() | [{module(), module_status()}].
Returns the status of Module in relation to the object file on disk. Vibe check between memory and storage. π
The status of a module can be one of:
not_loadedβ If Module is not currently loaded.loadedβ If Module is loaded, and the object file exists and contains the same code.removedβ If Module is loaded, but no corresponding object file can be found in the code path.modifiedβ If Module is loaded, but the object file contains code with a different MD5 checksum.
Preloaded modules are always reported as loaded, without inspecting the contents on disk. Cover-compiled modules will always be reported as modified if an object file exists, or as removed otherwise. Modules whose load path is an empty string (which is the convention for auto-generated code) will only be reported as loaded or not_loaded. So the rules change depending on who you are, which is very main character of them. π
See also modified_modules/0.
π objfile_extension/0
objfile_extension() -> nonempty_string().
Returns the object code file extension corresponding to the Erlang machine used.
For the official Erlang/OTP release, the return value is always .beam. No surprises, no plot twists. π«Ά
β¨ prepare_loading/1
prepare_loading(Modules) ->
{ok, Prepared} | {error, [{Module, What}]}
when
Modules ::
[Module | {Module, Filename, Binary}],
Module :: module(),
Filename :: file:filename(),
Binary :: binary(),
Prepared :: prepared_code(),
What ::
badfile | nofile |
on_load_not_allowed | duplicated.
Prepares to load the modules in the list Modules. It's the pre-game, bestie β the actual loading hasn't happened yet. π
Finish the loading by calling finish_loading(Prepared).
This function can fail with one of the following error reasons:
badfileβ The object code has an incorrect format or the module name in the object code is not the expected module name.nofileβ No file with object code exists.on_load_not_allowedβ A module contains an-on_loadfunction.duplicatedβ A module is included more than once in Modules.
πΈ priv_dir/1
priv_dir(Name) -> file:filename() | {error, bad_name}
when Name :: atom().
Returns the path to the priv directory in an application.
β οΈ WARNING: For backward compatibility, Name is also allowed to be a string. That will probably change in a future release.
π purge/1
purge(Module) -> boolean() when Module :: module().
Purges the code for Module, that is, removes code marked as old. It's giving spring cleaning but for the code server. π§Ή
If some processes still linger in the old code, these processes are killed before the code is removed. Yes, killed. Dramatic but fair. π
CHANGE: As of Erlang/OTP 20.0, a process is only considered to be lingering in the code if it has direct references to the code. For more information see documentation of erlang:check_process_code/3, which is used in order to determine whether a process is lingering.
Returns true if successful and any process needed to be killed, otherwise false.
π replace_path/3
replace_path(Name, Dir, cache()) -> replace_path_ret()
when Name :: atom(), Dir :: file:filename().
Replaces an old occurrence of a directory named .../Name-Vsn in the code path, with Dir. Swapping out the old for the new, glow-up edition. π¦
If Name does not exist, it adds the new directory Dir last in the code path. The new directory must also be named .../Name-Vsn. This function is to be used if a new version of the directory (library) is added to a running system β hot-swap moment. π₯
Argument Cache controls whether the content of the directory should be cached on first traversal. If Cache is cache, the directory contents will be cached; if Cache is nocache, it will not be cached.
Returns:
trueβ If successful{error, bad_name}β If Name is not found{error, bad_directory}β If Dir does not exist{error, {badarg, [Name, Dir]}}β If Name or Dir is invalid
π reset_coverage/1
reset_coverage(Module) -> ok when Module :: module().
Resets coverage information for module Module. Factory reset vibes, but for stats. π§Ό
If the coverage mode is either function or line, all booleans for Module keeping track of executed functions or lines are set to false.
If the coverage mode is either function_counters or line_counters, all counters for Module are reset to zero.
Failures:
badargβ If Module is not an atom.badargβ If Module does not refer to a loaded module.badargβ If Module was not loaded with coverage enabled.badargβ If the runtime system does not support coverage.
See also: Native Coverage Support
π§ root_dir/0
root_dir() -> file:filename().
Returns the root directory of Erlang/OTP, which is the directory where it is installed.
Like, the home base of your whole OTP install. The mothership. πΈ
Example:
1> code:root_dir().
"/usr/local/otp"
set_coverage_mode(Mode) -> OldMode
set_coverage_mode(Mode) -> OldMode
when
Mode :: coverage_mode(),
OldMode :: coverage_mode().
Okay so this sets the coverage mode for modules that get loaded after this call. It's basically the same energy as option +JPcover for erl. π
The mode you pick has these effects on code loaded following this call:
functionβ every module that gets loaded will be instrumented to keep track of which functions are executed. Wanna know which functions ran? Callget_coverage(function, Module).function_countersβ every module that gets loaded will be instrumented to count how many times each function is executed. Wanna see the counts? Callget_coverage(function, Module).lineβ when modules that were compiled with theline_coverageoption get loaded, they'll be instrumented to keep track of which lines have been executed. Get that info withget_coverage(line, Module), and info about which functions have been executed withget_coverage(function, Module).line_countersβ when modules compiled with theline_coverageoption get loaded, they'll be instrumented to count the number of times each line is executed. Get that withget_coverage(line, Module), and which functions have been executed withget_coverage(function, Module)β note that in this mode, counters for the number of times each function has been executed cannot be retrieved.noneβ modules just get loaded, no coverage instrumentation at all. Bare-faced, no filter.
And it returns the previous coverage mode. Time capsule vibes. β³
Failures:
badargβ ifModeis not a valid coverage mode. πbadargβ if the runtime system does not support coverage at all.
See also: Native Coverage Support
set_path(Path, cache()) -> set_path_ret()
set_path(Path, cache()) -> set_path_ret()
when Path :: [Dir :: file:filename()].
Sets the code path to the list of directories in Path. Glow-up for your search path, bestie. β¨
The Cache argument controls whether the content of the directory should be cached on first traversal. If Cache is cache, the directory contents will be cached; if Cache is nocache, they will not be. Pick your fighter.
Returns:
trueβ if successful. π{error, bad_directory}β if anyDiris not a directory name.
soft_purge(Module) -> boolean()
soft_purge(Module) -> boolean() when Module :: module().
Purges the code for Module β aka yeets the code marked as old β but only if no processes linger in it. It's a polite purge. It checks the vibe first. π«Ά
CHANGE: As of Erlang/OTP 20.0, a process is only considered to be lingering in the code if it has direct references to the code. For more info, see the documentation of erlang:check_process_code/3, which is what's used to determine whether a process is lingering.
Returns false if the module can't be purged because processes are lingering in old code; otherwise true.
stick_dir(Dir) -> ok | error
stick_dir(Dir) -> ok | error when Dir :: file:filename().
Marks Dir as sticky. Sticky = protected, do not touch, this directory said "not today". π«
Returns ok if successful, otherwise error.
unstick_dir(Dir) -> ok | error
unstick_dir(Dir) -> ok | error when Dir :: file:filename().
Unsticks a directory that's marked as sticky. Releasing them from the stickiness, freeing them, giving them main character energy again. π¦
Returns ok if successful, otherwise error.
where_is_file(Filename) -> non_existing | Absname
where_is_file(Filename) -> non_existing | Absname
when
Filename :: file:filename(),
Absname :: file:filename().
Searches the code path for Filename, which can be a file of literally any type. No judgement, any file. π
If it's found, the full name is returned. If the file cannot be found, non_existing comes back. This one is super handy for stuff like locating application resource files. π
which(Module) -> Which
which(Module) -> Which
when
Module :: module(),
Which :: loaded_filename() | non_existing.
If the module is not loaded, this function searches the code path for the first file containing object code for Module and returns the absolute filename.
- If the module is loaded, it returns the name of the file containing the loaded object code. π
- If the module is preloaded,
preloadedis returned. - If the module is Cover-compiled,
cover_compiledis returned. - If the module cannot be found,
non_existingis returned. π
And that's a wrap on code(3), bestie!! π You just read the whole thing and honestly? Obsessed. This gorgeous little page comes to you courtesy of Ericsson AB, shipping as part of kernel 11.0.3, and this version of the code(3) manual page is dated the same era. Go forth and load some code. Periodt. ππβ¨
π¦ where this page comes from
- ubuntu stonking: erlang-doc 1:29.0.6+dfsg-1 Β· Apache-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms