Find globals with LuaJIT (Linux, probably Mac too)

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Find globals with LuaJIT (Linux, probably Mac too)

Post by pgimeno »

I made this for myself some time ago, but in light of recent threads, it appears that it's not a very widely known or used solution to the problem of finding globals in your program.

So here it is. Make a shell script like this:

Code: Select all

#!/bin/sh
luajit -b -l "$1" | egrep '^.{,12}\bG[GS]ET\b' | fgrep -v -f /path/to/luajit-globals.txt
It needs a file 'luajit.globals.txt' with these contents:

Code: Select all

"love"
"arg"
"ffi"
"lfs"
"socket"
"coroutine"
"assert"
"tostring"
"tonumber"
"io"
"rawget"
"xpcall"
"ipairs"
"print"
"pcall"
"gcinfo"
"module"
"setfenv"
"pairs"
"jit"
"bit"
"package"
"error"
"debug"
"loadfile"
"rawequal"
"loadstring"
"rawset"
"unpack"
"table"
"require"
"_VERSION"
"newproxy"
"collectgarbage"
"dofile"
"next"
"math"
"load"
"os"
"_G"
"select"
"string"
"type"
"getmetatable"
"getfenv"
"setmetatable"
BE VERY CAREFUL to not include an empty line in luajit-globals.txt, as that will make the script not report any results.

Run it on each Lua file you want to check, like this:

Code: Select all

check-globals myfile.lua
It will print the names of the globals that file is using, other than the LÖVE or the Lua library ones. Unfortunately it doesn't tell line numbers.
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by raidho36 »

Alternatively:

Code: Select all

for k, _ in pairs ( _G ) do print ( k ) end
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by pgimeno »

Yeah but:
  • It doesn't tell you what files does it appear in.
  • It doesn't filter out the system globals.
  • It may miss some code paths.
The method I suggest doesn't have any of these caveats.
User avatar
Rucikir
Party member
Posts: 129
Joined: Tue Nov 05, 2013 6:33 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by Rucikir »

Do you know Luacheck ?
It’s a static analyzer and a linter for Lua, that is very mature and that has a lot of features. It is also well integrated with various editors.
For instance, a run of

Code: Select all

luacheck --std=love+luajit src/
is suitable for checking files using LÖVE.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by pgimeno »

Rucikir wrote: Wed Jun 05, 2019 12:27 pm Do you know Luacheck ?
Thanks, I heard about it, but I didn't realize it's available for Debian as the lua-check package.
Rucikir wrote: Wed Jun 05, 2019 12:27 pm For instance, a run of

Code: Select all

luacheck --std=love+luajit src/
is suitable for checking files using LÖVE.
That line doesn't work for me, it doesn't seem to recognize love. I can add my own globals to the command line though, so that's not a problem because LÖVE adds very few globals (just one in 11.x unless you use socket.ftp or mime).

My problem with this kind of static checkers is that they enforce a particular style. I don't like that. Of the 126 warnings it found in Gspot.lua, only one could be considered legitimate, namely a snippet with this form:

Code: Select all

  local var = 0
  var = fn()
which LuaJIT will probably optimize out anyway. The rest were just consequence of the style used. I'd have to disable lots of warnings before starting to use it. Having to replace unused identifiers with _ just to keep the linter happy, in particular, is a pet peeve of mine. It hides the meaning of the parameter or variable, and makes it one more place to change if I decide to use it later.

I tried it also on the Gspöt main.lua demo program, which (ab)uses globals, and it highlights another problem. The linter is not wise enough to know that love.load is executed right after executing the file, and reported every access to the globals that were defined in love.load as undeclared. That's another case where a particular style would be enforced just to keep the linter happy.

Maybe I spend some time analysing the list of warnings to see which ones to keep and which ones to ditch, but in its current state it's too unusable for me.
User avatar
Rucikir
Party member
Posts: 129
Joined: Tue Nov 05, 2013 6:33 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by Rucikir »

but I didn't realize it's available for Debian as the lua-check package
I don’t know if the package is up to date on Debian, but if you have installed luarocks, you may prefer to install lua-check this way.

Code: Select all

