How to properly use the deps folder in an Erlang project? - erlang

I am coming from the assumption that the deps folder of an erlang project should include symbolic links that point to other projects and applications, so all modules from that project can be accessed/visible.
For example, My project named project_final should access modules from project_a and application_b. The directory structure of them is as follows:
NOTICE: because I am using GIT, the projects have a double structure, so they are not direct siblings to each other, but instead they are placed under /projects/project_X/projectX/etc... I believe this is a problem. Any better suggestions how to manage this ?
/projects/project_a/project_a : contains ( ebin, include, src )
/projects/application_b/application_b : contains ( ebin, include, src )
/project/pro_final:
deps : has symbolic links that point to project_a and application_b
ebin
include
src : contain modules that use project_a and applicabion_b module's functions, but gives exception error: undefined function.
How I am executing the project_final test module is by:
cd /projects
erl -env ERL_LIBS "."
myprojectfinalmodule:test().
** exception error: undefined function project_a:test/0
The project_a:test module is exported and correct.

The deps directory is a Rebar convention, and should probably not be managed in any other way except through Rebar. If you're not using Rebar, don't put dependencies in a subdirectory of the application, put your individual applications under a common lib/ directory instead and use the ERL_LIBS environment variable (see http://erlang.org/doc/man/code.html) to tell Erlang where to look for applications.

Related

Should I add src/MAlonzo to .gitignore?

Compiling my Agda code results in a src/MAlonzo directory being created. (Where src/MyProject is where my Agda code lives.) It contains a bunch of .hs (Haskell) and .o (object) files.
Is there anything in this directory that I should commit, or do people typically add /src/MAlonzo to their .gitignore?
I'm asking because I'm surprised that build artifacts are being put in the src directory instead of the _build directory. I wonder if there's a reason for that.
Yes. MAlonzo is the GHC backend used for compiling and running Agda programs. Everything there is automatically generated from your Agda source files.

How to execute an application with nested module loading in Erlang?

I am creating an erlang application named (app_main) that will be initializing two other erlang applications ( app_1 and app_2 ):
Following is the structure of the code. Notice that app_1 and app_2 are under the deps directory and each have their own deps directory, which expand into further other nested references to other code directory structures, etc...
/app_main
/ebin
/main.erl
/deps
/app_1
/ebin
/deps
/...
/app_2
/ebin
/deps
/...
To start my app_main application, I am issuing the following command:
erl -pa ./ebin ./deps/*/ebin ./deps/*/deps/*/ebin -s app_main
The problem is that I need to know how many levels of nested deps references I may have... This sounds a bit illogical to me and I am wondering if there are better ways to achieve this.
For instance, would rebar be useful identifying nested rebar configs and add all dependencies to the app_main's deps directory automatically ?
Rebar is very useful for managing dependencies. You can define app 1 and 2 as dependencies for your main app and, assuming app 1 and 2 have their dependencies defined in Rebar, it will install them and their dependencies in your deps folder
See Rebar's documentation here: https://github.com/basho/rebar/wiki/Dependency-management
How are you specifying these dependencies, where do they come from, and how are you compiling them? When you're using 3rd party applications they will, in general, manage their own dependencies. Therefore, you should only ever to have start the shell like this:
erl -pa ebin deps/*/ebin
Both Rebar and erlang.mk are great tools for managing your applications and their dependencies.

Erlang: Location of *.hrl files in multiple applications

I'm developing a series of related applications that will eventually be integrated into a single release. Several of the applications share identical record structures.
Should I:
a) Duplicate the *.hrl files that define the record structure in the include directory of each of the applications?
b) Put a single file somewhere else in my application tree--- and, if so where?
Here's my current tree:
zpt$
apps
app1
ebin
include
myrecords.hrl
priv
src
app2
ebin
include
myrecords.hrl
priv
src
etc
Many thanks,
LRP
One approach I tried was to create an application which doesn't do anything, but contains the record definitions common to multiple projects. Then I used rebar to include it as a dependency. When including the hrl files, I use the include_lib syntax. That syntax allows you to include hrl files from another application.
app
ebin
include
priv
src
some_src.erl
deps
common_hrl_app
include
common_records.hrl
src
ebin
other_dep_app
src
other_src.erl
.
.
.
include_lib example which could appear in either some_src.erl or other_src.erl:
-include_lib("common_hrl_app/include/common_records.hrl").
I like this approach because:
It plays nicely with the rebar dependency system
It allows me to track the hrls in one place in version control
I can version this application, which allows me to pull specific versions if I want a new application to be compatible with another using the same records.
Answering questions from the comments:
I have a skeleton app file in the ebin directory which specifies the name and version of the application so rebar can verify the version. Here's an example
{application,common_hrl_app,
[{description,[]},
{vsn,"1"},
{registered,[]},
{applications,[kernel,stdlib]},
{env,[]},
{modules,[]}]}.
With rebar, you have the top level application, which can have multiple applications as dependencies. When rebar fetches these dependencies, it places them in the deps directory. If any of those applications has their own dependencies, those are also fetched to the deps directory, and so on. There isn't an infinitely nested hierarchy of deps directories.

