diff --git a/cmd/internal/flags/flags.go b/cmd/internal/flags/flags.go index c61927c3..830bcebb 100644 --- a/cmd/internal/flags/flags.go +++ b/cmd/internal/flags/flags.go @@ -21,6 +21,7 @@ var AbiMode int var CheckLinkArgs bool var CheckLLFiles bool var GenLLFiles bool +var ForceEspClang bool func AddBuildFlags(fs *flag.FlagSet) { fs.BoolVar(&Verbose, "v", false, "Verbose mode") @@ -32,6 +33,7 @@ func AddBuildFlags(fs *flag.FlagSet) { fs.BoolVar(&CheckLinkArgs, "check-linkargs", false, "check link args valid") fs.BoolVar(&CheckLLFiles, "check-llfiles", false, "check .ll files valid") fs.BoolVar(&GenLLFiles, "gen-llfiles", false, "generate .ll files for pkg export") + fs.BoolVar(&ForceEspClang, "force-espclang", false, "force to use esp-clang") } } @@ -56,5 +58,6 @@ func UpdateConfig(conf *build.Config) { conf.CheckLinkArgs = CheckLinkArgs conf.CheckLLFiles = CheckLLFiles conf.GenLL = GenLLFiles + conf.ForceEspClang = ForceEspClang } } diff --git a/internal/build/build.go b/internal/build/build.go index f32c5f7e..38e1286a 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -86,6 +86,7 @@ type Config struct { GenLL bool // generate pkg .ll files CheckLLFiles bool // check .ll files valid CheckLinkArgs bool // check linkargs valid + ForceEspClang bool // force to use esp-clang Tags string GlobalNames map[string][]string // pkg => names GlobalDatas map[string]string // pkg.name => data @@ -159,7 +160,8 @@ func Do(args []string, conf *Config) ([]Package, error) { conf.Goarch = runtime.GOARCH } // Handle crosscompile configuration first to set correct GOOS/GOARCH - export, err := crosscompile.Use(conf.Goos, conf.Goarch, IsWasiThreadsEnabled(), conf.Target) + forceEspClang := conf.ForceEspClang || conf.Target != "" + export, err := crosscompile.Use(conf.Goos, conf.Goarch, conf.Target, IsWasiThreadsEnabled(), forceEspClang) if err != nil { return nil, fmt.Errorf("failed to setup crosscompile: %w", err) } @@ -760,7 +762,6 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l check(err) if orgApp != app { - fmt.Printf("cross compile: %#v\n", ctx.crossCompile) err = firmware.MakeFirmwareImage(orgApp, app, ctx.crossCompile.BinaryFormat, ctx.crossCompile.FormatDetail) check(err) } diff --git a/internal/crosscompile/crosscompile.go b/internal/crosscompile/crosscompile.go index c128d8f1..a7946e37 100644 --- a/internal/crosscompile/crosscompile.go +++ b/internal/crosscompile/crosscompile.go @@ -158,7 +158,7 @@ func getMacOSSysroot() (string, error) { // getESPClangRoot returns the ESP Clang root directory, checking LLGoROOT first, // then downloading if needed and platform is supported -func getESPClangRoot() (clangRoot string, err error) { +func getESPClangRoot(forceEspClang bool) (clangRoot string, err error) { llgoRoot := env.LLGoROOT() // First check if clang exists in LLGoROOT @@ -168,6 +168,10 @@ func getESPClangRoot() (clangRoot string, err error) { return } + if !forceEspClang { + return "", nil + } + // Try to download ESP Clang if platform is supported platformSuffix := getESPClangPlatform(runtime.GOOS, runtime.GOARCH) if platformSuffix != "" { @@ -246,52 +250,57 @@ func getOrCompileWithConfig( return } -func use(goos, goarch string, wasiThreads bool) (export Export, err error) { +func use(goos, goarch string, wasiThreads, forceEspClang bool) (export Export, err error) { targetTriple := llvm.GetTargetTriple(goos, goarch) llgoRoot := env.LLGoROOT() // Check for ESP Clang support for target-based builds - clangRoot, err := getESPClangRoot() + clangRoot, err := getESPClangRoot(forceEspClang) if err != nil { return } // Set ClangRoot and CC if clang is available export.ClangRoot = clangRoot - export.CC = filepath.Join(clangRoot, "bin", "clang++") + if clangRoot != "" { + export.CC = filepath.Join(clangRoot, "bin", "clang++") + } else { + export.CC = "clang++" + } if runtime.GOOS == goos && runtime.GOARCH == goarch { - clangLib := filepath.Join(clangRoot, "lib") - clangInc := filepath.Join(clangRoot, "include") // not cross compile // Set up basic flags for non-cross-compile export.LDFLAGS = []string{ - "-L" + clangLib, "-target", targetTriple, "-Qunused-arguments", "-Wno-unused-command-line-argument", "-Wl,--error-limit=0", "-fuse-ld=lld", } - export.CFLAGS = append(export.CFLAGS, "-I"+clangInc) + if clangRoot != "" { + clangLib := filepath.Join(clangRoot, "lib") + clangInc := filepath.Join(clangRoot, "include") + export.CFLAGS = append(export.CFLAGS, "-I"+clangInc) + export.LDFLAGS = append(export.LDFLAGS, "-L"+clangLib) + // Add platform-specific rpath flags + switch goos { + case "darwin": + export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) + case "linux": + export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) + case "windows": + // Windows doesn't support rpath, DLLs should be in PATH or same directory + default: + // For other Unix-like systems, try the generic rpath + export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) + } + } export.CCFLAGS = []string{ "-Qunused-arguments", "-Wno-unused-command-line-argument", } - // Add platform-specific rpath flags - switch goos { - case "darwin": - export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) - case "linux": - export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) - case "windows": - // Windows doesn't support rpath, DLLs should be in PATH or same directory - default: - // For other Unix-like systems, try the generic rpath - export.LDFLAGS = append(export.LDFLAGS, "-Wl,-rpath,"+clangLib) - } - // Add sysroot for macOS only if goos == "darwin" { sysrootPath, sysrootErr := getMacOSSysroot() @@ -483,7 +492,7 @@ func useTarget(targetName string) (export Export, err error) { } // Check for ESP Clang support for target-based builds - clangRoot, err := getESPClangRoot() + clangRoot, err := getESPClangRoot(true) if err != nil { return } @@ -667,9 +676,9 @@ func useTarget(targetName string) (export Export, err error) { // Use extends the original Use function to support target-based configuration // If targetName is provided, it takes precedence over goos/goarch -func Use(goos, goarch string, wasiThreads bool, targetName string) (export Export, err error) { +func Use(goos, goarch, targetName string, wasiThreads, forceEspClang bool) (export Export, err error) { if targetName != "" && !strings.HasPrefix(targetName, "wasm") && !strings.HasPrefix(targetName, "wasi") { return useTarget(targetName) } - return use(goos, goarch, wasiThreads) + return use(goos, goarch, wasiThreads, forceEspClang) } diff --git a/internal/crosscompile/crosscompile_test.go b/internal/crosscompile/crosscompile_test.go index 8ea3f146..af323553 100644 --- a/internal/crosscompile/crosscompile_test.go +++ b/internal/crosscompile/crosscompile_test.go @@ -37,10 +37,10 @@ func TestUseCrossCompileSDK(t *testing.T) { name: "Same Platform", goos: runtime.GOOS, goarch: runtime.GOARCH, - expectSDK: true, // Changed: now we expect flags even for same platform - expectCCFlags: true, // Changed: CCFLAGS will contain sysroot - expectCFlags: true, // Changed: CFLAGS will contain include paths - expectLDFlags: true, // Changed: LDFLAGS will contain library paths + expectSDK: true, // Changed: now we expect flags even for same platform + expectCCFlags: true, // Changed: CCFLAGS will contain sysroot + expectCFlags: false, // Changed: CFLAGS will not contain include paths + expectLDFlags: false, // Changed: LDFLAGS will not contain library paths }, { name: "WASM Target", @@ -76,7 +76,7 @@ func TestUseCrossCompileSDK(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - export, err := use(tc.goos, tc.goarch, false) + export, err := use(tc.goos, tc.goarch, false, false) if err != nil { t.Fatalf("Unexpected error: %v", err) @@ -280,7 +280,7 @@ func TestUseTarget(t *testing.T) { func TestUseWithTarget(t *testing.T) { // Test target-based configuration takes precedence - export, err := Use("linux", "amd64", false, "esp32") + export, err := Use("linux", "amd64", "esp32", false, true) if err != nil { t.Fatalf("Unexpected error: %v", err) } @@ -292,7 +292,7 @@ func TestUseWithTarget(t *testing.T) { } // Test fallback to goos/goarch when no target specified - export, err = Use(runtime.GOOS, runtime.GOARCH, false, "") + export, err = Use(runtime.GOOS, runtime.GOARCH, "", false, false) if err != nil { t.Fatalf("Unexpected error: %v", err) }