What causes 'go build' to fail with 'unexpected NUL in input'? - go

I have a Linux VM where I am trying to compile a simple Go package. The package was retrieved into my user directory with git:
$ git clone [...]/test.go
Cloning into 'test.go'...
done.
$ cd test.go/
$ ls
main.go
I set up the GOPATH and build:
$ export GOPATH=$PWD; echo $GOPATH
/home/vagrant/test.go
$ go build
$ ls
main.go test.go*
So far so good. But now when I try to build again, it fails:
$ go build
can't load package: package .: read /home/vagrant/test.go/test.go: unexpected NUL in input
Deleting the test.go file before building will allow it to build. But this is inconvenient because tools like github.com/codegangsta/gin which try to rebuild the package will fail.

The repository was named [...]/test.go, and the default container directory for git clone is the repo name, so the containing directory is named test.go\.
From go help build:
If the package is main and file names are provided, the file name
derives from the first file name mentioned, such as f1 for 'go build
f1.go f2.go'; with no files provided ('go build'), the output file
name is the base name of the containing directory.
In this case the output is a file called test.go. The problem is:
In the directory containing the package, .go, .c, .h, and .s files are considered part of the package
During a go build if the output from a previous build, test.go, exists, it will be treated as a source file, triggering the 'unexpected NUL in input' message.
The problem can be resolved by renaming the directory to avoid the build output having a name that will be considered part of the package.

Related

install local package so it can find the location of the other files belonging to the project, without adding project directory to `$PATH`

I have a local Go project which requires another data file to live with it, as in
my_project/
go.mod
my_tool.go
data.txt
go.mod:
module my_project/my_tool
go 1.19
Until today, I had the path to my_project directory inserted in the $PATH environment variable so I could build the executable file with go build and run it from anywhere.
Then I wanted to try and run go install (with no arguments, as shown in this tutorial) from my_project directory. So I did and noticed that the command does two things:
go install builds the executable file just like go build does;
go install moves the executable file —the file itself, not its symlink— to the $GOPATH/bin directory.
But the go install command does not put any other project file to $GOPATH/pkg/mod — which is a no-go for my tool which requires its buddy data.txt file to be located in the same filepath.Dir(os.Executable()) directory as the executable file.
Neither does the go install my_project/my_tool command. Hence the question:
Is it possible to install a local Go package in the $GOPATH directory in such a way that it can find the location of the other files belonging to the project without me having to add the project directory to $PATH?

how to build go outside of source directory?

