Packages and environments
Last updated on 2025-02-09 | Edit this page
Overview
Questions
- How do I work with environments?
- What are these
Project.toml
andManifest.toml
files? - How do I install more dependencies?
Objectives
- pkg> status
- pkg> add (in more details)
- pkg> remove
- Project.toml
- Manifest.toml
- pkg> instantiate
- pkg> activate
- pkg> activate –temp
- pkg> activate @place
In general software development, it often makes sense to make use of
existing packages rather than implementing everything yourself. The
Julia world is no different, and provides a standard way to manage this,
via the Pkg
system.
In the following, we will explore using the Julia REPL to set up a project and manage adding dependencies.
Make a new project
We will first make a directory and move to it:
mkdir Dummy
cd Dummy
We open the Julia REPL and enter pkg
mode by pressing
]
:
julia
julia> # press ]
pkg>
In this mode, we can run a variety of commands for managing our project’s dependencies.
First we will use pkg> status
to check what the
current situation is, according to Julia:
pkg> status
The output gives us details about the current environment we are using. There will be a list of any dependencies that have been installed, and their versions.
The first line of output may look something like this:
OUTPUT
Status `~/.julia/environments/v1.11/Project.toml`
This shows the path to the current environment definition, which is
in a file called Project.toml
(we will discuss this later).
From the path we see that this is the default environment for our
version of Julia (in the above case, v1.11
). This is the
environment that will be used unless the user specifies a different
one.
In practice, we generally make specific environments for specific projects. This avoids issues of multiple/clashing versions of dependencies, removes unused dependencies (keeping the project environemtn clean) and allows you to easily publish your project as a package, if desired.
Therefore, let us indicate to Julia that we wish to use an
environment for our Dummy
project. We do this using the
pkg> activate
command:
pkg> activate .
Note that the .
is important here, as we are supplying a
path as an argument to activate
. This tells Julia that we
want to use the current (./
) directory as a location for a
project. Julia will confirm that you are activating a new project at
your current location (the Dummy/
directory).
As before, we can use pkg> status
at any time to
check what environment we are in:
pkg> status
This will now output “Status” followed by a path to the
Dummy/
directory. This indicates that we have successfully
begun working in an environment based there.
The output also indicates that this is an
(empty project)
. This is because we have not added any
dependencies yet.
Adding dependencies to your project
If we wish to use functionality of another package in our code, we
can add it as a dependency of our project. For example, let us say we
wish to add Julia’s Random
package as a dependency. We can
do this using pkg> add
:
pkg> add Random
Julia will now download a version of this package and pre-compile it.
pkg> status
Running pkg> status
now will list ‘Random’ as a
dependency, instead of showing “(empty project)” as it did before.
You may notice that a line in the output also indicates that a
Project.toml
file has been updated.
Project.toml
and Manifest.toml
Looking in the previously empty Dummy/
directory, you
should now see the appearance of two files: Project.toml
and Manifest.toml
.
From the terminal, you can open these in your currently running
vscode window using code -r
:
code -r Project.toml
OUTPUT
[deps]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Inspecting Project.toml
, we see that it has a
[deps]
section, which stands for “dependencies”. There is a
single dependency, Random
, along with a long string of
letters and numbers. This is the Universally Unique Identifier (UUID) of
the package. This will be covered in a later episode.
Next, we inspect Manifest.toml
.
code -r Manifest.toml
OUTPUT
# This file is machine-generated - editing it directly is not advised
julia_version = "1.11.3"
manifest_format = "2.0"
project_hash = "fa3e19418881bf344f5796e1504923a7c80ab1ed"
[[deps.Random]]
deps = ["SHA"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
version = "1.11.0"
[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"
Initially, we see that it contains some information that is similar
to the contents of Project.toml
. We see the
Random
package we added earlier, and its UUID, but now also
a specific version for that package. We also a dependency of the
Random
package itself.
So both Project.toml
and Manifest.toml
appear to specify the dependencies of the project. Generally speaking,
dependencies may have many versions which may be acceptable
(compatible). Project.toml
gives the requirements of the
project on a comparatively high-level, whereas
Manifest.toml
specifies exact versions for each dependency,
as well as a hash of the entire project. Therefore,
Manifest.toml
specifies a particular working installation
of the package. For most projects, many Manifest.toml
configurations could be possible.
Note: As the comment at the top of Manifest.toml
states,
the file is automatically generated and should generally not be edited
directly.
Removing dependencies
If a dependency was added by mistake, or if we no longer need it, we
may wish to remove it. In our case, we only added the
Random
package as an example - we have no plans to use it.
So let’s remove it as a dependency.
pkg> remove Random
If we check pkg> status
again, we see that we have
returned to the “(empty project)” state. Similarly, looking inside
Project.toml
we see that the dependency has indeed
disappeared from the project.
pkg> status
Add and remove the Dates package (3 min)
There is a Dates
standard Julia package. Try adding this
as a dependency, then check Project.toml
and
Manifest.toml
to see what has changed.
Then remove the Dates
dependency when you are done.
pkg> add Dates
pkg> status
pkg> code -r Project.toml Manifest.toml
pkg> remove Dates
Activating the default environment again
Sometimes you may wish to return to using the default environment for your Julia version.
If your version is e.g. 1.11
then the command would look
like:
pkg> activate @v1.11
Callout
Note the @
symbol before the environment name. This
tells us that it is a “shared” environment. That means it can be loaded
by name (i.e. without specifying the path to the
Project.toml
file explicitly. You can make your own shared
environments for various reasons but that is beyond the scope of the
present lesson.
You can also simply type activate
with no arguments and
Julia will also return to the default environment.
Temporary environments
In some cases, you may wish to work with a “throwaway” environment - one in which you can add dependencies without it affecting your current project.
You can do this using pkg> activate --temp
:
pkg> activate --temp
This will output something like
Activating new project at
/tmp/jl_4xvh88`.
You can now work with this as with any other environment, but without
the fear that changes you make are messing up the
Project.toml
of the project you are working on.
As an example, let’s add the Random
package again.
pkg> status
pkg> add Random
pkg> status
We see that Random
is installed in our temporary
environment.
We can now exit the Julia REPL and open our Project.toml
file as before:
code -r Project.toml
We see that this is empty (no dependencies), confirming that the project has not been affected by changes made to the temp environment.
Using another project
Simply activating a project does not actually make Julia download and
install any dependencies that may be listed in Project.toml
(and Manifest.toml
) but are missing on your machine.
You may have this sitation if someone you are developing with has
added a new dependency to the package, or shared their
Manifest.toml
with you.
In such a case, you can make Julia fetch and install any dependencies
you need using the pkg> instantiate
command, to install
exactly the packages specified in the Manifest.toml
.
pkg> instantiate
pkg> instantiate
will not do anything if you already
have everything you need, so it is safe to use.
Key Points
- Julia has a built-in package manager called
Pkg
. - The package manager is usually accessed from the REPL, by pressing
]
. -
Project.toml
lists the dependencies of a package. -
Manifest.toml
specifies a completely reproducible environment with exact versions.