jFasaJr
jFasaJr

Reputation: 487

Locally importing package

I have a package I want to break out my code with called foo and it's in a subdirectory called utils. When I try to import it to my main.go it can't find it. Not sure what I'm doing wrong.

Error when running go build

Error: main.go:7:2: local import "./utils/csrf" in non-local package

So I have folder structured as:

github.com/project
  /utils
    foo.go
  main.go

The package is written as so:

package foo

import (
  "fmt"
)

func Bar() {
  fmt.Printf("function")
}

Go Mod:

module github.com/project

go 1.15

And I'm trying to import is as so in my main.go file.

import (
  "fmt"
  "github.com/project/utils/foo"
)

Upvotes: 0

Views: 1508

Answers (2)

Zombo
Zombo

Reputation: 1

First, make a folder utils somewhere. You don't need to do any github.com/project folder. Just simply make a utils folder, and put it somewhere on your hard drive. Then go into that folder, and do go mod init github.com/project/utils. Then make utils/foo.go:

package utils
import "fmt"

func Bar() {
   fmt.Println("function")
}

Then make a folder utils/utils. Then make a file utils/utils/main.go:

package main
import "github.com/project/utils"

func main() {
   utils.Bar()
}

Then do go build. Done.

Upvotes: 2

bcmills
bcmills

Reputation: 5197

The error message main.go:7:2: local import "./utils/csrf" in non-local package comes from here. Barring an unexpected bug, it would imply that your main.go does not look like:

import (
  "fmt"
  "github.com/project/utils/foo"
)

as you described, but, rather, something more like:

import (
  "fmt"
  "./utils/foo"
)

However, relative import paths cannot be used in import statements in module mode. (The actual error message you get in module mode is somewhat confusing due to a bug in the go command, for which I've filed https://golang.org/issue/47088.)

In module mode, the module path declared in the go.mod file — presumably module github.com/project for your example — is a prefix of the import path, and you are intended to use the complete path in import statements.

So the solution here is likely:

  1. cd to the project folder.
  2. Run go mod init github.com/project.
  3. Change the import statements to use the full path instead of the relative one throughout the project:
    $ sed -i 's,"\./utils,"github.com/project/utils,' $(find -name *.go)
    

That should change your main.go to actually read:

import (
  "fmt"
  "github.com/project/utils/foo"
)

But now there is one more step: Go supports only one package per directory, and the package name declared with the package directive in the .go source file is (perhaps confusingly!) not a suffix of the package import path — it is completely independent.

So in order to make that import statement work, you need an extra layer of directory structure:

  1. mkdir utils/foo
  2. mv utils/foo.go utils/foo/foo.go

Now you have a single module, github.com/project, containing two packages: github.com/project with source file ./main.go, and github.com/project/utils/foo with source file ./utils/foo/foo.go.

Upvotes: 1

Related Questions