Umbrella Projects
Sometimes a project can get big, really big in fact. The Mix build tool allows us to split our code into multiple apps and make our Elixir projects more manageable as they grow.
Introduction
To create an umbrella project we start a project as if we were going to start a normal Mix project but pass in the --umbrella
flag.
For this example, we are going to make the shell of a machine learning toolkit.
Why a machine learning toolkit? Why not? It is made up of various learning algorithms and utility functions.
$ mix new machine_learning_toolkit --umbrella
* creating .gitignore
* creating README.md
* creating mix.exs
* creating apps
* creating config
* creating config/config.exs
Your umbrella project was created successfully.
Inside your project, you will find an apps/ directory
where you can create and host many apps:
cd machine_learning_toolkit
cd apps
mix new my_app
Commands like "mix compile" and "mix test" when executed
in the umbrella project root will automatically run
for each application in the apps/ directory.
As you can see from the shell command, Mix created a small skeleton project for us with two directories:
-
apps/
- where our sub (child) projects will reside -
config/
- where our umbrella project’s configuration will live
Child projects
Let’s change into the projects machine_learning_toolkit/apps
directory and create 3 normal applications using Mix as so:
$ mix new utilities
* creating README.md
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/utilities.ex
* creating test
* creating test/test_helper.exs
* creating test/utilities_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd utilities
mix test
Run "mix help" for more commands.
$ mix new datasets
* creating README.md
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/datasets.ex
* creating test
* creating test/test_helper.exs
* creating test/datasets_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd datasets
mix test
Run "mix help" for more commands.
$ mix new svm
* creating README.md
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/svm.ex
* creating test
* creating test/test_helper.exs
* creating test/svm_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd svm
mix test
Run "mix help" for more commands.
We should now have a project tree like so:
$ tree
.
├── README.md
├── apps
│ ├── datasets
│ │ ├── README.md
│ │ ├── lib
│ │ │ └── datasets.ex
│ │ ├── mix.exs
│ │ └── test
│ │ ├── datasets_test.exs
│ │ └── test_helper.exs
│ ├── svm
│ │ ├── README.md
│ │ ├── lib
│ │ │ └── svm.ex
│ │ ├── mix.exs
│ │ └── test
│ │ ├── svm_test.exs
│ │ └── test_helper.exs
│ └── utilities
│ ├── README.md
│ ├── lib
│ │ └── utilities.ex
│ ├── mix.exs
│ └── test
│ ├── test_helper.exs
│ └── utilities_test.exs
├── config
│ └── config.exs
└── mix.exs
If we change back to the umbrella project’s root, we can see that we can call all the typical commands such as compile. As the sub projects are just normal applications, you can change into their directories and do all the same stuff as usual that Mix enables you to do.
$ mix compile
==> svm
Compiled lib/svm.ex
Generated svm app
==> datasets
Compiled lib/datasets.ex
Generated datasets app
==> utilities
Compiled lib/utilities.ex
Generated utilities app
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
IEx
You may think that interacting with the apps would be a little different in an umbrella project.
Well believe it or not, you would be wrong! If we change directory into the top level directory, and start IEx with the iex -S mix
we can interact with all the projects normally.
Let’s alter the contents of apps/datasets/lib/datasets.ex
for this simple example.
defmodule Datasets do
def hello do
IO.puts("Hello, I'm the datasets")
end
end
$ iex -S mix
Erlang/OTP {{ site.erlang.OTP }} [erts-{{ site.erlang.erts }}] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
==> datasets
Compiled lib/datasets.ex
Consolidated List.Chars
Consolidated Collectable
Consolidated String.Chars
Consolidated Enumerable
Consolidated IEx.Info
Consolidated Inspect
Interactive Elixir ({{ site.elixir.version }}) - press Ctrl+C to exit (type h() ENTER for help)
iex> Datasets.hello
Hello, I'm the datasets
:ok
Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!