diff --git a/program/Language.cs b/program/Language.cs index a9afd86..8b89a70 100644 --- a/program/Language.cs +++ b/program/Language.cs @@ -6,10 +6,14 @@ public class Language { - private const string EngCssPath = "lang_eng.css"; - private const string JpnCssPath = "lang_jpn.css"; - private const string EngCsvPath = "info_eng.csv"; - private const string JpnCsvPath = "info_jpn.csv"; + // private const string EngCssPath = "lang_eng.css"; + // private const string JpnCssPath = "lang_jpn.css"; + // private const string EngCsvPath = "info_eng.csv"; + // private const string JpnCsvPath = "info_jpn.csv"; + private static readonly string EngCssPath = Paths.Get("lang_eng.css"); + private static readonly string JpnCssPath = Paths.Get("lang_jpn.css"); + private static readonly string EngCsvPath = Paths.Get("info_eng.csv"); + private static readonly string JpnCsvPath = Paths.Get("info_jpn.csv"); private readonly Dictionary _engText; private readonly Dictionary _jpnText; diff --git a/program/MainWindow.cs b/program/MainWindow.cs index b68f449..d2c513d 100644 --- a/program/MainWindow.cs +++ b/program/MainWindow.cs @@ -50,7 +50,7 @@ private static Builder CreateBuilder() { var builder = new Builder(); - builder.AddFromFile("homepageall.glade"); + builder.AddFromFile(Paths.Get("homepageall.glade")); return builder; } diff --git a/program/Makefile b/program/Makefile new file mode 100644 index 0000000..f50b32c --- /dev/null +++ b/program/Makefile @@ -0,0 +1,459 @@ +# ===================================================================== config +APP := ears +VERSION := 1.0.0 +MAINTAINER := Kazi +SUMMARY := Auscultation training software +HOMEPAGE = https://nlab.tms.chiba-u.jp/ +YEAR := $(shell date +%Y) +DATESTAMP := $(shell date -R) + +# literal '#', so make never eats shebangs or comment lines as its own comments +H := \# + +PREFIX ?= /usr +DESTDIR ?= +LIBDIR := $(PREFIX)/lib/$(APP) +BINDIR := $(PREFIX)/bin + +MCS := mcs +PKGS := -pkg:gtk-sharp-3.0 +MCSFLAGS := -optimize+ -langversion:latest -warn:4 + +# ------------------------------------------------------------- source discovery +# Uses src/ and data/ when present, otherwise the project root. +SRCDIR ?= $(if $(wildcard src/*.cs),src,.) +DATADIR ?= $(if $(wildcard data/*.glade),data,.) + +# .cs files in SRCDIR that must NOT be compiled (old WinForms code, scratch files) +EXCLUDE ?= Form1.cs Form2.cs + +SRC := $(filter-out $(addprefix $(SRCDIR)/,$(EXCLUDE)),$(wildcard $(SRCDIR)/*.cs)) +DATA := $(wildcard $(DATADIR)/*.glade) $(wildcard $(DATADIR)/*.css) \ + $(wildcard $(DATADIR)/*.csv) $(wildcard $(DATADIR)/*.png) + +# ---------------------------------------------------------------- output layout +OUT := bin +LOUT := $(OUT)/linux +LINST := $(LOUT)/installer +LGEN := $(LINST)/gen +LROOT := $(LINST)/root +EXE := $(LOUT)/$(APP).exe +DEB := $(LINST)/$(APP)_$(VERSION)_all.deb + +WOUT := $(OUT)/windows +WBUNDLE := $(WOUT)/$(APP) +WINST := $(WOUT)/installer +WGEN := $(WINST)/gen +DBGEXE := $(WBUNDLE)/$(APP)-debug.exe +WINZIP := $(WOUT)/$(APP)-$(VERSION)-windows.zip +SETUP := $(WINST)/$(APP)-$(VERSION)-setup.exe + +# gtk-sharp managed assemblies + their dllmap .config files (for the Win bundle) +GTKSHARP := $(shell pkg-config --variable=Libraries gtk-sharp-3.0 2>/dev/null) +ifeq ($(strip $(GTKSHARP)),) +GTKSHARP := $(wildcard /usr/lib/cli/*/*.dll) +endif +GTKSHARP_CFG := $(wildcard $(addsuffix .config,$(GTKSHARP))) + +MSYS2 ?= /c/msys64 +MINGW := $(MSYS2)/mingw64 +ISCC ?= iscc + +.DEFAULT_GOAL := all +.PHONY: all build run debug clean distclean dep-check show +.PHONY: gen install uninstall deb deb-install deb-remove deb-test lint +.PHONY: win win-gtk installer everything + +all: deb +build: $(EXE) +everything: deb win + +$(LOUT) $(LGEN) $(LROOT) $(WBUNDLE) $(WGEN): + mkdir -p $@ + +# ================================================================== 1. compile +$(EXE): $(SRC) | $(LOUT) + @test -n "$(strip $(SRC))" || { \ + echo "ERROR: no .cs files found (SRCDIR=$(SRCDIR)). Run 'make show'."; exit 1; } + $(MCS) -target:winexe $(PKGS) $(MCSFLAGS) -out:$@ $(SRC) + +# console build: -target:exe keeps Console.WriteLine visible on Windows +$(DBGEXE): $(SRC) | $(WBUNDLE) + @test -n "$(strip $(SRC))" || { \ + echo "ERROR: no .cs files found (SRCDIR=$(SRCDIR)). Run 'make show'."; exit 1; } + $(MCS) -target:exe -debug -define:DEBUG $(PKGS) -out:$@ $(SRC) + +debug: $(DBGEXE) + +run: build + EARS_DATADIR=$(CURDIR)/$(DATADIR) mono $(EXE) + +clean: + rm -rf $(OUT) +distclean: clean + +show: + @echo "SRCDIR = $(SRCDIR)" + @echo "DATADIR = $(DATADIR)" + @echo "SRC = $(words $(SRC)) file(s)" + @$(foreach f,$(SRC),echo " $(f)";) + @echo "DATA = $(words $(DATA)) file(s)" + @$(foreach f,$(DATA),echo " $(f)";) + @echo "EXE = $(EXE)" + @echo "DEB = $(DEB)" + @echo "GTK# = $(words $(GTKSHARP)) managed assemblies" + +dep-check: + @command -v $(MCS) >/dev/null || { echo "missing: mono-devel (mcs)"; exit 1; } + @pkg-config --exists gtk-sharp-3.0 || { echo "missing: gtk-sharp3"; exit 1; } + @command -v dpkg-deb >/dev/null || { echo "missing: dpkg-dev"; exit 1; } + @echo "toolchain OK" + +# ========================================================== 2. generated files +define GEN_WRAPPER +$(H)!/bin/sh +$(H) $(APP) launcher - generated by make, do not edit +: "$${EARS_DATADIR:=$(LIBDIR)}" +export EARS_DATADIR +exec /usr/bin/mono "$(LIBDIR)/$(APP).exe" "$$@" +endef + +define GEN_DESKTOP +[Desktop Entry] +Type=Application +Name=EARS +GenericName=Serial control panel +Comment=$(SUMMARY) +Exec=$(APP) +Icon=$(APP) +Terminal=false +Categories=Utility;Electronics; +Keywords=serial;esp32;arduino; +StartupNotify=true +endef + +define GEN_ICON + + + + + + + + + +endef + +define GEN_UDEV +$(H) generated by make - serial adapters used by $(APP) +$(H) TAG+="uaccess" gives the device to the active desktop user with no group. +$(H) GROUP="dialout" is the fallback for ssh / headless / WSL sessions. +ACTION!="add", GOTO="ears_end" +SUBSYSTEM!="tty", GOTO="ears_end" +ATTRS{idVendor}=="303a", MODE="0660", GROUP="dialout", TAG+="uaccess" +ATTRS{idVendor}=="10c4", MODE="0660", GROUP="dialout", TAG+="uaccess" +ATTRS{idVendor}=="1a86", MODE="0660", GROUP="dialout", TAG+="uaccess" +ATTRS{idVendor}=="0403", MODE="0660", GROUP="dialout", TAG+="uaccess" +ATTRS{idVendor}=="2341", MODE="0660", GROUP="dialout", TAG+="uaccess" +LABEL="ears_end" +endef + +define GEN_CONTROL +Package: $(APP) +Version: $(VERSION) +Section: utils +Priority: optional +Architecture: all +Depends: mono-runtime (>= 6.0), gtk-sharp3, libgtk-3-0 | libgtk-3-0t64, libmono-system4.0-cil | mono-complete +Recommends: mono-complete +Installed-Size: @SIZE@ +Maintainer: $(MAINTAINER) +Homepage: $(HOMEPAGE) +Description: $(SUMMARY) + GTK$(H)3 front end that talks to an ESP32 over a serial port, with + English/Japanese language switching and a live device log. + . + Architecture is "all" because the payload is architecture-neutral CIL + executed by the Mono runtime. +endef + +define GEN_POSTINST +$(H)!/bin/sh +set -e +case "$$1" in +configure) + if command -v udevadm >/dev/null 2>&1; then + udevadm control --reload-rules >/dev/null 2>&1 || true + udevadm trigger --subsystem-match=tty >/dev/null 2>&1 || true + fi + + if [ -n "$$SUDO_USER" ] && getent group dialout >/dev/null 2>&1; then + if ! id -nG "$$SUDO_USER" 2>/dev/null | tr ' ' '\n' | grep -qx dialout; then + usermod -aG dialout "$$SUDO_USER" >/dev/null 2>&1 || true + echo "$(APP): added '$$SUDO_USER' to group 'dialout'." + echo "$(APP): log out and back in for serial access to take effect." + fi + fi + + if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database -q /usr/share/applications || true + fi + if command -v gtk-update-icon-cache >/dev/null 2>&1; then + gtk-update-icon-cache -qtf /usr/share/icons/hicolor || true + fi + ;; +esac +exit 0 +endef + +define GEN_POSTRM +$(H)!/bin/sh +set -e +if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database -q /usr/share/applications || true +fi +if command -v gtk-update-icon-cache >/dev/null 2>&1; then + gtk-update-icon-cache -qtf /usr/share/icons/hicolor || true +fi +exit 0 +endef + +define GEN_CHANGELOG +$(APP) ($(VERSION)) stable; urgency=medium + + * Package generated by make. + + -- $(MAINTAINER) $(DATESTAMP) +endef + +define GEN_COPYRIGHT +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: $(APP) + +Files: * +Copyright: $(YEAR) $(MAINTAINER) +License: proprietary + All rights reserved. +endef + +gen: | $(LGEN) + @$(file >$(LGEN)/$(APP).sh,$(GEN_WRAPPER)) + @$(file >$(LGEN)/$(APP).desktop,$(GEN_DESKTOP)) + @$(file >$(LGEN)/$(APP).svg,$(GEN_ICON)) + @$(file >$(LGEN)/60-$(APP)-serial.rules,$(GEN_UDEV)) + @$(file >$(LGEN)/control,$(GEN_CONTROL)) + @$(file >$(LGEN)/postinst,$(GEN_POSTINST)) + @$(file >$(LGEN)/postrm,$(GEN_POSTRM)) + @$(file >$(LGEN)/changelog,$(GEN_CHANGELOG)) + @$(file >$(LGEN)/copyright,$(GEN_COPYRIGHT)) + @chmod 755 $(LGEN)/postinst $(LGEN)/postrm $(LGEN)/$(APP).sh + @echo "generated packaging sources in $(LGEN)" + +# =========================================================== 3. make install +install: build gen + install -d $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) + install -m 644 $(EXE) $(DESTDIR)$(LIBDIR)/$(APP).exe + @if [ -n "$(strip $(DATA))" ]; then \ + echo "install -m 644 <$(words $(DATA)) data files> $(DESTDIR)$(LIBDIR)/"; \ + install -m 644 $(DATA) $(DESTDIR)$(LIBDIR)/; \ + else \ + echo "WARNING: no data files found in '$(DATADIR)'"; \ + fi + install -m 755 $(LGEN)/$(APP).sh $(DESTDIR)$(BINDIR)/$(APP) + install -D -m 644 $(LGEN)/$(APP).desktop \ + $(DESTDIR)$(PREFIX)/share/applications/$(APP).desktop + install -D -m 644 $(LGEN)/$(APP).svg \ + $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/$(APP).svg + install -D -m 644 $(LGEN)/60-$(APP)-serial.rules \ + $(DESTDIR)/lib/udev/rules.d/60-$(APP)-serial.rules + install -D -m 644 $(LGEN)/copyright \ + $(DESTDIR)$(PREFIX)/share/doc/$(APP)/copyright + gzip -9nc $(LGEN)/changelog > $(LGEN)/changelog.gz + install -D -m 644 $(LGEN)/changelog.gz \ + $(DESTDIR)$(PREFIX)/share/doc/$(APP)/changelog.Debian.gz + +uninstall: + rm -rf $(DESTDIR)$(LIBDIR) $(DESTDIR)$(PREFIX)/share/doc/$(APP) + rm -f $(DESTDIR)$(BINDIR)/$(APP) \ + $(DESTDIR)$(PREFIX)/share/applications/$(APP).desktop \ + $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/$(APP).svg \ + $(DESTDIR)/lib/udev/rules.d/60-$(APP)-serial.rules + +# ==================================================================== 4. .deb +deb: build gen + rm -rf $(LROOT) + $(MAKE) --no-print-directory install DESTDIR=$(CURDIR)/$(LROOT) PREFIX=/usr + install -d $(LROOT)/DEBIAN + install -m 755 $(LGEN)/postinst $(LGEN)/postrm $(LROOT)/DEBIAN/ + sed "s|@SIZE@|$$(du -ks --exclude=DEBIAN $(LROOT) | cut -f1)|" \ + $(LGEN)/control > $(LROOT)/DEBIAN/control + cd $(LROOT) && find . -type f ! -path './DEBIAN/*' -printf '%P\0' \ + | LC_ALL=C sort -z | xargs -0 md5sum > DEBIAN/md5sums + find $(LROOT) -type d -exec chmod 755 {} + + dpkg-deb --build --root-owner-group $(LROOT) $(DEB) + @echo + @echo "==> $(DEB)" + @echo " sudo apt install ./$(DEB) # the ./ is required" + +deb-install: deb + sudo apt install -y ./$(DEB) + +deb-remove: + sudo apt remove -y $(APP) + +lint: deb + -lintian --no-tag-display-limit $(DEB) + +deb-test: deb + docker run --rm -v "$(CURDIR)/$(LINST)":/pkg:ro ubuntu:24.04 sh -c '\ + set -e; \ + apt-get update -qq; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ + /pkg/$(notdir $(DEB)) xvfb >/dev/null; \ + echo "--- files:"; dpkg -L $(APP) | head -20; \ + echo "--- runtime:"; mono --version | head -1; \ + echo "--- smoke test:"; \ + timeout 15 xvfb-run -a $(APP) || echo "exit=$$? (124 = window stayed open, OK)"' + +# ================================================================= 5. windows +define GEN_WINBAT +@echo off +setlocal +set "HERE=%~dp0" +set "EARS_DATADIR=%HERE%" +if exist "%HERE%gtk\bin" set "PATH=%HERE%gtk\bin;%PATH%" +if exist "%HERE%gtk\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache" set "GDK_PIXBUF_MODULE_FILE=%HERE%gtk\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache" +if exist "%HERE%gtk\share\glib-2.0\schemas" set "GSETTINGS_SCHEMA_DIR=%HERE%gtk\share\glib-2.0\schemas" +if exist "%HERE%gtk\share" set "XDG_DATA_DIRS=%HERE%gtk\share;%XDG_DATA_DIRS%" +set "MONO=mono" +where mono >nul 2>&1 || set "MONO=%ProgramFiles%\Mono\bin\mono.exe" +if /i not "%MONO%"=="mono" if not exist "%MONO%" ( + echo Mono for Windows was not found. + echo Install it from https://www.mono-project.com/download/stable/ + pause + exit /b 1 +) +start "" "%MONO%" "%HERE%$(APP).exe" %* +endef + +define GEN_WINBATDBG +@echo off +setlocal +set "HERE=%~dp0" +set "EARS_DATADIR=%HERE%" +if exist "%HERE%gtk\bin" set "PATH=%HERE%gtk\bin;%PATH%" +if exist "%HERE%gtk\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache" set "GDK_PIXBUF_MODULE_FILE=%HERE%gtk\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache" +if exist "%HERE%gtk\share\glib-2.0\schemas" set "GSETTINGS_SCHEMA_DIR=%HERE%gtk\share\glib-2.0\schemas" +if exist "%HERE%gtk\share" set "XDG_DATA_DIRS=%HERE%gtk\share;%XDG_DATA_DIRS%" +set "MONO=mono" +where mono >nul 2>&1 || set "MONO=%ProgramFiles%\Mono\bin\mono.exe" +set "MONO_LOG_LEVEL=warning" +echo Running $(APP) with console output. Close this window to quit. +"%MONO%" "%HERE%$(APP)-debug.exe" %* +echo. +echo exit code %ERRORLEVEL% +pause +endef + +win: build debug | $(WBUNDLE) + cp $(EXE) $(WBUNDLE)/$(APP).exe + @if [ -n "$(strip $(DATA))" ]; then cp $(DATA) $(WBUNDLE)/; \ + else echo "WARNING: no data files found in '$(DATADIR)'"; fi + @if [ -n "$(strip $(GTKSHARP))" ]; then \ + cp $(GTKSHARP) $(WBUNDLE)/; \ + echo "copied $(words $(GTKSHARP)) gtk-sharp assemblies"; \ + else echo "WARNING: gtk-sharp managed assemblies not found"; fi + @if [ -n "$(strip $(GTKSHARP_CFG))" ]; then cp $(GTKSHARP_CFG) $(WBUNDLE)/; fi + @$(file >$(WBUNDLE)/$(APP).bat,$(GEN_WINBAT)) + @$(file >$(WBUNDLE)/$(APP)-debug.bat,$(GEN_WINBATDBG)) + -$(MAKE) --no-print-directory win-gtk MSYS2=$(MSYS2) + cd $(WOUT) && rm -f $(notdir $(WINZIP)) && zip -qr $(notdir $(WINZIP)) $(APP) + @echo "==> $(WINZIP)" + +win-gtk: | $(WBUNDLE) + @test -d $(MINGW)/bin || { \ + echo "MSYS2 not found at $(MINGW) - shipping without native GTK."; \ + echo " pacman -S mingw-w64-x86_64-gtk3 mingw-w64-x86_64-librsvg mingw-w64-x86_64-ntldd"; \ + echo " then: make win MSYS2=/path/to/msys64"; exit 1; } + rm -rf $(WBUNDLE)/gtk + mkdir -p $(WBUNDLE)/gtk/bin $(WBUNDLE)/gtk/share $(WBUNDLE)/gtk/lib + @echo "resolving native GTK dependencies..." + @if command -v ntldd >/dev/null 2>&1; then \ + for root in libgtk-3-0.dll librsvg-2-2.dll libgdk_pixbuf-2.0-0.dll; do \ + [ -f $(MINGW)/bin/$$root ] || continue; \ + ntldd -R $(MINGW)/bin/$$root \ + | grep -io '[a-z]:[\\/][^ ]*mingw64[\\/]bin[\\/][^ ]*\.dll' \ + | tr '\\' '/' | sort -u \ + | while read -r dll; do cp -u "$$dll" $(WBUNDLE)/gtk/bin/ 2>/dev/null || true; done; \ + cp -u $(MINGW)/bin/$$root $(WBUNDLE)/gtk/bin/; \ + done; \ + else \ + echo "ntldd missing - copying all of mingw64/bin (larger bundle)"; \ + cp -u $(MINGW)/bin/*.dll $(WBUNDLE)/gtk/bin/; \ + fi + -cp -r $(MINGW)/lib/gdk-pixbuf-2.0 $(WBUNDLE)/gtk/lib/ + -cp -r $(MINGW)/share/glib-2.0 $(WBUNDLE)/gtk/share/ + -cp -r $(MINGW)/share/icons $(WBUNDLE)/gtk/share/ + -cp -r $(MINGW)/share/themes $(WBUNDLE)/gtk/share/ + @echo "gtk runtime staged ($$(du -sh $(WBUNDLE)/gtk | cut -f1))" + +define GEN_ISS +[Setup] +AppName=$(APP) +AppVersion=$(VERSION) +AppPublisher=$(MAINTAINER) +DefaultDirName={autopf}\$(APP) +DefaultGroupName=$(APP) +OutputBaseFilename=$(APP)-$(VERSION)-setup +OutputDir=. +Compression=lzma2/max +SolidCompression=yes +ArchitecturesInstallIn64BitMode=x64compatible +PrivilegesRequired=admin +UninstallDisplayIcon={app}\$(APP).exe +WizardStyle=modern + +[Files] +Source: "..\..\$(APP)\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs ignoreversion + +[Icons] +Name: "{group}\$(APP)"; Filename: "{app}\$(APP).bat"; IconFilename: "{app}\$(APP).exe" +Name: "{group}\$(APP) (console)"; Filename: "{app}\$(APP)-debug.bat"; IconFilename: "{app}\$(APP).exe" +Name: "{autodesktop}\$(APP)"; Filename: "{app}\$(APP).bat"; IconFilename: "{app}\$(APP).exe"; Tasks: desktopicon + +[Tasks] +Name: "desktopicon"; Description: "Create a desktop shortcut"; GroupDescription: "Additional icons:" + +[Run] +Filename: "{app}\$(APP).bat"; Description: "Launch $(APP)"; Flags: postinstall nowait skipifsilent shellexec + +[Code] +function MonoPresent(): Boolean; +begin + Result := FileExists(ExpandConstant('{commonpf}\Mono\bin\mono.exe')) or + FileExists(ExpandConstant('{commonpf32}\Mono\bin\mono.exe')) or + RegKeyExists(HKLM, 'SOFTWARE\Novell\Mono') or + RegKeyExists(HKLM, 'SOFTWARE\WOW6432Node\Novell\Mono'); +end; + +function InitializeSetup(): Boolean; +var Code: Integer; +begin + Result := True; + if not MonoPresent() then + if MsgBox('Mono for Windows was not detected. Open the download page now?', + mbConfirmation, MB_YESNO) = IDYES then + ShellExec('open', 'https://www.mono-project.com/download/stable/', + '', '', SW_SHOW, ewNoWait, Code); +end; +endef + +installer: win | $(WGEN) + @$(file >$(WGEN)/$(APP).iss,$(GEN_ISS)) + @command -v $(ISCC) >/dev/null 2>&1 || { \ + echo "Inno Setup compiler '$(ISCC)' not found."; \ + echo " Windows: make installer ISCC=\"/c/Program Files (x86)/Inno Setup 6/ISCC.exe\""; \ + echo " Linux: make installer ISCC=\"wine /path/to/ISCC.exe\""; exit 1; } + cd $(WGEN) && $(ISCC) $(APP).iss + mv $(WGEN)/$(APP)-$(VERSION)-setup.exe $(SETUP) + @echo "==> $(SETUP)" \ No newline at end of file diff --git a/program/Paths.cs b/program/Paths.cs new file mode 100644 index 0000000..16cf392 --- /dev/null +++ b/program/Paths.cs @@ -0,0 +1,33 @@ +using System; +using System.IO; +using System.Reflection; + +public static class Paths +{ + static readonly string ExeDir = + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + + public static readonly string DataDir = Resolve(); + + const string Probe = "homepageall.glade"; + + static string Resolve() + { + string[] candidates = { + Environment.GetEnvironmentVariable("EARS_DATADIR"), + ExeDir, + Path.Combine(ExeDir, "data"), + Path.Combine(ExeDir, "..", "data"), // make run from bin/linux + "/usr/lib/ears", + "/usr/local/lib/ears", + }; + + foreach (var c in candidates) + if (!string.IsNullOrEmpty(c) && File.Exists(Path.Combine(c, Probe))) + return Path.GetFullPath(c); + + return ExeDir; + } + + public static string Get(string name) => Path.Combine(DataDir, name); +} \ No newline at end of file diff --git a/program/tempMakefile.txt b/program/tempMakefile.txt new file mode 100644 index 0000000..dc9aa0b --- /dev/null +++ b/program/tempMakefile.txt @@ -0,0 +1,101 @@ +APP := ears +VERSION := 1.0.0 +OUT := bin/linux/installer +DIST := dist +STAGE := $(HOME)/.cache/$(APP)-build +PKGDIR := $(STAGE)/$(APP)_$(VERSION)_all + +SRC := $(filter-out Form1.cs Form2.cs, $(wildcard *.cs)) +GLADE := $(wildcard *.glade) +ASSETS := $(wildcard map sound) + +.ONESHELL: +.SHELLFLAGS := -ec +.PHONY: all run clean deb init-packaging list + +all: $(OUT)/program.exe + +$(OUT)/program.exe: $(SRC) $(GLADE) + mkdir -p $(OUT) + mcs -target:winexe -pkg:gtk-sharp-3.0 \ + $(foreach f,$(GLADE),-resource:$(f),$(notdir $(f))) \ + $(SRC) -out:$@ +run: all + mono $(OUT)/program.exe + +deb: all + rm -rf "$(PKGDIR)" + install -Dm755 packaging/launcher.sh "$(PKGDIR)/usr/bin/$(APP)" + install -Dm644 $(OUT)/program.exe "$(PKGDIR)/usr/lib/$(APP)/program.exe" + install -Dm644 packaging/app.desktop "$(PKGDIR)/usr/share/applications/$(APP).desktop" + install -Dm644 packaging/udev.rules "$(PKGDIR)/lib/udev/rules.d/99-$(APP).rules" + install -Dm644 packaging/control "$(PKGDIR)/DEBIAN/control" + install -Dm755 packaging/postinst "$(PKGDIR)/DEBIAN/postinst" + install -Dm755 packaging/postrm "$(PKGDIR)/DEBIAN/postrm" + if [ -n "$(ASSETS)" ]; then cp -r $(ASSETS) "$(PKGDIR)/usr/lib/$(APP)/"; fi + find "$(PKGDIR)" -type d -exec chmod 755 {} + + find "$(PKGDIR)" -type f -exec chmod 644 {} + + chmod 755 "$(PKGDIR)/usr/bin/$(APP)" \ + "$(PKGDIR)/DEBIAN/postinst" "$(PKGDIR)/DEBIAN/postrm" + sed -i 's/\r$$//' "$(PKGDIR)/usr/bin/$(APP)" \ + "$(PKGDIR)/DEBIAN/postinst" "$(PKGDIR)/DEBIAN/postrm" + mkdir -p $(DIST) + dpkg-deb --build --root-owner-group "$(PKGDIR)" $(DIST)/$(APP)_$(VERSION)_all.deb + dpkg -c $(DIST)/$(APP)_$(VERSION)_all.deb + +clean: + rm -rf $(OUT) $(DIST) "$(STAGE)" + +list: + @grep -E '^[a-zA-Z_-]+:' Makefile | cut -d: -f1 + +init-packaging: + mkdir -p packaging + cat > packaging/launcher.sh <<-'EOF' + #!/bin/sh + cd /usr/lib/$(APP) || exit 1 + exec /usr/bin/mono ./program.exe "$$@" + EOF + cat > packaging/app.desktop <<-EOF + [Desktop Entry] + Type=Application + Name=EARS + Comment=Auscultation Training Software + Exec=$(APP) + Icon=$(APP) + Terminal=false + Categories=Utility;Electronics; + EOF + cat > packaging/control <<-EOF + Package: $(APP) + Version: $(VERSION) + Section: utils + Priority: optional + Architecture: all + Depends: mono-runtime (>= 6.0), gtk-sharp3, libgtk-3-0 + Maintainer: kazi + Description: Arduino serial control tool + GTK# application that connects to the device over USB serial. + EOF + cat > packaging/udev.rules <<-'EOF' + SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1" + SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1" + SUBSYSTEM=="tty", ATTRS{idVendor}=="303a", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1" + SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1" + EOF + cat > packaging/postinst <<-'EOF' + #!/bin/sh + set -e + udevadm control --reload-rules || true + udevadm trigger --subsystem-match=tty || true + update-desktop-database -q /usr/share/applications || true + exit 0 + EOF + cat > packaging/postrm <<-'EOF' + #!/bin/sh + set -e + udevadm control --reload-rules || true + exit 0 + EOF + chmod 755 packaging/launcher.sh packaging/postinst packaging/postrm + echo "packaging/ created — edit control and udev.rules, then run: make deb" \ No newline at end of file