github.com/metux/go-metabuild@v0.0.0-20240118143255-d9ed5ab697f9/util/compiler/gnu/gcc.go (about)

     1  package gnu
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/metux/go-metabuild/util/cmd"
    10  	"github.com/metux/go-metabuild/util/compiler/base"
    11  )
    12  
    13  // FIXME: support multiple compiler types
    14  // FIXME: move over to builders ?
    15  
    16  type CCompilerGCC struct {
    17  	CompilerInfo base.CompilerInfo
    18  	cmdline      []string
    19  	TempDir      string
    20  }
    21  
    22  // --- command line construction ---
    23  // NOTE: these *need* pointer receiver
    24  
    25  func (cc *CCompilerGCC) cmdCC(out string, src []string) {
    26  	cc.cmdline = cc.CompilerInfo.Command
    27  	cc.cmdline = append(cc.cmdline, "-o", out)
    28  	cc.cmdline = append(cc.cmdline, src...)
    29  }
    30  
    31  func (cc *CCompilerGCC) cmdPkgImport(pkgimport []base.PkgConfigInfo) {
    32  	// FIXME: filter out duplicate flags
    33  	for _, pi := range pkgimport {
    34  		if pi.WantStatic && pi.WantShared {
    35  			panic("config error: cant have WantStatic && WantShared together")
    36  		}
    37  
    38  		if pi.WantStatic {
    39  			cc.cmdline = append(cc.cmdline, pi.StaticCflags...)
    40  			cc.cmdline = append(cc.cmdline, pi.StaticLdflags...)
    41  		} else {
    42  			cc.cmdline = append(cc.cmdline, pi.SharedCflags...)
    43  			cc.cmdline = append(cc.cmdline, pi.SharedLdflags...)
    44  		}
    45  	}
    46  }
    47  
    48  func (cc *CCompilerGCC) cmdDefines(cdefs []string) {
    49  	for _, x := range cdefs {
    50  		cc.cmdline = append(cc.cmdline, "-D"+x)
    51  	}
    52  }
    53  
    54  func (cc *CCompilerGCC) cmdShared() {
    55  	cc.cmdline = append(cc.cmdline, "-fPIC", "-shared")
    56  }
    57  
    58  func (cc *CCompilerGCC) cmdSoName(soname string) {
    59  	cc.cmdline = append(cc.cmdline, "-Wl,-soname,"+soname)
    60  }
    61  
    62  func (cc *CCompilerGCC) cmdAr(out string, objs []string) {
    63  	cc.cmdline = append(append(cc.CompilerInfo.Archiver, "-rc", out), objs...)
    64  }
    65  
    66  func (cc *CCompilerGCC) cmdAppend(args ...string) {
    67  	cc.cmdline = append(cc.cmdline, args...)
    68  }
    69  
    70  func (cc CCompilerGCC) cmdExec() error {
    71  	log.Println("CC cmd", cc.cmdline)
    72  	out, err := cmd.RunOut(cc.cmdline, true)
    73  	if out != "" {
    74  		log.Println(out)
    75  	}
    76  	return err
    77  }
    78  
    79  func (cc CCompilerGCC) CompileExecutable(args base.CompilerArg) error {
    80  	if args.Output == "" {
    81  		return fmt.Errorf("CompileExe: no output file")
    82  	}
    83  
    84  	cc.cmdCC(args.Output, args.Sources)
    85  	cc.cmdPkgImport(args.PkgImports)
    86  	cc.cmdDefines(args.Defines)
    87  	cc.cmdAppend(args.Flags...)
    88  	return cc.cmdExec()
    89  }
    90  
    91  func (cc CCompilerGCC) CompileLibraryStatic(args base.CompilerArg) error {
    92  	objs := []string{}
    93  	cmdlines := [][]string{}
    94  
    95  	// FIXME: move this into cc.cmdCompileObject()
    96  	for _, cfile := range args.Sources {
    97  		ofile := cc.TempDir + "/" + cfile + ".o"
    98  		os.MkdirAll(filepath.Dir(ofile), 0755)
    99  		objs = append(objs, ofile)
   100  		cc2 := CCompilerGCC{CompilerInfo: cc.CompilerInfo, TempDir: cc.TempDir}
   101  		cc2.cmdline = cc.CompilerInfo.Command
   102  		cc2.cmdDefines(args.Defines)
   103  		cc2.cmdPkgImport(args.PkgImports)
   104  		cc2.cmdAppend("-o", ofile, "-c", cfile)
   105  		cc2.cmdAppend(args.Flags...)
   106  		cmdlines = append(cmdlines, cc2.cmdline)
   107  	}
   108  
   109  	outs, errs := cmd.RunGroup(cmdlines)
   110  	for idx, _ := range outs {
   111  		if outs[idx] != "" {
   112  			log.Println(outs[idx])
   113  		}
   114  		if errs[idx] != nil {
   115  			log.Printf("Compile object %s failed: %s", objs[idx], errs[idx])
   116  			return errs[idx]
   117  		}
   118  	}
   119  
   120  	cc.cmdAr(args.Output, objs)
   121  	return cc.cmdExec()
   122  }
   123  
   124  func (cc CCompilerGCC) CompileLibraryShared(args base.CompilerArg) error {
   125  	cc.cmdCC(args.Output, args.Sources)
   126  	cc.cmdPkgImport(args.PkgImports)
   127  	cc.cmdDefines(args.Defines)
   128  	cc.cmdShared()
   129  	cc.cmdSoName(args.DllName)
   130  	cc.cmdAppend(args.Flags...)
   131  	return cc.cmdExec()
   132  }
   133  
   134  // FIXME: need to probe objdump
   135  func (cc CCompilerGCC) elfDepends(src string) []string {
   136  	libs, err := ELFDepends([]string{}, src)
   137  	if err != nil {
   138  		log.Println("CCompiler: ELFDepends failed", err)
   139  	}
   140  	return libs
   141  }
   142  
   143  func (cc CCompilerGCC) toolObjdump() []string {
   144  	return []string{}
   145  }
   146  
   147  func (cc CCompilerGCC) binaryArch(fn string) string {
   148  	arch, err := ELFArch(cc.toolObjdump(), fn)
   149  	if err != nil {
   150  		log.Println("CCompiler: ELFDepends failed", err)
   151  	}
   152  	return arch
   153  }
   154  
   155  // FIXME: check type and format
   156  func (cc CCompilerGCC) BinaryInfo(fn string) base.BinaryFileInfo {
   157  	return base.BinaryFileInfo{
   158  		Filename:   fn,
   159  		Depends:    cc.elfDepends(fn),
   160  		BinaryArch: cc.binaryArch(fn),
   161  	}
   162  }
   163  
   164  func NewCCompiler(ci base.CompilerInfo, tempdir string) base.CCompiler {
   165  	return CCompilerGCC{
   166  		CompilerInfo: ci,
   167  		TempDir:      tempdir,
   168  	}
   169  }