Files
llgo/internal/crosscompile/libc.go

118 lines
3.0 KiB
Go
Raw Normal View History

2025-08-25 19:05:30 +08:00
package crosscompile
import (
"fmt"
"os"
2025-08-28 20:11:13 +08:00
"os/exec"
2025-08-25 19:05:30 +08:00
"path/filepath"
2025-08-28 20:11:13 +08:00
"slices"
"strings"
"github.com/goplus/llgo/internal/clang"
2025-08-25 19:05:30 +08:00
)
2025-08-28 20:11:13 +08:00
type compileGroup struct {
OutputFileName string
Files []string // List of source files to compile
CFlags []string // C compiler flags specific to this libc
CCFlags []string
LDFlags []string // Linker flags
}
func (g compileGroup) IsCompiled(outputDir string) bool {
libcArchive := filepath.Join(outputDir, g.OutputFileName)
_, err := os.Stat(libcArchive)
return !os.IsNotExist(err)
}
func (g compileGroup) Compile(outputDir, cc, linkerName string, extraCCFlags, extraLDFlags []string) (err error) {
if g.IsCompiled(outputDir) {
return
}
tmpCompileDir, err := os.MkdirTemp("", "compile-libc-group*")
if err != nil {
return
}
defer os.RemoveAll(tmpCompileDir)
compileLDFlags := append(slices.Clone(extraLDFlags), g.LDFlags...)
compileCCFlags := append(slices.Clone(extraCCFlags), g.CCFlags...)
cfg := clang.NewConfig(cc, compileCCFlags, g.CFlags, compileLDFlags, linkerName)
var objFiles []string
compiler := clang.NewCompiler(cfg)
compiler.Verbose = true
libcArchive := filepath.Join(outputDir, g.OutputFileName)
fmt.Fprintf(os.Stderr, "Start to compile libc group %s to %s...\n", g.OutputFileName, libcArchive)
for _, file := range g.Files {
var tempObjFile *os.File
tempObjFile, err = os.CreateTemp(tmpCompileDir, fmt.Sprintf("%s*.o", strings.ReplaceAll(file, string(os.PathSeparator), "-")))
if err != nil {
return
}
fmt.Fprintf(os.Stderr, "Compile libc file %s to %s...\n", file, tempObjFile.Name())
lang := "c"
if filepath.Ext(file) == ".S" {
lang = "assembler-with-cpp"
}
err = compiler.Compile("-o", tempObjFile.Name(), "-x", lang, "-c", file)
if err != nil {
return
}
objFiles = append(objFiles, tempObjFile.Name())
}
args := []string{"rcs", libcArchive}
args = append(args, objFiles...)
ccDir := filepath.Dir(cc)
llvmAr := filepath.Join(ccDir, "llvm-ar")
cmd := exec.Command(llvmAr, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
return
}
2025-08-25 19:05:30 +08:00
// CompileLibcConfig represents libc compilation configuration
type compileLibcConfig struct {
Url string
2025-08-28 20:11:13 +08:00
Name string // Libc name (e.g., "picolibc", "musl", "glibc")
Groups []compileGroup
2025-08-25 19:05:30 +08:00
ArchiveSrcDir string
}
2025-08-28 20:11:13 +08:00
func (c compileLibcConfig) IsCompiled(outputDir string) bool {
for _, group := range c.Groups {
if !group.IsCompiled(outputDir) {
return false
}
}
return true
}
2025-08-25 19:05:30 +08:00
// GetCompileLibcConfigByName retrieves libc compilation configuration by name
// Returns compilation file lists and corresponding cflags
func getCompileLibcConfigByName(baseDir, libcName string) (*compileLibcConfig, error) {
if libcName == "" {
return nil, fmt.Errorf("libc name cannot be empty")
}
libcDir := filepath.Join(baseDir, libcName)
switch libcName {
case "picolibc":
return getPicolibcConfig(libcDir), nil
2025-08-28 20:11:13 +08:00
case "newlib-esp32":
return getNewlibESP32Config(libcDir, "xtensa"), nil
2025-08-25 19:05:30 +08:00
default:
return nil, fmt.Errorf("unsupported libc: %s", libcName)
}
}