Hello, all.
Could you explain how file inclusion actually works?
I have an umbrella project (Rebar3).
Structure of folders:
myproj = erl_app
├── apps
│ ├── c_app
│ └── erl_app
│ ├── c_src
│ ├── include %% | CASE 2
│ │ ├── erl_app.hrl %% | CASE 2
│ │ └── x.hrl %% | CASE 2
│ └── src
│ ├── some_folder
│ │ ├── x.erl
│ │ ├── x.hrl %% | CASE 3 WITHOUT INCLUDE FOLDER
│ │ └── x_server.erl
│ ├── myproj_app.erl
│ ├── myproj.app.src
│ ├── erl_app.hrl %% | CASE 3 WITHOUT INCLUDE FOLDER
│ └── myproj_sup.erl
├── config
├── doc
├── erlang_ls.config
├── include %% | CASE 1
│ ├── erl_app.hrl %% | CASE 1
│ └── x.hrl %% | CASE 1
├── LICENSE.md
├── priv
├── README.md
├── rebar.config
├── rebar.lock
└── test
According to this 7.4 Directory Structure
src
- Required. Contains the Erlang source code, the source of the .app file and internal include files used by the application itself.
include
- Optional. Used for public include files that must be reachable from other applications.
The tree shows 3 cases for include files, one of which is actually used.
I have internal include files only.
I am interested in the third case.
According to this 10.1 File Inclusion
If the filename
File
is absolute (possibly after variable substitution), the include file with that name is included. Otherwise, the specified file is searched for in the following directories, and in this order:
1. The current working directory
2. The directory where the module is being compiled
3. The directories given by theinclude
option
According to this Erlang Compiler
{i,Dir}
AddsDir
to the list of directories to be searched when including a file. When encountering an-include
or-include_lib
*directive, the compiler searches for header files in the following directories:
1."."
, the current working directory of the file server
2. The base name of the compiled file
3. The directories specified using optioni
; the directory specified last is searched first
It is noted here Erlang: what is the difference between “include_lib” and “include”?
One difference which is not obvious at first is that
-include
and-include_lib
use a different set of paths when looking for header files.-include_lib
in fact uses the code path, not the header file path.
Configuration of the rebar.config
file
1 CASE
- Working case without
i
compiler option
Openx.erl
fromroot_dir
i.e."."
ofmyproj
-include("include/x.hrl"). % The filename File is absolute.
- Non-working case with
i
compiler option
1 {erl_opts, [debug_info,
2
3 %% For internal include files used by the application itself.
4 %% Not the code path is used, but the header file path.
5 {i, ["include"]}
6 ]}.
-include("x.hrl"). % E: can't find include file "x.hrl"
2 CASE
- Working case without
i
compiler option
Openx.erl
fromroot_dir
i.e."."
ofmyproj
-include("apps/erl_app/include/x.hrl"). % The filename File is absolute.
- Non-working case with
i
compiler option
1 {erl_opts, [debug_info,
2
3 %% For internal include files used by the application itself.
4 %% Not the code path is used, but the header file path.
5 {i, ["apps/*/include"]}
6 ]}.
-include("x.hrl"). % E: can't find include file "x.hrl"
3 CASE
- Working case without
i
compiler option
Openx.erl
fromroot_dir
i.e."."
ofmyproj
-include("apps/erl_app/src/some_folder/x.hrl"). % The filename File is absolute.
- Non-working case with
i
compiler option
1 {erl_opts, [debug_info,
2
3 %% For internal include files used by the application itself.
4 %% Not the code path is used, but the header file path.
5 {i, ["apps/*/src", "apps/*/src/*"]}
6 ]}.
-include("x.hrl"). % E: can't find include file "x.hrl"
Since all 3 cases use -include
, then header file path
is used.
According to this Code Path
Environment variable
ERL_LIBS
(defined in the operating system) can be used to define more library directories to be handled in the same way as the standard OTP library directory described above, except that directories without anebin
directory are ignored.
If I understood correctly, we can use -include_lib
as it uses search path
aka code path
.
For example, for the 2 CASE
- Working case without
i
compiler option
Openx.erl
fromroot_dir
i.e."."
ofmyproj
-include_lib("erl_app/include/x.hrl").
The explanation is here 10.1 File Inclusion
The code server uses
code:lib_dir(kernel)
to find the directory of the current (latest) version of Kernel, and then the subdirectoryinclude
is searched for the filefile.hrl
.
Only instead of kernel
, you need to substitute erl_app
.
It should be noted that erl_app should not hide app from $OTPROOT/lib
, where $OTPROOT
is the installation directory of Erlang/OTP.
Result
Why is {i,Dir}
not working (It works, but I don’t understand how.)?