All checks were successful
build-dsl-smoke / Build judge (push) Successful in 12s
build-dsl-smoke / debug / clang / linux (push) Successful in 6s
build-dsl-smoke / debug / gcc / linux (push) Successful in 8s
build-dsl-smoke / release / clang / linux (push) Successful in 8s
build-dsl-smoke / release / gcc / linux (push) Successful in 6s
build-dsl-smoke / sanitized / clang / linux (push) Successful in 8s
build-dsl-smoke / sanitized / gcc / linux (push) Successful in 7s
build-dsl-smoke / debug / clang / windows (push) Successful in 13s
build-dsl-smoke / debug-valgrind / gcc / linux (push) Successful in 14s
build-dsl-smoke / release / clang / windows (push) Successful in 16s
build-dsl-smoke / debug / msvc / windows (push) Successful in 18s
build-dsl-smoke / release / msvc / windows (push) Successful in 17s
build-dsl-smoke / SUMMARY (push) Successful in 4s
Release / Build & publish (push) Successful in 48s
Reviewed-on: #1
199 lines
4.3 KiB
Go
199 lines
4.3 KiB
Go
package runner
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/Mond1c/judge/dsl"
|
|
)
|
|
|
|
type CompilerClass int
|
|
|
|
const (
|
|
CompilerUnknown CompilerClass = iota
|
|
CompilerGNU
|
|
CompilerMSVC
|
|
)
|
|
|
|
type Toolchain struct {
|
|
Class CompilerClass
|
|
Binary string
|
|
Name string
|
|
}
|
|
|
|
func ResolveToolchain(ccEnv string) Toolchain {
|
|
if ccEnv == "" {
|
|
ccEnv = defaultCC()
|
|
}
|
|
lower := strings.ToLower(ccEnv)
|
|
switch lower {
|
|
case "gcc", "g++":
|
|
return Toolchain{Class: CompilerGNU, Binary: ccEnv, Name: "gcc"}
|
|
case "clang", "clang++":
|
|
return Toolchain{Class: CompilerGNU, Binary: ccEnv, Name: "clang"}
|
|
case "cl", "cl.exe", "msvc":
|
|
return Toolchain{Class: CompilerMSVC, Binary: "cl", Name: "msvc"}
|
|
case "clang-cl", "clang-cl.exe":
|
|
return Toolchain{Class: CompilerMSVC, Binary: "clang-cl", Name: "clang-cl"}
|
|
case "cc":
|
|
return Toolchain{Class: CompilerGNU, Binary: "cc", Name: "cc"}
|
|
default:
|
|
return Toolchain{Class: CompilerGNU, Binary: ccEnv, Name: lower}
|
|
}
|
|
}
|
|
|
|
func ResolveToolchainSpec(spec *dsl.ToolchainSpec) Toolchain {
|
|
inferred := ResolveToolchain(spec.Name)
|
|
binary := spec.Binary
|
|
if binary == "" {
|
|
binary = inferred.Binary
|
|
}
|
|
var class CompilerClass
|
|
switch spec.Class {
|
|
case "gnu":
|
|
class = CompilerGNU
|
|
case "msvc":
|
|
class = CompilerMSVC
|
|
default:
|
|
class = inferred.Class
|
|
}
|
|
return Toolchain{Class: class, Binary: binary, Name: spec.Name}
|
|
}
|
|
|
|
func defaultCC() string {
|
|
if runtime.GOOS == "windows" {
|
|
return "cl"
|
|
}
|
|
return "cc"
|
|
}
|
|
|
|
func Compile(cfg dsl.BuildConfig, tc Toolchain, outputPath string) ([]string, error) {
|
|
switch tc.Class {
|
|
case CompilerGNU:
|
|
return compileGNU(cfg, tc, outputPath), nil
|
|
case CompilerMSVC:
|
|
return compileMSVC(cfg, tc, outputPath), nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown compiler class for toolchain %q", tc.Name)
|
|
}
|
|
}
|
|
|
|
func compileGNU(cfg dsl.BuildConfig, tc Toolchain, outputPath string) []string {
|
|
argv := []string{tc.Binary}
|
|
|
|
if cfg.Standard != "" {
|
|
argv = append(argv, "-std="+cfg.Standard)
|
|
}
|
|
|
|
switch cfg.Profile {
|
|
case dsl.ProfileRelease:
|
|
argv = append(argv, "-O2")
|
|
case dsl.ProfileDebug:
|
|
argv = append(argv, "-O0", "-g")
|
|
case dsl.ProfileSanitized:
|
|
argv = append(argv, "-O1", "-g", "-fno-omit-frame-pointer")
|
|
}
|
|
|
|
switch cfg.Warnings {
|
|
case dsl.WarningsStrict:
|
|
argv = append(argv, "-Wall", "-Wextra")
|
|
case dsl.WarningsPedantic:
|
|
argv = append(argv, "-Wall", "-Wextra", "-Wpedantic")
|
|
}
|
|
|
|
if len(cfg.Sanitize) > 0 {
|
|
argv = append(argv, "-fsanitize="+strings.Join(cfg.Sanitize, ","))
|
|
}
|
|
|
|
for _, inc := range cfg.Includes {
|
|
argv = append(argv, "-I"+inc)
|
|
}
|
|
|
|
for _, k := range sortedKeys(cfg.Defines) {
|
|
v := cfg.Defines[k]
|
|
if v == "" {
|
|
argv = append(argv, "-D"+k)
|
|
} else {
|
|
argv = append(argv, fmt.Sprintf("-D%s=%s", k, v))
|
|
}
|
|
}
|
|
|
|
argv = append(argv, cfg.Extra...)
|
|
argv = append(argv, cfg.Sources...)
|
|
argv = append(argv, "-o", outputPath)
|
|
|
|
for _, lib := range cfg.Link {
|
|
argv = append(argv, "-l"+lib)
|
|
}
|
|
return argv
|
|
}
|
|
|
|
func compileMSVC(cfg dsl.BuildConfig, tc Toolchain, outputPath string) []string {
|
|
argv := []string{tc.Binary, "/nologo"}
|
|
|
|
if cfg.Standard != "" {
|
|
argv = append(argv, "/std:"+cfg.Standard)
|
|
}
|
|
|
|
switch cfg.Profile {
|
|
case dsl.ProfileRelease:
|
|
argv = append(argv, "/O2")
|
|
case dsl.ProfileDebug:
|
|
argv = append(argv, "/Od", "/Zi")
|
|
case dsl.ProfileSanitized:
|
|
argv = append(argv, "/Od", "/Zi", "/fsanitize=address")
|
|
}
|
|
|
|
switch cfg.Warnings {
|
|
case dsl.WarningsStrict:
|
|
argv = append(argv, "/W4")
|
|
case dsl.WarningsPedantic:
|
|
argv = append(argv, "/W4", "/permissive-")
|
|
}
|
|
|
|
if containsString(cfg.Sanitize, "address") && cfg.Profile != dsl.ProfileSanitized {
|
|
argv = append(argv, "/fsanitize=address")
|
|
}
|
|
|
|
for _, inc := range cfg.Includes {
|
|
argv = append(argv, "/I"+inc)
|
|
}
|
|
|
|
for _, k := range sortedKeys(cfg.Defines) {
|
|
v := cfg.Defines[k]
|
|
if v == "" {
|
|
argv = append(argv, "/D"+k)
|
|
} else {
|
|
argv = append(argv, fmt.Sprintf("/D%s=%s", k, v))
|
|
}
|
|
}
|
|
|
|
argv = append(argv, cfg.Extra...)
|
|
argv = append(argv, cfg.Sources...)
|
|
argv = append(argv, "/Fe:"+outputPath)
|
|
return argv
|
|
}
|
|
|
|
func sortedKeys(m map[string]string) []string {
|
|
if len(m) == 0 {
|
|
return nil
|
|
}
|
|
keys := make([]string, 0, len(m))
|
|
for k := range m {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
return keys
|
|
}
|
|
|
|
func containsString(xs []string, x string) bool {
|
|
for _, v := range xs {
|
|
if v == x {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|