【问题标题】:what is `@.` in Julia `--project` command line option?Julia `--project` 命令行选项中的`@.` 是什么?
【发布时间】:2019-05-05 22:08:09
【问题描述】:

在命令行中启动 Julia 时,可以指定项目目录。其中一个选项是@.,可能是当前目录。在这种情况下,@. 是什么?

# from `julia --help`
--project[={<dir>|@.}]    Set <dir> as the home project/environment

来自docs

如果变量设置为@.,Julia 会尝试从当前目录及其父目录中查找包含 Project.toml 或 JuliaProject.toml 文件的项目目录。

我意识到 cli --project 参数解析发生在此 C code 中,并且显然被此 init code 使用,尽管我不确定两者之间的事件顺序。

特别是在initdefs.jl 我们有:

project = (JLOptions().project != C_NULL ?
    unsafe_string(Base.JLOptions().project) :
    get(ENV, "JULIA_PROJECT", nothing))
HOME_PROJECT[] =
    project == nothing ? nothing :
    project == "" ? nothing :
    project == "@." ? current_project() : abspath(project)

我对这段代码的阅读是@. 只是一个任意标记,它可能是一个简单的 cli 的. 吗? Julia 如何搜索“当前目录及其父目录。

LOAD_PATH(["@", "@v#.#", "@stdlib"]) 中使用了类似的符号, 正如herehere 所讨论的那样。 @. 是否与 LOAD_PATH 符号属于同一扩展系列?

【问题讨论】:

标签: command-line-interface julia


【解决方案1】:

家庭项目和--project

--project 标志定义了“家庭项目”或“家庭环境”。环境由Project.toml/Manifest.toml 定义,并定义可用于using/import 的包。

您可以将--project 设置为 (i) 目录(有或没有Project.toml)(ii) 到Project.toml 的路径或(iii) 到@.。 (i) 和 (ii) 是不言自明的——Julia 会将位于路径上的项目视为主项目。现在对于 (iii),如果您设置 --project=@.,Julia 将尝试查找 现有 Project.toml 文件并将其用作主项目。考虑以下示例:

~$ tree .
.
├── A
└── Project.toml

1 directory, 1 file

其中A 是一个空目录。我们可以轻松地尝试 (i) 和 (ii):

# existing file
[~]$ julia --project=Project.toml -E 'Base.active_project()'
"~/Project.toml"

# existing directory
[~]$ julia --project=A -E 'Base.active_project()'
"~/A/Project.toml"

# non-existing directory
[~]$ julia --project=B -E 'Base.active_project()'
"~/B/Project.toml"

# non-existing file
[~]$ julia --project=B/Project.toml -E 'Base.active_project()'
"~/B/Project.toml"

请注意,在上面的最后三个示例中,Project.toml 文件不存在,但它会在需要时创建(例如,当使用 Pkg 操作包时)。

现在,将其与@. 的行为进行比较,后者将查找现有项目文件:

# from our root directory
[~]$ julia --project=@. -E 'Base.active_project()'
"~/Project.toml"

# from inside the A directory
[~/A]$ julia --project=@. -E 'Base.active_project()'
"~/Project.toml"

在这两种情况下,我们都找到了相同的 Project.toml 文件。使用@. 选项,Julia 首先在当前目录中查找Project.toml 文件,如果未找到,则上一级到父文件夹并查找,依此类推。这就是第二个示例中发生的情况; Julia 在空的A 目录中没有找到Project.toml 文件,所以我们向上移动到父目录,找到了我们那里的Project.toml

是的,我们可以为此选择其他标记,但不是.,因为它已经有意义;它是当前目录的路径,也是与--project 一起使用的完全有效的路径。

加载路径和"@"

要加载一个包Example,我们在其[deps] 部分定义一个带有Example 的家庭项目是不够的;主项目还需要显示在 Julias 加载路径 (Base.load_path()) 中。默认情况下,加载路径从["@", "@v#.#", "@stdlib"] 扩展,其中"@v#.#" 扩展为~/.julia/environments/v#.## 替换为Julias 主要和次要版本号,"@stdlib" 扩展为包含Julias 标准库的目录。 "@" 扩展为 1. 活动项目(使用 Pkg.activate/pkg&gt; activate 激活)或 2. 主项目。我们可以用Base.load_path()检查扩展的加载路径:

# without home project; @ expands to nothing
[~]$ julia -E 'Base.load_path()'
["~/.julia/environments/v1.0/Project.toml", "~/julia10/usr/share/julia/stdlib/v1.0"]

# with home project; @ expands to our specified home project
[~]$ julia --project=@. -E 'Base.load_path()'
["~/Project.toml", "~/.julia/environments/v1.0/Project.toml", "~/julia10/usr/share/julia/stdlib/v1.0"]

最后,如果我们从加载路径中删除"@",那么我们定义了一个主项目并不重要:

[~]$ export JULIA_LOAD_PATH="" && julia --project=@. -E 'Base.load_path()'
String[]

【讨论】:

  • 感谢您的详细解答。尚不清楚--project 接受不存在的路径。在您提到的一个案例上(在activate 之前和之后)使用Base.load_path_expand("@") 也非常有启发性。我认为Base.load_path_expand() 的正确文档字符串(可能基于此答案),其中发生命名环境解析,也可能有所帮助:github.com/JuliaLang/julia/blob/…
【解决方案2】:

根据@fredrikekre 的回答,编写了一个脚本来探索Base.load_path()Base.active_project()Base.current_project() 的行为。

init_me.jl:

"""
Explore Base.load_path() behaviour in diffferent situations.

Run this file as:

    julia init_me.jl
    julia --project=@. init_me.jl
    julia --project=. init_me.jl

Try running in a folder that has or does not have Project.toml file.    
"""    

MESSAGE = Dict(true => " (exists)", false => " (does not exist)")
exist(path)::Bool = isfile(path) || isdir(path)
printexist(path::String) = println("  ", path, MESSAGE[exist(path)])
printexist(nothing) = println("nothing")
printf2(s,n=8) = print("  " * s * ' '^(n-length(s)))

p_ = Base.JLOptions().project
project_option = (p_ != C_NULL) ? unsafe_string(p_) : "option not provided"
println("--project:\n  ", project_option)

println("load_path():")
for path in Base.load_path()
    printexist(path)
end

println("Base.active_project():")
printexist(Base.active_project())
println("Base.current_project():")
printexist(Base.current_project())

println("alias expansion with Base.load_path_expand():")
for alias in ["@.", "@", "@stdlib", "@v1.0"] 
    printf2(alias)
    printexist(Base.load_path_expand(alias))
end

结果如下:

  • basecase: julia --project=@. init_me.jl 在 Project.toml 文件的文件夹中产生最预期的结果
  • julia --project=. init_me.jl 在路径包含非 ASCII 字符的文件夹上失败
  • 没有Project.toml 的文件夹可以在--project=&lt;some dir without Project.toml&gt; 上成为活动项目
  • 有时Base.active_project() 不是Base.current_project()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 2011-03-27
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多