Golang 1.18 - Exclude package for specific platform - go

I spent the whole day trying to apply a build constraint in my code:
I have an agent that is designed to work on Windows and Linux, however, I have to interact with the Windows registry (which obviously doesn't have any equivalent on Linux).
My package imports
"golang.org/x/sys/windows/registry"
The project builds on Windows but not on Linux.
I then learnt about build constraints: //go:build windows (or !linux)
I initially started with // +build windows but I saw that it's for older Go versions.
Here is the header of my package file:
//go:build windows
package utils
import (
"fmt"
"log"
"golang.org/x/sys/windows/registry"
)
...
I use VSCode both on Windows and Linux, I can also see a reference to in my go.mod file.
Any help with this please?
When I run the code above, I still get the following on Linux:
build golang.org/x/sys/windows/registry: cannot load
golang.org/x/sys/windows/registry: no Go source files (exit status 1)
Edit: I use the default VSCode tools to compile and run my project, however I have tried: go build . and I still get the same error.
Also, the _windows.go and _linux.go suffixes are not appropriate as the agent would be fore Mac in the future.

I couldn't write the entire thing in the comments but let me know if this small sample helps you:
utils_darwin.go:
package utils
import "fmt"
func Test() {
fmt.Println("Test from mac")
}
utils_linux.go
package utils
import "fmt"
func Test() {
fmt.Println("Test from linux")
}
utils_windows.go
package utils
import "fmt"
func Test() {
fmt.Println("Test from windows")
}
main.go
package main
import "github.com/ninadingole/go-dev-stuff/platform/utils"
func main() {
utils.Test()
}
When I compile the binary on mac and run it like:
GOOS=darwin go build -o prog ./platform
./prog
Test from mac
I tried to build the binary in docker for linux and got the below output
Test from linux
Let me know if this works for you otherwise I will delete the answer :D

Related

Golang Building Multi Platform Issue

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.

How do I fix VS Code error: "Not able to determine import path of current package by using cwd" for Go project

I'm following tutorials and I think I may have missed something.
I have a Go project located at:
/Users/just_me/development/testing/golang/example_server
The contents are:
main.go
package main
import "fmt"
func main() {
fmt.Println("hi world")
}
I have a ~/go directory.
go env shows:
GOPATH="/Users/just_me/go"
GOROOT="/usr/local/Cellar/go/1.12.9/libexec"
I installed the suggested packages in VSCode.
When I save my main.go I get:
Not able to determine import path of current package by using cwd: /Users/just_me/development/testing/golang/example_server and Go workspace:
/Users/just_me/development/testing/golang/example_server>
How do I fix this?
Since your package is outside of $GOPATH, you may need to create a module file.
You'll need to init your go module using
go mod init your.import/path
Change the import path to whatever you like.
This way you set the import path explicitly, which might help fix it.
The resulting go.mod file looks like this:
module your.import/path
go 1.14 // Your go version
So if the go.mod file is in the same directory as a main.go file, you can now import submodules from it:
E.g. main.go:
package main
import (
"your.import/path/somepackage" // Import package from a subdirectory. This only works if `go.mod` has been created as above
)
func main() {
somepackage.SomeMethod()
}
And in somepackage/whatever.go:
package somepackage
import "fmt"
func SomeMethod() {
fmt.Println("Success!")
}
if you are using vs code, check if the go and code runner extensions are enabled, if enabled, try disabling and enabling again, and if not, install and enable, and download all requested packages.

function call difference between go build and go run

I'm new to Golang and I'm trying out a few examples as part of my learning. I have 2 Go source files - hello.go and consts.go in my example. consts.go contains some constants which are used by the functions defined in hello.go. When I build both the source files like so:
go build consts.go hello.go and run the output ./hello
the function arrayDemo() is not called at all.
However, when I just run the file hello.go using go run hello.go, the function arrayDemo() is called.
What is the difference in both the approaches that's causing the function not to be called when building?
Here's the code for hello.go:
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func main() {
fmt.Printf("Speed is %f\n", computeSpeed(54.3, 3.4))
fmt.Printf("%d\n", arrayDemo())
}
func arrayDemo() int32 {
fmt.Println("in arrayDemo")
return 5
}
Code for consts.go:
package main
// Speed speed of a vehicle
type Speed float32
func computeSpeed(dist float32, t float32) Speed {
return Speed(dist / t)
}
go run works because go run works based on file names, but go build works based on package names.
also
go help build says:
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.
to my understanding this means you can not have multiple files in the main package and then get working executable by using go build

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

How to use multiple .go files in the same application

Good Morning All,
I am new to Golang. I want to move some of my functions out into separate files so that I will not have like a 10,000 line .go file at the end. lol. I created two files both have the same package called main. Do I need to change package name to be app specific? Anyway how do I get these two files to talk?
Example:
MainFile.go:
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello World!")
Test()
}
NewFile.go:
package main
import (
"fmt"
)
func Test() {
fmt.Println("Hello World Again!")
}
The test method is in the second file but cannot be reached by the first. I am sure this is some rudimentary thing I am missing.
Thanks
Update:
I tried specifying this on the command line: go build MainFile.go NewSourceFile.go. It comes back with no errors but never builds the binary. How do I get it to output the binary now?
If you run go run MainFile.go, Test() won't be found because its not in that file. You have to build the package then run the package:
Inside the folder where the 2 files are, run go build and you will get a binary in that folder. Then just run the binary: ./MyPackage

Resources