【问题标题】:How to tell SAS to compile a Macro each time it is called instead of doing it manually每次调用宏时如何告诉 SAS 编译宏而不是手动编译
【发布时间】:2019-03-29 13:29:41
【问题描述】:

上下文:我们使用SAS 9.4 和Enterprise Guide 7.15。目前,我们正在实施一些新的宏,当然必须在此过程中进行很多更改。有时更小,有时更大的变化。问题是,为了使更改生效,SAS 需要我们手动编译宏代码或重新启动会话,这有点乏味。

这是我们主文件中的当前设置(调用所有宏):

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

是否有可能在使用MAUTOSOURCE */ sasautos ="" 选项时,在每次调用宏时告诉SAS 来实际编译宏而不是使用会话存储的宏?理想情况下,只有在执行主文件(MAUTOSOURCE */ sasautos ="" 等)中的整行代码时才会编译宏,否则它应该在会话中保留编译版本。

我发现了这个paper (The Autocall Macro Facility in the SAS for Windows Environment),它在结论中声明

之后 SAS 将使用已经 被编译。如果对宏进行了更改,则必须 在更改生效之前再次编译。

我希望这并不意味着我必须手动完成。有没有可以设置的宏选项?

【问题讨论】:

  • 您的 SAS 会话保持活跃多长时间?您是否只使用 EG 作为您的用户界面,还是某些用户也直接调用 SAS 作为批处理/后台作业或使用 SAS Display Manger?
  • @Tom 基本上我从不退出会话,除非我必须这样做。我主要使用 EG(与 VS Code 结合使用,但我猜这不重要),是的,我们使用 SAS 服务器,所以其他用户也调用 SAS。我刚刚找到了一个选项%SYSMACDELETE macro_name;,它似乎可以满足我的要求-似乎也与数据 null 建议的相同...但是我想知道为什么我在WORK.SASMACR 中找不到已编译的宏.

标签: sas sas-macro


【解决方案1】:

在 SAS 9.3 中,他们添加了 %SYSMACDELETE 宏函数。因此,如果您只想让自动调用重新定义单个宏,请使用它来删除当前定义。

%symacdelete mymacro;

这是一个实用宏,它将查询 SASHELP.VCATALG 视图以在 WORK 库中查找已编译的宏并将其删除。它具有列出要删除或保留的宏名称的选项。请注意,普通 SAS 会话使用 WORK.SASMACR 来存储已编译的宏。但 SAS/Studio 和 EG(可能还有其他运行 SAS 的方式)改为使用 WORK.SASMAC1。

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;

例子:

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

运行 SAS/Studio 或 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

【讨论】:

  • 太棒了!我真的很喜欢你的两个答案。现在,情况并没有那么复杂,所以我们可能会坚持简单地调用%SYSMACDELETE macro_name; 或%include 'path_to_macro',但我会确保保留一份实用程序宏的副本,非常便利!顺便说一句,您是对的,目录是WORK.SASMAC1。知道为什么%SYSMACDELETE macro_name; 也会在此目录中删除,尽管它在文档中的说明不同(只有WORK.SASMACR 应该受到影响)?
  • EG 和 SAS/Studio 运行 SAS 的方式使其使用 WORK.SASMAC1。我从未在手册中找到对它们的任何引用。
  • 那我就照原样接受(尽管他们真的应该添加这个)。顺便说一句,您的最后一个示例可能是在 EG 而不是 SAS/Studio 中运行的?
  • EG也使用WORK.SASMAC1,但我不再使用EG了。
  • 我的意思是在你的回答中(“运行 SAS/Studio 时的示例:”):不应该是 WORK.SASMAC1 仅在使用 EG 时?虽然我没有在 SAS/Studio 中测试它...
【解决方案2】:

如果您从 WORK.SASMACR 中删除已编译的宏,当您再次调用该宏时,SAS 将不得不重新编译该宏。

proc catalog c=work.sasmacr;
   *contents;
   delete your-macro-to-recompile.macro;
   run;
   quit;

【讨论】:

  • 谢谢,只是为了澄清:我发现宏函数%SYSMACDELETE 至少看起来在我的主执行文件的标题中完全符合我的要求。此功能和您的建议是否以相同的方式执行?
  • 是的,文档明确指出:从 Work.SASMacr 目录中删除宏定义。
  • 我也阅读了定义,但有一件事我想不通(Tom 提到过):我的 MACros 没有出现在 WORK.SASMACR 中,而是出现在 WORK.SASMAC1 中,所以从技术上讲,该函数应该'不要仅仅因为目录WORK.SASMACR 甚至不存在就删除任何内容(如果您将sasmacr 更改为sasmac1,您的答案就完美了。)
  • 是的,您必须从存储宏的目录中删除该宏。
【解决方案3】:

对于您的普通用户,您应该设置更改的发布时间表。用户会知道他们需要在发布后重新开始一个新会话。

对于正在测试所做更改的开发人员,他们只需要使用 %INCLUDE 重新编译宏。因此,如果您知道宏 XYZ 已更改,则只需运行:

%include maclib('xyz.sas');

或者你可以强制它并重新编译你的自动调用库中的所有宏。

%incldue maclib('*.sas');

您可以更有趣并制作一个宏来清除已编译宏的实际目录。比如:

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

但是,如果您使用的是企业指南,则存在两个问题。

首先出于某种原因,它使用不同的目录来存储已编译的宏。 (为什么?)我认为是 WORK.SASMAC1 而不是 WORK.SASMACR。

Second EG 将手动编译一堆它需要的辅助宏。我不确定这些宏的完整列表是否有官方来源?您可以尝试在项目中添加代码,以便在项目启动时根据目录中的条目自动创建列表。这是我在 10 多年前尝试在生产环境中使用 EG 时制作的列表。但我确信它已经过时了。

%let s_eg_save= checkfmt checkhotfix
  eclibassign eclibunassign enterpriseguide gaccessible
  _eg_conditional_dropds
;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 2011-08-21
    • 2012-06-26
    相关资源
    最近更新 更多