BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Nasser_DRMCP
Lapis Lazuli | Level 10

Hello,

when I launch this code in an included program, via a main program  it works, I mean the log of the main program displays ===>"XXX"

but by replacing "XXX" by &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME it doesn't ,only / is displayed. I woud like to obtain the folder and program of the included prog.

thanks in advance for your help

regards

Nasser

%macro mc_get_program_name ;
%let v_path_prog =;

%let v_path_prog = "XXX" ; 

%mend ;

%mc_get_program_name ;

%let path_prog = &v_path_prog ;
%put ===>&path_prog ;

1 ACCEPTED SOLUTION

Accepted Solutions
s_lassen
Meteorite | Level 14

A slight modification to my solution: you can also put the RUN statement inside the macro, as log as you do not put the final semicolon.

%macro mc_get_program_name;
  data _null_;
    call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
  run
%mend;

Then, in your %INCLUDE program, just use the macro call with a semicolon:

%mc_get_program_name;

and things should work as you want, the datastep does not get executed before SAS encounters the semicolon (which is outside the macro).

View solution in original post

14 REPLIES 14
ed_sas_member
Meteorite | Level 14

Hi @Nasser_DRMCP 

 

You need to define the macrovariable as a global one to use it outside the macro-program:

%macro mc_get_program_name ;
%global v_path_prog; /*add this statement*/
%let v_path_prog =;

%let v_path_prog = "XXX" ; 

%mend ;

%mc_get_program_name ;

%let path_prog = &v_path_prog ;
%put ===>&path_prog ;

Best,

Nasser_DRMCP
Lapis Lazuli | Level 10
thanks for your quick respons but the result is still the same.
only "/" is printed in the logfile
Tom
Super User Tom
Super User

I don't see how the subject relates to the code you posted. There are no references to either of those system generated macro variables in the code you posted.  There is no %INCLUDE command in the code you posted.

 

Note those variables are only populated while you are including the file.  

Example to try:

filename code temp;
data _null_;
  file code ;
  put
 '%global mypath;'
/'%let mypath=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;'
  ;
run;

%include code / source2;
%put &mypath;
Nasser_DRMCP
Lapis Lazuli | Level 10
Sorry,

I launch a prog that only contains %include '/sbsas/ALBERTNA/include/nm_workshop_batch_inc.sas' ;
wich contains the code of the macro i posted
Tom
Super User Tom
Super User

@Nasser_DRMCP wrote:
Sorry,

I launch a prog that only contains %include '/sbsas/ALBERTNA/include/nm_workshop_batch_inc.sas' ;
wich contains the code of the macro i posted

If the file only includes the macro definition then including it will only DEFINE the macro, not run it.  So there is no place where those two system macro variables would be evaluated while they reflect that include file.  You need to either run the macro as part of the code included. Or as in my example above just create a global macro variable in the open code in the include file that you can then reference later after the code that was included as finished running.

 

To test make two files to include.  One with a macro definition that references the system macro variables.  The second with a call to that macro.  Include them in order and you should see that the path to the file with the call to macro is displayed.

Nasser_DRMCP
Lapis Lazuli | Level 10
Inside the included macro I have the code and the call (%mc_get_program_name 😉 but It does not work.
i tried 2 scenarios .first, the body and call inside the same prog . second scenario, one prog with body macro and another prog wich makes the include and the call.
Tom
Super User Tom
Super User

Please post CODE. Like this:

filename code 'C:\downloads\test1.sas';
data _null_;
  file code ;
  put
 '%macro test1;'
/'%put macroname=&sysmacroname. includepath=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;'
/'%mend test1;'
/'%test1;'
  ;
run;

%include code / source2;

Looks like SAS is treating the execution of the macro as not part of the inclusion process, so the macro variables are not populated.

Use one of the work arounds.

Nasser_DRMCP
Lapis Lazuli | Level 10
I tried the code you proposed. it works very well. but I would like to get the result via macro.
Tom
Super User Tom
Super User

@Nasser_DRMCP wrote:
I tried the code you proposed. it works very well. but I would like to get the result via macro.

Explain more what the use case actually is.  Some alternatives: 

1) If you are using SAS autocall there are options to have SAS display in the log the name of the file where a macro is compiled from.

2) If you are using a version control system they usually have a method to modify the text of the file when you check in the updates to include the filename (and other version control metadata).  I know we used to use this feature in RCS to keep comment sections of macro definitions up to date.

3)  You could make a naming convention for your own global macro variables and use the open code %LET method in my example.

%global location_mymacro;
%let location_mymacro= &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME;
%macro mymacro;
%put This macro was defined from source file &location_mymacro;
%mend mymacro;
Nasser_DRMCP
Lapis Lazuli | Level 10
Thanks,
I agree that your suggestion works well.
but I would like to have the macro's body and macro's call into 2 distincts programs. if it is possible
s_lassen
Meteorite | Level 14

