I have a package which is forked from a repository myproject. Inside the project, I want to use some functions from sha3 package, however, I need to first add a go file to sha3 package which contains some extra functionalities. I want to include this custom sha3 package inside my project. I copied and pasted the sha3 directory into myproject directory, and inside my go codes, I imported sha3 package as:
import . "github.com/myproject/sha3". Now, when I try to build myproject package, I am getting:
code in directory /src/github.com/myproject/sha3 expects import "golang.org/x/crypto/sha3". I cannot understand what the problem is. I checked all the go files inside sha3 directory and none of them requires any import!
line number 66 sha3/docs.go has the import comment.
import "golang.org/x/crypto/sha3"
You can get rid of the build error by removing that.
Related
Not so familiar with Golang, it's probably a stupid mistake I made... But still, I can't for the life of me figure it out.
So, I got a proto3 file (let's call it file.proto), whose header is as follows:
syntax = "proto3";
package [package_name];
option go_package = "github.com/[user]/[repository]";
And I use protoc:
protoc --go_out=$GOPATH/src --go-grpc_out=$GOPATH/src file.proto
So far so good, I end up with two generated files (file.pb.go and file_grpc.pb.go) inside /go/src/github.com/[user]/[repository]/, and they are defined inside the package [package_name].
Then, the code I'm trying to build has the following import:
import (
"github.com/[user]/[repository]/[package_name]"
)
And I naively thought it would work. However, it produces the following error when running go mod tidy:
go: downloading github.com/[user]/[repository] v0.0.0-20211105185458-d7aab96b7629
go: finding module for package github.com/[user]/[repository]/[package_name]
example/xxx imports
github.com/[user]/[repository]/[package_name]: module github.com/[user]/[repository]#latest found (v0.0.0-20211105185458-d7aab96b7629), but does not contain package github.com/[user]/[repository]/[package_name]
Any idea what I'm doing wrong here? Go version is go1.19 linux/amd64 within Docker (golang:1.19-alpine).
Note: I also tried to only import github.com/[user]/[repository], same issue obviously.
UPDATE:
OK so what I do is that I get the proto file from the git repository that only contains the proto file:
wget https://raw.githubusercontent.com/[user]/[repository]/file.proto
Then I generate go files from that file with protoc:
protoc --go_out=. --go-grpc_out=. file.proto
Right now, in current directory, it looks like:
- directory
| - process.go
| - file.proto
| - github.com
| - [user]
| - [repository]
| - file.pb.go
| - file_grpc.pb.go
In that same directory, I run:
go mod init xxx
go mod tidy
CGO_ENABLED=0 go build process.go
The import directive in process.go is as follows:
import (
"xxx/github.com/[user]/[repository]"
)
Now it looks like it finds it, but still getting a gRPC error, which is weird because nothing changed. I still have to figure out if it comes from the issue above or not. Thanks!
Your question is really a number of questions in one; I'll try to provide some info that will help. The initial issue you had was because
At least one file with the .go extension must be present in a directory for it to be considered a package.
This makes sense because importing github.com/[user]/[repository] would be fairly pointless if that repository does not contain any .go files (i.e. the go compiler could not really do anything with the files).
Your options are:
Copy the output from protoc directly into your project folder and change the package declarations to match your package. If you do this there is no need for any imports.
Copy (or set go_out argument to protoc) the output from protoc into a subfolder of your project. The import path will then be the value of the module declaration in your go.mod plus the path from the folder that the go.mod is in (this is what you have done).
Store the files in a repo (on github or somewhere else). This does not need to be the same repo as your .proto files if you "want it to be agnostic" (note that 2 & 3 can be combined if the generated files will only be used within one code base or the repo is accessible to all users).
Option 1 is simple but its often beneficial to keep the generated code separate (makes it clear what you should not edit and improves editor autocomplete etc).
Option 2 is OK (especially if protoc writes the files directly and you set go_package appropriately). However issues may arise when the generated files will be used in multiple modules (e.g. as part of your customers code) and your repo is private. They will need to change go_package before running protoc (or search/replace the package declarations) and importing other .proto files may not work well.
Option 3 is probably the best approach in most situations because this works with the go tooling. You can create github.com/[user]/goproto (or similar) and put all of your generated code in there. To use this your customers just need to import github.com/[user]/goproto (no need to run protoc etc).
Go Modules/package intro
The go spec does not detail the format of import paths, leaving it up to the implementation:
The interpretation of the ImportPath is implementation-dependent but it is typically a substring of the full file name of the compiled package and may be relative to a repository of installed packages.
As you are using go modules (pretty much the default now) the implementations rules for resolving package paths (synonym of import path) can be summarised as:
Each package within a module is a collection of source files in the same directory that are compiled together. A package path is the module path joined with the subdirectory containing the package (relative to the module root). For example, the module "golang.org/x/net" contains a package in the directory "html". That package’s path is "golang.org/x/net/html".
So if your "module path" (generally the top line in a go.mod) is set to xxx (go mod init xxx) then you would import the package in subfolder github.com/[user]/[repository] with import xxx/github.com/[user]/[repository] (as you have found). If you got rid of the intervening folders and put the files into the [repository] subfolder (directly off your main folder) then it would be import xxx/[repository]
You will note in the examples above that the module names I used are paths to repo (as opposed to the xxx you used in go mod init xxx). This is intentional because it allows the go tooling to find the package when you import it from a different module. For example if you had used go mod init github.com/[user]/[repository] and option go_package = "github.com/[user]/[repository]/myproto";" then the generated files should go into the myproto folder in your project and you import them with import github.com/[user]/[repository]/myproto.
While you do not have to follow this approach I'd highly recommend it (it will save you from a lot of pain!). It can take a while to understand the go way of doing this, but once you do, it works well and makes it very clear where a package is hosted.
I created the github.com project qjson/qjson-go that contains the package name qjson that you can see here. I named the github project this way because github.com/qjson/ contains other projects for different languages (e.g. qjson-c).
Unfortunately, I get the following error when I try to import the project as github.com/qjson/qjson-go:
$ go mod tidy
go: finding module for package github.com/qjson/qjson-go
go: downloading github.com/qjson/qjson-go v0.0.0-20210128102242-170c47e2db46
github.com/xxx/xxx imports
github.com/qjson/qjson-go: module github.com/qjson/qjson-go#latest found (v0.0.0-20210128102242-170c47e2db46), but does not contain package github.com/qjson/qjson-go
I’m apparently doing it wrong. I understand that due to the import statement we are then expected to use gjson-go as package identifier.
What must I do so that the git project can be named qjson-go and the package qjson ?
I assume that one solution is to create a sub-directory named qjson inside qjson-go and move all package files in it. The user would then import "github.com/qson/qson-go/qjson". Is that correct ? Is there another solution avoiding the stutter ?
This program works as expected:
package main
import (
"fmt"
"github.com/qjson/qjson-go/qjson"
)
func main() {
fmt.Println(qjson.ErrDivisionByZero)
}
The issue is that you are using this file structure:
qjson/engine.go
qjson/errors.go
When you should just be putting them at the top level, like this:
engine.go
errors.go
So you can either fix the directory, and tag a new version, or just leave the
files as is, and change your imports to match what I have above.
I have an log package in my project src folder. But when I include the log package from an another package as following, the go seams find the log in the system folder instead of my package.
import ("log")
And seams I cannot using relative path to import log package, because go install give following error:
local import "./log" in non-local package
So how can I let the go using my log package?
You need to add your package inside $GOPATH
So if your package is in
$GOPATH/src/github.com/ZijingWu/awesomeapp/src/
your log package would be in
$GOPATH/src/github.com/ZijingWu/awesomeapp/src/log
then it would be possible to use
import("github.com/ZijingWu/awesomeapp/src/log")
The paths seams a bit strange tho, and maybe you should consider adding the log package as a completely separate repository on github, so it would look something like.
import("github.com/ZijingWu/log")
Just using github as an example here, could of course be placed wherever, also just guessing at your username there. Doesnt need to be in github either you can just place it localy on your computer in the $GOPATH, but then noone else would be able to build your package.
In the process of learning go I was playing around with making my own libraries. Here is what I did: in my $GOPATH/src I have two folders: mylibs and test. The test folder has a file called test.go which contains
package test
import "mylibs/hi/saysHi"
func main() {
saysHi.SayHi()
}
The mylibs folder contains another folder called hi, which has a file called saysHi.go containing:
package saysHi
import "fmt"
func SayHi() {
fmt.Printf("Hi\n")
}
So the directory structure looks like this:
GOPATH/src
test
test.go
mylibs
hi
saysHi.go
The problem is that when I try to compile test it complains saying
cannot find package "mylibs/hi/saysHi" in any of:
[...]
$GOPATH/src/mylibs/hi/saysHi (from $GOPATH)
I have deliberately made the directory structure deeper than necessary. If I make a simpler directory structure where I place saysHi.go in $GOPATH/saysHi/saysHi.go then it works.
But I don't see a reason for why this wouldn't work. Any ideas?
Generally speaking, your directory name should match the package name. So if you define
package saysHi
and want to import it with
import "mylibs/hi/saysHi"
you should place it in a structure like this:
mylibs
hi
saysHi
saysHi.go
The name of the .go file(s) inside the package makes no difference to the import path, so you could call the .go file anything you like.
To explain it a bit further, the import path you use should be the name of the directory containing the package. But, if you define a different package name inside that directory, you should use that name to access the package inside the code. This can be confusing, so it's best to avoid it until you understand where it's best used (hint: package versioning).
It gets confusing, so for example, if you had your package in the path
mylibs
hi
saysHi.go
And inside saysHi.go defined,
package saysHi
Then in test.go you will import it with
import "mylibs/hi"
And use it with
saysHi.SayHi()
Notice how you import it with the final directory being hi, but use it with the name saysHi.
Final note
Just in case you didn't know the following: your test file is called test.go, and that's fine, if it's just as an example, and not an actual test file for saysHi.go. But if it is/were a file containing tests for saysHi.go, then the accepted Go standard is to name the file saysHi_test.go and place it inside the same package alongside saysHi.go.
One more final note
I mentioned how you are allowed to choose a different package name from the directory name. But there is actually a way to write the code so that it's less confusing:
import (
saysHi "mylibs/hi"
)
Would import it from the mylibs/hi directory, and make a note of the fact that it should be used with saysHi, so readers of your code understand that without having to go look at the mylibs/hi code.
I'm trying to make a simple calculator in Go. I'm designing it in such a way that I can build a command-line interface first and easily swap in a GUI interface. The project location is $GOPATH/src/gocalc (all paths hereafter are relative to the project location). The command-line interface logic is stored in a file gocalc.go. The calculator logic is stored in files calcfns/calcfns.go and operations/operations.go. All files have package names identical to their filename (sans extension) except the main program, gocalc.go, which is in the package main
calcfns.go imports operations.go via import "gocalc/operations"; gocalc.go imports calcfns.go via import "gocalc/calcfns"
To summarize:
$GOPATH/src/gocalc/
gocalc.go
package main
import "gocalc/calcfns"
calcfns/
calcfns.go
package calcfns
import "gocalc/operations"
operations/
operations.go
package operations
When I try to go build operations (from the project dir), I get the response: can't load package: package operations: import "operations": cannot find package
When I try go build gocalc/operations, I get can't load package: package gocalc/operations: import "gocalc/operations": cannot find package
When I try go build operations/operations.go, it compiles fine
When I try to go build calcfns or go build gocalc/calcfns, I get can't load package... messages, similar to those in operations; however, when I try to build calcfns/calcfns.go it chokes on the import statement: import "gocalc/operations": cannot find package
Finally, when I try go build . from the project dir, it chokes similar to the previous paragraph: import "gocalc/calcfns": cannot find package
How should I structure my child packages and/or import statements in such a way that go build won't fail?
Stupidly, I forgot to export my GOPATH variable, so go env displayed "" for GOPATH. (thanks to jnml for suggesting to print go env; +1).
After doing this (and moving the main program to its own folder {project-dir}/gocalc/gocalc.go), I could build/install the program via go install gocalc/gocalc.
Moral of the story, make sure you type export GOPATH=... instead of just GOPATH=... when setting your $GOPATH environment variable
Please try to also add output of $ go env to provide more clues. Otherwise both the directories structure and (the shown) import statements looks OK.
However the sentence
When I try to go build operations (from the project dir), I get the response: can't load package: package operations: import "operations": cannot find package
sounds strange. It seems to suggest you have
package operations
import "operations"
in 'operations.go', which would be the culprit then...?
Very easy:
Lets say I have a project/app named: golang-playground
Put your root dir under GOPATH/src/, in my case GOPATH=~/go/src (run command go env to get your GOPATH). so complete path for my app is ~/go/src/golang-playground
Lets say you want to use function Index() inside of file: router.go from my main.go file (which of course is on root dir). so in main.go:
import (
...
"golang-playground/router"
)
func main() {
foo.Bar("/", router.Index) // Notice caps means its public outside of file
}