bldr/util/gocompiler/build.go
Rama master · réplica de lectura del repositorio original.
package gocompiler
import (
"context"
"path/filepath"
"slices"
"strings"
"sync"
"time"
bldr_manifest "github.com/s4wave/spacewave/bldr/manifest"
bldr_platform "github.com/s4wave/spacewave/bldr/platform"
bldr_platform_go "github.com/s4wave/spacewave/bldr/platform/go"
opt_wasm "github.com/s4wave/spacewave/bldr/util/opt/wasm"
"github.com/sirupsen/logrus"
)
var tinyGoBuildMu sync.Mutex
// shouldDropWasmDebugSymbols reports whether the non-TinyGo Go build must pass
// -w -s. Diagnostic mode keeps the linker name section for CPU-profile
// symbolization, but only for WASM (non-native) output: native release builds
// always strip regardless of the diagnostic flag.
func shouldDropWasmDebugSymbols(isRelease, isNativeBuildPlatform, isWasmOutput, diagnostic bool) bool {
if isNativeBuildPlatform {
return isRelease
}
if isWasmOutput && diagnostic {
return false
}
return isRelease || !isNativeBuildPlatform
}
// shouldRunWasmOpt reports whether the release Go wasm build should run the
// Binaryen wasm-opt pass. Diagnostic mode bypasses it so the linker name
// section (and any DWARF) survives for CPU-profile symbolization.
func shouldRunWasmOpt(diagnostic bool) (bool, error) {
if diagnostic {
return false, nil
}
return GoWasmOptimizeEnabled()
}
// ExecBuildEntrypoint executes building an entrypoint main package.
func ExecBuildEntrypoint(
ctx context.Context,
le *logrus.Entry,
buildPlatform bldr_platform.Platform,
buildType bldr_manifest.BuildType,
workingPath,
outBinPath string,
enableCgo bool,
useTinygo bool,
buildTags []string,
ldFlags []string,
) error {
// Resolve the entrypoint build mode and wasm diagnostic setting.
isRelease := buildType.IsRelease()
isNativeBuildPlatform := buildPlatform.GetBasePlatformID() == bldr_platform.PlatformID_DESKTOP
isWasmOutput := strings.HasSuffix(outBinPath, ".wasm")
goWasmDiagnostic, err := GoWasmDiagnosticEnabled()
if err != nil {
return err
}
// Resolve the Go environment for the entrypoint platform.
platformEnv, err := bldr_platform_go.PlatformToGoEnv(buildPlatform)
if err != nil {
return err
}
// always disable cgo if not native platform or not go compiler or webassembly
if !isNativeBuildPlatform || isWasmOutput {
enableCgo = false
}
// build tags
buildTags = slices.Clone(buildTags)
buildTags = append(buildTags, NewBuildTags(buildType)...)
if useTinygo || !isNativeBuildPlatform || isWasmOutput {
buildTags = append(buildTags, PureGoBuildTag, SQLLiteBuildTag)
}
// ldflags
ldFlags = slices.Clone(ldFlags)
// relative output path
outBinPathRel, err := filepath.Rel(workingPath, outBinPath)
if err != nil {
return err
}
// args
var cmd string
var args []string
if !useTinygo {
cmd = "go"
args = append([]string{
"build",
"-trimpath",
"-o",
outBinPathRel,
}, GetDefaultArgs()...)
// if release or not native platform drop debugging symbols.
// Diagnostic mode keeps the linker name section for CPU-profile
// symbolization; release/default output is unchanged.
if shouldDropWasmDebugSymbols(isRelease, isNativeBuildPlatform, isWasmOutput, goWasmDiagnostic) {
ldFlags = append(ldFlags, "-w", "-s")
}
args = append(args, "-tags="+strings.Join(buildTags, ","))
} else {
cmd = "tinygo"
args, err = newTinyGoBuildArgs(buildPlatform, buildType, outBinPathRel, buildTags)
if err != nil {
return err
}
}
// ldflags
if len(ldFlags) != 0 {
args = append(args, "-ldflags", strings.Join(ldFlags, " "))
}
// module path
args = append(args, ".")
// go build
ecmd := NewGoCompilerCmd(ctx, cmd, args...)
ecmd.Dir = workingPath
if !useTinygo {
if enableCgo {
ecmd.Env = append(ecmd.Env, "CGO_ENABLED=1")
} else {
ecmd.Env = append(ecmd.Env, "CGO_ENABLED=0")
}
ecmd.Env = append(ecmd.Env, platformEnv...)
}
// Run the compiler and report the entrypoint build duration.
timeStart := time.Now()
if useTinygo {
// TinyGo's LLVM pipeline can exhaust GitHub Linux runner memory when
// multiple browser plugin compiles run inside one Bldr process.
err = func() error {
tinyGoBuildMu.Lock()
defer tinyGoBuildMu.Unlock()
return ExecGoCompiler(le, ecmd)
}()
} else {
err = ExecGoCompiler(le, ecmd)
}
if err != nil {
return err
}
le.
WithField("compiler", cmd).
WithField("dur", time.Since(timeStart).String()).
Info("compiled plugin binary")
// codesign the produced binary on darwin when BLDR_MACOS_SIGN_IDENTITY is set
if !useTinygo && !isWasmOutput && slices.Contains(platformEnv, "GOOS=darwin") {
if err := CodesignMacOS(ctx, le, outBinPath); err != nil {
return err
}
}
// az sign the produced binary on windows when BLDR_WINDOWS_SIGN_PROFILE is set
if !useTinygo && !isWasmOutput && slices.Contains(platformEnv, "GOOS=windows") {
if err := SignWindows(ctx, le, outBinPath); err != nil {
return err
}
}
// post-processing in release mode
if isWasmOutput && isRelease {
if useTinygo {
tinygoDebugInfo, err := TinyGoDebugInfoEnabled()
if err != nil {
return err
}
if tinygoDebugInfo {
le.Info("kept TinyGo wasm debug sections")
} else {
if err := opt_wasm.StripWasmDebugSections(ctx, le, workingPath, outBinPath); err != nil {
return err
}
}
} else {
optimize, err := shouldRunWasmOpt(goWasmDiagnostic)
if err != nil {
return err
}
if !optimize {
le.Info("skipped wasm-opt for Go wasm output")
return nil
}
if err := opt_wasm.OptimizeWasmBinary(ctx, le, workingPath, outBinPath); err != nil {
return err
}
}
}
return nil
}
const tinyGoInternalNoDWARFArg = "-internal-nodwarf"
func newTinyGoBuildArgs(
buildPlatform bldr_platform.Platform,
buildType bldr_manifest.BuildType,
outBinPathRel string,
buildTags []string,
) ([]string, error) {
// Resolve the TinyGo target, options and browser import tags.
tinygoPlat, err := bldr_platform_go.PlatformToTinyGoTarget(buildPlatform)
if err != nil {
return nil, err
}
tinygoArgs, err := GetDefaultTinygoArgs()
if err != nil {
return nil, err
}
tinygoDebugInfo, err := TinyGoDebugInfoEnabled()
if err != nil {
return nil, err
}
buildTags = slices.Clone(buildTags)
if shouldUseBldrTinyGoJSImportBuildTag(buildPlatform, tinygoPlat) {
buildTags = append(buildTags, BldrTinyGoJSImportBuildTag)
}
// Assemble the TinyGo command for the entrypoint output.
args := append([]string{
"build",
"-o",
outBinPathRel,
"-target", tinygoPlat,
}, tinygoArgs...)
// Browser staging investigations sometimes need TinyGo DWARF symbols;
// otherwise release and non-native builds drop debug info to keep wasm small.
if !tinygoDebugInfo && (buildType.IsRelease() || buildPlatform.GetBasePlatformID() != bldr_platform.PlatformID_DESKTOP) {
args = append(args, "-no-debug")
}
if !tinygoDebugInfo && shouldSkipTinyGoInternalDWARF(buildPlatform, buildType) {
args = append(args, tinyGoInternalNoDWARFArg)
}
// Include the selected build tags in the TinyGo command.
args = append(args, "-tags="+strings.Join(buildTags, " "))
return args, nil
}
func shouldUseBldrTinyGoJSImportBuildTag(buildPlatform bldr_platform.Platform, tinygoPlat string) bool {
return buildPlatform.GetBasePlatformID() == bldr_platform.PlatformID_WEB && tinygoPlat == "wasm"
}
func shouldSkipTinyGoInternalDWARF(buildPlatform bldr_platform.Platform, buildType bldr_manifest.BuildType) bool {
if !buildType.IsRelease() {
return false
}
np := bldr_platform.ToNativePlatform(buildPlatform)
if np == nil {
return false
}
return np.GetGOOS() == "js" && np.GetGOARCH() == "wasm"
}