4b2bb6998a
Añade soporte C++ al registry: vendor submodules (glfw, imgui, implot, tracy), sistema de build con CMake y toolchains cross-platform, runner C++ en fn CLI, parser de tests Google Test, y funciones bash para build Linux/Windows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
129 lines
3.5 KiB
Go
129 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"fn-registry/registry"
|
|
)
|
|
|
|
func buildCppCommand(fn *registry.Function, registryRoot, absPath string, args []string) (*exec.Cmd, error) {
|
|
cppRoot := filepath.Join(registryRoot, "cpp")
|
|
buildDir := filepath.Join(cppRoot, "build", "linux")
|
|
|
|
// Ensure build directory exists and cmake is configured
|
|
if _, err := os.Stat(filepath.Join(buildDir, "CMakeCache.txt")); os.IsNotExist(err) {
|
|
fmt.Fprintf(os.Stderr, "[fn run] configuring cmake for cpp...\n")
|
|
configure := exec.Command("cmake", "-B", buildDir, "-S", cppRoot)
|
|
configure.Dir = registryRoot
|
|
configure.Stdout = os.Stderr
|
|
configure.Stderr = os.Stderr
|
|
if err := configure.Run(); err != nil {
|
|
return nil, fmt.Errorf("cmake configure failed: %w", err)
|
|
}
|
|
}
|
|
|
|
dir := filepath.Dir(absPath)
|
|
|
|
// Check if the function's directory has its own CMakeLists.txt (app with main)
|
|
localCMake := filepath.Join(dir, "CMakeLists.txt")
|
|
hasMain := false
|
|
if _, err := os.Stat(localCMake); err == nil {
|
|
hasMain = true
|
|
}
|
|
// Also check for main.cpp in the same directory
|
|
mainCpp := filepath.Join(dir, "main.cpp")
|
|
if _, err := os.Stat(mainCpp); err == nil {
|
|
hasMain = true
|
|
}
|
|
|
|
if hasMain {
|
|
// Build and run the app binary
|
|
targetName := filepath.Base(dir)
|
|
build := exec.Command("cmake", "--build", buildDir, "--target", targetName)
|
|
build.Dir = registryRoot
|
|
build.Stdout = os.Stderr
|
|
build.Stderr = os.Stderr
|
|
fmt.Fprintf(os.Stderr, "[fn run] building target %s...\n", targetName)
|
|
if err := build.Run(); err != nil {
|
|
return nil, fmt.Errorf("cmake build failed: %w", err)
|
|
}
|
|
|
|
// Find the built binary
|
|
binaryPath := findBinary(buildDir, targetName)
|
|
if binaryPath == "" {
|
|
return nil, fmt.Errorf("built binary %q not found in %s", targetName, buildDir)
|
|
}
|
|
|
|
cmd := exec.Command(binaryPath, args...)
|
|
cmd.Dir = dir
|
|
return cmd, nil
|
|
}
|
|
|
|
// Library code: compile-check only (like go vet)
|
|
build := exec.Command("cmake", "--build", buildDir)
|
|
build.Dir = registryRoot
|
|
build.Stdout = os.Stderr
|
|
build.Stderr = os.Stderr
|
|
fmt.Fprintf(os.Stderr, "[fn run] %s is library code — running compile check\n", fn.ID)
|
|
|
|
if err := build.Run(); err != nil {
|
|
return nil, fmt.Errorf("compile check failed: %w", err)
|
|
}
|
|
|
|
// Return a no-op command that just prints success
|
|
cmd := exec.Command("echo", fmt.Sprintf("[fn run] %s compiled successfully", fn.ID))
|
|
return cmd, nil
|
|
}
|
|
|
|
// findBinary searches for an executable in the build tree.
|
|
func findBinary(buildDir, name string) string {
|
|
// Common locations cmake puts binaries
|
|
candidates := []string{
|
|
filepath.Join(buildDir, name),
|
|
filepath.Join(buildDir, "apps", name, name),
|
|
}
|
|
|
|
for _, c := range candidates {
|
|
if info, err := os.Stat(c); err == nil && !info.IsDir() {
|
|
// Check if executable
|
|
if info.Mode()&0111 != 0 {
|
|
return c
|
|
}
|
|
}
|
|
}
|
|
|
|
// Walk the build directory as fallback
|
|
var found string
|
|
filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil || info.IsDir() {
|
|
return nil
|
|
}
|
|
if info.Name() == name && info.Mode()&0111 != 0 {
|
|
found = path
|
|
return filepath.SkipAll
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// Also try without extension match for paths with subdirectories
|
|
if found == "" {
|
|
filepath.Walk(buildDir, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil || info.IsDir() {
|
|
return nil
|
|
}
|
|
base := strings.TrimSuffix(info.Name(), filepath.Ext(info.Name()))
|
|
if base == name && info.Mode()&0111 != 0 {
|
|
found = path
|
|
return filepath.SkipAll
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
return found
|
|
}
|