2.3 项目的创建与引入

到目前为止,我们已经对 Julia 的项目环境有了一定的了解,并讨论了仓库目录、程序包存储目录和环境配置这几个重要的概念。

项目的环境配置一般由项目文件Project.toml和清单文件Manifest.toml体现。全局环境配置针对的是 REPL 环境中的代码和独立的 Julia 程序。该环境配置的文件通常会在~/.julia/environments目录的特性版本子目录(如v1.3)中。

我们已经学会了在全局环境中怎样安装和导入程序包。这对于编写和部署一些脚本程序来说已经足够了。不过,我们在正式开发 Julia 项目的时候往往还需要专属的环境配置文件。这样才能与全局环境区别开。这么做有 3 个好处:

  1. 一旦有了专属的环境配置文件,我们的项目就可以独立地管理依赖包了。
  2. 针对某个 Julia 项目的程序包管理操作不会影响到全局的环境配置。反之亦然。
  3. 拥有环境配置文件的 Julia 项目可以为项目的分发(以供他人使用)做好准备。

换句话说,我们的 Julia 项目可以因此成为独立的、可重用的以及对分发友好的项目。

2.3.1 项目的创建

创建一个 Julia 项目很容易,在 REPL 环境中就可以办到。我们先在命令行中通过输入julia命令进入到 REPL 环境。然后,我们在它的 shell 模式中进入某个专用的目录(比如~/Projects),就像这样:

  1. shell> cd ~/Projects/
  2. /Users/haolin/Projects
  3. julia>

这时,我们可以再确认一下当前的目录:

  1. julia> pwd()
  2. "/Users/haolin/Projects"
  3. julia>

这里的pwd是 Print Working Directory 的缩写。所以,pwd函数的含义就是打印当前的工作目录。这与在命令行中输入pwd命令的作用是类似的。只不过调用表达式pwd()的求值结果是一个字符串。

在确认了工作目录之后,我们就可以切换到 REPL 环境的 pkg 模式,然后输入generate命令,并后跟一个空格和项目的名称Programs(你也可以用别的名字):

  1. (v1.3) pkg> generate Programs
  2. Generating project Programs:
  3. Programs/Project.toml
  4. Programs/src/Programs.jl
  5. (v1.3) pkg>

注意,我在generate命令后面追加的参数是我们要创建的 Julia 项目的名称。随后,这个命令创建了一个名为Programs的目录,并在该目录下生成了两个文件。一个是项目文件Project.toml,另一个是src目录(即源码目录)下的源码文件Programs.jl

我们先来看项目文件,它的内容如下:

  1. name = "Programs"
  2. uuid = "e525bb1a-bb1e-11e9-07f5-1125a61c95e2"
  3. authors = ["robert.hao <hypermind@outlook.com>"]
  4. version = "0.1.0"

这里有 4 个条目,分别代表项目的名称、UUID、作者信息和初始版本号。其中的 UUID 是 Julia 的程序包管理器自动生成的。而项目作者信息是从当前操作系统中的 Git 配置信息复制过来的。

我们再来看源码文件Programs.jl的内容:

  1. module Programs
  2. greet() = print("Hello World!")
  3. end # module

其中只定义了一个名为Programs的模块。并且,该模块仅包含了一个可以向计算机的标准输出打印Hello World!的函数greet。这显然只是一个简单的程序模板。不过,它为我们后续的编码开了个头。

注意,这个源码文件是有重要意义的:

  1. 该文件可以被称为Programs项目的源码入口。或者说,它是这个项目的主源码文件。这是由于该文件的主文件名与项目的(主)名称是一致的。
  2. 该文件中定义的(最外层的)模块Programs将会是其所属项目的主模块(或者说默认模块)。这是由于该模块的名称与项目的(主)名称是一致的。

