# 9.8 自定义包的目录结构、go install 和 go test

为了示范，我们创建了一个名为 uc 的简单包，它含有一个 `UpperCase` 函数将字符串的所有字母转换为大写。当然这并不值得创建一个自己包，同样的功能已被包含在 `strings` 包里，但是同样的技术也可以应用在更复杂的包中。

## 9.8.1 自定义包的目录结构

下面的结构给了你一个好的示范(uc 代表通用包名, 名字为粗体的代表目录，斜体代表可执行文件):

	/home/user/goprograms
		ucmain.go	(uc包主程序)
		Makefile (ucmain的makefile)
		ucmain
		src/uc	 (包含uc包的go源码)
			uc.go
		 	uc_test.go
		 	Makefile (包的makefile)
		 	uc.a
		 	_obj
				uc.a
			_test
				uc.a
		bin		 (包含最终的执行文件)
			 	ucmain
		pkg/linux_amd64
				uc.a	(包的目标文件)

将你的项目放在 goprograms 目录下(你可以创建一个环境变量 GOPATH，详见第 2.2/3 章节：在 .profile 和 .bashrc 文件中添加 `export GOPATH=/home/user/goprograms`)，而你的项目将作为 src 的子目录。uc 包中的功能在 uc.go 中实现。

示例 9.6 [uc.go](examples/chapter_9/uc.go)：

```go
package uc
import "strings"

func UpperCase(str string) string {
	return strings.ToUpper(str)
}
```

包通常附带一个或多个测试文件，在这我们创建了一个 uc_test.go 文件，如第 9.8 节所述。

示例 9.7 [test.go](examples/chapter_9/test.go)

```go
package uc
import "testing"

type ucTest struct {
	in, out string
}

var ucTests = []ucTest {
	ucTest{"abc", "ABC"},
	ucTest{"cvo-az", "CVO-AZ"},
	ucTest{"Antwerp", "ANTWERP"},
}

func TestUC(t *testing.T) {
	for _, ut := range ucTests {
		uc := UpperCase(ut.in)
		if uc != ut.out {
			t.Errorf("UpperCase(%s) = %s, must be %s", ut.in, uc,
			ut.out)
		}
	}
}
```

通过指令编译并安装包到本地：`go install uc`, 这会将 uc.a 复制到 pkg/linux_amd64 下面。

另外，使用 make ，通过以下内容创建一个包的 Makefile 在 src/uc 目录下:

```
include $(GOROOT)/src/Make.inc

TARG=uc
GOFILES=\
		uc.go\

include $(GOROOT)/src/Make.pkg
```

在该目录下的命令行调用: gomake

这将创建一个 _obj 目录并将包编译生成的存档 uc.a 放在该目录下。

这个包可以通过 go test 测试。

创建一个 uc.a 的测试文件在目录下，输出为 PASS 时测试通过。

在第 13.8 节我们将给出另外一个测试例子并进行深入研究。

备注：有可能你当前的用户不具有足够的资格使用 go　install(没有权限)。这种情况下，选择 root 用户 su。确保 Go 环境变量和 Go 源码路径也设置给 su，同样也适用你的普通用户(详见第 2.3 节)。

接下来我们创建主程序 ucmain.go:

示例 9.8 [ucmain.go](/examples/chapter_9/ucmain.go)：

```go
package main
import (
	"./uc/uc"
	"fmt"
)

func main() {
	str1 := "USING package uc!"
	fmt.Println(uc.UpperCase(str1))
}
```

然后在这个目录下输入 `go install`。

另外复制 uc.a 到 /home/user/goprograms 目录并创建一个 Makefile 并写入文本：

```
include $(GOROOT)/src/Make.inc
TARG=ucmain
GOFILES=\
	ucmain.go\

include $(GOROOT)/src/Make.cmd
```

执行 gomake 编译 `ucmain.go` 生成可执行文件ucmain

运行 `./ucmain` 显示: `USING PACKAGE UC!`。

## 9.8.2 本地安装包

本地包在用户目录下，使用给出的目录结构，以下命令用来从源码安装本地包：

	go install /home/user/goprograms/src/uc # 编译安装uc
	cd /home/user/goprograms/uc
	go install ./uc 	# 编译安装uc（和之前的指令一样）
	cd ..
	go install .	# 编译安装ucmain

安装到 `$GOPATH` 下：

如果我们想安装的包在系统上的其他 Go 程序中被使用，它一定要安装到 `$GOPATH` 下。
这样做，在 .profile 和 .bashrc 中设置 `export GOPATH=/home/user/goprograms`。

然后执行 go install uc 将会复制包存档到 `$GOPATH/pkg/LINUX_AMD64/uc`。

现在，uc 包可以通过 `import "uc"` 在任何 Go 程序中被引用。

## 9.8.3 依赖系统的代码

在不同的操作系统上运行的程序以不同的代码实现是非常少见的：绝大多数情况下语言和标准库解决了大部分的可移植性问题。

你有一个很好的理由去写平台特定的代码，例如汇编语言。这种情况下，按照下面的约定是合理的：

	prog1.go
	prog1_linux.go
	prog1_darwin.go
	prog1_windows.go

prog1.go 定义了不同操作系统通用的接口，并将系统特定的代码写到 prog1_os.go 中。
对于 Go 工具你可以指定 `prog1_$GOOS.go` 或 `prog1_$GOARCH.go`
或在平台 Makefile 中：`prog1_$(GOOS).go\` 或 `prog1_$(GOARCH).go\`。

## 链接

- [目录](directory.md)
- 上一节：[使用 go install 安装自定义包](09.7.md)
- 下一节：[通过 Git 打包和安装](09.9.md)
