From b48d4876433345347325aba819d218832d5f2177 Mon Sep 17 00:00:00 2001 From: JetSetIlly Date: Wed, 8 Nov 2023 16:04:56 +0000 Subject: [PATCH] added version package Makefile now sets the version string for the project. the version package tries to set a meaningful version string if the project is not built with the Makefile added VERSION command --- Makefile | 55 +++++++++++++++-------- debugger/commands.go | 14 ++++++ debugger/commands_help.go | 3 ++ debugger/commands_template.go | 2 + gopher2600.go | 25 ++++++++++- gui/sdlimgui/platform.go | 9 ++-- version/doc.go | 18 ++++++++ version/version.go | 84 +++++++++++++++++++++++++++++++++++ 8 files changed, 187 insertions(+), 23 deletions(-) create mode 100644 version/doc.go create mode 100644 version/version.go diff --git a/Makefile b/Makefile index b945d79f..2ad14285 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,14 @@ +version = v0.27.0 pre-release + goBinary = go -gcflags = '-c 3 -B -wb=false' +gcflags = -c 3 -B -wb=false +ldflags = -s -w +ldflags_version = $(ldflags) -X 'github.com/jetsetilly/gopher2600/version.number=$(version)' profilingRom = /home/steve/Desktop/2600_dev/zackattack/waterbed-bouncers-2600/source/bouncers.bin +### support targets .PHONY: all clean tidy generate check_git check_glsl glsl_validate check_pandoc readme_spell all: @@ -62,48 +67,50 @@ race_debug: generate test ### profiling targets .PHONY: profile profile_cpu profile_cpu_play profile_cpu_debug profile_mem_play profile_mem_debug profile_trace +ldflags_profile= $(ldflags) -X 'github.com/jetsetilly/gopher2600/version.number=profiling' + profile: @echo use make targets profile_cpu, profile_mem, etc. profile_cpu: generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "performance mode running for 20s" @./gopher2600 performance -profile=cpu -duration=20s $(profilingRom) @$(goBinary) tool pprof -http : ./gopher2600 performance_cpu.profile profile_cpu_play: generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "use window close button to end (CTRL-C will quit the Makefile script)" @./gopher2600 play -profile=cpu -elf=none $(profilingRom) @$(goBinary) tool pprof -http : ./gopher2600 play_cpu.profile profile_cpu_debug : generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "use window close button to end (CTRL-C will quit the Makefile script)" @./gopher2600 debug -profile=cpu -elf=none $(profilingRom) @$(goBinary) tool pprof -http : ./gopher2600 debugger_cpu.profile profile_mem_play : generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "use window close button to end (CTRL-C will quit the Makefile script)" @./gopher2600 play -profile=mem -elf=none $(profilingRom) @$(goBinary) tool pprof -http : ./gopher2600 play_mem.profile profile_mem_debug : generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "use window close button to end (CTRL-C will quit the Makefile script)" @./gopher2600 debug -profile=mem -elf=none $(profilingRom) @$(goBinary) tool pprof -http : ./gopher2600 debugger_mem.profile profile_trace: generate test - @$(goBinary) build -gcflags $(gcflags) + @$(goBinary) build -gcflags "$(gcflags)" -ldflags "$(ldflags_profile)" @echo "performance mode running for 20s" @./gopher2600 performance -profile=trace -duration=20s $(profilingRom) @$(goBinary) tool trace -http : performance_trace.profile ### binary building targets for host platform -.PHONY: fontrendering build release +.PHONY: fontrendering build # whether or not we build with freetype font rendering depends on the platform. # for now freetype doesn't seem to work on MacOS with an M2 CPU @@ -114,15 +121,24 @@ fontrendering=imguifreetype endif build: fontrendering generate - $(goBinary) build -pgo=auto -gcflags $(gcflags) -trimpath -tags="$(fontrendering)" + $(goBinary) build -pgo=auto -gcflags "$(gcflags)" -trimpath -ldflags "$(ldflags_version)" -tags="$(fontrendering)" -release: fontrendering generate - $(goBinary) build -pgo=auto -gcflags $(gcflags) -trimpath -ldflags="-s -w" -tags="$(fontrendering) release" +### release building + +.PHONY: version_check release + +version_check : +ifndef version + $(error version is undefined) +endif + +release: version_check fontrendering generate + $(goBinary) build -pgo=auto -gcflags "$(gcflags)" -trimpath -ldflags "$(ldflags_version)" -tags="$(fontrendering) release" mv gopher2600 gopher2600_$(shell go env GOHOSTOS)_$(shell go env GOHOSTARCH) ### cross compilation for windows (tested when cross compiling from Linux) -.PHONY: check_rscr windows_manifest cross_windows cross_windows_development cross_winconsole_development +.PHONY: check_rscr windows_manifest cross_windows_release cross_windows_development cross_winconsole_development check_rscr: ifeq (, $(shell which rsrc)) @@ -132,14 +148,17 @@ endif windows_manifest: check_rscr rsrc -ico .resources/256x256.ico,.resources/48x48.ico,.resources/32x32.ico,.resources/16x16.ico -cross_windows: generate windows_manifest - CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags $(gcflags) -trimpath -ldflags "-s -w -H=windowsgui" -o gopher2600_windows_amd64.exe . +cross_windows_release: version_check windows_manifest generate + CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags "$(gcflags)" -trimpath -ldflags "$(ldflags_version) -H=windowsgui" -o gopher2600_windows_amd64.exe . rm rsrc_windows_amd64.syso -cross_windows_development: generate windows_manifest - CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags $(gcflags) -trimpath -ldflags "-s -w -H=windowsgui" -o gopher2600_windows_amd64_$(shell git rev-parse --short HEAD).exe . +# intentionally using ldflags and not ldflags for +# cross_windows_development and cross_winconsole_development + +cross_windows_development: windows_manifest generate + CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags "$(gcflags)" -trimpath -ldflags "$(ldflags_version) -H=windowsgui" -o gopher2600_windows_amd64_$(shell git rev-parse --short HEAD).exe . rm rsrc_windows_amd64.syso -cross_winconsole_development: generate windows_manifest - CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags $(gcflags) -trimpath -ldflags "-s -w -H=windows" -o gopher2600_winconsole_amd64_$(shell git rev-parse --short HEAD).exe . +cross_winconsole_development: windows_manifest generate + CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" CXX="/usr/bin/x86_64-w64-mingw32-g++" GOOS="windows" GOARCH="amd64" CGO_LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/local/x86_64-w64-mingw32/lib" $(goBinary) build -pgo=auto -tags "static imguifreetype release" -gcflags "$(gcflags)" -trimpath -ldflags "$(ldflags_version) -H=windows" -o gopher2600_winconsole_amd64_$(shell git rev-parse --short HEAD).exe . rm rsrc_windows_amd64.syso diff --git a/debugger/commands.go b/debugger/commands.go index bc963037..5efbac9f 100644 --- a/debugger/commands.go +++ b/debugger/commands.go @@ -51,6 +51,7 @@ import ( "github.com/jetsetilly/gopher2600/hardware/television/coords" "github.com/jetsetilly/gopher2600/logger" "github.com/jetsetilly/gopher2600/patch" + "github.com/jetsetilly/gopher2600/version" ) var debuggerCommands *commandline.Commands @@ -2050,6 +2051,7 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error { case cmdLog: option, ok := tokens.Get() if ok { + option = strings.ToUpper(option) switch option { case "LAST": s := &strings.Builder{} @@ -2084,6 +2086,18 @@ func (dbg *Debugger) processTokens(tokens *commandline.Tokens) error { s.WriteString(fmt.Sprintf(" NumGC = %v", m.NumGC)) dbg.printLine(terminal.StyleLog, s.String()) + + case cmdVersion: + dbg.printLine(terminal.StyleLog, version.Version) + + option, ok := tokens.Get() + if ok { + option = strings.ToUpper(option) + switch option { + case "REVISION": + dbg.printLine(terminal.StyleLog, version.Revision) + } + } } return nil diff --git a/debugger/commands_help.go b/debugger/commands_help.go index 24040142..71e80a5c 100644 --- a/debugger/commands_help.go +++ b/debugger/commands_help.go @@ -521,4 +521,7 @@ The ONTRACE command can be used to supplement the TRACE output with contextual i Note that while "ONSTEP LOG LAST" is a valid construct it may not print what you expect - it will always print the last log entry after every step, even if the last log entry is not new. "ONSTEP LOG LAST; LOG CLEAR" is maybe more intuitive but with the maybe unwanted side effect of clearing the log.`, + + cmdMemUsage: "Print memory usage information", + cmdVersion: "Print version information for the emulator", } diff --git a/debugger/commands_template.go b/debugger/commands_template.go index f6f226b2..a8eba912 100644 --- a/debugger/commands_template.go +++ b/debugger/commands_template.go @@ -77,6 +77,7 @@ const ( // meta. cmdLog = "LOG" cmdMemUsage = "MEMUSAGE" + cmdVersion = "VERSION" ) const cmdHelp = "HELP" @@ -143,6 +144,7 @@ var commandTemplate = []string{ // emulation cmdLog + " (LAST|RECENT|CLEAR)", cmdMemUsage, + cmdVersion + " (REVISION)", } // list of commands that should not be executed when recording/playing scripts. diff --git a/gopher2600.go b/gopher2600.go index 02f26ec1..b45a4ec1 100644 --- a/gopher2600.go +++ b/gopher2600.go @@ -42,6 +42,7 @@ import ( "github.com/jetsetilly/gopher2600/recorder" "github.com/jetsetilly/gopher2600/regression" "github.com/jetsetilly/gopher2600/resources" + "github.com/jetsetilly/gopher2600/version" ) // communication between the main goroutine and the launch goroutine. @@ -220,7 +221,7 @@ func launch(sync *mainSync) { md := &modalflag.Modes{Output: os.Stdout} md.NewArgs(os.Args[1:]) md.NewMode() - md.AddSubModes("RUN", "PLAY", "DEBUG", "DISASM", "PERFORMANCE", "REGRESS") + md.AddSubModes("RUN", "PLAY", "DEBUG", "DISASM", "PERFORMANCE", "REGRESS", "VERSION") p, err := md.Parse() switch p { @@ -252,6 +253,9 @@ func launch(sync *mainSync) { case "REGRESS": err = regress(md, sync) + + case "VERSION": + err = showVersion(md) } if err != nil { @@ -803,6 +807,25 @@ with the LOG mode. Note that asking for log output will suppress regression prog return nil } +func showVersion(md *modalflag.Modes) error { + md.NewMode() + revision := md.AddBool("revision", false, + "display revision information from version control system (if available)") + + p, err := md.Parse() + if err != nil || p != modalflag.ParseContinue { + return err + } + + fmt.Println(version.Version) + + if *revision { + fmt.Println(version.Revision) + } + + return nil +} + // nopWriter is an empty writer. type nopWriter struct{} diff --git a/gui/sdlimgui/platform.go b/gui/sdlimgui/platform.go index 3e635f78..03786ec8 100644 --- a/gui/sdlimgui/platform.go +++ b/gui/sdlimgui/platform.go @@ -23,6 +23,7 @@ import ( "github.com/inkyblackness/imgui-go/v4" "github.com/jetsetilly/gopher2600/logger" + "github.com/jetsetilly/gopher2600/version" "github.com/veandco/go-sdl2/sdl" ) @@ -126,9 +127,9 @@ func newPlatform(img *SdlImgui) (*platform, error) { profile_s = " ES" } - var version sdl.Version - sdl.VERSION(&version) - logger.Logf("sdl", "version %d.%d.%d", version.Major, version.Minor, version.Patch) + var sdlVersion sdl.Version + sdl.VERSION(&sdlVersion) + logger.Logf("sdl", "version %d.%d.%d", sdlVersion.Major, sdlVersion.Minor, sdlVersion.Patch) logger.Logf("sdl", "using GL version %d.%d%s", major, minor, profile_s) plt := &platform{ @@ -145,7 +146,7 @@ func newPlatform(img *SdlImgui) (*platform, error) { // map sdl key codes to imgui codes plt.setKeyMapping() - plt.window, err = sdl.CreateWindow(windowTitle, + plt.window, err = sdl.CreateWindow(fmt.Sprintf("%s (%s)", windowTitle, version.Version), sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, int32(float32(plt.mode.W)*0.80), int32(float32(plt.mode.H)*0.80), sdl.WINDOW_OPENGL|sdl.WINDOW_ALLOW_HIGHDPI|sdl.WINDOW_RESIZABLE|sdl.WINDOW_HIDDEN|sdl.WINDOW_FOREIGN) diff --git a/version/doc.go b/version/doc.go new file mode 100644 index 00000000..7b983d42 --- /dev/null +++ b/version/doc.go @@ -0,0 +1,18 @@ +// This file is part of Gopher2600. +// +// Gopher2600 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Gopher2600 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Gopher2600. If not, see . + +// Package version provides a version string that can be used to indicate the +// version number of the project. +package version diff --git a/version/version.go b/version/version.go new file mode 100644 index 00000000..69b5892a --- /dev/null +++ b/version/version.go @@ -0,0 +1,84 @@ +// This file is part of Gopher2600. +// +// Gopher2600 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Gopher2600 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Gopher2600. If not, see . + +package version + +import ( + "fmt" + "runtime/debug" +) + +// if number is empty then the project was probably not built using the makefile +var number string + +// Version contains a the current version number of the project +// +// If the version string is "development" then it means that the project has +// been manually built (ie. not with the makefile). However, there is git +// information and so can be discerned to be part of the development process +// +// If the version string is "unknown" then it means that there is no no version +// number and no git information. This can happen when compiling/running with +// "go run ." +var Version string + +// Revision contains the git revision hash. If the source has been modified but +// has not been committed then the Revision string will be suffixed with +// "[modified]" +var Revision string + +func init() { + var vcs bool + var revision string + var modified bool + + info, ok := debug.ReadBuildInfo() + if ok { + for _, v := range info.Settings { + switch v.Key { + case "vcs": + vcs = true + case "vcs.revision": + revision = v.Value + case "vcs.modified": + switch v.Value { + case "true": + modified = true + default: + modified = false + } + } + } + } + + if revision == "" { + Revision = "no revision information" + } else { + Revision = revision + if modified { + Revision = fmt.Sprintf("%s [modified]", Revision) + } + } + + if number == "" { + if vcs { + Version = "development" + } else { + Version = "unknown" + } + } else { + Version = number + } +}