正因为有了这样的一个源码文件,使得Programs项目可以被 Julia 视为一个程序包。更明确地讲,如果存在一个名为XX.jl的 Julia 项目,只要该项目包含一个相对路径为src/X.jl的源码文件,并且在该文件中定义的最外层模块名为X,那么它就是一个有效的程序包。

最后,一个可选的操作是,我们可以把这个项目的名称变更为Programs.jl。如此可以让它更具 Julia 项目的特色。由前述内容可知,这样做并不会妨碍此项目成为一个有效的程序包。注意,项目Programs.jl所代表的程序包的名称依然是Programs,同时它的主模块的名称也依然是Programs

2.3.2 程序包的引入

既然Programs.jl项目已经是一个有效的程序包了,那么我们就可以在代码中对它进行引入(更明确地说,是引入它的主模块Programs)。具体怎么做呢?

当我们试图在全局环境中导入该程序包的时候,Julia 会提示找不到这个程序包:

  1. julia> import Programs
  2. ERROR: ArgumentError: Package Programs not found in current path:
  3. - Run `import Pkg; Pkg.add("Programs")` to install the Programs package.
  4. Stacktrace:
  5. [1] require(::Module, ::Symbol) at ./loading.jl:887
  6. julia>

为了解决这个问题,我们可以先在 REPL 环境下进入到Programs.jl项目所在的目录,然后切换到 pkg 模式,并输入命令activate .。注意,这里的输入是activate加一个空格`,再加一个英文点号.`。示例如下:

  1. shell> cd ~/Projects/Programs.jl
  2. /Users/haolin/Projects/Programs.jl
  3. (v1.3) pkg> activate .
  4. (Programs) pkg>

我们可以看到,在使用activate命令之后,REPL 环境的提示符再次改变了,变成了当前程序包的名称Programs,也就是在当前目录下的Project.toml文件中记录的那个名称。命令activate .的作用正是把程序包管理器的操作目录切换到当前项目所在的目录,即:~/Projects/Programs.jl。还记得吗?它原先的(或者说默认的)操作目录是~/.julia/environments/v1.3,对应于 Julia 的v1.3版本的全局环境。顺便说一下,如果你想切换回全局环境,那么只需要再次输入命令activate(不加任何参数)就可以了。

在这之后,我们再在当前的 REPL 环境中导入Programs就不会有问题了:

  1. julia> import Programs
  2. [ Info: Precompiling Programs [e525bb1a-bb1e-11e9-07f5-1125a61c95e2]
  3. julia> Programs.greet()
  4. Hello World!

如果我们确实需要在全局环境中引入Programs,那么可以先把这个项目上传到一个代码托管仓库(比如 GitHub)中,然后再使用 Julia 的程序包管理器把它安装到本地的仓库目录。

比如,我们的这个Programs.jl项目已经在 GitHub 上了,它的 git 地址是git@github.com:hyper0x/Programs.jl.git。所以,我们现在就可以直接在 REPL 环境中进行如下操作:

  1. (Programs) pkg> activate
  2. (v1.3) pkg> add git@github.com:hyper0x/Programs.jl.git
  3. Updating registry at `~/.julia/registries/General`
  4. Updating git-repo `https://github.com/JuliaRegistries/General.git`
  5. Cloning git-repo `git@github.com:hyper0x/Programs.jl.git`
  6. Updating git-repo `git@github.com:hyper0x/Programs.jl.git`
  7. Resolving package versions...
  8. Updating `~/.julia/environments/v1.3/Project.toml`
  9. [d2b7efac] + Programs v0.1.0 #master (git@github.com:hyper0x/Programs.jl.git)
  10. Updating `~/.julia/environments/v1.3/Manifest.toml`
  11. [d2b7efac] + Programs v0.1.0 #master (git@github.com:hyper0x/Programs.jl.git)
  12. (v1.3) pkg>

一旦Programs程序包被记录在了全局环境的项目文件中,我们在该环境下引入它也就不会有问题了。