Golang Building Multi Platform Issue - go

Golang Building Multi Platform Issue
I'm building a go application that I want to build for both Linux and Windows. For the Windows piece, I would like it to have the ability to install as a Windows Service. So in my app, I've included the following packages:
golang.org/x/sys/windows/svc
golang.org/x/sys/windows/svc/debug
golang.org/x/sys/windows/svc/eventlog
golang.org/x/sys/windows/svc/mgr
It builds fine for Windows and the service installs with no issues. But when I try to build it for linux:
GOOS=linux GOARCH=amd64 go build -o app-amd64-linux
package github.com/user/app
imports golang.org/x/sys/windows/svc: build constraints exclude all Go files in
C:\Users\User\go\pkg\mod\golang.org\x\sys#v0.0.0-20220728004956-3c1f35247d10\windows\svc\package github.com/user/app
imports golang.org/x/sys/windows/svc/debug: build constraints exclude all Go files in
C:\Users\User\go\pkg\mod\golang.org\x\sys#v0.0.0-20220728004956-3c1f35247d10\windows\svc\debug\package github.com/user/app
imports golang.org/x/sys/windows/svc/eventlog: build constraints exclude all Go files in
C:\Users\User\go\pkg\mod\golang.org\x\sys#v0.0.0-20220728004956-3c1f35247d10\windows\svc\eventlog\package github.com/user/app
imports golang.org/x/sys/windows/svc/mgr: build constraints exclude all Go files in
C:\Users\User\go\pkg\mod\golang.org\x\sys#v0.0.0-20enter code here220728004956-3c1f35247d10\windows\svc\mgr
In the code, I'm checking and only using these packages if the app is running as a windows service. Is there a way ignore these errors? Or only import them when building for Windows? Or maybe something I can change in go.mod to only require those for windows?

As a workaround you might use Build Constrants:
https://pkg.go.dev/go/build#hdr-Build_Constraints
Tim Cooper made in this post an elaborate answer how to implement those:
main.go
package main
func main() {
println("main()")
conditionalFunction()
}
a.go
// +build COMPILE_OPTION
package main
func conditionalFunction() {
println("conditionalFunction")
}
b.go
// +build !COMPILE_OPTION
package main
func conditionalFunction() {
}
Output:
*% go build -o example ; ./example
main()
% go build -o example -tags COMPILE_OPTION ; ./example
main()
conditionalFunction*
I copied the answer one-to-one in order not to lose it. Somebody might correct me if this ain't wished.

Related

How to test library functions in Golang

I'm learning Go so I'm writing some basic utils and libraries for fun that I can reuse in other modules.
When importing them inside another module (using go get for example), I can use them just fine.
As I understand, Go will look for a package main and a main function to know the entrypoint when trying to run a go app/module.
The thing is that the libraries are not in "package main", not in main.go and have no main function, so how am I supposed to use the cli and use go run . to test the behavior of my function?
Do I absolutely need to create another module with a main.go file inside a package main?
Or do I need to create a test file and use go test ?
Thank you!
Non-main packages (i.e., library packages) are not runnable.
To run the code in them, you must either run a main package that imports and runs their code, or write test functions in _test.go files to run the code. Note that test files are not just for unit tests; you can write whatever you want in them, and they can often be easier than creating a new main package for testing.
Modern IDEs now will allow you to easily run individual tests in debugging mode, so you can step through your code and see if it's working how you expect. If you prefer print debugging and doing everything from the command-line, you can still run an individual test and see the print output like this:
// something_test.go
package mylibrary
func TestSomeFunction(t *testing.T) {
SomeFunction()
}
go test mylibrary -v -run TestSomeFunction
go test is the preferred way to test Go code.
If you do not want to use go test for some reason, then use build constraints and the go run command to execute a main program from the same directory as your package.
Here's an example program with a build constraint. Place the file in the same directory as the package source files. The comment //go:build ignore is a build constraint that excludes the file from the package sources.
//go:build ignore
package main
import (
"your/package/import/path" // <-- modify to your path
"fmt"
)
func main() {
// do something with your package here.
fmt.Println("example")
}
Assuming that the above file is named program.go, run the program from the package directory with the command:
go run program.go
The go run command is OK for running toy or test programs like this. Prefer the go build command for anything else.

