I'm writing a package soon to be posted on SSC that will include an ado front end an mlib file. The problem I'm having is that I want the package to:
* Take advantage of a time-saving function introduced in Stata 13, panelsum().
* Be compatible with older versions of Stata, say, back to Stata 11.
I have written a function that checks the user's Stata version, uses panelsum() the version is >=13 and otherwise bypasses it with a Mata implementation of panelsum(), which is significantly slower. My idea s to compile that in Stata 11, and then share the resulting mlib for use in all versions 11 and higher.
As described, this actually doesn't work. It compiles, but fails at run time. Why? When I run my function in Stata 11, it tries to compile (or whatever the verb is) my function from object code to machine code and it chokes on the reference panelsum(), a function it does not know. It cannot link that reference. The fact that my function will never _call_ panelsum() in Stata 11 does not help.
I can fix that problem through indirection: create a function called _panelsum() that simply passes its arguments to panelsum(). My main function then refers to _panelsum() instead. At runtime, Stata 11 is happy with this because now all functions referenced by my main function clearly exist. And when it runs the main function, by design it never actually hits the call to _panelsum(), so it never wanders into that function, where it would again choke on the troublesome reference to panelsum().
But then I hit another problem. If I compile this in Stata 14, it runs as intended in Stata 14. If I compile this in Stata 11, it runs as intended in Stata 11. But if I compile this in Stata 11, it fails in Stata 14. Thus I cannot distribute my Stata 11-compiled mlib in the expectation that it will work with newer Statas.
What's going on? I guess when Stata 11 compiles my _panelsum(), with its undefined reference to future-built-in panelsum(), it produces object code that Stata 14 cannot comprehend at runtime. It does not recognize my intended reference to the new function.
All of which leads to my question: what is the most graceful way to produce an mlib compatible with multiple versions of Stata, yet taking advantage of built-in functions available in only some?
One elegant solution would to have -net install- run (compile) my mata file one time at installation, producing an mlib compatible with the user's Stata version. This would also let the user take advantage of any speed-ups in Mata made between version 11 and the user's version. But I am pessimistic that can be done.
Something else that might work is writing the ado code to check what version of Stata compiled it, and recompiling it if the version is old. This could be even better in that, if the user upgraded, the user's mlibs would be upgraded too. But I don't know how to do that.
I could also put the Mata code in the ado, so it compiles every time it is loaded. Ugly.
The fallback is to write to versions of the program, one for 11, one for 13. The two copies would be the same but all the functions in the 11 version would have "11" in their names. Each would be compiled in the corresponding Stata version. The ado front end would determine which to call. Workable but also ugly.
Any advice?
--David
* Take advantage of a time-saving function introduced in Stata 13, panelsum().
* Be compatible with older versions of Stata, say, back to Stata 11.
I have written a function that checks the user's Stata version, uses panelsum() the version is >=13 and otherwise bypasses it with a Mata implementation of panelsum(), which is significantly slower. My idea s to compile that in Stata 11, and then share the resulting mlib for use in all versions 11 and higher.
As described, this actually doesn't work. It compiles, but fails at run time. Why? When I run my function in Stata 11, it tries to compile (or whatever the verb is) my function from object code to machine code and it chokes on the reference panelsum(), a function it does not know. It cannot link that reference. The fact that my function will never _call_ panelsum() in Stata 11 does not help.
I can fix that problem through indirection: create a function called _panelsum() that simply passes its arguments to panelsum(). My main function then refers to _panelsum() instead. At runtime, Stata 11 is happy with this because now all functions referenced by my main function clearly exist. And when it runs the main function, by design it never actually hits the call to _panelsum(), so it never wanders into that function, where it would again choke on the troublesome reference to panelsum().
But then I hit another problem. If I compile this in Stata 14, it runs as intended in Stata 14. If I compile this in Stata 11, it runs as intended in Stata 11. But if I compile this in Stata 11, it fails in Stata 14. Thus I cannot distribute my Stata 11-compiled mlib in the expectation that it will work with newer Statas.
What's going on? I guess when Stata 11 compiles my _panelsum(), with its undefined reference to future-built-in panelsum(), it produces object code that Stata 14 cannot comprehend at runtime. It does not recognize my intended reference to the new function.
All of which leads to my question: what is the most graceful way to produce an mlib compatible with multiple versions of Stata, yet taking advantage of built-in functions available in only some?
One elegant solution would to have -net install- run (compile) my mata file one time at installation, producing an mlib compatible with the user's Stata version. This would also let the user take advantage of any speed-ups in Mata made between version 11 and the user's version. But I am pessimistic that can be done.
Something else that might work is writing the ado code to check what version of Stata compiled it, and recompiling it if the version is old. This could be even better in that, if the user upgraded, the user's mlibs would be upgraded too. But I don't know how to do that.
I could also put the Mata code in the ado, so it compiles every time it is loaded. Ugly.
The fallback is to write to versions of the program, one for 11, one for 13. The two copies would be the same but all the functions in the 11 version would have "11" in their names. Each would be compiled in the corresponding Stata version. The ado front end would determine which to call. Workable but also ugly.
Any advice?
--David
Comment