Golang import local package and import related details

Time:2020-10-23

1 local package declaration

Package is the basic unit of Go program, so the beginning of each go program source code is a package declaration:


package pkgName

This is the package declaration, and pkgname tells the compiler which package the current file belongs to. A package can correspond to multiple *. Go source files. The only basis for marking them as belonging to the same package is the package declaration. That is to say, no matter how many source files, as long as their starting package packages are the same, they belong to the same package. After compilation, only one. A file will be generated and stored in the $gopath / PKG folder.

Example:

(1) In the $gopath / directory, we create folders and files with the following structure:

Write the following codes respectively:

hello.go


//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

hello2.go


//hello2.go
package hello

import (
  "fmt"
)

func SayWorld() {
  fmt.Println("SayWorld()-->World")
}

main.go


//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
  hello.SayWorld()
}

analysis:

according to hello.go/hello2 According to the package declaration in. Go, they belong to the same package – Hello. According to analysis, only one *. A file will be generated after compilation.

Execute command:


go install hello

The meaning of this command is: compile and install the Hello package. The installation here means to put the generated *. A file into the working directory $gopath / PKG

After operation:

From the results, we can see that,Sure enough, only one package was generated and named hello. A

Then we raise the second questionIs the generated *. A file name the package name +. A suffix we defined?

To verify this, we made some changes to the source code:
take hello.go/hello2 Change the package declaration in. Go to as follows:


package hello_a

Before compiling the installation package, clear the last generated package:


go clean -i hello

Compile and install the package again:


go install hello_a

According to “normal reasoning”, the above command is OK, because we have changed the package name to hello_ A yes, but the actual operation results are as follows:

oh~No!!
So, let’s try this command again:


go install hello

what the fuck!! It’s a success!! Right?

So let’s try to build an executable program to see if it works properly?


go build main

Wrong report again!!!

Look at the error prompt. It seems that it should be corrected main.go Source code, then change it to the following:


//main.go
package main

import (
  "hello_a"
)

func main() {
  hello_a.SayHello()
  hello_a.SayWorld()
}

Is it reasonable to change it to the above one? After all, we define the package name as hello_ A!
Then compile it again


go build main

Continue to report errors!

wait!! There are new findings. Comparing the error information reported in the last two times, it can be seen that hello can be found for the first time_ A package, after changing the source code, you can’t find hello_ A yes??
OK, let’s change it back, but this time only the import statement of the package is changed to:


import (
  "hello"
)

Recompile:


go build main

what the fuck!! I didn’t report wrong!! Run the executable again:

Well, finally got the result you want!

So what does it mean here?

(1) A package can indeed consist of multiple source files, as long as the package at the beginning says the same
(2) A package generates a *. A file. The generated file name is not the package name +. A
(3) Go install ××× here is not the package name, but the pathname!!
(4) Import ××× here is not a package name, but also a pathname!
(5) The package name is used here!

Then the question comes again. How do we understand the path names in (3) and (4)?
I think it can be understood as follows:
The path name specified here represents the only package in this directory. The compiler connector will generate or use it by default, and we do not need to specify it manually!

Well, here comes the question,If there are multiple packages in one directory, is that ok? If so, how to compile and use it??

Let’s continue to change the source code:

First of all, keep hello2. Go unchanged and change it hello.go Is the following code:


//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

And change it main.go The source code is as follows


//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
  hello_a.SayWorld()
}

Clean up the last generated executable program and package again:


go clean -i hello
go clean -x main

You can try to execute the above command. If you can’t clear it, delete it manually!
Anyway, it is reduced to the following:

Then try to compile and install the package again, but notice that there are two packages in the Hello directory. No matter whether they are correct or not, let’s try it first:


go install hello

Oh ~ ~ sure enough, something went wrong!!

 
Did you see? It said it found two bags!!!

What does this mean??

In fact, this is more certain that our above conjecture is correct!

(3) Go install ××× here is not the package name, but the pathname!!

