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 and Manifest.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.