Julia package loading
When your Julia codebase grows larger, you might want to organize it into modules and packages.
Include other files as submodules¶
You could include jl files as submodules like this
include("foo.jl")
using .Foo
include("bar.jl")
using .Bar
module Foo
# content of Foo module
end
module Bar
# content of Bar module
end
- Best when the submodules are used exclusively for this project and will not be shared with others.
- Usually you want to include all dependent submodules in the top-most file, like a table of contents.
- The
include
andusing
lines need to be re-execute when the code in the submodule changes. (ifRevise.includet("foo.jl")
is not used) - Use relative module path when
Bar
depends onFoo
. - There may be recursive
include()
calls andreplace module
warnings. FromFile.jl can deal with these file inclusion duplications.
Automatic package loading in a project¶
In this example, the project folder is JuliaHello
. Note that main.jl
has access to the JuliaHello
module automatically.
module JuliaHello
greet() = print("Hello World!")
end # module
using JuliaHello
JuliaHello.greet()
"Developing" a temporary package¶
Us the Julia Pkg command dev --local pkg...
Assuming we have the file structure for the packages
. present working directory (pwd)
| - main.jl
| - Manifest.toml
| - Project.toml
|
+---Mod1.jl
| | - Manifest.toml (optional)
| | - Project.toml
| |
| \---src
| - Mod1.jl
|
\---Mod2.jl
| - Manifest.toml (optional)
| - Project.toml
|
\---src
- Mod2.jl
Add local packages and track the file changes in the Julia REPL
julia> ]
pkg> activate .
pkg> dev --local Mod1 Mod2
Or run the commands in the Julia script
import Pkg
# To generate Project.toml if not present
Pkg.activate(".")
Pkg.develop(PackageSpec(path="Mod1.jl"))
Pkg.develop(PackageSpec(path="Mod2.jl"))
- Best when
Mod1
andMod2
are modified frequently and shared. - Loaded code is determined by local files instead of package versions.
- The updates are loaded when
using
is invoked, along with precompilation. Revise.jl tracks and updates modified files and you don't have to restart the Julia process upon module code changes.
Make a hosted package¶
Make a Git repo for your custom package and publish it to Git service providers, e.g. GitHub / Gitlab. And then you can ]add https://github.com/username/Mod1.jl.git
PkgTemplates.jl or PkgSkeleton.jl is recommended to generate package with unit tests and CI/CD settings.
Nonetheless, it's just one step away from proper registeration to the general Julia registry to be used by more people.
Unit testing¶
You can have local dependencies for running tests in test/Project.toml
without the need of extra
and targets
sections in the main project's Project.toml
.
Though the build-in unit-test framework is good, but Jive.jl provides more flexibilities. See TestJive.jl for code examples.
- Discover unit testing
jl
files automatically. - Skip or select which test(s) to run.
- Multiprocessing for faster runs.
Documentation¶
Use Documenter.jl to generate the documentation for Julia packages.
You need an SSH deploy key to deploy docs to GitHub pages.
using DocumenterTools
DocumenterTools.genkeys(user="you", repo="YourPackage.jl")
Continuous integration / delivery (CI/CD)¶
PkgTemplates.jl
should set up the appropriate code structure for you. I would recommend to use GitHub to host Julia packages because
- Running GH actions is unlimited for public repositories, with multiple operating systems running concurrently (matrix build).
- Julia github actions are convenient to use.
- Automation bots integrate better with GitHub. e.g. TagBot, Registerbot, and Compat Helper.
Reference¶
- Julia workflow tips
- Pkg.jl docs
- Comparison between v0.6 and v0.7 (SO)
- Developing your Julia package (Medium post)
- YouTube: Developing Julia packages by Chris