func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, goRunTag string,
	st string, regexName *regexp.Regexp, notRegexName *regexp.Regexp, deleteTempFile bool, infiles ...string) (err error) {
	if len(infiles) == 0 {
		return
	}
	if outfile == "" || codecPkgPath == "" {
		err = errors.New("outfile and codec package path cannot be blank")
		return
	}
	if uid < 0 {
		uid = -uid
	}
	if uid == 0 {
		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
		uid = 101 + rr.Int63n(9777)
	}
	lastdir := filepath.Dir(outfile)
	absdir, err := filepath.Abs(lastdir)
	if err != nil {
		return
	}
	pkg, err := build.Default.ImportDir(absdir, build.AllowBinary)
	if err != nil {
		return
	}
	type tmplT struct {
		CodecPkgName    string
		CodecImportPath string
		ImportPath      string
		OutFile         string
		PackageName     string
		RandString      string
		BuildTag        string
		StructTags      string
		Types           []string
		CodecPkgFiles   bool
		UseUnsafe       bool
	}
	tv := tmplT{
		CodecPkgName:    genCodecPkg,
		OutFile:         outfile,
		CodecImportPath: codecPkgPath,
		BuildTag:        buildTag,
		UseUnsafe:       useUnsafe,
		RandString:      strconv.FormatInt(uid, 10),
		StructTags:      st,
	}
	tv.ImportPath = pkg.ImportPath
	if tv.ImportPath == tv.CodecImportPath {
		tv.CodecPkgFiles = true
		tv.CodecPkgName = "codec"
	}
	astfiles := make([]*ast.File, len(infiles))
	for i, infile := range infiles {
		if filepath.Dir(infile) != lastdir {
			err = errors.New("in files must all be in same directory as outfile")
			return
		}
		fset := token.NewFileSet()
		astfiles[i], err = parser.ParseFile(fset, infile, nil, 0)
		if err != nil {
			return
		}
		if i == 0 {
			tv.PackageName = astfiles[i].Name.Name
			if tv.PackageName == "main" {
				err = errors.New("codecgen cannot be run on types in the 'main' package")
				return
			}
		}
	}
	for _, f := range astfiles {
		for _, d := range f.Decls {
			if gd, ok := d.(*ast.GenDecl); ok {
				for _, dd := range gd.Specs {
					if td, ok := dd.(*ast.TypeSpec); ok {
						if len(td.Name.Name) == 0 {
							continue
						}
						switch td.Type.(type) {
						case *ast.StructType, *ast.Ident, *ast.MapType, *ast.ArrayType, *ast.ChanType:
							if regexName.FindStringIndex(td.Name.Name) != nil && notRegexName.FindStringIndex(td.Name.Name) == nil {
								tv.Types = append(tv.Types, td.Name.Name)
							}
						}
					}
				}
			}
		}
	}
	if len(tv.Types) == 0 {
		return
	}
	frunMainName := "codecgen-main-" + tv.RandString + ".generated.go"
	frunPkgName := "codecgen-pkg-" + tv.RandString + ".generated.go"
	if deleteTempFile {
		defer os.Remove(frunMainName)
		defer os.Remove(frunPkgName)
	}
	if _, err = gen1(frunMainName, genFrunMainTmpl, &tv); err != nil {
		return
	}
	if _, err = gen1(frunPkgName, genFrunPkgTmpl, &tv); err != nil {
		return
	}
	os.Remove(outfile)
	cmd := exec.Command("go", "run", "-tags="+goRunTag, frunMainName)  
	var buf bytes.Buffer
	cmd.Stdout = &buf
	cmd.Stderr = &buf
	if err = cmd.Run(); err != nil {
		err = fmt.Errorf("error running 'go run %s': %v, console: %s",
			frunMainName, err, buf.Bytes())
		return
	}
	os.Stdout.Write(buf.Bytes())
	return
}
Generate is given a list of *.go files to parse, and an output file (fout).

It finds all types T in the files, and it creates 2 tmp files (frun).
- main package file passed to 'go run'
- package level file which calls *genRunner.Selfer to write Selfer impls for each T.
We use a package level file so that it can reference unexported types in the package being worked on.
Tool then executes: "go run __frun__" which creates fout.
fout contains Codec(En|De)codeSelf implementations for every type T.
package main
import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"text/template"
	"time"
)
const genCodecPkg = "codec1978"  
const genFrunMainTmpl = ` 
package main
{{ if .Types }}import "{{ .ImportPath }}"{{ end }}
func main() {
	{{ $.PackageName }}.CodecGenTempWrite{{ .RandString }}()
}
`
const genFrunPkgTmpl = `
package {{ $.PackageName }}
import (
	{{ if not .CodecPkgFiles }}{{ .CodecPkgName }} "{{ .CodecImportPath }}"{{ end }}
	"os"
	"reflect"
	"bytes"
	"strings"
	"go/format"
)
func CodecGenTempWrite{{ .RandString }}() {
	fout, err := os.Create("{{ .OutFile }}")
	if err != nil {
		panic(err)
	}
	defer fout.Close()
	var out bytes.Buffer
	var typs []reflect.Type 
{{ range $index, $element := .Types }}
	var t{{ $index }} {{ . }}
	typs = append(typs, reflect.TypeOf(t{{ $index }}))
{{ end }}
	{{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}Gen(&out, "{{ .BuildTag }}", "{{ .PackageName }}", "{{ .RandString }}", {{ .UseUnsafe }}, {{ if not .CodecPkgFiles }}{{ .CodecPkgName }}.{{ end }}NewTypeInfos(strings.Split("{{ .StructTags }}", ",")), typs...)
	bout, err := format.Source(out.Bytes())
	if err != nil {
		fout.Write(out.Bytes())
		panic(err)
	}
	fout.Write(bout)
}
`