Understanding Golang Package Import

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Golang uses this syntax element to organize the source code, all syntax visibility is defined at the package level, compared to Java, Python and other languages, this is not an innovation, but compared with the C traditional include, it appears to be "advanced" a lot.

The definition and use of packages in Golang looks very simple:

Define packages with the Package keyword:

Package xxx

Using the Import keyword, import the standard library package or third-party dependency package that you want to use.

Import "A/B/C"
Import "FMT"

C.FUNC1 ()
Fmt. Println ("Hello, World")

Many Golang beginners see the above code, will take it for granted the "C", "FMT" after the import as the package name, and C. FUNC1 () and FMT. C and FMT in PRINTLN () are recognized as the same syntax element: the package name. But after deep Golang, many people will find that this is not actually the case. For example, when using the Go Client API provided by the live distributed messaging platform NSQ:

The paths we import are as follows:

Import "GITHUB.COM/BITLY/GO-NSQ"

However, when using the export functions it provides, it uses NSQ to prefix the package name:

Q, _: = nsq. Newconsumer ("Write_test", "ch", config)

One cannot help asking: what does the last element in the path after import represent? Is it a package name or is it just a path?  Let's take a look at the experiment together. Lab environment: DARWIN_AMD64, go 1.4.

The initial test environment catalog results are as follows:

Gopath =/users/tony/test/go/pkgtest/
pkgtest/
pkg/
src/
libproj1/
foo/
Foo1.go
app1/
Main.go

First, compile the use of the package source or. A

We know that a non-main package will generate a. A file (generated in the temp directory) after compiling, unless you are using go install to $goroot or $gopath, otherwise you won't see. A) for subsequent executable link use.

For example, the Go standard library package corresponding to the source code part path in: $GOROOT/SRC, and the standard library package compiled. A file path under $GOROOT/PKG/DARWIN_AMD64. A strange question rises up in my head, and at compile time, the compiler uses. A or source code?

Let's start with a user-defined package as an example of a small experiment.

$GOPATH/src/
libproj1/foo/
–foo1.go
App1
–main.go

Foo1.go
Package Foo

Import "FMT"

Func Foo1 () {
Fmt. Println ("Foo1")
}

Main.go
Package Main

Import (
"Libproj1/foo"
)

Func Main () {
Foo. Foo1 ()
}

Execute the Go install Libproj1/foo,go compiler to compile the Foo package and install FOO.A under $GOPATH/PKG/DARWIN_AMD64/LIBPROJ1.
Compile App1:go build App1, generate app1* executable in App1 directory, execute App1, we get an initial expected result:

$./app1
Foo1

Now we can not see whether to use the source of Foo or FOO.A, because their output is now consistent. Let's change the Foo1.go code:

Foo1.go
Package Foo

Import "FMT"

Func Foo1 () {
Fmt. Println ("foo1–modified")
}

To recompile the execution App1, we get the result as follows:

$./app1
Foo1–modified

The actual test results tell us:(1) when using a third-party package, when the source code and. A are installed, the compiler is linked to the source code.

Is it possible to link only. A, do not use the third-party package source code? We temporarily delete the libproj1 directory, but keep the libproj1/foo.a file that was previously install.

We try to compile App1 again and get the following error:

$go Build App1
Main.go:5:2:cannot Find Package "Libproj1/foo" in any of:
/users/tony/. Bin/go14/src/libproj1/foo (from $GOROOT)
/users/tony/test/go/pkgtest/src/libproj1/foo (from $GOPATH)

The compiler still went to find the source code, not. A, so we rely on third-party packages, we must get the third-party package source code, which is a feature of Golang package management.

In fact, through the compiler's detailed output we can also draw the above conclusions. We pass the-X-V option to the compiler when compiling APP1:

