diff --git a/internal/build/build.go b/internal/build/build.go index e0051ed9..0c9f2252 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -546,6 +546,83 @@ func createGlobals(ctx *context, prog llssa.Program, pkgs []*aPackage) (llssa.Pa return global, nil } +// compileExtraFiles compiles extra files (.s/.c) from target configuration and returns object files +func compileExtraFiles(ctx *context, verbose bool) ([]string, error) { + if len(ctx.crossCompile.ExtraFiles) == 0 { + return nil, nil + } + + var objFiles []string + llgoRoot := env.LLGoROOT() + + for _, extraFile := range ctx.crossCompile.ExtraFiles { + // Resolve the file path relative to llgo root + srcFile := filepath.Join(llgoRoot, extraFile) + + // Check if file exists + if _, err := os.Stat(srcFile); os.IsNotExist(err) { + if verbose { + fmt.Fprintf(os.Stderr, "Warning: extra file not found: %s\n", srcFile) + } + continue + } + + // Generate output file name + objFile, err := os.CreateTemp("", "extra-*"+filepath.Base(extraFile)) + if err != nil { + return nil, fmt.Errorf("failed to create temp file for %s: %w", extraFile, err) + } + objFile.Close() + + var outputFile string + ext := filepath.Ext(srcFile) + + if ctx.buildConf.GenLL { + outputFile = objFile.Name() + ".ll" + } else { + outputFile = objFile.Name() + ".o" + } + + // Prepare compilation arguments + var args []string + + // Add target-specific flags if available + if len(ctx.crossCompile.CCFLAGS) > 0 { + args = append(args, ctx.crossCompile.CCFLAGS...) + } + + // Handle different file types + switch ext { + case ".c": + args = append(args, "-x", "c") + case ".S", ".s": + args = append(args, "-x", "assembler-with-cpp") + } + + // Add output flags + if ctx.buildConf.GenLL { + args = append(args, "-emit-llvm", "-S", "-o", outputFile, "-c", srcFile) + } else { + args = append(args, "-o", outputFile, "-c", srcFile) + } + + if verbose { + fmt.Fprintf(os.Stderr, "Compiling extra file: clang %s\n", strings.Join(args, " ")) + } + + // Compile the file + cmd := ctx.compiler() + if err := cmd.Compile(args...); err != nil { + return nil, fmt.Errorf("failed to compile extra file %s: %w", srcFile, err) + } + + objFiles = append(objFiles, outputFile) + os.Remove(objFile.Name()) // Remove the temp file we created for naming + } + + return objFiles, nil +} + func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global llssa.Package, conf *Config, mode Mode, verbose bool) { pkgPath := pkg.PkgPath name := path.Base(pkgPath) @@ -594,6 +671,11 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l // defer os.Remove(entryLLFile) objFiles = append(objFiles, entryObjFile) + // Compile extra files from target configuration + extraObjFiles, err := compileExtraFiles(ctx, verbose) + check(err) + objFiles = append(objFiles, extraObjFiles...) + if global != nil { export, err := exportObject(ctx, pkg.PkgPath+".global", pkg.ExportFile+"-global", []byte(global.String())) check(err) diff --git a/internal/crosscompile/crosscompile.go b/internal/crosscompile/crosscompile.go index 3bfe029c..05880d8d 100644 --- a/internal/crosscompile/crosscompile.go +++ b/internal/crosscompile/crosscompile.go @@ -25,9 +25,10 @@ type Export struct { BuildTags []string GOOS string GOARCH string - Linker string // Linker to use (e.g., "ld.lld", "avr-ld") - ClangRoot string // Root directory of custom clang installation - ClangBinPath string // Path to clang binary directory + Linker string // Linker to use (e.g., "ld.lld", "avr-ld") + ExtraFiles []string // Extra files to compile and link (e.g., .s, .c files) + ClangRoot string // Root directory of custom clang installation + ClangBinPath string // Path to clang binary directory } const wasiSdkUrl = "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz" @@ -435,6 +436,7 @@ func useTarget(targetName string) (export Export, err error) { export.BuildTags = config.BuildTags export.GOOS = config.GOOS export.GOARCH = config.GOARCH + export.ExtraFiles = config.ExtraFiles // Build environment map for template variable expansion envs := buildEnvMap(env.LLGoROOT()) diff --git a/internal/targets/config.go b/internal/targets/config.go index 1a35a41f..8bb01356 100644 --- a/internal/targets/config.go +++ b/internal/targets/config.go @@ -20,6 +20,7 @@ type Config struct { LinkerScript string `json:"linkerscript"` CFlags []string `json:"cflags"` LDFlags []string `json:"ldflags"` + ExtraFiles []string `json:"extra-files"` // Code generation configuration CodeModel string `json:"code-model"` diff --git a/internal/targets/loader.go b/internal/targets/loader.go index 6b2febcb..e535e6d8 100644 --- a/internal/targets/loader.go +++ b/internal/targets/loader.go @@ -160,6 +160,9 @@ func (l *Loader) mergeConfig(dst, src *Config) { if len(src.LDFlags) > 0 { dst.LDFlags = append(dst.LDFlags, src.LDFlags...) } + if len(src.ExtraFiles) > 0 { + dst.ExtraFiles = append(dst.ExtraFiles, src.ExtraFiles...) + } } // GetTargetsDir returns the targets directory path