Skip to content

Commit

Permalink
try best to reserve trace when -cover enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Nov 10, 2024
1 parent 7f408a3 commit a6f0088
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 21 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ The general rule is to make these two tags remain the same with each other, and
Here is a guide on how to make a new release:
- update `VERSION` in [cmd/xgo/version.go](cmd/xgo/version.go).
- update `CORE_VERSION` to match `VERSION` if there is a change in this version that makes `cmd/xgo` depends on the newest runtime, otherwise, keep it untouched.
- run `go generate ./...`.
- check whether `CORE_REVISION`,`CORE_NUMBER` matches `REVISION`,`NUMBER` if `CORE_VERSION` is updated to the same with `VERSION`, if not, run `go generate ./...` again and check, and manually update if necessary.
- run `go run ./script/generate`.
- check whether `CORE_REVISION`,`CORE_NUMBER` matches `REVISION`,`NUMBER` if `CORE_VERSION` is updated to the same with `VERSION`, if not, run `go run ./script/generate` again and check, and manually update if necessary.
- run `git add -A`.
- run `git commit -m "release v1.0.49"`, this will run git hooks that updates `REVISION` and `NUMBER`, and copies `CORE_VERSION`,`CORE_REVISION`,`CORE_NUMBER` to [runtime/core/version.go](runtime/core/version.go) so that if a runtime is running with an older xgo, it will print warnings.
- run `git tag v1.0.49`, if there is runtime update, run `git tag runtime/v1.0.49`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type frameVisitor func(file string, line int, name string, offset uintptr)
// synchronized.
type SyncMarker int

//go:generate stringer -type=SyncMarker -trimprefix=Sync
// removed go:generate stringer -type=SyncMarker -trimprefix=Sync

