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  }