My go application directory structure is like this:
/app
go.mod
go.sum
main.go
When I build the app I usually cd into that directory and build.
cd app
go build
I wonder if I can build without cd in to app directory.
When I go go build /app, it prints go: go.mod file not found in current directory or any parent directory; see 'go help modules'.
See https://golang.org/ref/mod#commands-outside :
go build needs to be run from a module directory.
The simplest way is to cd into your module directory (cd /app) to run your go build command.
(there probably is some way to create a phony local go.mod file, and reference your /app module from there, but I wasn't able to devise a hack to do this)
Go now can change directory before build with the help of flag -C:
go build -C app
"The go subcommands now accept -C to change directory to before performing the command"
Source: https://tip.golang.org/doc/go1.20
(You don't need to run cd .. after this command. Shell stays in the same directory)
I'm pretty sure to build you will need to be in the app directory.
As a workaround if you are just wanting to be on the command line in a different directory and want to run the build with one command you can just chain the cd and go build commands together like this:
cd app; go build ; cd ..
This is the same amount of typing but could be in your command history just a couple presses of the up arrow away.
Note this is for bash or similar UNIX style shell. If using Windows cmd then I think it would be something like this (Not tested as I don’t have readily available access to a Windows machine right now):
cd app & go build & cd ..

Building Golang project properly

I have a project structure that looks like so:
I was planning on just using a shell script (build.sh) to set GOPATH and build the project.
I am not sure how to build a Golang project properly, my short term goal is to just to build the packages in the src directory and put the binaries into the bin directory.
I am not sure what go build command can do that, I have tried a few things.
So first my question is - is this a reasonable project structure and second, how can I compile my src directory to bin?
What I have gives me the following error:
can't load package: package .: no buildable Go source files in /home/oleg/WebstormProjects/oresoftware/stack-server
So I believe I need to tell Go to look in the src directory, because Go is only looking for .go files in the project root, but I am not sure how to do that.
If it matters, the main.go file has a package name of "main".
GOPATH=$PROJECT_DIR && cd $PROJECT_DIR && go install main
Also move your main.go file into src/main/main.go.
This will produce a bin/main executable.
If you have multiple executables you wanna build, you have to put each main.go file into a separate folder/package. The name of the generated executable is taken from the directory name the file is inside. The package name of the main.go files must always be main if it should create a binary.
To compile multiple executables you have to use:
GOPATH=$PROJECT_DIR && cd $PROJECT_DIR && go install ...
The ... matches all folders/packages.

go ignoring vendor directory

Everything I read about the vendor directory gives me the understanding that if I have a directory:
$GOPATH/src/vendor
And put my dependencies in there (I am using godeps), when doing go run, go should check in that directory first.
If I run my code in a Docker image I have, this works fine. However now that I try to run the same code on my Windows machine, go simply ignores the vendor/ directory, and fails to find the dependencies.
What am I doing wrong?
main.go:7:2: cannot find package "gopkg.in/alecthomas/kingpin.v2" in any of:
C:\Go\src\gopkg.in\alecthomas\kingpin.v2 (from $GOROOT)
C:\Users\js\dev\my_project\rest\src\gopkg.in\alecthomas\kingpin.v2 (from $GOPATH)
C:\Users\js\dev\go\src\gopkg.in\alecthomas\kingpin.v2
Is the output when I try to do:
go run main.go
A directory vendor/ exists in this directory.
go version go1.7 windows/amd64
The exact commands I run (in windows cmd.exe)
> cd C:\Users\js\dev\my_project\rest\
> set GOPATH=C:\Users\js\dev\my_project\rest\;c:\Users\js\dev\go
> cd src
> dir
...
2016-09-01 23:20 2 923 main.go
...
2016-09-03 01:27 <DIR> vendor
> go run main.go
The reason this did not work is because you are not supposed to put any code directly into the $GOPATH/src/ directory.
The solution is to put your project into a sub-directory like so:
$GOPATH/src/app/*.go
Seems your GOPATH is incorrect?
The GOPATH should specify the location of your workspace i.e. directory containing src, pkg and bin directories at its root.
Try doing
set GOPATH=C:\Users\js\dev\my_project\rest\;c:\Users\js\dev\go
More details at: https://golang.org/doc/code.html
The first thing to understand is that godep save is simply copying dependencies from your $GOPATH to a vendor directory inside your project.
You will have to go get your dependencies first. After you have them in $GOPATH, you can do a godep save to copy the current version to your project, and be assured that even if the version in $GOPATH changes, you will have a fixed version in your project until you explicitly change it via godep.
So, if I have a $GOPATH of /home/me/go_workspace, and a project called $GOPATH/src/github.com/project_x with a dependency of github.com/you/xyz, then I would do go get github.com/you/xyz, and godep save from within my project directory. This would create a vendor folder with the dependency at its current commit inside.

Command line application install using GoLang

I'm not sure how this would work but I'm basically trying to write a command line app that I can run commands and subcommands from. I'm using this popular third party library for parsing command line parameters:
https://github.com/urfave/cli
My problem is I have a project folder where my .go files will live:
MyProject
so even if in the code in my main.go file, using their example, I have:
package main
import (
"fmt"
"os"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) error {
fmt.Println("Hello friend!")
return nil
}
app.Run(os.Args)
}
when I run go install,
in my $GOPATH/bin directory, I actually get MyProject built. And then when I run MyProject from the terminal, I get
USAGE:
myproject [global options] command [command options] [arguments...]
But in reality, I don't need the myproject command first. Is there a way this is normally done with command line apps or third party packages to create command line apps so that I can run greet from the command line instead of myproject as the first command?
Check the documentation for the go build command
go build [-o output] [-i] [build flags] [packages]
When compiling a single main package, build writes the resulting
executable to an output file named after the first source file ('go
build ed.go rx.go' writes 'ed' or 'ed.exe') or the source code
directory ('go build unix/sam' writes 'sam' or 'sam.exe'). The '.exe'
suffix is added when writing a Windows executable.
When compiling multiple packages or a single non-main package, build
compiles the packages but discards the resulting object, serving only
as a check that the packages can be built.
The -o flag, only allowed when compiling a single package, forces
build to write the resulting executable or object to the named output
file, instead of the default behavior described in the last two
paragraphs.
Try building it like this go build -o greet and do not forget to add the resulting executable to your $PATH if you want it to be accessible from everywhere.
Alternatively, you can just 1) create an alias; or 2) symlink to the actual executable:
alias greet='myproject'
ln -s $GOPATH/bin/myproject greet (the link will be created in the current dir)

Resources