Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Common variables being initialized

Kipling__Michael
Beginner
1,251 Views

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

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
1,251 Views

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.

View solution in original post

0 Kudos
9 Replies
Steve_Lionel
Honored Contributor III
1,252 Views

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.

0 Kudos
Kipling__Michael
Beginner
1,251 Views

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 

 

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,251 Views

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.

0 Kudos
Kipling__Michael
Beginner
1,251 Views

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

0 Kudos
Kipling__Michael
Beginner
1,251 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,251 Views

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.

0 Kudos
Steve_Lionel
Honored Contributor III
1,251 Views

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.

0 Kudos
Kipling__Michael
Beginner
1,251 Views

Thanks for the update.

Mike

0 Kudos
Ron_Green
Moderator
1,251 Views

Thanks Steve for the bug report.  The bug ID is CMPLRIL0-32575

0 Kudos
Reply