Noz.i.kor
Noz.i.kor

Reputation: 3747

Fortran substitute subroutine name using macro

I am writing a module that allows users to log information. I want to provide an interface that logs a string message, which can be called as

call m_log(msg)

So in file m_logger.f90, I will have

module m_logger
..
  subroutine m_log(msg)
  ..
end module 

In file main.f90, a user will have

program main
use m_logger

call m_log(msg)
end program 

Now how can I substitute call m_log(msg) with call m_log(msg, __FILE__, __LINE__) ?

Because of this substitution, a different subroutine subroutine m_log(msg, filename, linenum) in the logger module will be called instead.

If I use a macro like #define m_log(msg) m_log(msg,__FILE__,__LINE__) , it will have to be added to every user file that uses the logger.

Also, I do not want to enforce the user to pass __FILE__ and __LINE__ explicitly.

Is there a way I can do this? Or are there any other alternatives altogether?

Thanks in advance

Edit: I had a discussion on comp.lang.fortran. Adding a link for reference. here

Upvotes: 3

Views: 1579

Answers (3)

Xiaolei Zhu
Xiaolei Zhu

Reputation: 527

Since you want them to be passed as compiler macros by the user, you would first have to choose different names for your macros. __FILE__ and __LINE__ are both predefined macros. These two macros are defined by preprocessor, not passed by the user. I think that might have cause some confusion.

If you would like to allow users to optionally supply the macros through compiler options, it is probably best to include #ifdef directive in your subroutine:

subroutine m_log(msg)
  implicit none
  character(len=*) :: msg
  character(len=something) :: file
  integer ::line
  !Initialize file and line to some default value
  file=...
  line=...
#ifdef __KVM_FILE__
   file=__KVM_FILE__
#endif
#ifdef __KVM_LINE__
   line=__KVM_LINE__
#endif
   ...

This way the user will always call the subroutine with the same syntax call m_log(something), but the effect will change according to your compilation macros. Of course, that would also require the user to recompile your code every time they change this macro. If this is too costly to do, you can set up a subroutine with optional argument (as in Kyle's answer), then enclose #define macro in #ifdef blocks, and put them into an .h file, and have your user always include that file. (similar to Vladimir's answer)

Upvotes: 0

In this case you would have to use the same approach C uses. Define the macro you proposed

 #define log(msg) m_log(msg,__FILE__,__LINE__)

in a separate file (possibly with other useful macros) and include it using #include "file.inc" (standard Fortran include won't suffice).

If the macro has a different name, than the subroutine it actually calls, you can ensure that the user has to use the include and cannot forget it.

Upvotes: 4

Kyle Kanos
Kyle Kanos

Reputation: 3264

If you don't want to force __file__ and __line__ explicitly, then you can use the optional flag, such that your subroutine looks like:

subroutine m_log(msg, filename, linenum)
   character(len=*) :: msg
   character(len=*), optional :: filename
   integer, optional :: linenum
   if(present(filename)) then
      <something with filename>
   endif
   if(present(linenum)) then
      <something with linenume>
   endif
   <normal stuff with msg>
end subroutine

The intrinsic function present returns a true value if filename or linenum have any values attached to it, returning false otherwise.

Upvotes: 3

Related Questions