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 }