The path name specified here represents the only package in this directory. The compiler connector will generate or use it by default, and we do not need to specify it manually!

Well, it proves that this is exciting!! Let’s go on!!

If there are two or more packages in a directory, how to generate them??
With the attitude of trying, I tried many possibilities, but none of them was correct. The result of the last command made me collapse


go help install

okay! yes! Install the packages named by the import paths
What the fuck!!

Well, to sum up, there can only be one package in a directory, because they are all specified paths, and there is no way to specify a specific package under the path. In fact, this practice is also very good, making the source code structure clearer!

2 package import

Import package:

  • The standard package uses a given short path, such as “FMT”, “net / HTTP”
  • For your own package, you need to specify a directory under the working directory (gopath), and improve to import the package is actually a folder directory based on the working directory

There are several ways to import packages:

  • Import “test / lib” directly according to the $gopath / SRC directory (the path is actually $gopath / SRC / test / LIB)
  • Import alias_ Name “test / lib”. In this way, you can use the alias directly
  • Import with period: import. “Test / lib”, which directly omits the package name
  • Import with underline: improve_ “Test / lib”, this operation only introduces the package. When importing a package, all its init() functions will be executed, but sometimes it is not really necessary to use these packages, just want its init() function to be executed. It can be used at this time_ The operation refers to the package. I.e. use_ The operation reference package cannot call the exported function in the package through the package name, but simply to call its init function(). Often, these init functions register the engine in their own package, so that external users can use them conveniently. For example, the packages that implement database / SQL are all called in the init function sql.Register (name string, driver driver.Driver )Register yourself and use it externally.
  • Import the model directory of the same directory as the current file with the relative path. However, it is not recommended to import in this way

First of all, we have to make a change to the above example program. This time, we will make it simpler, because the next discussion may be slightly different

First, delete hello2.go and clean up the compiled files. The other files are as follows:

hello.go


//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello")
}

main.go


//main.go
package main

import (
  "hello"
)

func main() {
  hello.SayHello()
}

Finally, keep the whole as follows:

Let’s compile once to make the program run


go install hello
go build main
./main

Well, if you can see the output, that’s fine!
Now, let’s look at the overall structure:

According to the way of C / C + +, the link library hello. A is generated at this time, so the source files should not be necessary, so…. Let’s do this. Let’s change it hello.go Source code, but do not compile it!
hello.go


//hello.go
package hello

import (
  "fmt"
)

func SayHello() {
  fmt.Println("SayHello()-->Hello_modifi...")
}

Then, we delete the previous executable file main and rebuild it


rm main
go build main

Well, I’ll take a look at the running results

What the fuck!!! Why is this product coming out???

Well, in order to find out, we delete the main file again and recompile it again. However, we have to do something about the command. We need to see what the compiler connector two little bitches have done. Why is Lao Wang’s son coming out next door??!!


rm main
go build -x -v main

result:

Let’s analyze this result step by step

#First, it seems to specify a temporary working directory
WORK=/tmp/go-build658882358 

#It looks as if it is preparing to compile packages in the Hello directory
hello
#Then a series of temporary folders are created
mkdir -p $WORK/hello/_obj/  
mkdir -p $WORK/

#Enter the source file directory of the package
cd /home/yuxuan/GoProjects/import/src/hello 

#Call 6G to compile and generate hello. A, which is stored in the $work / temporary directory
/opt/go/pkg/tool/linux_amd64/6g -o $WORK/hello.a -trimpath $WORK -p hello -complete -D _/home/yuxuan/GoProjects/import/src/hello -I $WORK -pack ./hello.go

#To compile the package under the main directory
main
#Or create a series of temporary folders
mkdir -p $WORK/main/_obj/  
mkdir -p $WORK/main/_obj/exe/

#Enter the main folder
cd /home/yuxuan/GoProjects/import/src/main

