- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a fairly simple console program that takes a single argument from the command line and the implements a progress update (to eventually be used in a larger program) ...
! fortranconsole.f90
program Console
use MyLib
implicit none
!character(:), allocatable :: taskId
character(len=36) :: taskId
procedure(ProgressUpdateAction), pointer :: progressUpdate
! Print splash line
print *, 'Analysis Console'
call ProcessCommandLine(taskId)
! Print the task id to the command line
print *, taskId
call DoWork(progressUpdate)
contains
subroutine ProcessCommandLine(taskId)
character(len=36), intent(out) :: taskId
integer :: myArgLength
integer ::myStat
! Check command line for supplied arguments
if (Command_argument_count() == 0) then
stop "Error: There were no command line arguments."
end if
call Get_command_argument(1, length=myArgLength, status=myStat)
if (0 < myStat) then
stop "Error: Could not retrieve the first command argument."
end if
if (36 < myArgLength) then
stop "Error: Argument more than 36 characters long."
end if
! Get first argument
call Get_command_argument(1, value=taskId, status=myStat)
if (myStat /= 0) then
stop "Error GET_COMMAND_ARGUMENT failed unexpectedly."
end if
end subroutine
end program
! modules.f90
module MyLib
implicit none
interface
subroutine ProgressUpdateAction(percentProgress)
integer, intent(in) :: percentProgress
end subroutine
end interface
contains
subroutine DoWork(progressUpdate)
!DIR$ ATTRIBUTES DLLEXPORT :: DoWork
!DIR$ ATTRIBUTES ALIAS: 'DoWork' :: DoWork
!DIR$ ATTRIBUTES REFERENCE :: progressCallBack
procedure(ProgressUpdateAction), intent(in), pointer :: progressUpdate
integer, parameter :: STEP_COUNT = 9
integer, parameter :: OP_COUNT = 100000000
integer :: i, j, percentProgress
real(8) :: n
do i = 1, STEP_COUNT
! Update the status.
percentProgress = (i - 1) * 100.0 / STEP_COUNT
call progressUpdate(percentProgress)
! Do something expensive.
!do j = 1, OP_COUNT
! n = sqrt(real(j,8))
! if (j == OP_COUNT) print *, n
!end do
end do
end subroutine
end module
When I try to debug the code in VS2022 (v16.0.6), I get this ...
... which looks to be where the call to progressUpdate is made. If I run the executable from the command line I get this ...
My compiler/IDE/etc. setup (which is all the latest installs) ...
Am I doing something wrong in implementing the interface? Is the procedure/pointer throwing things off?
Many thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In the blog post that you link to, the author has written the equivalent of a Fortran procedure in C# that does something (it writes to the console) when the DoWork subroutine requests a progress update by invoking the progressUpdate procedure pointer. There's nothing equivalent to that in your code. How does your code know what to do when a progressUpdate is requested?
You could write a procedure something like:
module MyThings
implicit none
contains
! This procedure matches the characteristics
! defined by the ProgressUpdateAction abstract interface
! in the MyLib module.
subroutine my_progress_updater(percentProgress)
integer, intent(in) :: percentProgress
write (*, "('I am about ',i0,'% of the way there.')") &
percentProgress
end subroutine my_progress_updater
end module MyThings
and then pointer assign progressUpdate prior to the call to DoWork
use MyThings
...
progressUpdate => my_progress_updater
call DoWork(progressUpdate)
(The author of the blog post made the progressUpdate thing a procedure pointer possibly because of some idiosyncrasy associated with interfacing with C# (or possibly because they just like pointers). But there's no need for it in a a Fortran-Fortran case.)
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
At a first glance I would say that you forgot to define the procedure pointer. At least, I do not see a statement like:
progressUpdate => progressUpdateAction
or something similar.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks @Arjen_Markus . Tried your suggestion by inserting that statement below line 20 in modules.for (in the MyLib module).
! modules.f90
module MyLib
implicit none
interface
subroutine ProgressUpdateAction(percentProgress)
integer, intent(in) :: percentProgress
end subroutine
end interface
contains
subroutine DoWork(progressUpdate)
!DIR$ ATTRIBUTES DLLEXPORT :: DoWork
!DIR$ ATTRIBUTES ALIAS: 'DoWork' :: DoWork
!DIR$ ATTRIBUTES REFERENCE :: progressCallBack
procedure(ProgressUpdateAction), intent(in), pointer :: progressUpdate
progressUpdate => progressUpdateAction ! <--
integer, parameter :: STEP_COUNT = 9
integer, parameter :: OP_COUNT = 100000000
integer :: i, j, percentProgress
real(8) :: n
do i = 1, STEP_COUNT
! Update the status.
percentProgress = (i - 1) * 100.0 / STEP_COUNT
call progressUpdate(percentProgress)
! Do something expensive.
!do j = 1, OP_COUNT
! n = sqrt(real(j,8))
! if (j == OP_COUNT) print *, n
!end do
end do
end subroutine
end module
Tried compiling and get "Warning warning #8889: Explicit interface or EXTERNAL declaration is required. [DOWORK]" (referring to line 22 in fortanconsole.for) and then a bunch of errors.
I also tried putting that statement below line 12 in fortranconsole.f90 ...
! fortranconsole.f90
program Console
use MyLib
implicit none
!character(:), allocatable :: taskId
character(len=36) :: taskId
procedure(ProgressUpdateAction), pointer :: progressUpdate
progressUpdate => progressUpdateAction ! <--
! Print splash line
print *, 'Analysis Console'
call ProcessCommandLine(taskId)
! Print the task id to the command line
print *, taskId
call DoWork(progressUpdate)
contains
subroutine ProcessCommandLine(taskId)
character(len=36), intent(out) :: taskId
integer :: myArgLength
integer ::myStat
! Check command line for supplied arguments
if (Command_argument_count() == 0) then
stop "Error: There were no command line arguments."
end if
call Get_command_argument(1, length=myArgLength, status=myStat)
if (0 < myStat) then
stop "Error: Could not retrieve the first command argument."
end if
if (36 < myArgLength) then
stop "Error: Argument more than 36 characters long."
end if
! Get first argument
call Get_command_argument(1, value=taskId, status=myStat)
if (myStat /= 0) then
stop "Error GET_COMMAND_ARGUMENT failed unexpectedly."
end if
end subroutine
end program
... but instead get "Error error LNK2019: unresolved external symbol PROGRESSUPDATEACTION referenced in function MAIN__ fortranconsole.obj" and "fatal error LNK1120: 1 unresolved externals x64\Debug\FortranConsole.exe".
I don't think what I'm trying to do is too wild. The code is based off of Calling Fortran from C# – Monitoring Progress Using Callbacks. Any other suggestions? Could there be something in the project properties that I need to set?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Definitely nothing too wild :), but what I meant to explain is that the pointer you pass to the routine DoWork must be pointing to an existing routine. Now you use the name of the interface. Your second solution is the way to go (because otherwise you could leave out the argument altogether), but you need an actual routine to do the work.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In the blog post that you link to, the author has written the equivalent of a Fortran procedure in C# that does something (it writes to the console) when the DoWork subroutine requests a progress update by invoking the progressUpdate procedure pointer. There's nothing equivalent to that in your code. How does your code know what to do when a progressUpdate is requested?
You could write a procedure something like:
module MyThings
implicit none
contains
! This procedure matches the characteristics
! defined by the ProgressUpdateAction abstract interface
! in the MyLib module.
subroutine my_progress_updater(percentProgress)
integer, intent(in) :: percentProgress
write (*, "('I am about ',i0,'% of the way there.')") &
percentProgress
end subroutine my_progress_updater
end module MyThings
and then pointer assign progressUpdate prior to the call to DoWork
use MyThings
...
progressUpdate => my_progress_updater
call DoWork(progressUpdate)
(The author of the blog post made the progressUpdate thing a procedure pointer possibly because of some idiosyncrasy associated with interfacing with C# (or possibly because they just like pointers). But there's no need for it in a a Fortran-Fortran case.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you @Arjen_Markus and @IanH . Your responses have provided the solution I was looking for. I really appreciate the speedy replies.
I have updated my code and it compiles and run fine. Here is where I ended up ...
! fortranconsole.f90
program Console
use Library
implicit none
character(len=36) :: taskId
procedure(IProgressUpdateAction), pointer :: progressUpdate
! Print splash line
print *, 'Analysis Console'
call ProcessCommandLine(taskId)
! Print the task id to the command line
print *, taskId
progressUpdate => ProgressUpdateAction
call DoWork(progressUpdate)
contains
subroutine ProcessCommandLine(taskId)
character(len=36), intent(out) :: taskId
integer :: myArgLength
integer ::myStat
! Check command line for supplied arguments
if (Command_argument_count() == 0) then
stop "Error: There were no command line arguments."
end if
call Get_command_argument(1, length=myArgLength, status=myStat)
if (0 < myStat) then
stop "Error: Could not retrieve the first command argument."
end if
if (36 < myArgLength) then
stop "Error: Argument more than 36 characters long."
end if
! Get first argument
call Get_command_argument(1, value=taskId, status=myStat)
if (myStat /= 0) then
stop "Error GET_COMMAND_ARGUMENT failed unexpectedly."
end if
end subroutine
subroutine ProgressUpdateAction(percentProgress)
integer, intent(in) :: percentProgress
write (*, "('I am about ',i0,'% of the way there.')") &
percentProgress
end subroutine
end program
! modules.f90
module Library
implicit none
interface
subroutine IProgressUpdateAction(percentProgress)
integer, intent(in) :: percentProgress
end subroutine
end interface
contains
subroutine DoWork(progressUpdate)
!DIR$ ATTRIBUTES DLLEXPORT :: DoWork
!DIR$ ATTRIBUTES ALIAS: 'DoWork' :: DoWork
!DIR$ ATTRIBUTES REFERENCE :: progressCallBack
procedure(IProgressUpdateAction), intent(in), pointer :: progressUpdate
integer, parameter :: STEP_COUNT = 9
integer, parameter :: OP_COUNT = 100000000
integer :: i, j, percentProgress
real(8) :: n
do i = 1, STEP_COUNT
! Update the status.
percentProgress = (i - 1) * 100.0 / STEP_COUNT
call progressUpdate(percentProgress)
! Do something expensive.
!do j = 1, OP_COUNT
! n = sqrt(real(j,8))
! if (j == OP_COUNT) print *, n
!end do
end do
end subroutine
end module
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
This issue has been already resolved by our community members. Therefore, we will no longer respond to this thread.
If you require some further assistance from Intel, please start a new thread.
Any further interaction in this thread will be considered community only.
Regards,
Khalik.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page