3

Context: We use SAS 9.4 and Enterprise Guide 7.15. Currently, we are implementing some new Macros and of course have to change a lot along the way. Sometimes smaller, sometimes bigger changes. The problem is, that in order to get the changes to work, SAS needs us to manually compile the Macro code or to restart the session which is a bit tedious.

This is the current setup in our main file (which calls all the Macros):

/* Macro options */
     MAUTOSOURCE  sasautos = "<path to macro>" mlogic mlogicnest mprint mprintnest MRECALL

Is it possible, while using the MAUTOSOURCE */ sasautos ="" option, to tell SAS every time the Macro is called to actually also compile the Macro instead of using the session-stored Macro? Ideally, the Macro would only be compiled when the whole line of code from the main file (MAUTOSOURCE */ sasautos ="" etc.) is executed, otherwise it should keep a compiled version in the session.

I found this paper (The Autocall Macro Facility in the SAS for Windows Environment) which states in the conclusion

After that SAS will use the code that has already been compiled. If changes are made to the macro, it must be compiled again before the changes go into effect.

which I hope doesn't mean that I have to do it manually. Is there any Macro option to set?

user190080
  • 525
  • 1
  • 8
  • 29
  • How long are you keeping your SAS session active? Do you only use EG as your user interface or are some users also calling SAS directly either as batch/background jobs or using SAS Display Manger? – Tom Mar 29 '19 at 13:46
  • @Tom Basically I never quit the session unless I have to. I am mostly using EG (in combination with VS Code but this shouldn't matter I guess) and yes, we use SAS Server so other users are also calling SAS. I just found an option `%SYSMACDELETE macro_name;` which seems to do what I want - seems also the same as data _null_ suggests...nevertheless I wonder why I can't find the compiled macro in `WORK.SASMACR`. – user190080 Mar 29 '19 at 14:07

3 Answers3

5

In SAS 9.3 they added the %SYSMACDELETE macro function. So if you just want to let autocall redefine a single macro then use that to remove the current definition.

%symacdelete mymacro;

Here is a utility macro that will query SASHELP.VCATALG view to find compiled macros in the WORK library and delete them. It has options to either list names of macros to delete or keep. Note that normal SAS sessions use WORK.SASMACR to store the compiled macros. But SAS/Studio and EG (and perhaps other ways of running SAS) use WORK.SASMAC1 instead.

https://github.com/sasutils/macros/blob/master/macdelete.sas

%macro macdelete(delete,keep);
/*----------------------------------------------------------------------------
Remove compiled macros using %SYSMACDELETE macro statement.

Use DELETE parameter to list macro names to delete.
Use KEEP parameter to list macro names to NOT delete.
Calling it with no values will delete all macros not currently running.
----------------------------------------------------------------------------*/
%local libname memname objname objtype fid i;
%do i=1 %to %sysmexecdepth;
  %let keep=%sysmexecname(&i) &keep;
%end;
%if %length(&delete) %then %let delete=and findw("&delete",objname,',','sit');
%let fid=%sysfunc(open( sashelp.vcatalg(keep=libname memname objname objtype
 where=(libname='WORK' and objtype='MACRO' and memname like 'SASMAC_'
   and not findw("&keep",objname,',','sit') &delete))));
%if (&fid) %then %do;
  %syscall set(fid);
  %do %while(0=%sysfunc(fetch(&fid)));
    %put %sysfunc(compbl(Removing &objname from &libname catalog &memname));
    %sysmacdelete &objname;
  %end;
  %let fid=%sysfunc(close(&fid));
%end;
%else %put %qsysfunc(sysmsg());
%mend macdelete;

Example:

3348  %macro test1; %mend;
3349  %macro test2; %mend;
3350  %macro test3; %mend;
3351  %macro test4; %mend;
3352  %macdelete(test1 test3);
Removing TEST1 from WORK catalog SASMACR
Removing TEST3 from WORK catalog SASMACR
3353  %macdelete(keep=test2);
Removing TEST4 from WORK catalog SASMACR

Example when running SAS/Studio or Enterprise Guide:

 97         %macro test1; %mend;
 98         %macro test2; %mend;
 99         %macro test3; %mend;
 100        %macro test4; %mend;
 101        %macdelete(test1 test3);
 Removing TEST1 from WORK catalog SASMAC1
 Removing TEST3 from WORK catalog SASMAC1
Tom
  • 47,574
  • 2
  • 16
  • 29
  • Great! I really like both of your answers. Right now, the situation is not *that* complex so probably we'll just stick with a simple call of `%SYSMACDELETE macro_name;` or `%include 'path_to_macro'` but I'll make sure to keep a copy of your utility macro, very handy! BTW you were right, the catalog is `WORK.SASMAC1`. Any idea why `%SYSMACDELETE macro_name;` also deletes in this catalog although it states differently in the documentation (only `WORK.SASMACR` should be affetcted)? – user190080 Mar 29 '19 at 15:26
  • Some how the way that EG and SAS/Studio are running SAS makes it use WORK.SASMAC1. I never found any reference to them in the manuals. – Tom Mar 29 '19 at 15:31
  • Then I just take it as it is (though they really should add this). BTW Your last example is probably run in EG instead of SAS/Studio? – user190080 Mar 29 '19 at 15:35
  • EG also uses WORK.SASMAC1, but I don't use EG anymore. – Tom Mar 29 '19 at 15:37
  • I meant in your answer ("Example when running SAS/Studio:"): Shouldn't it be WORK.SASMAC1 only when using EG? I didn't test it in SAS/Studio though... – user190080 Mar 29 '19 at 15:40
3

If you delete the compiled macro from WORK.SASMACR SAS will have to re-compile the macro when you call it again.

proc catalog c=work.sasmacr;
   *contents;
   delete your-macro-to-recompile.macro;
   run;
   quit;
data _null_
  • 8,534
  • 12
  • 14
  • Thx, just for clarification: I found the macro function `%SYSMACDELETE` which *at least seems* to do exactly what I want when placed in the header of my main excecution file. Does this function and your suggestion perform in the same way? – user190080 Mar 29 '19 at 14:11
  • Yes the documentation states exactly that: Deletes a macro definition from the Work.SASMacr catalog. – data _null_ Mar 29 '19 at 14:33
  • I read the definition as well but one thing I can't figure out (Tom mentioned it): my MAcros do not end up in `WORK.SASMACR` but instead in `WORK.SASMAC1` so technically the function shouldn't delete anything simply because the catalog `WORK.SASMACR` does not even exist (if you change `sasmacr` to `sasmac1` your answer works perfectly.) – user190080 Mar 29 '19 at 14:38
  • Yes you must deleted the macro from the catalog where it is stored. – data _null_ Mar 29 '19 at 14:58
3

For your normal users you should set a release schedule of changes. The users will know they need to re-start a new session after the release is made.

For your developers that are testing the changes as they are made they just need to use %INCLUDE to re-compile the macro. So if you know that macro XYZ is changed then just run:

%include maclib('xyz.sas');

Or you could brute force it and recompile all of the macros in your autocall library.

%incldue maclib('*.sas');

You could get fancier and make a macro that cleans out the actual catalog of compiled macros. Something like:

%macro clean_autocall;
proc catalog force c=work.sasmacr;
 save clean_autocall /et=macro;
quit;
options mrecall mautosource;
%mend clean_autocall;

But if you are using Enterprise Guide there are two issues.

First for some reason it uses a different catalog to store the compiled macros. (Why?) I think it is WORK.SASMAC1 instead of WORK.SASMACR.

Second EG will manually compile a bunch of helper macros that it needs. I am not sure if there is an official source for the complete list of these macros? You could try adding code to your project to automatically create the list based on what entries are in the catalog when your project starts. Here is a list I made 10+ years ago when I tried using EG with production environment. But I am sure that it is out of date.

%let s_eg_save= checkfmt checkhotfix
  eclibassign eclibunassign enterpriseguide gaccessible
  _eg_conditional_dropds
;
Tom
  • 47,574
  • 2
  • 16
  • 29