$go build-x-v app1
work=/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/t/go-build797811168
Libproj1/foo
Mkdir-p $WORK/libproj1/foo/_obj/
mkdir-p $WORK/libproj1/
cd/users/tony/test/go/pkgtest/src/libproj1/ Foo
/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6g-o $WORK/libproj1/foo.a-trimpath $WORK-P libproj1/foo-complete-d _/Users/tony/ Test/go/pkgtest/src/libproj1/foo-i $WORK-pack/foo1.go./foo2.go
App1
mkdir-p $WORK/app1/_obj/
Mkdir-p $ work/app1/_obj/exe/
Cd/users/tony/test/go/pkgtest/src/app1
/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6g-o $WORK/app1.a-trimpath $WORK-P app1-complete-d _/users/tony/test/go/pkgtest/src /app1-i $WORK-i/users/tony/test/go/pkgtest/pkg/darwin_amd64-pack./main.go
CD.
/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6l-o $WORK/app1/_obj/exe/a.out-l $WORK-L/users/tony/test/go/pkgtest/pkg/darwin_ Amd64-extld=clang $WORK/app1.a
mv $WORK/app1/_obj/exe/a.out App1

You can see that the compiler 6g first compiles the dependent package FOO.A under the temporary path and puts it under $work/libproj1. However, we did not explicitly see the App1 link under $work/libproj1 foo.a in the last 6L linker's execution statement. But in terms of the-l parameter of the 6L linker:-L$WORK-L/USERS/TONY/TEST/GO/PKGTEST/PKG/DARWIN_AMD64, we find that the $work directory is in front, we guess 6l first searched for $ Work under the LIBPROJ1/FOO.A.

In order to verify our inference, we followed the compiler output and executed the command manually once, but at the end of the execution of the 6l command, the-l $WORK was removed:

/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6l-o $WORK/app1/_obj/exe/a.out-l/users/tony/test/go/pkgtest/pkg/darwin_amd64- Extld=clang $WORK/app1.a

The result of this is:

$./app1
Foo1

The compiler links the foo.a under $gopath/pkg. (2) Here we understand the so-called use of third-party package source code, is actually linked to the latest source code compiled . A file in the temp directory.

is the package in the Go standard library the same way? For the standard library, such as FMT, compile, when the use of $GOROOT/SRC under the source code or $GOROOT/PKG has been compiled. A?

We might as well try it out, one of the simplest examples of Hello world:
Main.go
Import "FMT"

Func Main () {
Fmt. Println ("Hello, World")
}

Let's start by rename the $goroot/src/fmt directory to Fmtbak and see how the Go compiler reacts?
Go build-x-V/

$go Build-x-V/
work=/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/t/go-build957202426
Main.go:4:8:cannot Find Package "FMT" in any of:
/users/tony/. Bin/go14/src/fmt (from $GOROOT)
/users/tony/test/go/pkgtest/src/fmt (from $GOPATH)

The FMT package could not be found. Obviously the standard library at compile time also must be source code. However, unlike a custom package, even if you modify the source of the FMT package (without recompiling the Go installation package), the user source code is compiled, will not attempt to recompile the FMT package, is still only linked to the compiled fmt.a. This can be verified by the following GC output:

$go Build-x-V/
work=/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/t/go-build773440756
App1
Mkdir-p $WORK/app1/_obj/
Mkdir-p $WORK/app1/_obj/exe/
Cd/users/tony/test/go/pkgtest/src/app1
/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6g-o $WORK/app1.a-trimpath $WORK-P app1-complete-d _/users/tony/test/go/pkgtest/src /app1-i $WORK-pack./main.go
Cd.
/users/tony/. Bin/go14/pkg/tool/darwin_amd64/6l-o $WORK/app1/_obj/exe/a.out-l $WORK-extld=clang $WORK/app1.a
MV $WORK/app1/_obj/exe/a.out App1

As you can see, the compiler did not attempt to compile the FMT source code in the standard library.

Second, the directory name or package name?

From the first section of the experiment, we learned that the compiler in the compilation process depends on the package source code path, which for the subsequent experiments laid the foundation. Let's take a look at the last element in the go language after the import is the package name or path name?

The Experimental directory structure:
$GOPATH
src/
libproj2/
foo/
Foo1.go
app2/
Main.go

According to the Golang language habit, all the source files of a go package are placed in the same directory, and the directory name is the same as the package name, for example, the Libproj1/foo directory is foo,foo1.go, foo2.go ... The source files that make up the Foo package together. But the directory name and package name can also be different, let's try different.

