github.com/atrn/dcc@v0.0.0-20220806184050-4470d2553272/msvc.go (about) 1 // dcc - dependency-driven C/C++ compiler front end 2 // 3 // Copyright © A.Newman 2015. 4 // 5 // This source code is released under version 2 of the GNU Public License. 6 // See the file LICENSE for details. 7 // 8 9 package main 10 11 import ( 12 "bufio" 13 "bytes" 14 "fmt" 15 "io" 16 "io/ioutil" 17 "os" 18 "os/exec" 19 "path/filepath" 20 "strings" 21 ) 22 23 type msvcCompiler struct { 24 } 25 26 func (cl *msvcCompiler) Name() string { 27 return "cl" 28 } 29 30 func msvcScrapeShowIncludes(r io.Reader, deps io.Writer, nonDeps io.Writer, source string) { 31 const prefix = "Note: including file:" 32 scanner := bufio.NewScanner(r) 33 for scanner.Scan() { 34 line := scanner.Text() 35 if strings.HasPrefix(line, prefix) { 36 filename := strings.TrimSpace(strings.TrimPrefix(line, prefix)) 37 fmt.Fprintln(deps, filename) 38 } else if line != source { 39 fmt.Fprintln(nonDeps, line) 40 } 41 } 42 } 43 44 func (cl *msvcCompiler) Compile(source, object, deps string, options []string, stderr io.Writer) error { 45 r, w, err := os.Pipe() 46 if err != nil { 47 return err 48 } 49 defer r.Close() 50 defer w.Close() 51 52 depsFile, err := os.Create(deps) 53 if err != nil { 54 return err 55 } 56 57 fmt.Fprintln(depsFile, object) 58 59 go msvcScrapeShowIncludes(r, depsFile, os.Stdout, filepath.Base(source)) 60 61 args := append([]string{}, options...) 62 args = append(args, "/nologo", "/showIncludes", "/c", source, "/Fo"+object) 63 cmd := exec.Command(cl.Name(), args...) 64 cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, w, stderr 65 err = cmd.Run() 66 err2 := depsFile.Close() 67 if err != nil { 68 os.Remove(deps) 69 return err 70 } 71 if err2 != nil { 72 os.Remove(deps) 73 return err2 74 } 75 return err 76 } 77 78 func (cl *msvcCompiler) ReadDependencies(path string) (string, []string, error) { 79 data, err := ioutil.ReadFile(path) 80 if err != nil { 81 return "", nil, err 82 } 83 84 input := bufio.NewScanner(bytes.NewReader(data)) 85 if !input.Scan() { 86 return "", nil, ErrUnexpectedEOF 87 } 88 89 target := input.Text() 90 91 var filenames = make([]string, 0, 1000) 92 for input.Scan() { 93 filename := input.Text() 94 filenames = append(filenames, filename) 95 } 96 97 return target, filenames, nil 98 } 99 100 // NewMsvcCompiler returns a CompilerDriver using Microsoft's 101 // cl.exe C/C++ compiler. 102 func NewMsvcCompiler() Compiler { 103 return &msvcCompiler{} 104 } 105 106 func (cl *msvcCompiler) DefineExecutableArgs(exeName string) []string { 107 args := make([]string, 1) 108 args[0] = fmt.Sprintf("/Fe%s", exeName) 109 return args 110 }