上传代码
|
注意本章讨论下载软件包的技术特性。 要安装软件包,请使用 |
定义
Julia有两种代码加载机制。
-
代码包含,例如
include("源。jl"). 启用允许您将程序拆分为多个源代码文件。 使用表达式时include("源。jl")文件内容来源。jl它是在调用发生的模块的全局范围内计算的。包括. 如果include("源。jl")它被调用多次,文件被计算的次数相同。来源。jl. 激活路径来源。jl相对于发生调用的文件进行解释包括. 这使得移动源代码文件的子树变得容易。 在REPL中,包含路径相对于当前工作目录进行解释。残疾人士(). -
包下载,例如
进口X或使用X. 导入机制允许您下载一个包-一个包含在模块中的独立的,可重用的Julia代码块-并按名称使该模块可用。X导入模块内。 如果在Julia会话期间有相同的包X它被导入了几次,并且只加载了第一次。 稍后,导入模块接收到它的链接。 但是,请记住,操作员进口X它可以在不同的上下文中加载不同的包:在主项目中X它可以引用具有名称的单个包X,并在依赖项-到其他包,也与名称X. 有关更多信息,请参阅下文。
代码的包含非常简单:指定的源代码文件是在调用模块的上下文中计算的。 下载包是基于包含代码,但它服务 另一个目标。 本章的其余部分讨论了包下载的工作原理。
_pack_是一个源代码树,具有标准结构,提供可在其他Julia项目中使用的功能。 使用运算符加载包 进口X 或 使用X. 他们制作了一个带有名字的包 X 在调用import语句的模块中可用。 意义 X 在表达式中 进口X 取决于上下文:正在下载的包 X 取决于使用运算符的代码。 因此,表达式的处理 进口X 它发生在两个阶段:首先,确定哪个包是包。 X 在这个上下文中,然后这个包位于哪里 X.
要回答这些问题,将在常量中列出的项目环境中执行搜索 LOAD_PATH对于项目文件(项目。汤姆尔 或 朱利亚项目。汤姆尔),清单文件(清单。汤姆尔 或 JuliaManifest.汤姆尔 或带有后缀的相同名称 -v{major}.{minor}.汤姆 对于某些版本)或具有源代码文件的文件夹。
包裹联合会
通常,包由其名称唯一标识。 但是,有时一个项目可能需要使用两个名称相同的不同包。 虽然您可以简单地重命名其中一个包来执行此操作,但这样的操作可能会在大型共享代码库中导致严重问题。 因此,Julia代码加载机制允许您使用相同的名称来引用应用程序的不同部分中的不同包。
Julia支持联合包管理。 这意味着不同的独立方可以维护自己的公共和私有软件包的注册管理机构,项目可以使用来自不同注册管理机构的公共和私有软件包的组合。 一组通用的工具和工作流用于安装和管理来自不同注册表的软件包。 包管理器 Pkg,Pkg Julia附带的,允许您安装和管理项目依赖项。 它允许您创建项目文件(描述项目所依赖的其他项目)和清单文件(其中包含项目的完整依赖关系图的版本),以及使用它们。
联邦的一个后果是缺乏集中的包命名系统。 不同的对象可以使用相同的名称来引用不相关的包。 这是不可避免的,因为对象不协调它们的行动,甚至可能不知道彼此的存在。 由于缺乏集中的命名系统,具有相同名称的不同包最终可能会在同一个项目中使用。 Julia中的包加载机制不要求包名称是全局唯一的,即使在单个项目的依赖关系图中也是如此。 相反,包由https://en.wikipedia.org/wiki/Universally_unique_identifier 创建包时分配给每个包的[通用唯一标识符](Uuid)。 通常不需要直接使用这些相当繁琐的128位标识符,因为它接管了生成和跟踪它们的任务。 Pkg,Pkg. 但是,由于UUID,您可以得到一个明确的问题答案--which package指的是 X?
由于分散式命名的问题相当抽象,因此分析特定情况以了解它可能是有用的。 假设您正在开发一个名为 应用程序,其中使用两个包: 酒吧 和 普里夫. 普里夫 --这是您自己创建的私人包,并且 酒吧 --您使用但不控制的公共包。 你什么时候创建的包 普里夫,一个名为 普里夫 没有。 但是,后来有人创建了一个完全不同的包。 普里夫,这是出版,并成为流行。 而且,它已经开始在包中使用 酒吧. 所以下次更新的时候 酒吧 要获得最新的功能和修复错误,请在 应用程序 因此,将使用两个名称不同的包。 普里夫,而这只是作为更新的结果。 申请表格 应用程序 它直接依赖于您的私人包 普里夫 和间接依赖,通过 酒吧,从新的公共包 普里夫. 由于这些包 普里夫 它们是不同的,但两者都是正确操作所必需的。 应用程序,表达 进口Priv 它应该引用不同的包。 普里夫 取决于它的应用位置:在代码中 应用程序 或者在代码中 酒吧. 为此,Julia中的包加载机制区分了两个包 普里夫 通过Uuid Id并根据上下文(调用语句的模块的上下文)选择适当的Id `进口`如何发生这种情况取决于环境,并在以下各节中描述。
星期三
环境定义了操作符的含义 进口X 和 使用X 在不同的代码上下文中以及它们加载哪些文件。 Julia中有两种类型的环境。
-
*项目环境*是一个包含项目文件和可能是清单文件的目录。 它们形成了一个隐式环境。 项目文件定义项目的直接依赖项的名称和标识符。 清单文件(如果可用)描述完整的依赖关系图,包括所有直接和间接依赖关系、每个依赖关系的确切版本以及查找和下载正确版本所需的信息。
-
*包目录*包含一组包的源代码树的嵌套目录。 它形成了一个隐式环境。 如果
X--这是包目录中的嵌套目录,有一个文件X/src/X.jl所以,包X在包目录环境中可用,以及X/src/X.jl--这是通过它下载的源代码文件。
这些环境可以组合使用以创建多层环境:一组有序的项目环境和包目录,它们重叠以形成单个复合环境。 在这种情况下,将确定哪些包可用以及从哪里下载它们的优先级和可见性规则相结合。 例如,Julia下载路径形成多层环境。
每个环境都有自己的用途。
项目环境提供*可重复性。 通过将项目环境与项目源代码的其余部分一起添加到版本控制系统(如Git存储库),您可以重现项目及其所有依赖项的确切状态。 特别是,清单文件包含每个依赖项的确切版本,该依赖项由源代码树的加密哈希标识。 这允许调度程序 Pkg,Pkg 获取确切的版本并为每个依赖项下载正确的代码。
当需要仔细监控的项目环境时,包目录提供*方便。 如果您需要在某处放置一组包并直接使用它们,而无需为它们创建项目环境,则它们非常有用。
*多层环境允许您*添加*工具到主环境。 您可以将开发环境放在堆栈的末尾,以便可以从REPL和脚本访问它们,但不能从包访问它们。
|
注意从堆栈上的其他环境(而非活动环境)加载包时,包将在活动环境的上下文中加载。 这意味着包将被加载,就像它被导入到活动环境中一样,这可能会影响其依赖项版本的解析。 在预编译期间,这样的包将被标记为预编译作业。 |
在最一般的层面上,每个环境都定义了三种模式:根、图形和路径。 确定表达式的值时 进口X 使用根方案和图形来标识包。 X,并利用所述路径图,确定其源代码的位置。 下面详细描述三种方案中的每一种方案的目的。
根*(roots): 名称::符号 ⟶ 掳忙篓霉::UUID
环境根架构将包名称分配给环境使主项目可用的所有顶级依赖项的Uuid(即,可以上载到 主要). 当Julia遇到表达式 进口X 在主项目中,它标识 X 如何 根[:X].
graph*(图表): 上下文::UUID ⟶ 名称::符号 ⟶ 掳忙篓霉::UUID
环境图是一个多级架构,它在上下文中分配每个UUID(上下文环境)将名称映射到Uuid。 它的工作方式与根方案相同,但在给定的上下文中(上下文环境). 当Julia遇到表达式 进口X 在带有UUID的包代码中 上下文环境,它识别 X 如何 图[上下文][:X]. 特别是,这意味着表达式 进口X 它可以根据不同的包引用不同的包 上下文环境.
*路径(路径): 掳忙篓霉::UUID × 名称::符号 ⟶ 路径::字符串
路径方案为每对Uuid和包名称分配具有此包入口点的源代码文件所在的位置。 元素之后 X 在表达式中 进口X 它通过根方案或图形(取决于下载是从主项目还是从依赖项)解析为UUID,Julia确定需要下载哪个文件才能接收 X,通过搜索 路径[uuid,:X] 环境中。 包含此文件时,将使用名称定义模块 X. 下载包后,解析为相同标识符的所有后续导入操作 uuid,将导致创建一个绑定到一个已经下载的包模块。
对于每种类型的环境,这三种方案的定义不同,如下面各节所述。
|
注意为了清楚起见,本章中的示例为根、图和路径模式提供了完整的数据结构。 但是,Julia包下载代码不会显式创建它们。 相反,它"懒惰地"只计算每个结构中足以加载给定包的那部分。 |
项目环境
项目环境是由一个包含一个名为"项目文件"的目录形成的 工程。汤姆尔,以及一个名为的可选清单文件 清单。汤姆尔. 这些文件也可以具有名称 朱利亚项目。汤姆尔 和 JuliaManifest.汤姆尔;在这种情况下,文件 项目。汤姆尔 和 清单。汤姆尔 它们被忽略了。 这使您可以在同一时间使用依赖于命名文件的工具。 工程。汤姆尔 和 清单。汤姆尔. 但是,对于仅在Julia上的项目,名称为 工程。汤姆尔 和 清单。汤姆尔 优选。 但是,从Julia版本1.10.8开始, (朱莉娅)Manifest-v{major}.{minor}.汤姆 它被识别为一种格式,其中特定的清单文件应该在某个版本的Julia中使用,即在同一个文件夹中。 清单-v1.11。汤姆尔 它将由版本1.11使用,并且 清单。汤姆尔 --朱莉娅的任何其他版本。
项目环境的根、图和路径的方案定义如下。
环境的*根架构*由项目文件的内容确定,特别是其元素 姓名 和 uuid 顶层和部分 [deps] (所有这些都是可选的)。 考虑以下虚构应用程序的项目文件示例 应用程序,其如上所述。
name = "App"
uuid = "8f986787-14fe-4607-ba5d-fbff2944afa9"
[deps]
Priv = "ba13f791-ae1d-465a-978b-69c3ad90f72b"
Pub = "c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1"
此项目文件假定以下根方案,以Julia字典的形式呈现。
roots = Dict(
:App => UUID("8f986787-14fe-4607-ba5d-fbff2944afa9"),
:Priv => UUID("ba13f791-ae1d-465a-978b-69c3ad90f72b"),
:Pub => UUID("c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1"),
)
有了这个根方案,运营商 进口Priv 在代码中 应用程序 指示Julia执行搜索 根[:Priv],导致值 ba13f791-ae1d-465a-978b-69c3ad90f72b --包的UUID 普里夫 应该在这种情况下加载。 UUID决定使用哪个包。 普里夫 计算运算符时必须加载和使用 进口Priv 在主应用程序中。
项目环境的依赖关系图由清单文件的内容(如果有)确定。 如果没有清单文件,则图表为空。 清单文件对项目的每个直接或间接依赖项都有一个单独的部分。 对于每个依赖项,包的UUID和源代码树的散列或源代码的显式路径都在文件中指定。 考虑以下应用程序的清单文件示例 应用程序:
[[Priv]] # частный
deps = ["Pub", "Zebra"]
uuid = "ba13f791-ae1d-465a-978b-69c3ad90f72b"
path = "deps/Priv"
[[Priv]] # общедоступный
uuid = "2d15fe94-a1f7-436c-a4d8-07a9a496e01c"
git-tree-sha1 = "1bf63d3be994fe83456a03b874b409cfd59a6373"
version = "0.1.5"
[[Pub]]
uuid = "c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1"
git-tree-sha1 = "9ebd50e2b0dd1e110e842df3b433cb5869b0dd38"
version = "2.1.4"
[Pub.deps]
Priv = "2d15fe94-a1f7-436c-a4d8-07a9a496e01c"
Zebra = "f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62"
[[Zebra]]
uuid = "f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62"
git-tree-sha1 = "e808e36a5d7173974b90a15a353b564f3494092f"
version = "3.4.2"
此清单文件完全描述了项目可能的依赖关系图。 应用程序.
*应用程序使用两个不同的包命名 普里夫:private,这是根依赖项,public,这是间接依赖项via 酒吧. 它们在其独特的Uuid上有所不同,并且具有不同的依赖关系。
私人包裹 普里夫 取决于包装 酒吧 和 斑马.
对于公共包 普里夫 没有依赖关系。
*应用程序也取决于包 酒吧 反过来,这取决于公共包 普里夫 而从同一个包 斑马 私人包取决于哪个 普里夫.
依赖关系图,表示为字典,如下所示:
graph = Dict(
# Частный пакет Priv:
UUID("ba13f791-ae1d-465a-978b-69c3ad90f72b") => Dict(
:Pub => UUID("c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1"),
:Zebra => UUID("f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62"),
),
# Общедоступный пакет Priv:
UUID("2d15fe94-a1f7-436c-a4d8-07a9a496e01c") => Dict(),
# Pub:
UUID("c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1") => Dict(
:Priv => UUID("2d15fe94-a1f7-436c-a4d8-07a9a496e01c"),
:Zebra => UUID("f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62"),
),
# Zebra:
UUID("f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62") => Dict(),
)
有了这个图(图表)Julia遇到表达式时的依赖关系 进口Priv 在包 酒吧 用UUID c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1,执行以下搜索:
graph[UUID("c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1")][:Priv]
结果,返回值 2d15fe94-a1f7-436c-a4d8-07a9a496e01c,这意味着在包的上下文中 酒吧 表达方式 进口Priv 公共软件包的链接 普里夫,而不是一个私人的,应用程序直接依赖。 就像那个名字一样 普里夫 在主项目中,您可以引用此名称在依赖项中指示的包以外的包,这使得在包系统中可以使用相同的名称。
计算表达式时会发生什么 进口斑马 在主代码中 应用程序? 由于包 斑马 没有在项目文件中指定,导入将失败,尽管事实上 斑马 它在清单文件中。 而且,如果操作者 进口斑马 它是在公共包中使用的 普里夫 用UUID 2d15fe94-a1f7-436c-a4d8-07a9a496e01c 它也会失败,因为这个包有 普里夫 清单文件中没有声明的依赖项,因此它无法下载其他软件包。 包裹 斑马 它只能由清单文件中明确指定为依赖项的包加载,即包 酒吧 和其中一个包 普里夫.
项目环境的*路径图*是从清单文件中提取的。 带有标识符的包的路径 uuid 还有名字 X 根据以下规则(按指定顺序)确定。
-
如果目录中的项目文件与ID匹配
uuid还有名字X,则发生以下情况。 **如果它有一个元素入口文件在顶层,那么uuid它映射到此路径,该路径相对于包含项目文件的目录进行解释。
*否则 uuid 被映射到路径 src/X.jl 关于包含项目文件的目录。
-
-
如果不满足上述条件,但存在项目文件的清单文件,该清单文件具有与标识符对应的节
uuid,发生以下情况。 ***如果它包含一个元素路径,使用此路径(相对于包含清单文件的目录)。**如果它包含一个元素 `git-树-sha1`,为 `uuid` 和价值观 `git-树-sha1` 一个确定性的哈希函数是根据它的结果计算的(让我们调用这个值 `鼻涕虫`)并在全局数组中的每个目录中 `DEPOT_PATH` 朱莉娅在找目录 `包装/X/$slug`. 将使用第一个这样找到的目录。 . 如果是目录,则 `uuid` 与之相比 `src/X.jl`,但清单对应行中有条目的情况除外 `入口文件`,这在这种情况下使用。 在这两种情况下,这些条目都相对于2.1中的目录。
-
如果满足这些条件中的任何一个,则到源代码入口点的路径将是获得的结果,或者是相对于此结果的路径,并添加 src/X.jl. 否则,标识符对应的路径 uuid,没有。 如果在下载软件包时 X 找不到源代码的路径,搜索失败,可能会提示用户安装相应版本的软件包或以另一种方式修复情况(例如,宣布 X 作为成瘾)。
在上面的示例清单文件中,第一个包的路径是 普里夫 (用UUID ba13f791-ae1d-465a-978b-69c3ad90f72b)定义如下:Julia在manifest文件中搜索这个包的一个部分,找到元素 路径,想办法 副警长/Priv 关于项目目录 应用程序 (假设代码 应用程序 位于途中 /home/me/项目/应用),找到文件夹 /home/me/项目/应用/deps/Priv 并因此下载包 普里夫 "她反问道。
如果有必要下载另一个软件包 普里夫 (用UUID 2d15fe94-a1f7-436c-a4d8-07a9a496e01c),Julia环境会在清单中找到它的部分,但是其中没有元素 路径 但有一个元素 git-树-sha1. 因此,将计算该值 鼻涕虫 对于这对UUID和SHA-1哈希,得到结果 HDkrT的 (这个计算究竟是如何执行的并不重要,但函数是一致的和确定性的)。 这意味着包的路径是 普里夫 会有办法的 包/Priv/HDkrT/src/Priv。jl 包存储库之一中。 假设变量 DEPOT_PATH 包含值 ["/家/我/。julia","/usr/local/julia"]. 在这种情况下,Julia会检查以下路径是否存在:
-
/家/我/。朱莉娅/包/Priv/HDkrT -
usr/本地/朱莉娅/包装/Priv/HDkrT
Julia然后尝试下载公共包。 普里夫 从文件 包/Priv/HDKrT/src/Priv。jl 在找到这些路径中的第一个的存储库中。
示例项目环境的可能路径图如下所示。 应用程序 在本地文件系统中搜索后,它在上面依赖关系图的清单中呈现的形式。
paths = Dict(
# Частный пакет Priv:
(UUID("ba13f791-ae1d-465a-978b-69c3ad90f72b"), :Priv) =>
# относительная точка входа внутри репозитория `App`:
"/home/me/projects/App/deps/Priv/src/Priv.jl",
# Общедоступный пакет Priv:
(UUID("2d15fe94-a1f7-436c-a4d8-07a9a496e01c"), :Priv) =>
# пакет, установленный в системном хранилище:
"/usr/local/julia/packages/Priv/HDkr/src/Priv.jl",
# Pub:
(UUID("c07ecb7d-0dc9-4db7-8803-fadaaeaf08e1"), :Pub) =>
# пакет, установленный в пользовательском хранилище:
"/home/me/.julia/packages/Pub/oKpw/src/Pub.jl",
# Zebra:
(UUID("f7a24cb4-21fc-4002-ac70-f0e3a0dd3f62"), :Zebra) =>
# пакет, установленный в системном хранилище:
"/usr/local/julia/packages/Zebra/me9k/src/Zebra.jl",
)
在示例图中,有三种不同类型的包位置(第一个和第三个位置是默认下载路径的一部分)。
-
"https://stackoverflow.com/a/35109534 [自己的副本]"私人包
普里夫托管在存储库中应用程序. -
公共包裹
普里夫和斑马它们位于系统存储中,系统管理员在其中安装和管理软件包。 它们可供系统的所有用户使用。 -
包裹
酒吧它位于用户存储中,其中软件包由活动用户安装。 它们仅对安装它们的用户可用。
包装目录
包目录是一种更简单的环境类型,不允许解决名称冲突。 在包目录中,一组顶级包是一组"看起来"像包的嵌套目录。 包裹 X 如果此目录包含以下入口点文件之一,则存在于包目录中:
-
X.jl -
X/src/X.jl -
X.jl/src/X.jl
包可以在包目录中导入哪些依赖项取决于包中是否存在项目文件。
*如果存在项目文件,则只能导入其部分中指定的包。 [deps].
*如果没有项目文件,则可以导入任何顶级包,即可以在模块中加载的相同包。 主要 或者在REPL中。
*根架构*通过分析项目目录的内容并创建所有可用包的列表来确定。 此外,在文件夹中找到的每个包 X,一个UUID分配如下。
-
如果有文件
X/项目。汤姆尔它有一个元素uuid,那么这个元素uuid它将是ID值。 -
如果文件
X/项目。汤姆尔有一个虚拟标识符,但其中没有顶级UUID元素uuid它是通过散列规范(真实)路径生成的X/项目。汤姆尔. -
否则(如果文件
工程。汤姆尔号)IDuuid它将包括https://en.wikipedia.org/wiki/Universally_unique_identifier#Nil_UUID [只是零]。
包目录的依赖关系图由每个包子目录中项目文件的存在和内容决定。 以下规则适用。
*如果包的子目录中没有项目文件,则该包不包含在图表中,并且其代码中的导入运算符在主项目和REPL中都被视为顶级运算符。
*如果包的附加目录中有一个项目文件,则该方案将用作其UUID的图形元素。 [deps] 从项目文件。 如果缺少此部分,则该元素将被视为空。
假设包目录具有以下结构和内容:
Aardvark/
src/Aardvark.jl:
import Bobcat
import Cobra
山猫/
项目。汤姆尔:
[deps]
眼镜蛇="4725e24d-f727-424b-bca0-c4307a3456fa"
Dingo="7a7925be-828c-4418-bbeb-bac8dfc843bc"
src/山猫.jl:
进口眼镜蛇
进口野狗
眼镜蛇,眼镜蛇/
项目。汤姆尔:
uuid="4725e24d-f727-424b-bca0-c4307a3456fa"
[deps]
Dingo="7a7925be-828c-4418-bbeb-bac8dfc843bc"
src/眼镜蛇.jl:
进口野狗
野狗/
项目。汤姆尔:
uuid="7a7925be-828c-4418-bbeb-bac8dfc843bc"
src/野狗.jl:
#没有进口
以字典的形式,相应的根结构将呈现如下:
roots = Dict(
:Aardvark => UUID("00000000-0000-0000-0000-000000000000"), # файла проекта нет, нулевой UUID
:Bobcat => UUID("85ad11c7-31f6-5d08-84db-0a4914d4cadf"), # фиктивный UUID на основе пути
:Cobra => UUID("4725e24d-f727-424b-bca0-c4307a3456fa"), # UUID из файла проекта
:Dingo => UUID("7a7925be-828c-4418-bbeb-bac8dfc843bc"), # UUID из файла проекта
)
以字典的形式,相应的图结构将表示如下:
graph = Dict(
# Bobcat:
UUID("85ad11c7-31f6-5d08-84db-0a4914d4cadf") => Dict(
:Cobra => UUID("4725e24d-f727-424b-bca0-c4307a3456fa"),
:Dingo => UUID("7a7925be-828c-4418-bbeb-bac8dfc843bc"),
),
# Cobra:
UUID("4725e24d-f727-424b-bca0-c4307a3456fa") => Dict(
:Dingo => UUID("7a7925be-828c-4418-bbeb-bac8dfc843bc"),
),
# Dingo:
UUID("7a7925be-828c-4418-bbeb-bac8dfc843bc") => Dict(),
)
注意一些重要的规则。
-
没有项目文件的包可以依赖于任何顶级包,并且由于包目录中的所有包都在顶级可用,因此它可以导入环境中的所有包。
-
具有项目文件的包不能依赖于没有这样的文件的包,因为具有项目文件的包只能加载模式中可用的包。
图表,并且其中没有没有项目文件的包。 -
只有没有项目文件的包可以依赖于具有项目文件的包,但没有明确指定的UUID,因为分配给这些包的虚拟Uuid仅用于内部使用。
让我们看看这些规则在我们的例子中是如何应用的。
-
土豚可以导入任何包山猫,眼镜蛇,眼镜蛇或野狗;实际进口山猫和眼镜蛇,眼镜蛇. -
山猫它可以而且确实导入包眼镜蛇,眼镜蛇和野狗,其中没有带有Uuid的项目文件,并且在节中声明为依赖项[deps]包装山猫. -
山猫可能取决于土豚,由于包有土豚没有项目文件。 -
眼镜蛇,眼镜蛇可以并且确实导入一个包野狗,它有一个项目文件和一个UUID,并在节中声明为依赖项[deps]包装眼镜蛇,眼镜蛇. -
眼镜蛇,眼镜蛇它不能依赖于包土豚或山猫因为他们没有任何真正的Uuid。 *包装野狗他不能导入任何东西,因为他有一个项目文件,但没有分区。[deps].
*包目录中的路径方案*非常简单:在其中,嵌套目录的名称映射到入口点的路径。 换句话说,如果我们的例子中的项目目录的路径看起来像 /家/我/动物,则方案 路径 它可以用这样的字典来表示:
paths = Dict(
(UUID("00000000-0000-0000-0000-000000000000"), :Aardvark) =>
"/home/me/AnimalPackages/Aardvark/src/Aardvark.jl",
(UUID("85ad11c7-31f6-5d08-84db-0a4914d4cadf"), :Bobcat) =>
"/home/me/AnimalPackages/Bobcat/src/Bobcat.jl",
(UUID("4725e24d-f727-424b-bca0-c4307a3456fa"), :Cobra) =>
"/home/me/AnimalPackages/Cobra/src/Cobra.jl",
(UUID("7a7925be-828c-4418-bbeb-bac8dfc843bc"), :Dingo) =>
"/home/me/AnimalPackages/Dingo/src/Dingo.jl",
)
由于根据定义,包目录环境中的所有包都是具有相应入口点文件的嵌套目录,因此它们的模式元素 路径 他们总是有这种形式。
媒体堆栈
第三和最后类型的环境是其中其他类型的环境彼此重叠的环境,形成其中每个组件环境的包可用的单个环境。 这种复合介质称为介质堆栈。 在Julia全局变量中 LOAD_PATH Julia进程在其中运行的环境堆栈已被定义。 为了使Julia进程只能从一个项目或包目录访问包,请不要指定 LOAD_PATH 其他环境。 但是,访问一些工具通常很有用-标准库,分析器,调试器,辅助程序等。 -即使它们不是当前项目的依赖项。 如果您将具有这些工具的环境添加到下载路径,它们将立即在顶级代码中可用,因此您不需要将它们添加到项目中。
属于媒体堆栈的组件的根,图和路径的数据结构非常简单地组合为字典,并且在密钥匹配的情况下,优先考虑较早的条目。 换句话说,如果有一个堆栈 堆栈=[env₁,env₂,…],则发生以下情况。
roots = reduce(merge, reverse([roots₁, roots₂, …]))
graph = reduce(merge, reverse([graph₁, graph₂, …]))
paths = reduce(merge, reverse([paths₁, paths₂, …]))
变量 根!, graphᵢ 和 路径? 下标对应于环境 envᵢ 包含较低的索引 堆叠. 功能 反向 它的使用原因是当字典中的键作为参数传递给函数匹配时 合并;合并,优先考虑最后一个参数,而不是第一个。 这种方法有几个值得注意的特点。
-
主环境,即堆栈中的第一个环境,完全集成到多层环境中。 堆栈中第一个环境的依赖关系图保证完全和不变地包含在分层环境中,包括所有依赖关系的相同版本。
-
来自非核心环境的软件包最终可能会使用不兼容的依赖版本,即使它们自己的环境完全兼容。 如果其中一个依赖项被堆栈中较早环境的版本替换(根据graph,path或两者),则会发生这种情况。
由于主要环境通常是当前项目的环境,并且堆栈中的后续环境包含额外的工具,因此这种折衷是合理的:开发工具停止工作比整个项目更好。 通常,如果发生这种不兼容性,则有必要将开发工具更新为与主项目兼容的版本。
软件包扩展
包扩展是在当前Julia会话中加载某组其他包(其"触发器")时自动加载的模块。 扩展在部分中的项目文件中定义 [扩展]. 扩展触发器是本节中列出的其他包的子集 [弱者] (也许,但很少,在部分 [deps])的项目文件。 这些包可能有compat条目,就像其他包一样。
name = "MyPackage"
[compat]
ExtDep = "1.0"
OtherExtDep = "1.0"
[weakdeps]
ExtDep = "c9a23..." # uuid
OtherExtDep = "862e..." # uuid
[extensions]
BarExt = ["ExtDep", "OtherExtDep"]
FooExt = "ExtDep"
...
部分中的键 扩展 --这些是扩展名。 当右侧列出的所有包(触发器)加载时,它们被加载。 如果扩展只有一个触发器,则为了简洁起见,触发器列表可以写成字符串。 扩展的切入点 N.食物,食物 位于 ext/FooExt。jl 或 ext/FooExt/FooExt。jl. 扩展的内容通常具有这种结构:
module FooExt #加载主包和触发器 使用MyPackage,ExtDep #通过触发器的类型扩展主包的功能 我的包装。func(x::ExtDep.SomeStruct)=。.. 结束
当扩展包添加到环境中时,节 弱者,弱者 和 扩展 它们保存在此包部分的清单文件中。 包的依赖关系搜索规则与其"父"相同,只是列表中的触发器也被视为依赖关系。
工作区
项目文件可以通过指定包含在该工作区中的一组项目来定义该工作区。:
[workspace]
projects = ["test", "benchmarks", "docs:", "SomePackage"]
阵列中列出的每个项目 工程项目,由从工作区根部的相对路径指示。 它可以是直接的子目录(例如, "测试")或嵌套的子目录(例如, "嵌套/细分/MyPackage"). 每个项目都包含自己的文件 项目。汤姆尔,这可能包括附加的依赖性和兼容性限制。 在这种情况下,包管理器从工作区中的所有项目收集所有依赖项信息,生成一个清单文件,该清单文件结合了所有依赖项的版本。
当Julia下载一个项目时,它会搜索父目录,直到它到达用户的主目录以查找包含该项目的工作区。 这允许工作区项目嵌套到工作区目录树中的任何深度。
此外,工作区可以是"嵌套的",这意味着定义工作区的项目也可以是另一个工作区的一部分。 此方案仍然使用与"根项目"(没有包含它的另一个工作区的项目)一起存储的单个清单文件。 文件结构的示例可能如下所示:
Project.toml # projects = ["MyPackage"]
Manifest.toml
MyPackage/
Project.toml # projects = ["test"]
test/
Project.toml
包和环境首选项
首选项是影响环境中包行为的元数据字典。 首选项系统支持在编译时读取首选项。 这意味着在下载代码之前,您需要确保Julia选择的预编译文件是根据当前环境的首选项构建的。 用于更改首选项的公共API包含在包中https://github.com/JuliaPackaging/Preferences.jl [首选项。jl]。 首选项作为TOML字典存储在文件中 (朱莉娅)LocalPreferences。汤姆尔 当前活动项目旁边。 导出时,首选项将传输到文件。 (朱莉娅)项目。汤姆尔. 这个想法是共享项目可以有共同的首选项,但用户可以在LocalPreferences中使用自己的设置复盖它们。toml文件,顾名思义,应该添加到文件中。吉蒂尼诺尔。
编译期间访问的首选项会自动标记为编译时首选项。 对它们的任何更改都会强制Julia编译器重新编译所有缓存的预编译文件(.纪 及对应的文件 .所以, .dll 或 .迪利布)对于这个模块。 为此,在编译期间,序列化所有编译时首选项的散列,然后在搜索必要的文件时,检查是否符合当前环境。
可以在存储级别为首选项设置默认值;如果Foo包安装在全局环境中并具有指定的首选项,则只要在 LOAD_PATH. 与环境堆栈中较高的环境相关的首选项由下载路径中较低级别的条目复盖,直到当前活动项目。 这允许默认首选项存在于项目级别,并且在为活动项目继承时,它们可以组合甚至完全复盖。 有关如何允许或禁用组合首选项的详细信息,请参阅docstring函数。 偏好。set_preferences!().