We set up the Libproj2/foo directory, where the FOO1.GO code is as follows:

Foo1.go
Package Bar

Import "FMT"

Func Bar1 () {
Fmt. Println ("Bar1")
}

Note: Here the package is named Bar, which is completely different from the directory name foo.

The next question for APP2 is: How do I import a bar package?

Let's assume that the last element in the import path is the package name, not the path name.

App2/main.go

Package Main

Import (
"Libproj2/bar"
)

Func Main () {
Bar. BAR1 ()
}

Compile APP2:

$go Build-x-V app2
work=/var/folders/2h/xr2tmnxx6qxc4w4w13m01fsh0000gn/t/go-build736904327
Main.go:5:2:cannot Find Package "Libproj2/bar" in any of:
/users/tony/. Bin/go14/src/libproj2/bar (from $GOROOT)
/users/tony/test/go/pkgtest/src/libproj2/bar (from $GOPATH)

Compilation failed, the corresponding Libproj2/bar package could not be found under two paths.

Our hypothesis is wrong, we change it to a path:

App2/main.go

Package Main

Import (
"Libproj2/foo"
)

Func Main () {
Bar. BAR1 ()
}

Then compile the execution:

$go Build App2
$app 2
Bar1

This time the compilation passes smoothly, the execution result is also OK. So we get the conclusion:(3) The last element after import should be the path, which is the directory, not the package name .

The go compiler is looking for the bar package under these paths (Libproj2/foo). In this way, the Go language Convention is only a special case, that is, the directory name coincides with the package name. This means that the two Foo in the following example has a different meaning:

Import "Libproj1/foo"

Func Main () {
Foo. Foo ()
}

The foo in import is just a path to the filesystem. and below Foo. Foo () in Foo is the package name. And this package is found in the source code under the Libproj1/foo directory.

Then analogy to the standard library package FMT.

Import "FMT"
Fmt. PRINTLN ("xxx")

In the next two lines, although all are "FMT", but the same meaning, one is the path, for the standard library, is $goroot/src/fmt this path. The FMT in the second row is the package name. The GC will find the source file for the FMT package under the $GOROOT/SRC/FMT path.

Third, import m "Lib/math"

An example of Go language specification in the import package is as follows:

Import declaration Local name of Sin

Import "Lib/math" math. Sin
Import M "Lib/math" M.sin
Import. "Lib/math" Sin

We see the import M "Lib/math" M.sin line. We said Lib/math is a path, the import statement replaces Lib/math with M, and accesses the exported function sin in the math package through m in the code.

Is that m the package name or the path? Since I can access sin through m, that M must be the package name, right!. The import M "Lib/math" how to understand it?

Based on the conclusions in the one or two sections above, we try to understand that M:(4) m refers to the only package under the Lib/math path .

Can there be two packages in a directory? Let's try that.

We have added a go source file under Libproj1/foo, Bar1.go:

Package Bar

Import "FMT"

Func Bar1 () {
Fmt. Println ("Bar1")
}

Let's rebuild the package under this directory:

$go Build Libproj1/foo
Can ' t load package:package libproj1/foo:found packages Bar1.go (bar) and Foo1.go (foo) in/users/tony/test/go/pkgtest/sr C/libproj1/foo

We received an error message that the compiler found two packages under this path, which is not allowed.

Let's do another experiment to verify our interpretation of the meaning of M.

We establish APP3 directory, the source code of its main.go is as follows:

Main.go
Package Main

Import M "Libproj2/foo"

Func Main () {
M.BAR1 ()
}

Libproj2/foo the package under the path is named bar, according to our inference, m refers to the bar of this package, through m we can access bar's Bar1 export function.

Compile and execute the above main.go:

$go Build App3
$app 3
Bar1

The results of the implementation are in full accord with our inference.

Appendix: 6g, 6l document location:

6g– $GOROOT/src/cmd/gc/doc.go
6l– $GOROOT/src/cmd/ld/doc.go

Bigwhite. All rights reserved.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.