luarocks install luacheck
they enforce a particular style
I tend to like conforming myself to a linter or a formatter. Anyway, they're just tools. They have their limitations.
Having to replace unused identifiers with _ just to keep the linter happy, in particular, is a pet peeve of mine. It hides the meaning of the parameter or variable, and makes it one more place to change if I decide to use it later.
I disagree on this point. It’s just a convention to name a variable `_`, but it does clearly tell the reader that the variable is unused. If I see an unused variable, I want it removed. It’s already a burden to keep track of all the other used variables ;-)

Of course, it’s painful to convert existing code to what Luacheck enjoys, but if you start developing right away with it, it can be rewarding. With dynamically-typed languages (especially Lua), when I misspell a variable I’m actually defining a new global. I like that Luacheck is able to catch that early. I’like even more static typing.
reported every access to the globals that were defined in love.load as undeclared
If I have to declare globals I do it the ugly way with `_G`. I also do declarations of "globals to the file chunk".

Code: Select all

local x, y, z
function love.load()
   x = some_resource()
   -- ...
end
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by pgimeno »

Rucikir wrote: Sat Jun 08, 2019 10:35 am I disagree on this point. It’s just a convention to name a variable `_`, but it does clearly tell the reader that the variable is unused. If I see an unused variable, I want it removed. It’s already a burden to keep track of all the other used variables ;-)
Not always can you remove it. Like when you want e.g. the second result of a function, or the third parameter, or you need to use ipairs but you don't need the loop variable. I think that this:

Code: Select all

function love.keypressed(key, scancode, is_repeat)
  if scancode == "w" then
    -- stuff
  end
  -- more stuff
end
is clearer than this:

Code: Select all

function love.keypressed(_, scancode, _)
  if scancode == "w" then
    -- stuff
  end
  -- more stuff
end
and if you have reasons to use is_repeat or key, you don't need to look up where they must go.

Rucikir wrote: Sat Jun 08, 2019 10:35 am With dynamically-typed languages (especially Lua), when I misspell a variable I’m actually defining a new global. I like that Luacheck is able to catch that early. I’like even more static typing.
That's what the OP is about :) Misspelling a variable is usually caught early in debugging, though, but forgetting 'local' isn't. And I agree about static typing.
User avatar
Karai17
Party member
Posts: 930
Joined: Sun Sep 02, 2012 10:46 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by Karai17 »

I definitely like the _ idiom. If I am calling a function that has optional variables, I want it to be very obvious if I am not using them. A note about your example, in Lua you can just leave out trailing variables if you do not need to use them.

Code: Select all

function love.keypressed(_, scancode, _)
could be written as

Code: Select all

function love.keypressed(_, scancode)
This makes it very clear that scancode is the only arg being used. Now, sometimes I can get a little ticked off about luacheck poking me about colon syntax in functions that don't use self. I want my API to be consistant so I want all functions to be called with colons, not making people remember which ones have colons and which ones do not. But I end up agreeing that writing the code "correctly" is actually better since it is clear that the function only interacts with local state and does not affect the state of anything else while still making my API consistant.

Code: Select all

function Object:method(a, b, c) end

local o = Object.new()
o:method(a, b, c)
becomes

Code: Select all

function Object.method(_, a, b, c) end -- static function locally accessable to the object

local o = Object.new()
o:method(a, b, c) -- o:method() instead of Object.method()
STI - An awesome Tiled library
LÖVE3D - A 3D library for LÖVE 0.10+

Dev Blog | GitHub | excessive ❤ moé
User avatar
raidho36
Party member
Posts: 2063
Joined: Mon Jun 17, 2013 12:00 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by raidho36 »

Unused variables is something that Lua does a lot in general, so the linter should be able to handle it gracefully rather than force users into particular way of writing code - which is against Lua's principles.

My idea of this is that it should be able to pick up metacomments about it and issue warning if declared and factual data don't align, the same way as it does now except the default "all variables declared as used" can be overridden.

Code: Select all

function ( a, b, c, d )
--luacheck-unused: b, d
end
User avatar
Karai17
Party member
Posts: 930
Joined: Sun Sep 02, 2012 10:46 pm

Re: Find globals with LuaJIT (Linux, probably Mac too)

Post by Karai17 »

the underscore method is idiomatic Lua so i think it's fine~
STI - An awesome Tiled library
LÖVE3D - A 3D library for LÖVE 0.10+

Dev Blog | GitHub | excessive ❤ moé
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 46 guests