scons - source/include paths

Let's say I have this directory structure:
SConstruct
src/
a.cpp
b.cpp
include/
a.h
b.h
in SConstruct I don't want to specify ['src/a.cpp', 'scr/b.cpp'] every time; I'm looking for some way to set the base source directory to 'src'
any hint? I've been looking into the docs but can't find anything useful
A couple of options for you:
First, scons likes to use SConscript files for subdirectories. Put an SConscript in src/ and it can refer to local files (and will generate output in a build subdir as well). You can set up your environment once in the SConstruct. Then you "load" the SConscript from your master SConstruct.
SConscript('src/SConscript')
As your project grows, managing SConscript files in subdirectories is easier than putting everything in the master SConstruct.
Second, here's a similar question / answer that might help -- it uses Glob with a very simple example.
Third, since it's just python, you can make a list of files without the prefix and use a list comprehension to build the real list:
file_sources = [ 'a.c', 'b.c' ]
real_sources = [os.path.join('src', f) for f in file_sources]

"Bundling" external libraries in Erlang?

I have an erlang application I have been writing which uses the erldis library for communicating with redis.
Being a bit of a newbie with actually deploying erlang applications to production, I wanted to know if there was anyway to 'bundle' these external libraries with the application rather than installing into my system wide /usr/lib/erlang/lib/ folder.
Currently my directory structure looks like...
\
--\conf
--\ebin
--\src
I have a basic Makefile that I stole from a friend's project, but I am unsure how to write them properly.
I suspect this answer could involve telling me how to write my Makefile properly rather than just which directory to plonk some external library code into.
You should really try to avoid project nesting whenever possible. It can lead to all sorts of problems because of how module/application version is structured within Erlang.
In my development environment, I do a few things to simplify dependancies and multiple developed projects. Specifically, I keep most of my projects sourced in a dev directory and create symlinks into an elibs dir that is set in the ERL_LIBS environmental variables.
~/dev/ngerakines-etap
~/dev/jacobvorreuter-log_roller
~/dev/elib/etap -> ~/dev/ngerakines-etap
~/dev/elib/log_roller -> ~/dev/jacobvorreuter-log_roller
For projects that are deployed, I've either had package-rpm or package-apt make targets that create individual packages per project. Applications get boot scripts and init.d scripts for easy start/stop controls but libraries and dependancy projects just get listed as package dependencies.
I use mochiweb-inspired style. To see example of this get your copy of mochiweb:
svn checkout http://mochiweb.googlecode.com/svn/trunk/ mochiweb
and use
path/to/mochiweb/scripts/new_mochiweb.erl new_project_name
to create sample project of the structure (feel free to delete everything inside src afterwards and use it for your project).
It looks like this:
/
/ebin/
/deps/
/src/
/include/
/support/
/support/include.mk
Makefile
start.sh
ebin contains *.beam files
src contains ***.erl files and local *.hrl files
include contains global *.hrl files
deps contains symlinks to root directories of dependencies
Makefile and include.mk takes care of including appropriate paths when project is built.
start.sh takes care of including appropriate paths when project is run.
So using symlinks in deps directory you are able to fine tune the versions of libraries you use for every project. It is advised to use relative paths, so afterwards it is enough to rsync this structure to the production server and run it.
On more global scale I use the following structure:
~/code/erlang/libs/*/
~/code/category/project/*/
~/code/category/project/*/deps/*/
Where every symlink in deps points to the library in ~/code/erlang/libs/ or to another project in the same category.
The simplest way to do this would be to just create a folder named erldir and put the beams you need into it and then in your start script just use the -pa flag to the erlang runtime to point out where it should fetch the beams.
The correct way (at least if you buy into the OTP distribution model) would be to create a release using reltool (http://www.erlang.org/doc/man/reltool.html) or systools (http://www.erlang.org/doc/man/systools.html) which includes both your application and erldis.
Add the external libraries that you need, anywhere you want them, and add them to your ERL_LIBS environment variable. Separate the paths with colon in unix or semicolon in dos.
Erlang will add the "ebin"-named subdirs to its code loading path.
Have your *.app file point out the other applications it depends on.
This is a good halfway-there approach for setting up larger applications.
Another way is put your lib path in ~/.erlang.
code:add_pathz("/Users/brucexin/sources/mochiweb/ebin").
code:add_pathz("/Users/brucexin/sources/webnesia/ebin").
code:add_pathz("./ebin").
code:add_pathz("/Users/brucexin/sources/erlang-history/ebin/2.15.2").

Resources