# Handling Kernel quit

One can use $Epilog to do something when the Kernel is quit or put an end.m file next to the init.m. For Wolfram System sessions, $Epilog is conventionally defined to read in a file named end.m.

But if $Epilog is set by the user, then end.m is skipped. Question: So what to do if I want something to be done each time Kernel is quit but I also want to be able to play with $Epilog. In that sense that if I set $Epilog I would like my default action to be taken anyway? I need to stress out that I want to establish an action that will not be accidentally overwritten with daily (but advanced) mma usage. • Hackety-hack: could you define an upvalue on SetDelayed[$Epilog,f_] such that you append the calling of your end.m to the execution of f? – Martin Ender Mar 16 '16 at 12:21
• @MartinBüttner it's worth considering that. I need to stress out that I wan't to establish an action on quit that will not be accidentally overwritten with daily (but advanced) mma usage. So your solution is quite stable except the fact I have to include it in init.m. – Kuba Mar 16 '16 at 12:23
• I'd post it as an answer, but thinking about it I'm actually not quite sure how I'd call the unmodified SetDelayed inside the upvalue definition (so as not to run into infinite recursion). I'm sure it's possible, but I'm not that familiar with upvalues. – Martin Ender Mar 16 '16 at 12:30
• mathematica.stackexchange.com/q/104403/12 I have no robust solution for cleaning up on exit and playing nice with any other software that messes with $Epilog or end.m. I gave up on this. – Szabolcs Mar 16 '16 at 13:11 • I asked about it on W Community: community.wolfram.com/groups/-/m/t/824185 – Szabolcs Mar 16 '16 at 14:26 ## 3 Answers If you are willing to rely on undocumented behavior you can move $Epilog out of the System context, and give it a definition that evaluates both an internal (default) expression as well as the public expression assigned to System$Epilog. Your specialized setup: Context[System$Epilog] = "hidden";
hidden$Epilog := (Print["internal"]; System$Epilog)


An arbitrary public definition:

$Epilog := Print["external"]  Now when the kernel is terminated: Exit[]  internal external  • Why does it work? :) In what conditions Mathematica calls $Epilog so it is found on hidden  context first? – Kuba Mar 16 '16 at 12:47
• @Kuba hidden$Epilog is still the internal Mathematica function and it is called by low level reference, I assume. This is no different from moving any other Symbol out of the System context and having it still function when called directly, e.g. you can move Range to fooRange and when you use fooRange[1, 5] it still works. – Mr.Wizard Mar 16 '16 at 13:01 • Yeah but $Epilog := Print["external"] knows you are using System  because it is on context path, why MMA doesn't know it is there too when it calls $Epilog at the end? – Kuba Mar 16 '16 at 13:05 • @Kuba I believe the reference is made at a lower level, meaning that the Kernel is not parsing and evaluating a textual input $Epilog but instead performing e.g. "operation 3F70BE" which happens to correspond to $Epilog. Contexts are a higher-level abstraction. – Mr.Wizard Mar 16 '16 at 13:10 • Doing Context[StringQ] = "myContext" before loading the documentation center seems to break the documentation center. – Jacob Akkerboom Mar 17 '16 at 9:05 In principle this can be done using LibraryLink. Just run an action on library unload. The library will be unloaded on kernel exit, if you don't unload it manually before. Warning: This is a heavyweight solution that just won't be practical in most cases. But it does work and it does not conflict with other packages. If you need to do the cleanup privately, only on your own computer, then it can be useful. If you need to do the cleanup from a package that already uses LibraryLink, then it is useful. Otherwise I wouldn't use it. For reasons of laziness, here's with LTemplate: << LTemplate tem = LClass["Cleanup", {}]; SetDirectory[$TemporaryDirectory];
code = "
struct Cleanup {
~Cleanup() {
mma::print(\"C++: Cleaning up\");

// this below calls myCleanupFunction[]
}
};
";
Export["Cleanup.h", code, "String"];

CompileTemplate[tem, "ShellOutputFunction" -> Print]



This will be called on exit:

myCleanupFunction[] := Print["Mathematica: Cleaning up"]


We create a special object. When this object is no longer referenced, or when the library is unloaded, the cleanup code will be run.

globalCleaner = Make["Cleanup"]

(* Cleanup[1] *)


Now we quit:

Quit


Quitting triggers unloading the library and this gets printed:

C++: Cleaning up

Mathematica: Cleaning up


Standard LibraryLink is a bit different than LTemplate. You'll need to put the code form the destructor above into WolframLibrary_uninitialize() and there's no need a create a special object like Cleanup[1]. I have not tested it (again: laziness), but I expect it will work the same way.

Add the default epilog code to your own. This is what the default does.

?? $Epilog  $Epilog:=If[FindFile[end]=!=\$Failed,<<end]

• The point is, I want to set an action in end.m or any other way and I don't want to care about that. Using composition each time is not an option, unless we use a trick suggested by Martin in the comment. – Kuba Mar 16 '16 at 12:26