#Call the 6G compiler, compile and generate main. A, which is stored in the $work / temporary directory
/opt/go/pkg/tool/linux_amd64/6g -o $WORK/main.a -trimpath $WORK -p main -complete -D _/home/yuxuan/GoProjects/import/src/main -I $WORK -I /home/yuxuan/GoProjects/import/pkg/linux_amd64 -pack ./main.go

#Finally, it enters a "current directory", which should be the directory where we execute the go build command
cd .

#Call connector 6L, and then it links to generate a.out and store it with $work / main in the temporary directory/_ Obj / exe / folder, but hello. A is not found directly in the link options
#From link options: - L $work - L / home / yuan / goprojects / import / PKG / Linux_ As can be seen from AMD64, the connector first searches all *. A files in the temporary directory of $work, and then searches / home / yuan / goprojects / import / PKG / Linux_ The *. A file in the AMD64 directory. The reason is visible
/opt/go/pkg/tool/linux_amd64/6l -o $WORK/main/_obj/exe/a.out -L $WORK -L /home/yuxuan/GoProjects/import/pkg/linux_amd64 -extld=gcc $WORK/main.a

#Finally, move the executable and rename it
mv $WORK/main/_obj/exe/a.out main

At this point, it is almost concluded that the connector does not use the hello. A file in our working directory when connecting, but the hello. A file in the temporary folder compiled with the latest source code.

Of course, if you have doubts about this conclusion, you can try to execute the above command manually. In the final link, remove the – L $work option and see the running results!

So, this is a third-party library for source code. What if there is no source code?

In fact, the result is obvious. Without source code, the above temporary compilation cannot be successful, so there is no possibility under the temporary directory. a file, so the last link can only be linked to the working directory. a file!

But what about the go standard library?

In fact, you can also use the above method to verify the verification process?
The final result is: for the standard library, even if the source code is modified, as long as the go source code is not recompiled, then the compiled *. A file will be used when linking!

Three modes of importing package

There are three modes of package import: normal mode, alias mode and simple mode

An example of import package in go language specification 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 line “import m” lib / math “m.sin. In the above conclusion, it is said that lib / math is the path, the import statement replaces lib / math with m, and accesses the function sin exported in math package through M in the code.
Is m a package name or a path?
The answer is obvious. If you can access sin through M, then M must be the package name!
Then the question comes again. How to understand import m “lib / math”?

Based on the above conclusion, we try to understand that M: m refers to the only package in the Lib / math path!

4 Summary

After the long discussion above, it is time to summarize the achievements:

Multiple source files can belong to the same package, as long as the package name specified in package is the same when declaring. A package generates a *. A file, and the generated file name is not composed of package name +. A, but directory name +. A. go install ×× where the corresponding is not the package name, but the path name!! Import ××× is not a package name, but also a path name. Sayhello() is a package name! Specifying the path name of ××× represents the only package in this directory. The compiler connector will generate or use it by default, and we do not need to specify it manually! There can only be one package in a directory. For calling a third-party package with source code, the connector does not use it in our working directory when connecting. a file, but in the temporary folder compiled with the latest source codeIf the. A file is used to call a third-party package without source code, the above temporary compilation cannot succeed, so it is impossible to have it in the temporary directory. a file, so the last link can only be linked to the working directoryFor the standard library, even if the source code is modified, as long as the go source code is not recompiled, the compiled *. A file package is imported in three modes: normal mode, alias mode and simple mode

This article on the golang import local package and import issues related to the article introduced here, more related to the content of the golang import package, please search the previous articles of developeppaer or continue to browse the related articles below, I hope you can support developeppaer more in the future!

Recommended Today

The function of jump to definition, automatic completion and hover prompt of vscode plug-in development strategy

Jump to definition Jump to the definition is actually very simple, through thevscode.languages.registerDefinitionProviderSign up for oneproviderThis oneproviderIf you returnnew vscode.Location()It means that the current cursor word supports jump, and jump to the corresponding location. To make the example more meaningful, I write a support herepackage.jsonindependencies、devDependenciesExample of jumping to the corresponding dependent packagejump-to-definition.js(of course, we just […]