Currently trying to work out why building twice from same source creates different buildid and more specifically different actionID part.
I have vendored the dependencies with the following main.go
package main
import (
"context"
"fmt"
awsConfig "github.com/aws/aws-sdk-go-v2/config"
)
func main() {
awsCfg, err := awsConfig.LoadDefaultConfig(context.Background())
if err != nil {
fmt.Println(err)
}
_ = awsCfg
fmt.Println("hello world")
}
go build -o bootstrap -mod=vendor -trimpath -buildvcs=false cmd/main.go
go clean --cache
go build -o bootstrap2 -mod=vendor -trimpath -buildvcs=false cmd/main.go
will produce the following difference respectively:
4PSJ2COQu-WEdQUCy9GF/bEj2KquhCFU77YWE3s8m/M-Eq01RmuZNuSlF4NvKh/Sw9yCoyvM-OHIpXpdNG5
1B4wdixPXI9YqxSglbgJ/bEj2KquhCFU77YWE3s8m/M-Eq01RmuZNuSlF4NvKh/Sw9yCoyvM-OHIpXpdNG5
This is causing updates to a lambda function has the produced hash from aws-cdk differs between builds on circleci even if nothing within the actual function has changed. I understand we could pass ldflags=-buildid= as a build argument (??) but want to understand what could be causing this change in actionId
This change is not consistent and sometimes produces the same buildId
go version go1.19 darwin/amd64
edit:
The following issue 33772 states this was resolved when using -trimpath
Related
I'm making a Go program and have created a module to divide it. Here is my working tree (the minimal directory is in $GOPATH/src/):
minimal/
├── main.go
└── ui
├── go.mod
├── go.sum
└── ui.go
In the ui module I have the following:
package ui
import "github.com/satori/go.uuid"
func SomeFunction() {
id, err := uuid.NewV4()
if err == nil {
print(id.String())
} else {
print(err)
}
}
The main package uses this module as follows
package main
import "minimal/ui"
func main() {
ui.SomeFunction()
}
Here is the go.mod file:
module minimal/ui
go 1.14
require github.com/satori/go.uuid v1.2.0
When running go build in the main package folder, everything works and the binary is generated. However, when building only the ui module, it gives the following compilation error:
ui$ go build
# minimal/ui
./ui.go:6:10: assignment mismatch: 2 variables but uuid.NewV4 returns 1 values
You can check https://github.com/satori/go.uuid to see that the function returns two values. What has me puzzled is that building the main package works, but the module doesn't. Why is that?
github.com/satori/go.uuid documentation appears to support GOPATH builds. go module builds, however, produce inconsistent results.
Take the simple API usage from it's README.md:
package main
import "github.com/satori/go.uuid"
func main() {
u, err := uuid.NewV4()
_, _ = u, err
}
And try to compile it with go modules:
go mod init
go build
go: finding module for package github.com/satori/go.uuid
go: found github.com/satori/go.uuid in github.com/satori/go.uuid v1.2.0
./main.go:6:9: assignment mismatch: 2 variables but uuid.NewV4 returns 1 values
it pulled tagged v1.2.0 and it failed to compile.
So now pull the latest commit:
go get github.com/satori/go.uuid#master
go: github.com/satori/go.uuid master => v1.2.1-0.20181028125025-b2ce2384e17b
Now it compiles:
go build && echo $?
0
So what is happening here?
github.com/satori/go.uuid is tagged with a mature v1 release, so all dot releases should be feature enhancements with no breaking changes.
The latest tagged version v1.2.0 returns only one value from uuid.NewV4().
The latest commit (which go modules infers a pseudo dot release version of v1.2.1-0.20181028125025-b2ce2384e17b) has code that matches the README.md.
If this repo ever becomes tagged as v1.2.1 - this would be a breaking change, as it changes the signature of a function published in a previous v1 release. This would be a violation of semver rules.
Conclusion:
The documentation matches a GOPATH (i.e. non-go modules) build. GOPATH builds always pull the latest commit.
From a go modules perspective, while one may be able to coerce a working build, it does not look like it's supported. Yes, the git repo uses semver tags, but there is no go.mod.
I would not trust this package with a go modules build. Perhaps consider using github.com/google/uuid which does.
The uuid package has different versions. In the latest version, function NewV4() returns just one variable but in the previous versions, it returns two variables which one of them is an error.
You create a go.mod file in the subdirectory of your project, So when you compile your project in the main directory, go-compiler uses one version, and in your ui directory it uses another version to compile. You should just edit the version of uuid package in your go.mod file.
I'm writing two binaries, and both of them use two libraries (we can call them libA and libB).
Each lib is in a dedicated git repo, with git-tags to declare versions.
For example, libA is at v1.0.9 and libB is v0.0.12.
Both binaries have CLI flags, and I would like to add a debug flag to display lib versions like that:
> ./prog -d
Used libraries:
- libA, v1.0.9
- libB, v0.0.12
I don't know how to do that.
The only way I see to set variable from "outside" is to use ldflags (go build -ldflags="-X 'main.Version=v1.0.0'" for example). But this way don't seems scalable, how to add a libC? It also imply to manage tags two times, one time for git, and one time in goreleaser.yml or makefile.
Can you help me to find a solution?
The Go tool includes module and dependency information in the executable binary. You may use runtime/debug.ReadBuildInfo() to acquire it. It returns you a list of dependencies, including module path and version. Each module / dependency is described by a value of type debug.Module which contains these info:
type Module struct {
Path string // module path
Version string // module version
Sum string // checksum
Replace *Module // replaced by this module
}
For example:
package main
import (
"fmt"
"log"
"runtime/debug"
"github.com/icza/bitio"
)
func main() {
_ = bitio.NewReader
bi, ok := debug.ReadBuildInfo()
if !ok {
log.Printf("Failed to read build info")
return
}
for _, dep := range bi.Deps {
fmt.Printf("Dep: %+v\n", dep)
}
}
This outputs (try it on the Go Playground):
Dep: &{Path:github.com/icza/bitio Version:v1.0.0 Sum:h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8= Replace:<nil>}
Also see related question: How to get Go detailed build logs, with all used packages in GOPATH and "go module" mode?
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
I have a variable VERSION in a make file that sets the version for binary at compile time using -ldflags
VERSION = $(strip $(TIMESTAMP))
LDFLAGS = -ldflags "-X main.buildTime $(BUILD_TIME) -X main.buildNumber $(VERSION)"
Now I want to get the VERSION in a package which is not main and print it. I tried bunch of options, but not able to make it work.
My question is how can I get it in the package and then print it to client at run time, such as you are connected to app version 2.0..??
Directory structure:
- main.go
- test/
- test.go
test.go
package test
var Version = ""
main.go
package main
import (
"fmt"
"test"
)
func main() {
fmt.Println(test.Version)
}
Finally, run:
go run -ldflags="-X test.Version 2.0.0" main.go
Outputs:
> 2.0.0
Since we can specify import path, we can set the value of a string everywhere, not only in main.
From go 1.5 up, syntax is changed to importpath.name=string.
If I compile this program
package main
import (
"fmt"
"os"
)
var version = os.Getenv("VERSION")
func main() {
fmt.Println(version)
}
It prints the env var when I run it
VERSION="0.123" ./example
> 0.123
Is there a way to compile the env var into the binary, for example:
VERSION="0.123" go build example.go
Then get the same output when I run
./example
Go 1.5 and above edit:
As of now, the syntax has changed.
On Unix use:
go build -ldflags "-X main.Version=$VERSION"
On Windows use:
go build -ldflags "-X main.Version=%VERSION%"
This is what -X linker flag is for. In your case, you would do
go build -ldflags "-X main.Version $VERSION"
Edit: on Windows this would be
go build -ldflags "-X main.Version %VERSION%"
More info in the linker docs.
Ainer-G's answer led me to the right place, but it wasn't a full code sample answering the question. A couple of changes were required:
Declare the version as var version string
Compile with -X main.version=$VERSION
Here's the full code:
package main
import (
"fmt"
)
var version string
func main() {
fmt.Println(version)
}
Now compile with
go build -ldflags "-X main.version=$VERSION"
There is an os.Setenv() function which you can use to set environment variables.
So you can start your application by setting the environment variable like this:
func init() {
os.Setenv("VERSION", "0.123")
}
If you don't want to do this by "hand", you could create a tool for this which would read the current value of the VERSION environment variable and generate a .go source file in your package containing exactly like the code above (except using the current value of the VERSION environment variable). You can run such code generation by issuing the go generate command.
Read the Generating code blog post for more details about go generate.