main: move compile options to compileopts package
Этот коммит содержится в:
родитель
ef600965aa
коммит
59cc901340
3 изменённых файлов: 83 добавлений и 80 удалений
21
compileopts/options.go
Обычный файл
21
compileopts/options.go
Обычный файл
|
@ -0,0 +1,21 @@
|
||||||
|
package compileopts
|
||||||
|
|
||||||
|
// Options contains extra options to give to the compiler. These options are
|
||||||
|
// usually passed from the command line.
|
||||||
|
type Options struct {
|
||||||
|
Opt string
|
||||||
|
GC string
|
||||||
|
PanicStrategy string
|
||||||
|
Scheduler string
|
||||||
|
PrintIR bool
|
||||||
|
DumpSSA bool
|
||||||
|
VerifyIR bool
|
||||||
|
Debug bool
|
||||||
|
PrintSizes string
|
||||||
|
CFlags []string
|
||||||
|
LDFlags []string
|
||||||
|
Tags string
|
||||||
|
WasmAbi string
|
||||||
|
HeapSize int64
|
||||||
|
TestConfig TestConfig
|
||||||
|
}
|
126
main.go
126
main.go
|
@ -48,40 +48,22 @@ func (e *multiError) Error() string {
|
||||||
return e.Errs[0].Error()
|
return e.Errs[0].Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildConfig struct {
|
|
||||||
opt string
|
|
||||||
gc string
|
|
||||||
panicStrategy string
|
|
||||||
scheduler string
|
|
||||||
printIR bool
|
|
||||||
dumpSSA bool
|
|
||||||
verifyIR bool
|
|
||||||
debug bool
|
|
||||||
printSizes string
|
|
||||||
cFlags []string
|
|
||||||
ldFlags []string
|
|
||||||
tags string
|
|
||||||
wasmAbi string
|
|
||||||
heapSize int64
|
|
||||||
testConfig compileopts.TestConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function for Compiler object.
|
// Helper function for Compiler object.
|
||||||
func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *BuildConfig, action func(string) error) error {
|
func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, options *compileopts.Options, action func(string) error) error {
|
||||||
if config.gc == "" && spec.GC != "" {
|
if options.GC == "" && spec.GC != "" {
|
||||||
config.gc = spec.GC
|
options.GC = spec.GC
|
||||||
}
|
}
|
||||||
|
|
||||||
root := goenv.Get("TINYGOROOT")
|
root := goenv.Get("TINYGOROOT")
|
||||||
|
|
||||||
// Merge and adjust CFlags.
|
// Merge and adjust CFlags.
|
||||||
cflags := append([]string{}, config.cFlags...)
|
cflags := append([]string{}, options.CFlags...)
|
||||||
for _, flag := range spec.CFlags {
|
for _, flag := range spec.CFlags {
|
||||||
cflags = append(cflags, strings.Replace(flag, "{root}", root, -1))
|
cflags = append(cflags, strings.Replace(flag, "{root}", root, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge and adjust LDFlags.
|
// Merge and adjust LDFlags.
|
||||||
ldflags := append([]string{}, config.ldFlags...)
|
ldflags := append([]string{}, options.LDFlags...)
|
||||||
for _, flag := range spec.LDFlags {
|
for _, flag := range spec.LDFlags {
|
||||||
ldflags = append(ldflags, strings.Replace(flag, "{root}", root, -1))
|
ldflags = append(ldflags, strings.Replace(flag, "{root}", root, -1))
|
||||||
}
|
}
|
||||||
|
@ -101,12 +83,12 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
for i := 1; i <= minor; i++ {
|
for i := 1; i <= minor; i++ {
|
||||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||||
}
|
}
|
||||||
if extraTags := strings.Fields(config.tags); len(extraTags) != 0 {
|
if extraTags := strings.Fields(options.Tags); len(extraTags) != 0 {
|
||||||
tags = append(tags, extraTags...)
|
tags = append(tags, extraTags...)
|
||||||
}
|
}
|
||||||
scheduler := spec.Scheduler
|
scheduler := spec.Scheduler
|
||||||
if config.scheduler != "" {
|
if options.Scheduler != "" {
|
||||||
scheduler = config.scheduler
|
scheduler = options.Scheduler
|
||||||
}
|
}
|
||||||
compilerConfig := &compileopts.Config{
|
compilerConfig := &compileopts.Config{
|
||||||
Triple: spec.Triple,
|
Triple: spec.Triple,
|
||||||
|
@ -114,20 +96,20 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
Features: spec.Features,
|
Features: spec.Features,
|
||||||
GOOS: spec.GOOS,
|
GOOS: spec.GOOS,
|
||||||
GOARCH: spec.GOARCH,
|
GOARCH: spec.GOARCH,
|
||||||
GC: config.gc,
|
GC: options.GC,
|
||||||
PanicStrategy: config.panicStrategy,
|
PanicStrategy: options.PanicStrategy,
|
||||||
Scheduler: scheduler,
|
Scheduler: scheduler,
|
||||||
CFlags: cflags,
|
CFlags: cflags,
|
||||||
LDFlags: ldflags,
|
LDFlags: ldflags,
|
||||||
ClangHeaders: getClangHeaderPath(root),
|
ClangHeaders: getClangHeaderPath(root),
|
||||||
Debug: config.debug,
|
Debug: options.Debug,
|
||||||
DumpSSA: config.dumpSSA,
|
DumpSSA: options.DumpSSA,
|
||||||
VerifyIR: config.verifyIR,
|
VerifyIR: options.VerifyIR,
|
||||||
TINYGOROOT: root,
|
TINYGOROOT: root,
|
||||||
GOROOT: goroot,
|
GOROOT: goroot,
|
||||||
GOPATH: goenv.Get("GOPATH"),
|
GOPATH: goenv.Get("GOPATH"),
|
||||||
BuildTags: tags,
|
BuildTags: tags,
|
||||||
TestConfig: config.testConfig,
|
TestConfig: options.TestConfig,
|
||||||
}
|
}
|
||||||
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
c, err := compiler.NewCompiler(pkgName, compilerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -142,7 +124,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
}
|
}
|
||||||
return &multiError{errs}
|
return &multiError{errs}
|
||||||
}
|
}
|
||||||
if config.printIR {
|
if options.PrintIR {
|
||||||
fmt.Println("; Generated LLVM IR:")
|
fmt.Println("; Generated LLVM IR:")
|
||||||
fmt.Println(c.IR())
|
fmt.Println(c.IR())
|
||||||
}
|
}
|
||||||
|
@ -150,7 +132,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
return errors.New("verification error after IR construction")
|
return errors.New("verification error after IR construction")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = interp.Run(c.Module(), config.dumpSSA)
|
err = interp.Run(c.Module(), options.DumpSSA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -167,7 +149,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
// keep functions interoperable, pass int64 types as pointers to
|
// keep functions interoperable, pass int64 types as pointers to
|
||||||
// stack-allocated values.
|
// stack-allocated values.
|
||||||
// Use -wasm-abi=generic to disable this behaviour.
|
// Use -wasm-abi=generic to disable this behaviour.
|
||||||
if config.wasmAbi == "js" && strings.HasPrefix(spec.Triple, "wasm") {
|
if options.WasmAbi == "js" && strings.HasPrefix(spec.Triple, "wasm") {
|
||||||
err := c.ExternalInt64AsPtr()
|
err := c.ExternalInt64AsPtr()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -176,7 +158,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
|
|
||||||
// Optimization levels here are roughly the same as Clang, but probably not
|
// Optimization levels here are roughly the same as Clang, but probably not
|
||||||
// exactly.
|
// exactly.
|
||||||
switch config.opt {
|
switch options.Opt {
|
||||||
case "none:", "0":
|
case "none:", "0":
|
||||||
err = c.Optimize(0, 0, 0) // -O0
|
err = c.Optimize(0, 0, 0) // -O0
|
||||||
case "1":
|
case "1":
|
||||||
|
@ -188,7 +170,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
case "z":
|
case "z":
|
||||||
err = c.Optimize(2, 2, 5) // -Oz, default
|
err = c.Optimize(2, 2, 5) // -Oz, default
|
||||||
default:
|
default:
|
||||||
err = errors.New("unknown optimization level: -opt=" + config.opt)
|
err = errors.New("unknown optimization level: -opt=" + options.Opt)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -255,7 +237,7 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
if spec.GOARCH == "wasm" {
|
if spec.GOARCH == "wasm" {
|
||||||
// Round heap size to next multiple of 65536 (the WebAssembly page
|
// Round heap size to next multiple of 65536 (the WebAssembly page
|
||||||
// size).
|
// size).
|
||||||
heapSize := (config.heapSize + (65536 - 1)) &^ (65536 - 1)
|
heapSize := (options.HeapSize + (65536 - 1)) &^ (65536 - 1)
|
||||||
ldflags = append(ldflags, "--initial-memory="+strconv.FormatInt(heapSize, 10))
|
ldflags = append(ldflags, "--initial-memory="+strconv.FormatInt(heapSize, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,12 +279,12 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
return &commandError{"failed to link", executable, err}
|
return &commandError{"failed to link", executable, err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.printSizes == "short" || config.printSizes == "full" {
|
if options.PrintSizes == "short" || options.PrintSizes == "full" {
|
||||||
sizes, err := Sizes(executable)
|
sizes, err := Sizes(executable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if config.printSizes == "short" {
|
if options.PrintSizes == "short" {
|
||||||
fmt.Printf(" code data bss | flash ram\n")
|
fmt.Printf(" code data bss | flash ram\n")
|
||||||
fmt.Printf("%7d %7d %7d | %7d %7d\n", sizes.Code, sizes.Data, sizes.BSS, sizes.Code+sizes.Data, sizes.Data+sizes.BSS)
|
fmt.Printf("%7d %7d %7d | %7d %7d\n", sizes.Code, sizes.Data, sizes.BSS, sizes.Code+sizes.Data, sizes.Data+sizes.BSS)
|
||||||
} else {
|
} else {
|
||||||
|
@ -335,13 +317,13 @@ func Compile(pkgName, outpath string, spec *compileopts.TargetSpec, config *Buil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Build(pkgName, outpath, target string, config *BuildConfig) error {
|
func Build(pkgName, outpath, target string, options *compileopts.Options) error {
|
||||||
spec, err := compileopts.LoadTarget(target)
|
spec, err := compileopts.LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compile(pkgName, outpath, spec, config, func(tmppath string) error {
|
return Compile(pkgName, outpath, spec, options, func(tmppath string) error {
|
||||||
if err := os.Rename(tmppath, outpath); err != nil {
|
if err := os.Rename(tmppath, outpath); err != nil {
|
||||||
// Moving failed. Do a file copy.
|
// Moving failed. Do a file copy.
|
||||||
inf, err := os.Open(tmppath)
|
inf, err := os.Open(tmppath)
|
||||||
|
@ -369,15 +351,15 @@ func Build(pkgName, outpath, target string, config *BuildConfig) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test(pkgName, target string, config *BuildConfig) error {
|
func Test(pkgName, target string, options *compileopts.Options) error {
|
||||||
spec, err := compileopts.LoadTarget(target)
|
spec, err := compileopts.LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
spec.BuildTags = append(spec.BuildTags, "test")
|
spec.BuildTags = append(spec.BuildTags, "test")
|
||||||
config.testConfig.CompileTestBinary = true
|
options.TestConfig.CompileTestBinary = true
|
||||||
return Compile(pkgName, ".elf", spec, config, func(tmppath string) error {
|
return Compile(pkgName, ".elf", spec, options, func(tmppath string) error {
|
||||||
cmd := exec.Command(tmppath)
|
cmd := exec.Command(tmppath)
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
@ -396,7 +378,7 @@ func Test(pkgName, target string, config *BuildConfig) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flash(pkgName, target, port string, config *BuildConfig) error {
|
func Flash(pkgName, target, port string, options *compileopts.Options) error {
|
||||||
spec, err := compileopts.LoadTarget(target)
|
spec, err := compileopts.LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -432,7 +414,7 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
|
||||||
return errors.New("unknown flash method: " + spec.FlashMethod)
|
return errors.New("unknown flash method: " + spec.FlashMethod)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compile(pkgName, fileExt, spec, config, func(tmppath string) error {
|
return Compile(pkgName, fileExt, spec, options, func(tmppath string) error {
|
||||||
// do we need port reset to put MCU into bootloader mode?
|
// do we need port reset to put MCU into bootloader mode?
|
||||||
if spec.PortReset == "true" {
|
if spec.PortReset == "true" {
|
||||||
err := touchSerialPortAt1200bps(port)
|
err := touchSerialPortAt1200bps(port)
|
||||||
|
@ -503,7 +485,7 @@ func Flash(pkgName, target, port string, config *BuildConfig) error {
|
||||||
//
|
//
|
||||||
// Note: this command is expected to execute just before exiting, as it
|
// Note: this command is expected to execute just before exiting, as it
|
||||||
// modifies global state.
|
// modifies global state.
|
||||||
func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig) error {
|
func FlashGDB(pkgName, target, port string, ocdOutput bool, options *compileopts.Options) error {
|
||||||
spec, err := compileopts.LoadTarget(target)
|
spec, err := compileopts.LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -513,7 +495,7 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
|
||||||
return errors.New("gdb not configured in the target specification")
|
return errors.New("gdb not configured in the target specification")
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compile(pkgName, "", spec, config, func(tmppath string) error {
|
return Compile(pkgName, "", spec, options, func(tmppath string) error {
|
||||||
// Find a good way to run GDB.
|
// Find a good way to run GDB.
|
||||||
gdbInterface := spec.FlashMethod
|
gdbInterface := spec.FlashMethod
|
||||||
switch gdbInterface {
|
switch gdbInterface {
|
||||||
|
@ -594,13 +576,13 @@ func FlashGDB(pkgName, target, port string, ocdOutput bool, config *BuildConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile and run the given program, directly or in an emulator.
|
// Compile and run the given program, directly or in an emulator.
|
||||||
func Run(pkgName, target string, config *BuildConfig) error {
|
func Run(pkgName, target string, options *compileopts.Options) error {
|
||||||
spec, err := compileopts.LoadTarget(target)
|
spec, err := compileopts.LoadTarget(target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return Compile(pkgName, ".elf", spec, config, func(tmppath string) error {
|
return Compile(pkgName, ".elf", spec, options, func(tmppath string) error {
|
||||||
if len(spec.Emulator) == 0 {
|
if len(spec.Emulator) == 0 {
|
||||||
// Run directly.
|
// Run directly.
|
||||||
cmd := exec.Command(tmppath)
|
cmd := exec.Command(tmppath)
|
||||||
|
@ -777,26 +759,26 @@ func main() {
|
||||||
command := os.Args[1]
|
command := os.Args[1]
|
||||||
|
|
||||||
flag.CommandLine.Parse(os.Args[2:])
|
flag.CommandLine.Parse(os.Args[2:])
|
||||||
config := &BuildConfig{
|
options := &compileopts.Options{
|
||||||
opt: *opt,
|
Opt: *opt,
|
||||||
gc: *gc,
|
GC: *gc,
|
||||||
panicStrategy: *panicStrategy,
|
PanicStrategy: *panicStrategy,
|
||||||
scheduler: *scheduler,
|
Scheduler: *scheduler,
|
||||||
printIR: *printIR,
|
PrintIR: *printIR,
|
||||||
dumpSSA: *dumpSSA,
|
DumpSSA: *dumpSSA,
|
||||||
verifyIR: *verifyIR,
|
VerifyIR: *verifyIR,
|
||||||
debug: !*nodebug,
|
Debug: !*nodebug,
|
||||||
printSizes: *printSize,
|
PrintSizes: *printSize,
|
||||||
tags: *tags,
|
Tags: *tags,
|
||||||
wasmAbi: *wasmAbi,
|
WasmAbi: *wasmAbi,
|
||||||
}
|
}
|
||||||
|
|
||||||
if *cFlags != "" {
|
if *cFlags != "" {
|
||||||
config.cFlags = strings.Split(*cFlags, " ")
|
options.CFlags = strings.Split(*cFlags, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *ldFlags != "" {
|
if *ldFlags != "" {
|
||||||
config.ldFlags = strings.Split(*ldFlags, " ")
|
options.LDFlags = strings.Split(*ldFlags, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *panicStrategy != "print" && *panicStrategy != "trap" {
|
if *panicStrategy != "print" && *panicStrategy != "trap" {
|
||||||
|
@ -806,7 +788,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if config.heapSize, err = parseSize(*heapSize); err != nil {
|
if options.HeapSize, err = parseSize(*heapSize); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
|
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
|
||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -833,7 +815,7 @@ func main() {
|
||||||
if target == "" && filepath.Ext(*outpath) == ".wasm" {
|
if target == "" && filepath.Ext(*outpath) == ".wasm" {
|
||||||
target = "wasm"
|
target = "wasm"
|
||||||
}
|
}
|
||||||
err := Build(pkgName, *outpath, target, config)
|
err := Build(pkgName, *outpath, target, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "build-builtins":
|
case "build-builtins":
|
||||||
// Note: this command is only meant to be used while making a release!
|
// Note: this command is only meant to be used while making a release!
|
||||||
|
@ -856,15 +838,15 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if command == "flash" {
|
if command == "flash" {
|
||||||
err := Flash(flag.Arg(0), *target, *port, config)
|
err := Flash(flag.Arg(0), *target, *port, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
} else {
|
} else {
|
||||||
if !config.debug {
|
if !options.Debug {
|
||||||
fmt.Fprintln(os.Stderr, "Debug disabled while running gdb?")
|
fmt.Fprintln(os.Stderr, "Debug disabled while running gdb?")
|
||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := FlashGDB(flag.Arg(0), *target, *port, *ocdOutput, config)
|
err := FlashGDB(flag.Arg(0), *target, *port, *ocdOutput, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
}
|
}
|
||||||
case "run":
|
case "run":
|
||||||
|
@ -873,7 +855,7 @@ func main() {
|
||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := Run(flag.Arg(0), *target, config)
|
err := Run(flag.Arg(0), *target, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "test":
|
case "test":
|
||||||
pkgName := "."
|
pkgName := "."
|
||||||
|
@ -884,7 +866,7 @@ func main() {
|
||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := Test(pkgName, *target, config)
|
err := Test(pkgName, *target, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "clean":
|
case "clean":
|
||||||
// remove cache directory
|
// remove cache directory
|
||||||
|
|
16
main_test.go
16
main_test.go
|
@ -115,14 +115,14 @@ func runTest(path, tmpdir string, target string, t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the test binary.
|
// Build the test binary.
|
||||||
config := &BuildConfig{
|
config := &compileopts.Options{
|
||||||
opt: "z",
|
Opt: "z",
|
||||||
printIR: false,
|
PrintIR: false,
|
||||||
dumpSSA: false,
|
DumpSSA: false,
|
||||||
verifyIR: true,
|
VerifyIR: true,
|
||||||
debug: false,
|
Debug: false,
|
||||||
printSizes: "",
|
PrintSizes: "",
|
||||||
wasmAbi: "js",
|
WasmAbi: "js",
|
||||||
}
|
}
|
||||||
binary := filepath.Join(tmpdir, "test")
|
binary := filepath.Join(tmpdir, "test")
|
||||||
err = Build("./"+path, binary, target, config)
|
err = Build("./"+path, binary, target, config)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче