- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I have a main program using a common block.from an include file. Variables in the common block are being initialized with values in the main program. The main program is calling a subroutine with no call list. The subroutine uses the same include file with the common block. When I step into the subroutine, all of the variables in the common block have been reset to 0. I am stumped. Can you suggest why the variables might be re-initialized in the subroutine?
I should mention that the subroutine is stored in a DLL and exported. While trying to solve the problem I have tried exporting the common block also, but this had no effect.
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A small but complete test case would make it easier to help you, but I can guess what is going on.
The main program and the DLL each have their own copy of the COMMON, which is why you see no effect of the main program initialization. It is not enough to DLLEXPORT the COMMON, you also have to DLLIMPORT it in the main program, otherwise the compiler has no idea you want to use the DLL's version.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A small but complete test case would make it easier to help you, but I can guess what is going on.
The main program and the DLL each have their own copy of the COMMON, which is why you see no effect of the main program initialization. It is not enough to DLLEXPORT the COMMON, you also have to DLLIMPORT it in the main program, otherwise the compiler has no idea you want to use the DLL's version.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Correct again Steve.
In the main program I removed the include file, added the DLLIMPORT and variable definitions and the common block definition. That fixed the problem.
I have a subroutine in a DLL, and the top level subroutine has 130 integer and double precision variables including arrays. Another group wants to call the subroutine from C code. I am modifying my subroutine to use a common block containing the 130 variables which I can export from the DLL.
Is there a better way to keep from passing all of those variables instead of exporting common blocks or through the call list?
Thanks,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'll comment that if you put the COMMON in a module, with a DLLEXPORT, and USE the module in the main program, everything will be imported automatically.
130 variables - wow. An advantage of the COMMON method is that in C you can declare it as a single struct that gets DLLIMPORTed. In fact, that's pretty much the way you'll have to do it. Ideally, you'd have a derived type (struct) that is a "context block" you could pass as a single argument. You might want to give some thought as to how this code communicates with its callers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the tip Steve.
Here is the test code I ended up with.
PROGRAM Main1 USE Test_Mod IMPLICIT NONE var1 = 11.0d0 var2 = 22.d0 CALL Test_Sub END PROGRAM Main1 SUBROUTINE Test_Sub USE Test_Mod IMPLICIT NONE !DEC$ ATTRIBUTES DLLEXPORT::Test_Sub var1 = 13.0d0 var2 = 14.0d0 RETURN END SUBROUTINE Test_Sub MODULE Test_Mod IMPLICIT NONE !DEC$ ATTRIBUTES DLLEXPORT :: TEST_CMN REAL*8 :: var1 REAL*8 :: var2 COMMON /TEST_CMN/ var1, var2 END MODULE Test_Mod
Here is an example of how I suggested that The C programmers could make use of the common block:
Using Fortran Common in C:
1 Export common block:
!DEC$ ATTRIBUTES DLLEXPORT :: C_EMESSN
2 Import common block in C header file structure:
extern __declspec(dllimport) struct {
long cda_emun;
long cda_estat;
long fdi_emun;
long fdi_estat;
} C_EMESSN;
#define Fcda_emun (C_EMESSN.cda_emun)
#define Fcda_estat (C_EMESSN.cda_estat)
#define Ffdi_emun (C_EMESSN.fdi_emun)
#define Ffdi_estat (C_EMESSN.fdi_estat)
Again thanks for the help,
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
The values I am passing to the C code through the common block will all need to be passed back to Fortran through a call from C to a different Fortran routine. I do not have an example of how to do this, and have not tried it yet. Do you have a suggestion on how to code this?
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I would correct one part:
1 Export common block:
!DEC$ ATTRIBUTES DLLEXPORT :: /C_EMESSN/
The manual says the slashes are required, though my experimentation suggests that the compiler allows their omission in some cases. I am getting some weird results in my tests and may have some things to send on to the developers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here's an example where it makes a difference:
subroutine dllsub1 !DEC$ ATTRIBUTES DLLEXPORT :: dllsub1 integer :: boo, goo common /goo/ boo, goo !DEC$ ATTRIBUTES DLLEXPORT :: /goo/ data boo /999/ data goo /888/ print *, "GOO=",goo print *, "BOO=",boo end
program test integer :: boo, goo common /goo/ boo, goo !DEC$ ATTRIBUTES DLLIMPORT :: /goo/ goo = 42 call dllsub1 end
D:\Projects>t2.exe GOO= 42 BOO= 999
Ok, that's what I expect. Now look what happens when I take the slashes off in the DLLEXPORT:
subroutine dllsub1 !DEC$ ATTRIBUTES DLLEXPORT :: dllsub1 integer :: boo, goo common /goo/ boo, goo !DEC$ ATTRIBUTES DLLEXPORT :: goo data boo /999/ data goo /888/ print *, "GOO=",goo print *, "BOO=",boo end
When I link the executable, I get the warning:
LINK : warning LNK4217: symbol 'GOO' defined in '' is imported by 't2.obj' in function 'MAIN__'
and when I run it:
D:\Projects>t2.exe GOO= 888 BOO= 999
I note that the compiler does not allow me to omit the slashes on the DLLIMPORT:
t2.f90(4): error #6406: Conflicting attributes or multiple declaration of name. [GOO] !DEC$ ATTRIBUTES DLLIMPORT :: goo ------------------------------^
I think it's a bug that the compiler allows you to DLLEXPORT a variable named in a COMMON statement - the documentation allows only module variables to be DLLEXPORTed. If the variable is not in COMMON , it complains. The Fortran standard allows you to have a local name and a COMMON name be the same.
Issue 04527871 submitted.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the update.
Mike
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Steve for the bug report. The bug ID is CMPLRIL0-32575
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page