Added build statistics

This commit is contained in:
Eduard Urbach 2025-02-05 23:10:50 +01:00
parent 12894dbcc5
commit 37afbde0da
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
6 changed files with 54 additions and 18 deletions

View File

@ -42,8 +42,12 @@ func buildWithArgs(args []string) (*build.Build, error) {
case "-d", "--dry": case "-d", "--dry":
config.Dry = true config.Dry = true
case "-s", "--statistics":
config.Statistics = true
case "-v", "--verbose": case "-v", "--verbose":
config.Assembler = true config.Assembler = true
config.Statistics = true
case "--arch": case "--arch":
i++ i++
@ -105,6 +109,10 @@ func makeExecutable(b *build.Build) error {
result.PrintInstructions() result.PrintInstructions()
} }
if config.Statistics {
result.PrintStatistics()
}
if config.Dry { if config.Dry {
return nil return nil
} }

View File

@ -7,19 +7,22 @@ import (
// Help shows the command line argument usage. // Help shows the command line argument usage.
func Help(w io.Writer, code int) int { func Help(w io.Writer, code int) int {
fmt.Fprintln(w, `Usage: q [command] [options] fmt.Fprintln(w, `Usage:
commands: q [command] [options]
build [directory | file] Commands:
run [directory | file]
help
system
build options: build [directory | file] build an executable from a file or directory
--arch [arch] cross-compile for a different CPU architecture (x86, arm or riscv)
--assembler, -a show assembler instructions
--dry, -d skip writing the executable to disk
--os [os] cross-compile for a different OS (linux, mac or windows)
--statistics, -s show statistics
--verbose, -v show everything
--assembler, -a Show assembler instructions. run [directory | file] build and run the executable
--comments, -c Show assembler comments. system show system information
--verbose, -v Show everything.`) help show this help`)
return code return code
} }

View File

@ -105,6 +105,7 @@ func Compile(files <-chan *fs.File, functions <-chan *core.Function, structs <-c
result.Main = main result.Main = main
result.Functions = allFunctions result.Functions = allFunctions
result.finalize()
return result, nil return result, nil
} }

View File

@ -2,6 +2,7 @@ package compiler
import ( import (
"bufio" "bufio"
"fmt"
"io" "io"
"os" "os"
@ -13,6 +14,7 @@ import (
"git.akyoto.dev/cli/q/src/macho" "git.akyoto.dev/cli/q/src/macho"
"git.akyoto.dev/cli/q/src/pe" "git.akyoto.dev/cli/q/src/pe"
"git.akyoto.dev/cli/q/src/x64" "git.akyoto.dev/cli/q/src/x64"
"git.akyoto.dev/go/color/ansi"
) )
// Result contains all the compiled functions in a build. // Result contains all the compiled functions in a build.
@ -21,10 +23,13 @@ type Result struct {
Functions map[string]*core.Function Functions map[string]*core.Function
InstructionCount int InstructionCount int
DataCount int DataCount int
Code []byte
Data []byte
DLLs dll.List
} }
// finalize generates the final machine code. // finalize generates the final machine code.
func (r *Result) finalize() ([]byte, []byte, dll.List) { func (r *Result) finalize() {
// This will be the entry point of the executable. // This will be the entry point of the executable.
// The only job of the entry function is to call `main` and exit cleanly. // The only job of the entry function is to call `main` and exit cleanly.
// The reason we call `main` instead of using `main` itself is to place // The reason we call `main` instead of using `main` itself is to place
@ -50,7 +55,7 @@ func (r *Result) finalize() ([]byte, []byte, dll.List) {
final.DLLCall("kernel32.ExitProcess") final.DLLCall("kernel32.ExitProcess")
} }
dlls := dll.List{ r.DLLs = dll.List{
{Name: "kernel32", Functions: []string{"ExitProcess"}}, {Name: "kernel32", Functions: []string{"ExitProcess"}},
} }
@ -61,7 +66,7 @@ func (r *Result) finalize() ([]byte, []byte, dll.List) {
for _, library := range f.DLLs { for _, library := range f.DLLs {
for _, fn := range library.Functions { for _, fn := range library.Functions {
dlls = dlls.Append(library.Name, fn) r.DLLs = r.DLLs.Append(library.Name, fn)
} }
} }
}) })
@ -82,8 +87,7 @@ func (r *Result) finalize() ([]byte, []byte, dll.List) {
final.DLLCall("kernel32.ExitProcess") final.DLLCall("kernel32.ExitProcess")
} }
code, data := final.Finalize(dlls) r.Code, r.Data = final.Finalize(r.DLLs)
return code, data, dlls
} }
// eachFunction recursively finds all the calls to external functions. // eachFunction recursively finds all the calls to external functions.
@ -119,10 +123,17 @@ func (r *Result) PrintInstructions() {
}) })
} }
// PrintStatistics shows the statistics.
func (r *Result) PrintStatistics() {
ansi.Dim.Println("╭──────────────────────────────────────────────────────────────────────────────╮")
ansi.Dim.Printf("│ %-44s%-32s │\n", "Code:", fmt.Sprintf("%d bytes", len(r.Code)))
ansi.Dim.Printf("│ %-44s%-32s │\n", "Data:", fmt.Sprintf("%d bytes", len(r.Data)))
ansi.Dim.Println("╰──────────────────────────────────────────────────────────────────────────────╯")
}
// Write writes the executable to the given writer. // Write writes the executable to the given writer.
func (r *Result) Write(writer io.Writer) error { func (r *Result) Write(writer io.Writer) error {
code, data, dlls := r.finalize() return write(writer, r.Code, r.Data, r.DLLs)
return write(writer, code, data, dlls)
} }
// Write writes an executable file to disk. // Write writes an executable file to disk.

View File

@ -14,9 +14,12 @@ const (
) )
var ( var (
// Shows the assembly instructions at the end of the compilation. // Shows the assembly instructions at the end.
Assembler bool Assembler bool
// Shows statistics at the end.
Statistics bool
// Calculates the result of operations on constants at compile time. // Calculates the result of operations on constants at compile time.
ConstantFold bool ConstantFold bool
@ -33,6 +36,7 @@ var (
// Reset resets the configuration to its default values. // Reset resets the configuration to its default values.
func Reset() { func Reset() {
Assembler = false Assembler = false
Statistics = false
ConstantFold = true ConstantFold = true
Dry = false Dry = false
TargetArch = runtime.GOARCH TargetArch = runtime.GOARCH

View File

@ -12,6 +12,15 @@ import (
func (f *Function) PrintInstructions() { func (f *Function) PrintInstructions() {
ansi.Dim.Println("╭──────────────────────────────────────────────────────────────────────────────╮") ansi.Dim.Println("╭──────────────────────────────────────────────────────────────────────────────╮")
if len(f.Input) > 0 {
for i, input := range f.Input {
ansi.Dim.Printf("│ %-44s%-32s", input.Name, f.CPU.Input[i])
ansi.Dim.Print(" │\n")
}
ansi.Dim.Println("├──────────────────────────────────────────────────────────────────────────────┤")
}
for i, x := range f.Assembler.Instructions { for i, x := range f.Assembler.Instructions {
ansi.Dim.Print("│ ") ansi.Dim.Print("│ ")