Archive: Best Practices for Debugging NSIS Scripts?


Best Practices for Debugging NSIS Scripts?
I am embarrassed to admit that I have been going very long writing hundreds of NSIS scripts (with varying degrees of complexity) without ever using a debugger. So far, I have been able to get away with it, but every once in a while I stumble upon a problem that makes me wish there would be a way to single-step or view some console output.

What is the recommended way to debug NSIS scripts?

Is it the same for scripts that have 'SilentInstall silent' and 'SetSilent silent' on?

More specifically, I have a single line that doesn't work for some reason, but I have no clue why, because the NSIS script has 'SilentInstall silent' and 'SetSilent silent' on:

ReadEnvStr$varCOMSPECCOMSPEC
nsExec
::Exec'"$varCOMSPEC"/C"$SYSDIR\attrib$PROFILE\Desktop\*">dtattr.txt'

Our biggest sanity saver is a logging macro that allows us to log to a text file in Documents and thus we can just add in a ${LogWrite} "varCOMSPEC=$varCOMSPEC" or return codes or what have you. We can also do log levels and wrap certain logging in a "${If} $LogLevel > 1" block.

After that, there was a Debug/DumpState plug-in that we used to use (although looking on my system right now, I can't find it anymore). This plug-in with put up a dialog with current variable and stack states. I don't know if it would work in a silent installer as we haven't specifically tried it in that state.


Well I usually use message boxes but those don't typically show in silent installs. I have noticed that using a banner shows up even on silent install (this may not be on purpose, but it could be a useful bug for you :)). So you could do something like:

Banner::show "Some stuff ${some variable}"
;you may have to put an artificial delay here depending on what you're doing.
Banner::destroy

Also, looking at what you are trying to do, I am wondering why you are needing the ENVIRONMENT variable COMSPEC? I understand it holds the path to cmd.exe, but is it necessary to call cmd.exe? could you simply run:

nsExec::Exec '"$SYSDIR\attrib $PROFILE\Desktop\*" > dtattr.txt ' ?

Also, you spelled "attrib" wrong (you've got "atrrib"). As a side note, the attrib function also expects some sort of attribute to be passed in before the file name for which you are modifying. So I would expect to see something like:

nsExec::Exec '"$SYSDIR\attrib R $PROFILE\Desktop\*" > dtattr.txt ' for Read only.

I haven't used 'attrib' much so these are simple observations that may not be helpful.

When I run into problems calling an executable, I always open an actual command prompt and try it from there (by copying and pasting the relevant text from my installer so as to catch spelling errors like the one above). Hope this helps.


Originally posted by blh83
Well I usually use message boxes but those don't typically show in silent installs
That's what I've been using too. Interestingly, in my silent install MessageBox does show up, so it helps.

Originally posted by blh83
Also, you spelled "attrib" wrong (you've got "atrrib").
You are correct. That was a typo in the posting, not in the script (I usually copy & paste verbatim but this time I failed to do so).

Thanks.

Originally posted by CrushBug
Our biggest sanity saver is a logging macro that allows us to log to a text file in Documents and thus we can just add in a ${LogWrite} "varCOMSPEC=$varCOMSPEC"... We can also do log levels and wrap certain logging in a "${If} $LogLevel > 1" block.
I looked at the NSIS User Manual but I couldn't find ${LogWrite}. Is that a plugin? Where do I find it?

Thanks.

It was just an internally developed set of macros that use the built-in NSIS FileOpen 'a', FileSeek END and FileWrite $LogString commands. I would like to post the code and some future date, but we are in the middle of finalling a project right now, so it will be some time before I can get to it.


Something like this should be sufficient:

Var mylogfile

Function .onInit
FileOpen $mylogfile "$TEMP\nsislog.txt" "a"
FunctionEnd

!macro _LogWrite text
FileWrite $mylogfile '${text}'
!macroend

!define LogWrite !insertmacro _LogWrite

Maybe you could use this: http://nsis.sourceforge.net/Nsisdbg_plug-in

NSIS Debugger is a NSIS plugin which allows you to debug your NSIS installers. The plugin will create a dialog which will be displayed alongside the NSIS window. The first thing you will get familiar with is the tabbed pages. Use them to switch between variable list, stack view, debug log, config. and about page.
I did not test it, but it seems good.

I wrote a set of macros specific to my project that logged the name of the function/section, the values of all the registers, and the contents of the stack (using the stack plugin). Then, at the start and end of every function/section I called a "DebugPre" and "DebugPost" macro which wrote out all that information, as well as storing it in another huge set of registers dedicated to the purpose. That way, I could tell if the registers or stack were getting messed up by any function automatically (it would pop up a message box if there was an error at the end of a function).

Of course, this took a while to implement and debug the debug code so that it was stable and didn't cause any problems itself.

And a basic installer produced a 50MB log file when there were no errors.

You might call it overkill, but for a big/complex project it might be worth it - I was surprised by how many register/stack issues I had introduced that went unnoticed 99% of the time. (It depends on how functional you make an installer, and how many levels deep your macro/function calls go)

Although I do have to disable the debug code when releasing an installer because, even without the log file, it still slows down the installer a lot.