golang build constraints exclude all Go files in

I build a simple "Hello, World" wasm app like:
GOARCH=wasm GOOS=js go build -o lib.wasm main.go
All is well. But then I want to test my code in my local (Linux) environment. So I change it to a pretty standard:
package main
import "fmt"
func main () {
fmt.Println("test")
}
And do a simple:
go run .
but now I get:
package xxx: build constraints exclude all Go files in xxx
I understand that if I specify a wasm build, I can't expect to run it locally. But I'm not trying to do a wasm build anymore. There are no build constraints in my .go source file, and my go.mod file just has the package and go version.
If I copy these file to a new directory and only do the go run . without the wasm build - all is good.
And if I do:
go build filename.go
it works properly.
It's like something "remembers" that this directory was supposed to be built with wasm - but I cant find what/where.
Is there a cache or something elsewhere that's remembering some build settings that I need to clear? I've tried go clean and go clean -cache - no luck!
The answer seems to be that if a filename ends in wasm.go - go will assume this is indeed a wasm file.
This means that a normal build or run will fail (if you don't specify proper OS and arch) - though a run with an explicit filename (even if it ends in wasm.go will work correctly.
???

go test fails with "can't load package build constraints exclude all Go files"

When I run this command
go test -tags integration $(go list ./... | grep -v /vendor/)
go fails with this for some packages that has all tests marked with // +build !integration
can't load package: build constraints exclude all Go files
Is there a way I can make go test ignore those packages in this case, instead of failing? Thanks
You will only get that error if all the files in the package are excluded by your build constraints, not just the test files. If that's what you want, just add a single package file with no code and the package will still be able to be loaded. For example, many packages put their package level docs in a separate file, which you could use to always have a valid package:
// Package foo does foo
package foo
For whatever it's worth : I was seeing similar errors while building my code. In my case, my main file had // +build go1.13 at the top of it and I was trying to get the file built using go1.12.x. Removing +build go1.13 fixed the issue.
The package you are importing might contain some source files with a conditional complication flag, which is a directive you may find at the top of the files like:
//+build linux darwin windows
package main
import "fmt"
func main() {
fmt.Println("hello")
}
The +build directive followed by one or multiple platforms indicates where this source code is supposed to be compiled on.
Therefore, you can simply try removing this directive to resolve the failure.
It worked for me.
Following on from snowfox's answer, if you can't remove the directive (becuase it was likely put there for a reason), you can still run the test by using the tag that was applied to that file (more info here).
If your file start looks like this:
//go:build bar
package foo
Then you can run the test by running go test ./foo_test.go --tags=bar

Struct from the same parent folder as main is not visible

I have a small go demo project in Gogland with the structure:
awsomeProject
->src
->awsomeProject
->configuration.go
->main.go
Configuration file has a simple structure just for demo:
configuration.go:
package main
type Config struct {
Data int
}
Main file just uses the Config struct:
main.go
package main
import "fmt"
func main(){
var cfg Config
cfg.Data = 1
fmt.Println("lalala")
}
The error that I have is:
/usr/local/go/bin/go run /Users/lapetre/Work/awsomeProject/src/awsomeProject/main.go
command-line-arguments
src/awsomeProject/main.go:6: undefined: Config
Process finished with exit code 2
Any idea why the Config is not seen in main?
Thanks
When you build reusable pieces of code, you will develop a package as a shared library. But when you develop executable programs, you will use the package “main” for making the package as an executable program. The package “main” tells the Go compiler that the package should compile as an executable program instead of a shared library. The main function in the package “main” will be the entry point of our executable program.
That's why you should use the following structure:
awsomeProject
->src
->awsomeProject
->configuration.go
->main.go
with main.go
package main
import "fmt"
func main(){
var cfg awsomeProject.Config
cfg.Data = 1
fmt.Println("lalala")
}
and configuration.go
package awsomeProject
type Config struct {
Data int
}
For more details:
https://golang.org/doc/code.html
https://thenewstack.io/understanding-golang-packages
How are you calling go run? If you're calling it like
go run main.go
then that's the problem.
Go run only runs the file(s) you tell it to. So you need to tell it to also run configuration.go, or if you have several go files to run you can use
go run *.go
as eXMoor suggested.
There are some limits/drawbacks to "go run *.go" however, so the better alternative is to use go build instead of go run.
go build
Will compile everything. Then, to run the executable:
./awesomeProject
To combine all of this into one command that will compile and run whatever app you're working on, you can use:
go build && ./${PWD##*/}
I have it aliased to
gorunapp
just to make it easier.
This may not actually be the answer to the problem you're having, but hopefully you'll find it useful information regardless.
Try to run your application with command:
go run *.go

Build and reference my own local package in Go

I'm playing with Google Go and I'm having fun (!), but I'm having some problems with package subsystem.
I'm running Go 1.0.1 on Mac OS X Lion. I've build also various single file programs without problems (I've also build a small webapp using html/templates without problems and it compiles and runs without any error).
I've defined a "reusable" package (even.go):
package even
func Even(i int) bool {
return i % 2 == 0
}
func Odd(i int) bool {
return i % 2 == 1
}
and a consumer program (useeven.go):
package main
import (
"./even"
"fmt"
)
func main() {
a := 5
b := 6
fmt.Printf("%d is even %v?\n", a, even.Even(a))
fmt.Printf("%d is odd %v?\n", b, even.Odd(b))
}
But when I compile the "library" using
go build even.go
I got nothing... No errors, no message... What happens?
How should I do this?
The answer to your question, "How should I do this?" is explained in How to Write Go Code. It's really pretty important stuff and worth taking a look at.
The behavior of go build might seem puzzling, but is actually conventional for command line programs--no output means that the program ran successfully. So what did it do? For that your answer is in go help build
... Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
What, you wanted more? Of course. "How to Write Go Code" explains good ways of doing this. For a quick fix to your program, I'll explain that the go command expects each package and each executable program to be in a separate directory. If you just make a directory called even, immediately under the location of useeven.go, and move even.go to it, then go run useeven.go should run just as you have it.
go build only generates an output file when it builds a "single main package". If you want to output a file for your other package you should use go install. That will build and install that package to your pkgs directory.
As noted in a comment by the OP, go build and go run useeven.go work fine, once you put even.go in its own folder: ./even/even.go. There is a bit of Go magic in the ./ (in the import) that makes the "local package" build automatically without requiring it to be installed anywhere.
useeven/
├── even
│   └── even.go
└── useeven.go
If you wanted to make this work without the magic ./, then the library need to be installed. A quick-and-dirty way (at the risk of polluting your library namespace) of making this work for your project is to simply register the library's source location by using a symbolic link like so (in this example GOPATH is ~/go):
[ useeven ]
$ ln -s $(pwd)/even ~/go/src
Now when you build the program, it automatically performs a go get even to install an up-to-date version of your library.
Note that this doesn't make go install* work for the library, it just makes doing that unnecessary.
There are more idiomatic ways of doing this, if you're not in a hurry: How to import local packages in go?
The reason that output is not being generated here is because you're running the
go build even.go
command on the package and not the main go file. Doing so on the package will check for errors on the package, but because it's not a main with an output, no success messages will be generated. If there are issues with the package's contents, errors will be displayed, otherwise if it compiles fine there will be no output
Instead, you should run:
go build useeven.go
To create the binary, then to execute the binary and get output from the program:
./useeven

Resources