diff --git a/Makefile b/Makefile
index b945d79f5..2ad142855 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 building
+
+.PHONY: version_check release
-release: fontrendering generate
- $(goBinary) build -pgo=auto -gcflags $(gcflags) -trimpath -ldflags="-s -w" -tags="$(fontrendering) 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 bc9630371..5efbac9f9 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 24040142c..71e80a5ca 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 f6f226b22..a8eba912d 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 02f26ec19..b45a4ec10 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 3e635f780..03786ec89 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 000000000..7b983d423
--- /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 000000000..69b5892af
--- /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
+ }
+}