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
Fileis 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 theincludeoption
According to this Erlang Compiler
{i,Dir}
AddsDirto the list of directories to be searched when including a file. When encountering an-includeor-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
-includeand-include_libuse a different set of paths when looking for header files.-include_libin fact uses the code path, not the header file path.
Configuration of the rebar.config file
1 CASE
- Working case without
icompiler option
Openx.erlfromroot_diri.e."."ofmyproj-include("include/x.hrl"). % The filename File is absolute. - Non-working case with
icompiler 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
icompiler option
Openx.erlfromroot_diri.e."."ofmyproj-include("apps/erl_app/include/x.hrl"). % The filename File is absolute. - Non-working case with
icompiler 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
icompiler option
Openx.erlfromroot_diri.e."."ofmyproj-include("apps/erl_app/src/some_folder/x.hrl"). % The filename File is absolute. - Non-working case with
icompiler 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 anebindirectory 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
icompiler option
Openx.erlfromroot_diri.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 subdirectoryincludeis 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.)?



