# Create an implicit environment with package directories

**URL:** <https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207>\
**Category:** New to Julia\
**Created:** [January 24, 2024, 7:38pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207 "2024-01-24T19:38:49Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![francis-gagnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francis-gagnon/32/50424_2.png) [@francis-gagnon](https://discourse.julialang.org/u/francis-gagnon)\
**Post date:** [January 24, 2024, 7:38pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/1 "2024-01-24T19:38:49Z")

</div>

The [manual](https://docs.julialang.org/en/v1/manual/code-loading/#Package-directories) mention that it’s possible to create an _implicit environnement_ with package directories (i.e. directories without `Project.toml` files). Like @plafer in [this post](https://discourse.julialang.org/t/confused-by-package-directory-environments/26194/7), I tried to replicate the example in the manual with this file structure:

```julia
Aardvark/
    src/Aardvark.jl:
        import Bobcat
        import Cobra

Bobcat/
    Project.toml:
        [deps]
        Cobra = "4725e24d-f727-424b-bca0-c4307a3456fa"
        Dingo = "7a7925be-828c-4418-bbeb-bac8dfc843bc"

    src/Bobcat.jl:
        import Cobra
        import Dingo

Cobra/
    Project.toml:
        uuid = "4725e24d-f727-424b-bca0-c4307a3456fa"
        [deps]
        Dingo = "7a7925be-828c-4418-bbeb-bac8dfc843bc"

    src/Cobra.jl:
        import Dingo

Dingo/
    Project.toml:
        uuid = "7a7925be-828c-4418-bbeb-bac8dfc843bc"

    src/Dingo.jl:
        # no imports

```

and I have exactly the same error:

```julia
ERROR: could not find project file in package at `Aardvark` maybe `subdir` needs to be specified

```

It seems that this part of the manual was written before the addition of Pkg and is missing some details, am I wrong ?

Thanks!

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 24, 2024, 8:31pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/2 "2024-01-24T20:31:17Z")

</div>

> [@francis-gagnon](#):
>
> missing some details

I think this only works if you explicitly put the “package directory” in the `LOAD_PATH`, e.g. using something like:

```julia
pushfirst!(LOAD_PATH, ".")

```

  

> [@francis-gagnon](#):
>
> It seems that this part of the manual was written before the addition of Pkg

I’m not sure when this part of the manual was written, but I’d say the current consensus these days would be to avoid this kind of project organization. Explicit dependencies management in `Project.toml`/`Manifest.toml` is more robust IMO, and you can make it work for such a “local ecosystem” in at least two ways that know of:

- by carefully `Pkg.develop`ing each dependency into its dependent (can become tedious), or
- be registering all projects in a [`LocalRegistry`](https://github.com/GunnarFarneback/LocalRegistry.jl).

---

<div class="post-metadata">

**Author:** ![francis-gagnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francis-gagnon/32/50424_2.png) [@francis-gagnon](https://discourse.julialang.org/u/francis-gagnon)\
**Post date:** [January 24, 2024, 9:17pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/3 "2024-01-24T21:17:52Z")

</div>

Thank you, it does work by calling `pushfirst!(LOAD_PATH, ".")` beforehand:

```julia-repl
julia> pushfirst!(LOAD_PATH, ".")
4-element Vector{String}:
 "."
 "@"
 "@v#.#"
 "@stdlib"

shell> ls
Aardvark

julia> using Aardvark

julia> 

```

If it’s really mandatory, it should be mentioned in this part of the manual, no?

But, from my understanding, it should work without this call, since the `@` entry in `LOAD_PATH` means current active environment:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/0/d/0d9504fac460b355e7d5cc500f16d77a27085324.png)  
and:

```julia-repl
julia> LOAD_PATH
3-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"

(@v1.10) pkg> activate .
  Activating new project at `~/Documents/Code/test`

(test) pkg> status
Status `~/Documents/Code/test/Project.toml` (empty project)

shell> ls
Aardvark

julia> using Aardvark
ERROR: ArgumentError: Package Aardvark not found in current path.

```

Am I missing something?

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [January 24, 2024, 9:19pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/4 "2024-01-24T21:19:21Z")

</div>

Recently I stumbled upon this too, and I think what is described there should also be supported.

In particular, for personal projects (or call them mono repos) I can’t see any benefit in

- having to mess with `Pkg.develop`, a top-level `Project.toml` and several `Project.toml`s in every subfolder I want to have.
- maintaining a `LocalRegistry` just for the sake of versioning something that does not need to be versioned in separation.

Why would a single top-level `Project.toml` not be sufficient to declare that all code that is loaded in this environment should stick to exactly those versions?

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 24, 2024, 9:30pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/5 "2024-01-24T21:30:00Z")

</div>

> [@francis-gagnon](#):
>
> But, from my understanding, it should work without this call, since the `@` entry in `LOAD_PATH` means current active environment:

My current understanding is that `@` always refers to a “project environment” as opposed to a “package directory”, but I’m not actually 100% sure it is the case (and if so I agree that it could be clearer in the documentation).

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 24, 2024, 9:44pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/6 "2024-01-24T21:44:11Z")

</div>

> [@fatteneder](#):
>
> for personal projects (or call them mono repos) I can’t see any benefit in

I was merely trying to explain how I understand things work, and what I believe the current consensus is among the community. But I would personally tend to agree with you. I actually think there would be room for better tooling, especially as far as monorepos are concerned. For example an automated tool could look at a tree of julia projects/packages and

1. build a list of all packages (characterized by the presence of a valid `Project.toml` at the root of each of them),
2. build a map linking each package `UUID` to its path,
3. use these information to `Pkg.develop` the local packages into each of their dependants.

I don’t think it would be too complicated to build such a tool, but I never really had a need for it, so I never did it myself.

  

**EDIT:**

> [@fatteneder](#):
>
> Why would a single top-level `Project.toml` not be sufficient to declare that all code that is loaded in this environment should stick to exactly those versions?

I think part of the issue here is: when you look at the code in `Aardvark/src/Aardvark.jl`, how do you know what `Bobcat` refers to? This is why I say explicit dependencies declared in a `Project.toml` file are more robust IMO: you always know at least what you need to look for. (And if we had automated tools to populate the `Manifest.toml` to know _where_ to look, that’s all the better).

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [January 24, 2024, 10:09pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/7 "2024-01-24T22:09:40Z")

</div>

> [@ffevotte](#):
>
> I think part of the issue here is: when you look at the code in `Aardvark/src/Aardvark.jl`, how do you know what `Bobcat` refers to?

Yes, if I want `Aardvark` to be a standalone pkg, I will have to declare inside `Aardvark/Project.toml` where `Bobcat` is coming from.

But if `Aardvark` only makes sense inside my mono repo, which might look like

```julia
monorepo|⇒ tree
.
├── Aardvark
│ └── src
│ └── Aardvark.jl
├── Bobcat
│ └── src
│ └── Bobcat.jl
├── Cobra
│ └── src
│ └── Cobra.jl
├── Dingo
│ └── src
│ └── Dingo.jl
└── Project.toml

```

then it should be straightforward to figure out: `Bobcat` is either another monorepo local pkg, or it is an external pkg and as such needs to be declared in the `Project.toml`.

* * *

EDIT: With this directory setup, running

```julia-repl
julia> pushfirst!(LOAD_PATH, ".")

julia> Aardvark

```

does not work!  
I guess that is the behavior that is mentioned in the second paragraph of the linked docs.  
Only if you remove `Project.toml`, it works that way.  
So this means my desired monorepo layout above is not supported!

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 24, 2024, 10:23pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/8 "2024-01-24T22:23:28Z")

</div>

Even if `Aardvark` only makes sense in the local monorepo, it could still require external (registered) dependencies, no? These would need to be declared in a `Project.toml`. Or, in the case of the directory structure you propose, would you declare all external dependencies for all sub packages in the same top-level `Project.toml`?

> [@fatteneder](#):
>
> I wonder whether this can be automated.

I don’t know of any pure-julia way of doing this, but maybe tools like `direnv` can help you with this. See for example this blog post:

> **[Project specific Julia configuration with direnv | Fredrik Ekre](https://fredrikekre.se/posts/direnv-with-julia/#package_environments)**
>
> Improve your workflow with direnv: this post describes how direnv can be used effectively together with Julia.

---

<div class="post-metadata">

**Author:** ![francis-gagnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francis-gagnon/32/50424_2.png) [@francis-gagnon](https://discourse.julialang.org/u/francis-gagnon)\
**Post date:** [January 24, 2024, 10:26pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/9 "2024-01-24T22:26:34Z")

</div>

> [@fatteneder](#):
>
> EDIT: With this directory setup, running
> 
> ```julia
> julia> pushfirst!(LOAD_PATH, ".")
> 
> julia> Aardvark
> 
> ```
> 
> does not work!  
> I guess that is the behavior that is mentioned in the second paragraph of the linked docs.  
> Only if you remove `Project.toml`, it works that way.

Exactly! Now I’m really lost. It works only _if there is no `Project.toml` in the parrent dir_. It does not work anymore if the file is there, even without activating any environnement:

```julia-repl
[francis@thinkpad-x1 test]$ ls
Aardvark
[francis@thinkpad-x1 test]$ julia --quiet
julia> using Aardvark
ERROR: ArgumentError: Package Aardvark not found in current path.
[...]
julia> push!(LOAD_PATH, ".")
4-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"
 "."

julia> using Aardvark

julia> exit()
[francis@thinkpad-x1 test]$ >Project.toml
[francis@thinkpad-x1 test]$ ls
Aardvark Project.toml
[francis@thinkpad-x1 test]$ julia --quiet
julia> using Aardvark
ERROR: ArgumentError: Package Aardvark not found in current path.
[...]
julia> push!(LOAD_PATH, ".")
4-element Vector{String}:
 "@"
 "@v#.#"
 "@stdlib"
 "."
julia> using Aardvark
ERROR: ArgumentError: Package Aardvark not found in current path.
[...]

```

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [January 24, 2024, 10:27pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/10 "2024-01-24T22:27:51Z")

</div>

> [@ffevotte](#):
>
> Or, in the case of the directory structure you propose, would you declare all external dependencies for all sub packages in the same top-level `Project.toml`?

Yes, because I should only be able load one version of any external pkg at a time. I personally would not put two subprojects that depend on the same pkg, but different versions, into the same monorepo.

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [January 24, 2024, 10:32pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/11 "2024-01-24T22:32:26Z")

</div>

@ffevotte’s link above also discusses how `LOAD_PATH` works. Sorry, did not read that first.

* * *

So the ‘problem’ (or intended behavior) is that julia does not literally take what is in `LOAD_PATH` for loading, but instead it normalizes the entries first. The result you can see with `Base.load_path()`:

```julia-repl
shell> ls
Aardvark Bobcat Cobra Dingo

julia> pushfirst!(LOAD_PATH, ".")
4-element Vector{String}:
 "."
 "@"
 "@v#.#"
 "@stdlib"

julia> Base.load_path()
3-element Vector{String}:
 "/tmp/jltest/monorepo/"
 "/home/flo/.julia/environments/v1.10/Project.toml"
 "/home/flo/.julia/juliaup/julia-" ⋯ 20 bytes ⋯ "ux.gnu/share/julia/stdlib/v1.10"

shell> touch Project.toml

shell> ls
Aardvark Bobcat Cobra Dingo	Project.toml

julia> Base.load_path()
3-element Vector{String}:
 "/tmp/jltest/monorepo/Project.toml"
 "/home/flo/.julia/environments/v1.10/Project.toml"
 "/home/flo/.julia/juliaup/julia-" ⋯ 20 bytes ⋯ "ux.gnu/share/julia/stdlib/v1.10"

```

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 24, 2024, 10:46pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/12 "2024-01-24T22:46:14Z")

</div>

> [@fatteneder](#):
>
> So this means my desired monorepo layout above is not supported!

Perhaps something like this is close enough?

```julia
├── Aardvark
│ └── src
│ └── Aardvark.jl # using Bobcat, Example
├── Bobcat
│ └── src
│ └── Bobcat.jl
└── env # dedicated subdir for the project env
    ├── Project.toml # declares dep on Example
    └── Manifest.toml

```

```julia-repl
▷ JULIA_LOAD_PATH="$PWD:@:@v#.#:@stdlib" julia --project=env
julia> using Aardvark
[Info: Precompiling Aardvark [top-level]

julia> Aardvark.Bobcat
Bobcat

julia> Aardvark.Example
Example

```

---

<div class="post-metadata">

**Author:** ![fatteneder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fatteneder/32/33991_2.png) [@fatteneder](https://discourse.julialang.org/u/fatteneder)\
**Post date:** [January 24, 2024, 11:06pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/13 "2024-01-24T23:06:09Z")

</div>

That’s a neat idea.

And now put that unwieldy command into a bash script `julia.sh`

```julia
#!/usr/bin/env bash
thisdir=$(dirname -- "$0")
JULIA_LOAD_PATH="$thisdir:@:@v#.#:@stdlib" julia --project="$thisdir/env" $@

```

and make it exectuable, `chmod +x julia.sh`.

I think I can live with that. 🙂

---

<div class="post-metadata">

**Author:** ![francis-gagnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francis-gagnon/32/50424_2.png) [@francis-gagnon](https://discourse.julialang.org/u/francis-gagnon)\
**Post date:** [January 24, 2024, 11:54pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/14 "2024-01-24T23:54:59Z")

</div>

> [@ffevotte](#):
>
> `JULIA_LOAD_PATH="$PWD:@:@v#.#:@stdlib" julia`

Do you think something similar could be achieved by using the `.vscode/settings.json` file instead? I tried adding this setting:

```julia
{
   "julia.executablePath": "JULIA_LOAD_PATH=".:@:@v#.#:@stdlib" julia"
}

```

but it did not work.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 25, 2024, 7:13am UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/15 "2024-01-25T07:13:04Z")

</div>

> [@francis-gagnon](#):
>
> Do you think something similar could be achieved by using the `.vscode/settings.json` file instead?

You could put the relevant command in a shell script, and put the path to that script into the `julia.executablePath` VSCode setting.

But then I’m not sure whether the LanguageServer will correctly support such a project organization. Again, although it’s a bit more work to setup initially, I really think that in the long run you’d be better off with an explicit project environment.

---

<div class="post-metadata">

**Author:** ![francis-gagnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/francis-gagnon/32/50424_2.png) [@francis-gagnon](https://discourse.julialang.org/u/francis-gagnon)\
**Post date:** [January 25, 2024, 8:53pm UTC](https://discourse.julialang.org/t/create-an-implicit-environment-with-package-directories/109207/16 "2024-01-25T20:53:18Z")

</div>

The script in `executablePath` did not work, but I found another solution that seems to work well. Simply add this line in `.vscode/setting.json`:

```json
  "julia.additionalArgs": [  
      "-e pushfirst!(LOAD_PATH, pwd())"
  ],

```

With this, a fresh REPL session in VS Code give:

```julia-repl
shell> ls
Aardvark env

julia> using Aardvark

julia> 

```
