Starting an Erlang Project, Part II
Continuing on with the previous Erlang post, there have been a couple of developments: 1) Programming Erlang arrived from Amazon, 2) trapexit.org came back online, and 3) I found this awesome blog.
To remind you of my immediate goal: I want to figure out how to organize a large-scale Erlang project. I want to learn the conventional project directory/file structure and create a useful build environment. Then I want to set up an infrastructure for configuration and logging. My initial stab at this involved using some stub generator code to get up and running. It seemed to do something pretty reasonable, and we walked through it up to the point where we implement the gen_server behaviour. I have to say, though, that I’m not a huge fan of stub generation. I like to know why every line of code is there, and for learning purposes, I want to set things up myself. So I’m going to sort of ignore what I did the other day and start again.
First, directory structure: In his book, Joe Armstrong is very agnostic about directories. He sort of has a “stick it where it makes sense” approach. I can appreciate that, but I like a little more structure. Stoyan Zhekov has exactly the attitude I’m looking for when he quotes the Ruby motto “Convention over configuration.” He says, that the conventional way to go is:
ebin/for compiled BEAM filessrc/for .erl source filesinclude/for .hrl include filespriv/for application-specific configuration
This is pretty much just like C/C++ development with regard to src and include, and also mirrors tutorial by Pete Kazmier, with the exception that he puts his external Python program in the priv directory. Perhaps external programs and libraries would be better in bin and lib directories, respectively? If it seems like I’m being pedantic, well, I am. For me, a project is most fun when everything is still nice and beautiful and unhacky. I try to hang on to that as long as I can, so I like to make decisions like these carefully so I know I can live with them.
Next up is build management. When I write C or C++, I use Make and when I write Java, I use ant. They’ve got their quirks, but they’re well documented and you can cut-and-paste your build files from past projects with only a little bit of modification. So what does Joe use for building Erlang projects? Make! Stoyan does something that looks like Make, but actually defines an Emakefile, which is for an Erlangified implementation of a make-like concept. What I like about the Erlang make module is that it is obviously Erlang-aware. What I don’t like is that I expect to be integrating code from other languages, and it won’t be able to handle those dependencies. Also, the man page is pretty sparse. It doesn’t say anything about recursively using Emakefiles, etc. – things that are well-documented in Gnu Make. So, I think I’m going to stick with good old Make for now then. Without further ado, here is my basic Makefile (for Gnu Make only):
MODULES = foo bar baz BEAMS = $(MODULES:%=%.beam) BINDIR = ebin SRCDIR = src INCDIR = include VPATH = $(BINDIR):$(SRCDIR):$(INCDIR) ERL = erl ERLC = erlc ERLCFLAGS = -W -smp all: $(BEAMS) %.beam : %.erl %.hrl $(ERLC) -b beam $(ERLCFLAGS) -I $(INCDIR) -o $(BINDIR) $< .PHONY: clean clean: rm -rf $(BINDIR)/*.beam $(INCDIR)/*~ $(SRCDIR)/*~ *~
This uses a couple of features: it remaps the list of modules to have .beam extensions, it uses VPATH to search directories for dependencies, and it uses the pattern-matching rules to enforce dependencies on .erl and .hrl files. Also, I always like to remove all the Emacs backup files when I clean things up. I use Subversion and am a compulsive committer, so it has almost never come up that I've found these files useful.
In the next installment, we'll look (again) at setting up an application in our nice new project structure.