const (
_ SyncMarker = iota
Expand Down
14 changes: 13 additions & 1 deletion cmd/xgo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,20 @@ func handleBuild(cmd string, args []string) error {
logDebug("debug compile package: %s", debugCompilePkg)
}
if stackTrace == "on" && overlay == "" {
// coverage and trace auto loading may conflict,
// see https://github.com/xhd2015/xgo/issues/285
var mayHaveCover bool
// example:
// -cover -coverpkg github.com/xhd2015/xgo/... -coverprofile cover.out
for _, arg := range args {
if strings.HasPrefix(arg, "-cover") {
mayHaveCover = true
break
}
}

// check if xgo/runtime ready
impResult, impRuntimeErr := importRuntimeDep(cmdTest, instrumentGoroot, instrumentGo, goVersion, modfile, realXgoSrc, projectDir, subPaths, mainModule, mod, remainArgs)
impResult, impRuntimeErr := importRuntimeDep(cmdTest, mayHaveCover, instrumentGoroot, instrumentGo, goVersion, modfile, realXgoSrc, projectDir, subPaths, mainModule, mod, remainArgs)
if impRuntimeErr != nil {
// can be silently ignored
fmt.Fprintf(os.Stderr, "WARNING: --strace requires: import _ %q\n failed to auto import %s: %v\n", RUNTIME_TRACE_PKG, RUNTIME_TRACE_PKG, impRuntimeErr)
Expand Down
27 changes: 25 additions & 2 deletions cmd/xgo/patch_compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,29 @@ func importCompileInternalPatch(goroot string, xgoSrc string, forceReset bool, s
return nil
}

// according to https://pkg.go.dev/embed
//
// 'separator is a forward slash, even on Windows systems'
func joinEmbedPath(paths []string) string {
return strings.Join(paths, "/")
}
func concatEmbedPath(a string, b string) string {
if a == "" {
return b
}
if b == "" {
return a
}
return a + "/" + b
}

func embedPathToFsPath(embedPath string) string {
if filepath.Separator == '/' {
return embedPath
}
return strings.ReplaceAll(embedPath, "/", string(filepath.Separator))
}

func copyEmbedDir(srcFS embed.FS, subName string, dstDir string) error {
return fs.WalkDir(srcFS, subName, func(path string, d fs.DirEntry, err error) error {
if err != nil {
Expand All @@ -435,8 +458,8 @@ func copyEmbedDir(srcFS embed.FS, subName string, dstDir string) error {
if path == subName {
return os.MkdirAll(dstDir, 0755)
}
// TODO: test on Windows if "/" works
dstPath := filepath.Join(dstDir, path[len(subName)+len("/"):])
// join without prefix `subName`, also works on windows
dstPath := filepath.Join(dstDir, embedPathToFsPath(path[len(subName)+len("/"):]))
if d.IsDir() {
return os.MkdirAll(dstPath, 0755)
}
Expand Down
8 changes: 8 additions & 0 deletions cmd/xgo/runtime_gen/trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ type testInfo struct {
var effectMainModule string

func init() {
if false {
// debug
fmt.Fprintf(os.Stderr, "flags.MAIN_MODULE: %s\n", flags.MAIN_MODULE)
fmt.Fprintf(os.Stderr, "flags.STRACE: %s\n", flags.STRACE)
fmt.Fprintf(os.Stderr, "flags.STRACE_DIR: %s\n", flags.STRACE_DIR)
fmt.Fprintf(os.Stderr, "flags.STRACE_SNAPSHOT_MAIN_MODULE_DEFAULT: %s\n", flags.STRACE_SNAPSHOT_MAIN_MODULE_DEFAULT)
fmt.Fprintf(os.Stderr, "flags.TRAP_STDLIB: %s\n", flags.TRAP_STDLIB)
}
if flags.MAIN_MODULE != "" {
// fmt.Fprintf(os.Stderr, "DEBUG main module from flags: %s\n", flags.MAIN_MODULE)
effectMainModule = flags.MAIN_MODULE
Expand Down
54 changes: 41 additions & 13 deletions cmd/xgo/trace.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"bytes"
"embed"
"encoding/json"
"errors"
Expand Down Expand Up @@ -33,7 +34,7 @@ var runtimeGenFS embed.FS
// has github.com/xhd2015/xgo/runtime as dependency,
// if not, dynamically modify the go.mod to include that,
// and add a blank import in the main package
func importRuntimeDep(test bool, goroot string, goBinary string, goVersion *goinfo.GoVersion, absModFile string, xgoSrc string, projectDir string, modRootRel []string, mainModule string, mod string, args []string) (*importResult, error) {
func importRuntimeDep(test bool, mayHaveCover bool, goroot string, goBinary string, goVersion *goinfo.GoVersion, absModFile string, xgoSrc string, projectDir string, modRootRel []string, mainModule string, mod string, args []string) (*importResult, error) {
if mainModule == "" {
// only work with module
return nil, nil
Expand Down Expand Up @@ -88,10 +89,11 @@ func importRuntimeDep(test bool, goroot string, goBinary string, goVersion *goin
}

pkgArgs := getPkgArgs(args)
fileReplace, err := addBlankImports(goroot, goBinary, projectDir, pkgArgs, test, tmpProjectDir)
fileReplace, err := addBlankImports(goroot, goBinary, projectDir, pkgArgs, test, mayHaveCover, tmpProjectDir)
if err != nil {
return nil, err
}

replace := make(map[string]string, len(modReplace)+len(fileReplace))
for k, v := range modReplace {
replace[k] = v
Expand All @@ -104,6 +106,7 @@ func importRuntimeDep(test bool, goroot string, goBinary string, goVersion *goin
if err != nil {
return nil, err
}
logDebug("mod replace: %d, go file replace: %d, overlay: %s", len(modReplace), len(fileReplace), overlayFile)
res.overlayFile = overlayFile

return res, nil
Expand Down Expand Up @@ -226,21 +229,39 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
return nil, err
}
} else {
files := []string{"core", "trap", "trace", "go.mod"}
allExists := true
for _, file := range files {
if !exists(filepath.Join(tmpRuntime, file)) {
allExists = false
break
var skipCopy bool

const runtimeGenRoot = "runtime_gen"
// compare version
versionFilePath := []string{"core", "version.go"}

fsVersionFile := filepath.Join(tmpRuntime, filepath.Join(versionFilePath...))
fsVersion, readFsVersionErr := os.ReadFile(fsVersionFile)
if readFsVersionErr != nil {
if !os.IsNotExist(readFsVersionErr) {
return nil, readFsVersionErr
}
}
if len(fsVersion) > 0 {
genFSVersion, err := runtimeGenFS.ReadFile(concatEmbedPath(runtimeGenRoot, joinEmbedPath(versionFilePath)))
if err != nil {
return nil, err
}
// you need to run go run ./script/generate to sync runtime and cmd/xgo/runtime_gen
if bytes.Equal(fsVersion, genFSVersion) {
logDebug("fs and embed runtime version same, skip extracting from xgo")
skipCopy = true
}
}

// cache copy
if !allExists {
if !skipCopy {
logDebug("extracting runtime from xgo to %s", tmpRuntime)
err := os.RemoveAll(tmpRuntime)
if err != nil {
return nil, err
}
err = copyEmbedDir(runtimeGenFS, "runtime_gen", tmpRuntime)
err = copyEmbedDir(runtimeGenFS, runtimeGenRoot, tmpRuntime)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -350,13 +371,15 @@ func loadDependency(goroot string, goBinary string, goVersion *goinfo.GoVersion,
}
}

logDebug("require %s v%s, replaced: %s", RUNTIME_MODULE, VERSION, tmpRuntime)
err = cmd.Env([]string{
"GOROOT=" + goroot,
}).Run(goBinary, "mod", "edit",
fmt.Sprintf("-require=%s@v%s", RUNTIME_MODULE, VERSION),
fmt.Sprintf("-replace=%s=%s", RUNTIME_MODULE, tmpRuntime),
tmpGoMod,
)
logDebug("replaced go.mod: %s", tmpGoMod)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -431,7 +454,7 @@ func createOverlayFile(tmpProjectDir string, replace map[string]string) (string,
return overlayFile, nil
}

func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs []string, test bool, tmpProjectDir string) (replace map[string]string, err error) {
func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs []string, test bool, mayHaveCover bool, tmpProjectDir string) (replace map[string]string, err error) {
// list files, add init
// NOTE: go build tag applies,
// ignored files will be placed to IgnoredGoFiles
Expand Down Expand Up @@ -462,7 +485,7 @@ func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs
replace = make(map[string]string)
for _, pkg := range pkgs {
if pkg.Standard {
// skip standarding packages
// skip std packages
continue
}
type pkgInfo struct {
Expand All @@ -477,9 +500,14 @@ func addBlankImports(goroot string, goBinary string, projectDir string, pkgArgs
// it is a catch-all workaround
// when there is no source files, then we add to all tests
// the fact is: go allows duplicate blank imports

var hasGoFiles bool
if len(pkg.GoFiles) > 0 {
hasGoFiles = true
pkgInfos = append(pkgInfos, pkgInfo{pkg.Imports, pkg.GoFiles, false})
} else {
}
if !hasGoFiles || mayHaveCover {
// mayHaveCover: see https://github.com/xhd2015/xgo/issues/285
pkgInfos = append(pkgInfos, pkgInfo{nil, pkg.TestGoFiles, true})
pkgInfos = append(pkgInfos, pkgInfo{nil, pkg.XTestGoFiles, true})
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import "fmt"
// VERSION is manually updated when needed a new tag
// see also runtime/core/version.go
const VERSION = "1.0.51"
const REVISION = "4415cd5818ec1cc7720d4ff1313468a11d981b80+1"
const NUMBER = 322
const REVISION = "7f408a387574ea73849b2cb3d82fe3b2c44f885a+1"
const NUMBER = 323

// the matching runtime/core's version
// manually updated
Expand Down
8 changes: 8 additions & 0 deletions runtime/trace/trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ type testInfo struct {
var effectMainModule string

func init() {
if false {
// debug
fmt.Fprintf(os.Stderr, "flags.MAIN_MODULE: %s\n", flags.MAIN_MODULE)
fmt.Fprintf(os.Stderr, "flags.STRACE: %s\n", flags.STRACE)
fmt.Fprintf(os.Stderr, "flags.STRACE_DIR: %s\n", flags.STRACE_DIR)
fmt.Fprintf(os.Stderr, "flags.STRACE_SNAPSHOT_MAIN_MODULE_DEFAULT: %s\n", flags.STRACE_SNAPSHOT_MAIN_MODULE_DEFAULT)
fmt.Fprintf(os.Stderr, "flags.TRAP_STDLIB: %s\n", flags.TRAP_STDLIB)
}
if flags.MAIN_MODULE != "" {
// fmt.Fprintf(os.Stderr, "DEBUG main module from flags: %s\n", flags.MAIN_MODULE)
effectMainModule = flags.MAIN_MODULE
Expand Down
8 changes: 8 additions & 0 deletions script/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"

"github.com/xhd2015/xgo/script/build-release/revision"
"github.com/xhd2015/xgo/support/cmd"
"github.com/xhd2015/xgo/support/git"
"github.com/xhd2015/xgo/support/goparse"
"github.com/xhd2015/xgo/support/transform"
Expand All @@ -21,6 +22,7 @@ import (
type GenernateType string

const (
GenernateType_DotAll GenernateType = "./..."
GenernateType_CompilerPatch GenernateType = "compiler-patch"
GenernateType_CompilerHelperCode GenernateType = "compiler-helper-code"
GenernateType_CompilerPatternCode GenernateType = "compiler-pattern-code"
Expand Down Expand Up @@ -81,6 +83,12 @@ func generate(rootDir string, subGens SubGens) error {
}
rootDir = resolvedRoot
}
if subGens.Has(GenernateType_DotAll) {
err := cmd.Dir(rootDir).Run("go", "generate", "./...")
if err != nil {
return err
}
}
if subGens.Has(GenernateType_CompilerPatch) {
err := generateCompilerPatch(rootDir)
if err != nil {
Expand Down

0 comments on commit a6f0088

Please sign in to comment.