Avatar ·

Ошибка "package XXX is not in GOROOT" при сборке Go-проекта

Всем привет! Я только начал изучать Go и столкнулся с непонятной ошибкой. Создал простой проект, структура такая: ``` myapp/ ├── main.go └── utils/ └── helper.go ``` В `main.go` я импортирую свой пакет: ```go package main import "myapp/utils" func main() { utils.SayHello() } ``` А в `utils/helper.go`: ```go package utils import "fmt" func SayHello() { fmt.Println("Hello from utils!") } ``` Пытаюсь собрать: `go build main.go` — и получаю: ``` main.go:3:8: package myapp/utils is not in GOROOT (/usr/local/go/src/myapp/utils) ``` Go версии 1.21, установил через официальный инсталлятор. Проект лежит в `~/projects/myapp`. Переменную `GOPATH` не настраивал. Пробовал запускать `go env -w GO111MODULE=off`, но тогда появляется другая ошибка про отсутствие пакета в GOPATH. Что я делаю не так? Нужно ли создавать go.mod файл? Или я неправильно импортирую внутренние пакеты? Буду благодарен за подробное объяснение, как правильно организовать проект с несколькими файлами/пакетами в современном Go. <<>>

Проблема: вы используете устаревший подход без модулей

Ошибка возникает, потому что Go не знает, где искать ваш пакет myapp/utils. В современных версиях Go (1.11+) стандартный способ работы — через Go modules, которые заменяют старую систему с GOPATH. Без модуля Go ищет пакеты только в GOROOT (стандартная библиотека) и GOPATH (ваши проекты, но с определённой структурой).

Решение: инициализируйте модуль

Сделайте корневую папку вашего проекта модулем:

cd ~/projects/myapp
go mod init myapp

Эта команда создаст файл go.mod с содержимым:

module myapp

go 1.21

Теперь Go понимает, что myapp — это имя вашего модуля, и все импорты вида import "myapp/utils" будут искаться внутри этого модуля.

Как теперь собирать проект

Есть два правильных способа:

  1. go build . — собирает текущий пакет (все .go файлы в папке, включая main.go).
  2. go build ./... — собирает все пакеты проекта рекурсивно.
  3. go run . — запускает без явной сборки.

Почему не работает go build main.go

Когда вы указываете конкретный файл, Go пытается собрать один файл изолированно, игнорируя модуль. Для проектов с несколькими файлами/пакетами всегда используйте сборку пакета (через точку . или путь).

Дополнительные советы для новичков

  • Не трогайте GOPATH и GO111MODULE — современный Go сам всё настраивает.
  • Файл go.mod должен быть в корне проекта, а не в подпапках.
  • Имена пакетов внутри модуля должны совпадать с именами папок (но это не строгое правило, просто конвенция).
  • Внешние зависимости (например, сторонние библиотеки) автоматически подтянутся в go.sum при первом go build или go mod tidy.

Пример правильной структуры после исправления

myapp/
├── go.mod          (содержит "module myapp")
├── main.go         (import "myapp/utils")
└── utils/
    └── helper.go   (package utils)

Теперь команды go build . и go run . будут работать без ошибок.

<<>>

Альтернативный подход: используйте относительные пути в импортах (не рекомендуется)

Если по каким-то причинам вы не хотите использовать модули (например, для очень простых скриптов), можно заменить импорт на относительный путь. Однако это плохая практика и работает только внутри одного проекта:

// main.go
package main

import "./utils"

func main() {
    utils.SayHello()
}

Но такой подход сломается, если вы переместите папку проекта или попытаетесь использовать внешние зависимости. В современном Go (1.16+) относительные импорты даже запрещены по умолчанию, и их нужно явно включать через флаг -mod=mod.

Лучшее решение: всегда используйте Go modules

Даже для самых маленьких проектов делайте go mod init. Это занимает 2 секунды и избавляет от кучи проблем. Модули — стандарт де-факто с 2019 года, все инструменты (IDE, линтеры, CI/CD) ожидают именно такую структуру.