I am not certain I am answering exactly the question you are asking, but you bring up some issues that many students of mine have had, so here is what I usually tell them.
In Julia you use Project.toml
files for two slightly different purposes: Creating a self-contained environment in which to work and track dependencies (similar to virtualenv in python); and creating a library that can be used by other libraries or interactively by others.
Creating a self-contained environment
This is somewhat comparable to virtualenvs in python. E.g. you go to a folder, start julia with julia --project=FOLDER_PATH
(for instances, --project=.
if you want to use the current directory). Or equivalently you start julia without arguments but then go to package mode and do activate FOLDER_PATH
. Now, if you add new packages to this environment, you will see a Project.toml
files with a list of these dependencies. You can start working in this folder, potentially adding more files, in any subfolder structure you like. You probably would benefit of using the VSCode IDE with the Julia plugin, and setting that folder as your root folder in VSCode.
There will also be a Manifest.toml
file that is not meant for you to edit, rather it is exact listing of what versions of various packages were installed (as dependencies of packages you have requested directly that are already listed in Project.toml
).
You probably will be using include
or Revise.includet
for the various script files you have.
This is NOT a library, this is an “environment” in which you can work. Inside of that environment you can install libraries or you can even start creating libraries of your own in it.
For such libraries you would use import
or using
to import them in your REPL after you have installed them in your environment.
I am being imprecise with the distinction between modules/libraries/packages – there are some caveats about their differences, but they are not too important right now.
Creating a package (a library)
For that you probably want to already be in some environment, and then use generate LibraryName
in pkg mode. That will create a new folder, and that folder will have its own internal Project.toml
that describes the dependencies of the library you are creating. That folder will also have a certain internal subfolder structure, expected by the package manager (./src
folder and maybe ./docs
or ./tests
).
To have access to whatever is created in that library, your environment will need to have the library added (as any other library). So your environment’s Project.toml
file will now have an entry for your library.
You never really need to activate a library the way you are activating an environment.
Example
Consider this folder tree
- my_julia_environment
|-- some_script.jl
|-- Project.toml
|-- Manifest.toml
|-- MyPackage
|-- Project.toml
|-- src
|-- MyPackage.jl
|-- some_other_internal_library_file.jl
If I want to just run some_script.jl
I would do either of these:
cd my_julia_environment
then julia --project=.
then include("some_script.jl")
cd my_julia_environment
then julia --project=. some_script.jl
if I do not need an interactive REPL
- open
my_julia_environment
in VSCode, set it as active environment and use the VSCode REPL which has a lot of nice extra features
If I want to make the local version of the library MyPackage
available and usable in julia I would do:
cd my_julia_environment
then julia --project=.
then ] dev ./MyPackage
– the last pkg command simply tells julia to:
- record the need for the library
MyLibrary
in the environment’s Project.toml
- record the exact version and location of
MyLibrary
in the environment’s Manifest.toml
- thanks to all of this now I can simply do
import MyPackage
The MyPackage
folder does not actually need to be inside of the folder for your environment. Many Julia programmers actually keep such things in ~/.julia/dev
(which is also what happens if you do ] dev SomePublicOpensourceLibrary
– it gets cloned from github or elsewhere and made available to you)
my_julia_environment/Project.toml
by default just contains a list of dependencies in [deps]
and no more metadata. You can add extra information, like a [compat]
section, listing required versions for the dependencies
The MyPackage
folder does not contain scripts, only library files. They are expected to be organized in modules (you can use modules for your scripts, but no need to do that). So it is expected that:
You never need to activate
a package, only to dev
or add
(or generate
) it. You need to activate
an environment and inside of the environment you can add
a package.
You can share an environment in a reproducible fashion by preserving its Project.toml and Manifest.toml files. E.g. if you want to share some data processing scripts that generated some plots. No need for packages. You activate an environment with activate SOME_PATH
You make a package when you want something that can be reused by other libraries (a.k.a. packages). There is no Manifest.toml in these cases. You probably would want to register such packages so others can simply install them from within Julia. You do not activate packages, you add
them.
TLDR: There is a difference between “an environment in which I execute some scripts and potentially share with others who want to execute the scripts in a reproducible fashion” and “a reusable library that other libraries can depend on”, but they both are structured around a Project.toml
file. You do not need anything more than include
for environments (but you can use local modules if you want). You have to use modules for structuring a library.