Here is a slightly dirty way to accomplish your goal. Define your macro like this:

%macro mc_get_program_name;
  data _null_;
    call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
%mend ;

Then, the data step will not be executed immediately, but only when SAS encounters a RUN statement or a step boundary.

 

In your %INCLUDE program, you should then (just to be safe) put a RUN after the macro call:

%mc_get_program_name;
run;

And your macro variable will have the right value.

Patrick
Opal | Level 21

The main challenge here is what happens during macro compilation and macro execution time. 

 

During macro compilation time (that's what happens when you execute your %include statement) any macro variable used within a macro definition does NOT get resolved. SAS just compiles your macro "as is". In below example SAS will compile statement "%put &=someMacroVar;" and not the resolved value of the macro variable. 

%symdel someMacroVar/nowarn;
/** macro compilation **/
%let someMacroVar=ABC;
%macro demo(); 
  %put &=someMacroVar;
%mend;

During macro execution time SAS will resolve the macro variable. Because in below example the macro variable doesn't exist anymore during execution time SAS will throw a warning.

%symdel someMacroVar/nowarn;
/** macro execution **/
%demo();
38         %demo();
WARNING: Apparent symbolic reference SOMEMACROVAR not resolved.

The only way I can think of to compile a macro with a resolved macro variable (like &SYSINCLUDEFILEDIR in your case) would be to have a data step which dynamically creates the macro code and then execute (compile) the generated code.

 

Having said all that: If you just want in the log an indication from where the macro has been compiled from whenever you call (execute) it then much simpler would be to store the macro definition in a .sas file in a folder that is part of the autocall facility. If you do so then you don't need the %include statement anymore. You just call the macro - and if you set option MAUTOLOCDISPLAY then you'll get in the SAS log where the macro has been compiled from.

Tom
Super User Tom
Super User

@Nasser_DRMCP wrote:

Hello,

when I launch this code in an included program, via a main program  it works, I mean the log of the main program displays ===>"XXX"

but by replacing "XXX" by &SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME it doesn't ,only / is displayed. I woud like to obtain the folder and program of the included prog.

thanks in advance for your help

regards

Nasser

%macro mc_get_program_name ;
%let v_path_prog =;

%let v_path_prog = "XXX" ; 

%mend ;

%mc_get_program_name ;

%let path_prog = &v_path_prog ;
%put ===>&path_prog ;


Not sure what the purpose of this is, but if you want to record the name of the file you including just move the %LET statements to OUTSIDE of the macro definition. 

You can place it either before or after the code that defines a macro, but if you want to use the new macro variable inside the body of the macro then make sure the macro variable you create is defined before you call the macro.

%let v_path_prog=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME ;
%put  Before macro definition: &=v_path_prog;
%macro my_functional_macro;
* This macro does something actually useful ;
%put &=sysmacroname &=v_path_prog;
%mend  my_functional_macro;
%put  After macro definition: &=v_path_prog;
%my_functional_macro;
%put  After macro execution: &=v_path_prog;

Results:

1     %include 'c:\downloads\code.sas' / source2 ;
NOTE: %INCLUDE (level 1) file c:\downloads\code.sas is file c:\downloads\code.sas.
2    +%let v_path_prog=&SYSINCLUDEFILEDIR/&SYSINCLUDEFILENAME ;
3    +%put  Before macro definition: &=v_path_prog;
Before macro definition: V_PATH_PROG=c:\downloads/code.sas
4    +%macro my_functional_macro;
5    +* This macro does something actually useful ;
6    +%put &=sysmacroname &=v_path_prog;
7    +%mend  my_functional_macro;
8    +%put  After macro definition: &=v_path_prog;
After macro definition: V_PATH_PROG=c:\downloads/code.sas
9    +%my_functional_macro;
SYSMACRONAME=MY_FUNCTIONAL_MACRO V_PATH_PROG=c:\downloads/code.sas
10   +%put  After macro execution: &=v_path_prog;
After macro execution: V_PATH_PROG=c:\downloads/code.sas
11   +
NOTE: %INCLUDE (level 1) ending.

 

s_lassen
Meteorite | Level 14

A slight modification to my solution: you can also put the RUN statement inside the macro, as log as you do not put the final semicolon.

%macro mc_get_program_name;
  data _null_;
    call symputx('v_path_prog',catx('/',symget('SYSINCLUDEFILEDIR'),symget('SYSINCLUDEFILENAME')));
  run
%mend;

Then, in your %INCLUDE program, just use the macro call with a semicolon:

%mc_get_program_name;

and things should work as you want, the datastep does not get executed before SAS encounters the semicolon (which is outside the macro).

hackathon24-white-horiz.png

2025 SAS Hackathon: There is still time!

Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!

Register Now

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 14 replies
  • 3291 views
  • 0 likes
  • 5 in conversation