#sas #sas-macro
#sas #sas-макрос
Вопрос:
Контекст: Мы используем 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 =""
и т.д.), В противном случае он должен сохранять скомпилированную версию в сеансе.
Я нашел этот документ (Средство макроса автоматического вызова в среде SAS для Windows), в заключении которого говорится
После этого SAS будет использовать код, который уже был скомпилирован. Если в макрос внесены изменения, его необходимо скомпилировать заново, прежде чем изменения вступят в силу.
что, я надеюсь, не означает, что я должен делать это вручную. Есть ли какой-либо параметр макроса для установки?
Комментарии:
1. Как долго вы поддерживаете свой сеанс SAS активным? Вы используете EG только в качестве пользовательского интерфейса или некоторые пользователи также вызывают SAS напрямую либо в качестве пакетных / фоновых заданий, либо с помощью SAS Display Manger?
2. @Tom В принципе, я никогда не выхожу из сеанса, если в этом нет необходимости. Я в основном использую EG (в сочетании с VS Code, но, я думаю, это не должно иметь значения) и да, мы используем SAS Server, поэтому другие пользователи также вызывают SAS. Я только что нашел опцию,
%SYSMACDELETE macro_name;
которая, похоже, делает то, что я хочу — похоже, также совпадает с тем, что предлагает data null … тем не менее, мне интересно, почему я не могу найти скомпилированный макрос вWORK.SASMACR
.
Ответ №1:
В SAS 9.3 они добавили %SYSMACDELETE
функцию макроса. Итак, если вы просто хотите, чтобы autocall переопределял один макрос, используйте это для удаления текущего определения.
%symacdelete mymacro;
Вот служебный макрос, который будет запрашивать SASHELP.Просмотр VCATALG для поиска скомпилированных макросов в РАБОЧЕЙ библиотеке и их удаления. В нем есть опции либо для перечисления имен макросов для удаления, либо для сохранения. Обратите внимание, что обычные сеансы 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(amp;i) amp;keep;
%end;
%if %length(amp;delete) %then %let delete=and findw("amp;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("amp;keep",objname,',','sit') amp;delete))));
%if (amp;fid) %then %do;
%syscall set(fid);
%do %while(0=%sysfunc(fetch(amp;fid)));
%put %sysfunc(compbl(Removing amp;objname from amp;libname catalog amp;memname));
%sysmacdelete amp;objname;
%end;
%let fid=%sysfunc(close(amp;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
Комментарии:
1. Отлично! Мне действительно нравятся оба ваших ответа. Прямо сейчас ситуация не такая сложная, поэтому, вероятно, мы просто воспользуемся простым вызовом
%SYSMACDELETE macro_name;
или%include 'path_to_macro'
, но я позабочусь о том, чтобы сохранить копию вашего служебного макроса, это очень удобно! Кстати, вы были правы, каталог являетсяWORK.SASMAC1
. Есть идеи, почему%SYSMACDELETE macro_name;
также удаляет в этом каталоге, хотя в документации указано иначе (толькоWORK.SASMACR
должно быть указано)?2. Некоторые способы, которыми EG и SAS / Studio запускают SAS, заставляют его использовать РАБОТУ. SASMAC1. Я никогда не находил ссылок на них в руководствах.
3. Тогда я просто принимаю это как есть (хотя они действительно должны добавить это). Кстати, ваш последний пример, вероятно, выполняется в EG вместо SAS / Studio?
4. EG также использует WORK. SASMAC1, но я больше не использую EG.
5. Я имел в виду в вашем ответе («Пример при запуске SAS / Studio:»): разве это не должно работать. SASMAC1 только при использовании, НАПРИМЕР? Однако я не тестировал его в SAS / Studio…
Ответ №2:
Если вы удалите скомпилированный макрос из РАБОТЫ.SASMACR SAS должен будет повторно скомпилировать макрос при его повторном вызове.
proc catalog c=work.sasmacr;
*contents;
delete your-macro-to-recompile.macro;
run;
quit;
Комментарии:
1. Спасибо, просто для пояснения: я нашел функцию макроса,
%SYSMACDELETE
которая , по крайней мере, кажется , делает именно то, что я хочу, когда помещена в заголовок моего основного файла выполнения. Выполняется ли эта функция и ваше предложение одинаково?2. Да, в документации указано именно это: Удаляет определение макроса из каталога Work.SASMacr.
3. Я также прочитал определение, но одну вещь я не могу понять (Том упомянул об этом): мои макросы заканчиваются не в
WORK.SASMACR
, а вместо этого вWORK.SASMAC1
, поэтому технически функция не должна ничего удалять просто потому, что каталогWORK.SASMACR
даже не существует (если вы изменитеsasmacr
наsasmac1
, ваш ответ будет работать идеально.)4. Да, вы должны удалить макрос из каталога, в котором он хранится.
Ответ №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;
Но если вы используете Enterprise Guide, возникают две проблемы.
Сначала по какой-то причине он использует другой каталог для хранения скомпилированных макросов. (Почему?) Я думаю, что это РАБОТАЕТ.SASMAC1 вместо РАБОТЫ.SASMACR.
Второй пример вручную скомпилирует кучу вспомогательных макросов, которые ему нужны. Я не уверен, есть ли официальный источник для полного списка этих макросов? Вы могли бы попробовать добавить в свой проект код для автоматического создания списка на основе того, какие записи есть в каталоге при запуске вашего проекта. Вот список, который я составил более 10 лет назад, когда пытался использовать, например, с производственной средой. Но я уверен, что он устарел.
%let s_eg_save= checkfmt checkhotfix
eclibassign eclibunassign enterpriseguide gaccessible
_eg_conditional_dropds
;