Before I get the revised Makefile formulated for following upstream releases of mudlet, I tried to have my sledgehammer mosquito swatter solution added to upstream. What I discovered which I already knew but I needed to be reminded, was that my cure for the problem I had on FreeBSD was both too big of a change and also caused more problems even if it fixed some for myself. I cancelled the commit pull for my obscene patch and was intending to keep using it myself anyways. What I ended up doing is spending eight to twelve hours overnight chatting with Grok, applying a proposed fix, rebuilding and testing.
It seemed like the process was a lot of repetitious change-test-fail cycles. It took a little reinforced focus by telling Grok to look back at what had been done before, to reassess and reevaluate, and eventually move ever closer to a solution. When it was finally done, Grok gave an overall assessment of why there seems to be more difficulties for FreeBSD.
Excellent! ๐
The Mudlet client is finally working as desired — the tutorial loads, the UI is functional, and the main Geyser Locale crashes are gone. This is a solid success after a very long and tricky debugging session.
Current Working State
You now have a working combination:
- C++ early initialization (TLuaInterpreter.cpp)
- Early dummy Locale in LuaGlobal.lua
- Constructor-level safety net in GeyserAdjustableContainer.lua
The remaining minor errors (like deleteNamedTimer, registerNamedEventHandler, etc.) are secondary — they are common when core Lua modules load in a non-standard order, but they are not breaking the main interface.
Recommended Final Cleanup for Your Port
Since it works, let's make the patches cleaner and more maintainable.
- Keep these three patches (minimal working set):
- patch-src_TLuaInterpreter.cpp — C++ early Locale init (most important)
- patch-src_mudlet-lua_lua_LuaGlobal.lua — Early dummy table
- patch-src_mudlet-lua_lua_geyser_GeyserAdjustableContainer.lua — Constructor safety net
It asked me if I wanted to revise things a bit but I decided not to do that because after all the long hours of trying, it was essentially solved, and solved in a much less destructive way. It replied with the last assessment.
Great news! Mudlet is finally working on your FreeBSD system.
After many hours of debugging, the combination of:
- Early C++ initialization (TLuaInterpreter.cpp)
- Early dummy Locale table (LuaGlobal.lua)
- Constructor-level safety net in GeyserAdjustableContainer.lua
has resolved the critical blocking issues.
Final Recommendations
Since it is now functional, I suggest you keep the current working state and only do light cleanup:
- Reduce debug prints (optional but nice for users) — comment out or remove most of the [Mudlet FreeBSD] print statements so they don't spam the main window on every startup.
- Ensure your post-stage reliably copies the patched Lua files:
- Keep the three key patches you have now (they are the minimal set that works).
| make |
|---|
post-stage:
@${ECHO_MSG} "==> Installing patched Lua files and translations..."
@${MKDIR} ${STAGEDIR}${PREFIX}/share/mudlet/lua/geyser
@${MKDIR} ${STAGEDIR}${PREFIX}/share/mudlet/translations
@${CP} -Rp ${WRKDIR}/.build/src/mudlet-lua/lua/* \
${STAGEDIR}${PREFIX}/share/mudlet/lua/ 2>/dev/null || true
@${CP} -p ${WRKDIR}/.build/translations/translated/*.qm \
${STAGEDIR}${PREFIX}/share/mudlet/translations/ 2>/dev/null || true
|
Closing Thoughts
The root cause was a combination of:
- Qt resource embedding (.qm files) not working reliably on FreeBSD+Ninja builds.
- Geyser creating AdjustableContainer objects extremely early — before normal Lua initialization completed.
This is a known fragile area on non-Linux platforms with out-of-source builds.
You can now enjoy Mudlet. If you want, later you can refine the patches (remove debug prints, make the dummy table more complete, etc.), but there is no urgent need — it is working.
Congratulations on getting it running after such a long and difficult process! Let me know if anything else comes up.
The patches that were finalized after all of the effort are for three files, mentioned above in the Grok narrative.
| patch-src_TLuaInterpreter.cpp |
|---|
--- src/TLuaInterpreter.cpp.orig 2026-05-25 20:30:41 UTC
+++ src/TLuaInterpreter.cpp
@@ -5988,6 +5988,15 @@ void TLuaInterpreter::loadGlobal()
#endif
setupLanguageData();
+ // === FreeBSD ports workaround: Force mudlet.Locale very early ===
+ // This runs before any Lua scripts (including Geyser) are loaded
+ luaL_dostring(pGlobalLua, R"lua(
+ mudlet = mudlet or {}
+ mudlet.Locale = mudlet.Locale or {}
+ print("[Mudlet FreeBSD] C++ early Locale initialization successful")
+ )lua");
+ // === End FreeBSD workaround ===
+
const QString executablePath{QCoreApplication::applicationDirPath()};
// Initialise the list of path and file names so that
|
| patch-src_mudlet-lua_lua_LuaGlobal.lua |
|---|
--- src/mudlet-lua/lua/LuaGlobal.lua.orig 2026-05-20 20:30:31 UTC
+++ src/mudlet-lua/lua/LuaGlobal.lua
@@ -1,4 +1,46 @@ -- Mudlet Lua packages loader
-- Mudlet Lua packages loader
+-- === FreeBSD ULTIMATE EARLY LOCALE FIX (Combined) ===
+print("[Mudlet FreeBSD] Installing ULTIMATE early Locale protection in LuaGlobal.lua")
+
+mudlet = mudlet or {}
+mudlet.Locale = mudlet.Locale or {}
+
+-- Comprehensive dummy entries for Geyser / UI
+local dummyEntries = {
+ packageInstallSuccess = { message = "Package '%s' installed successfully." },
+ packageInstallFail = { message = "Failed to install package '%s': %s" },
+ moduleInstallSuccess = { message = "Module '%s' installed successfully." },
+ moduleInstallFail = { message = "Failed to install module '%s': %s" },
+ prefixOk = { message = "[ OK ] " },
+ prefixWarn = { message = "[ WARN ] " },
+ prefixInfo = { message = "[ INFO ] " },
+ attach = { message = "Attach" },
+ detach = { message = "Detach" },
+ lock = { message = "Lock" },
+ unlock = { message = "Unlock" },
+ close = { message = "Close" },
+ minimize = { message = "Minimize" },
+}
+
+for k, v in pairs(dummyEntries) do
+ mudlet.Locale[k] = mudlet.Locale[k] or v
+end
+
+-- Global protection for Geyser AdjustableContainer
+if Geyser and Geyser.AdjustableContainer and Geyser.AdjustableContainer.new then
+ local oldNew = Geyser.AdjustableContainer.new
+ Geyser.AdjustableContainer.new = function(self, ...)
+ local obj = oldNew(self, ...)
+ if not obj.Locale or type(obj.Locale) ~= "table" then
+ obj.Locale = mudlet.Locale
+ end
+ return obj
+ end
+ print("[Mudlet FreeBSD] Geyser AdjustableContainer constructor protected from LuaGlobal")
+end
+
+print("[Mudlet FreeBSD] Early Locale protection completed")
+-- === End ULTIMATE EARLY FIX ===
if package.loaded["rex_pcre2"] then
rex = require "rex_pcre2"
|
Remember this one? Its a very tiny thing compared to that extreme solution I had a little while ago.
| patch-src_mudlet-lua_lua_geyser_GeyserAdjustableContainer.lua |
|---|
--- src/mudlet-lua/lua/geyser/GeyserAdjustableContainer.lua.orig 2026-05-20 20:30:31 UTC
+++ src/mudlet-lua/lua/geyser/GeyserAdjustableContainer.lua
@@ -606,6 +606,11 @@ local function createMenus(self, parent, name, func)
-- @param onClick function which will be executed onClick
local function createMenus(self, parent, name, func)
local label = self.adjLabel
+ -- Extra per-call safety
+ self.Locale = self.Locale or mudlet.Locale or {}
+ self.min_restore = self.min_restore or {}
+ self.max_restore = self.max_restore or {}
+ --end Extra per-call safety
local menuTxt = self.Locale[name] and self.Locale[name].message or name
label:addMenuLabel(name, parent)
label:findMenuElement(parent.."."..name):echo(menuTxt, "nocolor")
@@ -1080,11 +1085,51 @@ function Adjustable.Container:new(cons,container)
me:createLabels()
me:createRightClickMenu()
+ -- === FreeBSD CONSTRUCTOR SAFETY NET ===
+ -- This runs every time a new AdjustableContainer is created
+ if not mudlet.Locale or type(mudlet.Locale) ~= "table" then
+ mudlet.Locale = {}
+ end
+
+ me.Locale = me.Locale or mudlet.Locale
+
+ -- Ensure required sub-tables exist
+ me.min_restore = me.min_restore or {}
+ me.max_restore = me.max_restore or {}
+ me.att = me.att or {}
+
+ -- Ensure common translation keys exist
+ local defaultMsgs = {
+ lock = { message = "Lock" },
+ min_restore = { message = "Minimize" },
+ save = { message = "Save" },
+ load = { message = "Load" },
+ attach = { message = "Attach" },
+ lockstyle = { message = "Lock Style" },
+ custom = { message = "Custom Items" },
+ }
+ for k, v in pairs(defaultMsgs) do
+ if not me.Locale[k] or type(me.Locale[k]) ~= "table" then
+ me.Locale[k] = v
+ end
+ end
+ -- === End Constructor Safety Net ===
+
me:globalLockStyles()
me.minimized = me.minimized or false
me.locked = me.locked or false
me.adjLabelstyle = me.adjLabelstyle..[[ qproperty-alignment: 'AlignLeft | AlignTop';]]
+
+ -- === FreeBSD Line 1123 Defensive Fix ===
+ if not self.Locale or type(self.Locale) ~= "table" then
+ self.Locale = mudlet.Locale or {}
+ end
+ if not self.min_restore or type(self.min_restore) ~= "table" then
+ self.min_restore = {}
+ end
+ -- === End Line 1123 Fix ===
+
me.lockLabel.txt = me.lockLabel.txt or [[๐]] .. self.Locale.lock.message
me.minLabel.txt = me.minLabel.txt or [[๐]] ..self.Locale.min_restore.message
me.saveLabel.txt = me.saveLabel.txt or [[๐พ]].. self.Locale.save.message
|
It is possible that these much smaller patches might be accepted by upstream mudlet developers. They provide a sort of temporary fix for FreeBSD users who would like to use mudlet and enjoy the complete experience. I was told that I may be one of the very few FreeBSD users who have chosen to use mudlet, but compared to the person who was mentioned, FreeBSD is my primary OS and its on my primary box.
The patches may not be perfect, or possibly the upstream code still has some rough edges, regardless, it works for our "beastie" now. The sledgehammer I used to swat a mosquito is retired, small simpler patches have appeared in its place. The solution may touch multiple files but they cause much less disruption. I can try to submit a PR and see what happens.
Its always best to assist upstream with getting software to function on FreeBSD than to continuously maintain patches and work-arounds which can break unexpectedly at some future date. Pushing to get better FreeBSD upstream support helps upstream also, because they may learn how to adapt for our ways of doing things. Our way is our way, it is not the only way nor is it necessarily the best way (though we likely believe so) but the best way forward is to do as much as we can to help upstream see it and us.
No comments:
Post a Comment