mirror of
https://github.com/goplus/llgo.git
synced 2025-10-05 07:37:01 +08:00
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
package compile
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/goplus/llgo/internal/clang"
|
|
)
|
|
|
|
type CompileOptions struct {
|
|
CC string // Compiler to use
|
|
Linker string
|
|
CCFLAGS []string
|
|
CFLAGS []string
|
|
LDFLAGS []string
|
|
}
|
|
|
|
type CompileGroup struct {
|
|
OutputFileName string
|
|
Files []string // List of source files to compile
|
|
CFlags []string // C compiler flags
|
|
CCFlags []string
|
|
LDFlags []string // Linker flags
|
|
}
|
|
|
|
// IsCompiled checks if the compile group has already been compiled by verifying
|
|
// if the output archive file exists in the specified directory
|
|
func (g CompileGroup) IsCompiled(outputDir string) bool {
|
|
archive := filepath.Join(outputDir, filepath.Base(g.OutputFileName))
|
|
_, err := os.Stat(archive)
|
|
return err == nil
|
|
}
|
|
|
|
// Compile compiles all source files in the group into a static library archive
|
|
// If the archive already exists, compilation is skipped
|
|
func (g CompileGroup) Compile(
|
|
outputDir string, options CompileOptions,
|
|
) (err error) {
|
|
if g.IsCompiled(outputDir) {
|
|
return
|
|
}
|
|
tmpCompileDir, err := os.MkdirTemp("", "compile-group*")
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer os.RemoveAll(tmpCompileDir)
|
|
|
|
compileLDFlags := append(slices.Clone(options.LDFLAGS), g.LDFlags...)
|
|
compileCCFlags := append(slices.Clone(options.CCFLAGS), g.CCFlags...)
|
|
compileCFFlags := append(slices.Clone(options.CFLAGS), g.CFlags...)
|
|
|
|
cfg := clang.NewConfig(options.CC, compileCCFlags, compileCFFlags, compileLDFlags, options.Linker)
|
|
|
|
var objFiles []string
|
|
|
|
compiler := clang.NewCompiler(cfg)
|
|
|
|
compiler.Verbose = true
|
|
|
|
archive := filepath.Join(outputDir, filepath.Base(g.OutputFileName))
|
|
fmt.Fprintf(os.Stderr, "Start to compile group %s to %s...\n", g.OutputFileName, archive)
|
|
|
|
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
|
|
}
|
|
|
|
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", archive}
|
|
args = append(args, objFiles...)
|
|
|
|
ccDir := filepath.Dir(options.CC)
|
|
llvmAr := filepath.Join(ccDir, "llvm-ar")
|
|
|
|
cmd := exec.Command(llvmAr, args...)
|
|
// TODO(MeteorsLiu): support verbose
|
|
// cmd.Stdout = os.Stdout
|
|
// cmd.Stderr = os.Stderr
|
|
err = cmd.Run()
|
|
return
|
|
}
|
|
|
|
// CompileConfig represents compilation configuration
|
|
type CompileConfig struct {
|
|
Groups []CompileGroup
|
|
ExportCFlags []string
|
|
}
|
|
|
|
type LibConfig struct {
|
|
Url string
|
|
Name string // Library name (e.g., "picolibc", "musl", "glibc")
|
|
Version string
|
|
ResourceSubDir string
|
|
}
|
|
|
|
// String returns a string representation of the library configuration
|
|
// in the format "name-version"
|
|
func (cfg LibConfig) String() string {
|
|
return fmt.Sprintf("%s-%s", cfg.Name, cfg.Version)
|
|
}
|