- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a large mainframe program (mixed Fortran - 170000 lines, with some PL/1 and assembler), in which all the Fortran is fortunately quite well organised into "modules" (not F90 modules - it is all F77 - some with user interfaces, the rest being service modules), but is not stored as a single executable. On the mainframe it is built every time it is used from a script and a library.
I could put all the subroutines into a static library and build as per the mainframe, but want to access the 50 or so user modules from a framework (such as Phoenix Analysis Server). This means the user modules need to be DLLs to be wrapped with COM interfaces (when I figure out how to do that - don't ask). It also seems appropriate that most of the service modules be DLLs as well. There is also a large pool of general service routines more appropriately held in a static library.
I have DVF 5.0a, and unfortunately am unlikely to get any money to upgrade (though I may be able to use a reply to persuade my company to do so).
From posts and replies in comp.lang.fortran I have got the program to run with its modules organised as DLLs. In order to avoid polluting the code (as I wish only to keep a single source repository for mainframe and PC), I have created .DEF files to expose the symbols in the DLLs. However the COMMON data is not getting across. I was advised to post here instead of in comp.lang.fortran for specific implementations, so I have the following questions for you:
1) Can all symbols be controlled solely by .DEF files?
2) I eventually figured out that blank common is defined by BLNK__, but nowhere does your documentation say this. Are there any special characteristics of blank common?
3) The program will not link with slashes around the COMMON names in the .DEF file. If you remove the slashes, the program will link, but as this is not what the manual tells you to do, I get rather worried about whether it will work.
YDPCTB.DEF : error LNK2001: unresolved external symbol /XXPFIL/
4) What is the import and export of COMMON data about - it is very poorly explained in your documentation? To my F77 mind, COMMON is simply a memory area shared by subroutines. There are no suppliers and clients so the very concept of "import" and "export" is illogical. If there were just suppliers and clients, you would not have used COMMON in the first place. My COMMON data may be used by the main program and by several DLLs; just internally within a DLL; or between DLLs; I have never had to know before. So precisely which should be "importing" or "exporting" what?
5) What happens if more than one DLL "exports" the same COMMON symbol?
6) The code polluting *DEC$ ATTRIBUTES construct has both IMPORT and EXPORT functions, yet .DEF files only have EXPORTS. What is going on here?
7) There is obviously much more about .DEF files than is described in your documentation - look at your code examples. Why?
8) When I have done all this and the program links, data is not being transferred via COMMON, and I do not know where to start to figure out why.
9) Might it be better to INCLUDE every COMMON declaration in the main program? If so, then how would a framework like Phoenix or a VB GUI handle such data?
--------------------------------------------------------------------------
The following describes some of the changes I have had to make to the compiler/linker switches to get t he program to run. I am a little disappointed at what appears to be the Microsoft culture (i.e. forget what IBM and Digital did with Fortran and re-invent the wheel), which underly the need to do all these things.
* As F77 programmers tend to use variable subroutine arguments, you have to set the "Default Calling Convention" (Project>Settings>Fortran>External Procedures) to C, by reference. Otherwise the program may not link - as the compiler appends the number of argument address bytes to the name.
* You cannot use some library routines (e.g. CHANGEDIRQQ) which require the default calling convention if you have set this to C, by reference. The linker will not find them. I have tried forcing just these routines to use the default mechanism (with *DEC$ ATTRIBUTES) without success.
* If passing CHARACTER arguments, you must set the "String Length Arg Passing" to After All Args. Otherwise the string length bytes get pushed into the next argument to corrupt its values (and all subsequent arguments). This is, in fact, the default mechanism for most other compilers, but M$, as usual, have to do it differently.
* As the program will need to know where the DLLs are, it is best to link them into the same folder. You will have to manually change the output file name to point to this folder (Project>Settings>Link>General).
* I found it necessary to specifically exclude (Project>Settings>Link>Input>Ignore Libraries) the following libraries to avoid clashes: libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
* You have to do the preceding operations for EVERY project in your workspace. Service routines which are used generally by the program are best organised in a static library (such as I am used to on mainframe and VAX systems).
You have to tell each project which other projects it depends on (Project>Dependencies) or it will not link. The system will not do this for you.
Later versions of Fortran (currently Intel Fortran 7.0) have improvements, so I am told. There are other issues related to debugging in which PC Fortran is very unfriendly compared to mainframe and VAX systems (such as no trace back, loss of output window and diagnostics, loss of call stack and local variables on abnormal termination). On VAX systems, the program stops at the offending statement, all variables are held, multidimensional arrays are viewed as such (and not as C would have them) and you are not limited to viewing only 300 array elements.
I could put all the subroutines into a static library and build as per the mainframe, but want to access the 50 or so user modules from a framework (such as Phoenix Analysis Server). This means the user modules need to be DLLs to be wrapped with COM interfaces (when I figure out how to do that - don't ask). It also seems appropriate that most of the service modules be DLLs as well. There is also a large pool of general service routines more appropriately held in a static library.
I have DVF 5.0a, and unfortunately am unlikely to get any money to upgrade (though I may be able to use a reply to persuade my company to do so).
From posts and replies in comp.lang.fortran I have got the program to run with its modules organised as DLLs. In order to avoid polluting the code (as I wish only to keep a single source repository for mainframe and PC), I have created .DEF files to expose the symbols in the DLLs. However the COMMON data is not getting across. I was advised to post here instead of in comp.lang.fortran for specific implementations, so I have the following questions for you:
1) Can all symbols be controlled solely by .DEF files?
2) I eventually figured out that blank common is defined by BLNK__, but nowhere does your documentation say this. Are there any special characteristics of blank common?
3) The program will not link with slashes around the COMMON names in the .DEF file. If you remove the slashes, the program will link, but as this is not what the manual tells you to do, I get rather worried about whether it will work.
YDPCTB.DEF : error LNK2001: unresolved external symbol /XXPFIL/
4) What is the import and export of COMMON data about - it is very poorly explained in your documentation? To my F77 mind, COMMON is simply a memory area shared by subroutines. There are no suppliers and clients so the very concept of "import" and "export" is illogical. If there were just suppliers and clients, you would not have used COMMON in the first place. My COMMON data may be used by the main program and by several DLLs; just internally within a DLL; or between DLLs; I have never had to know before. So precisely which should be "importing" or "exporting" what?
5) What happens if more than one DLL "exports" the same COMMON symbol?
6) The code polluting *DEC$ ATTRIBUTES construct has both IMPORT and EXPORT functions, yet .DEF files only have EXPORTS. What is going on here?
7) There is obviously much more about .DEF files than is described in your documentation - look at your code examples. Why?
8) When I have done all this and the program links, data is not being transferred via COMMON, and I do not know where to start to figure out why.
9) Might it be better to INCLUDE every COMMON declaration in the main program? If so, then how would a framework like Phoenix or a VB GUI handle such data?
--------------------------------------------------------------------------
The following describes some of the changes I have had to make to the compiler/linker switches to get t he program to run. I am a little disappointed at what appears to be the Microsoft culture (i.e. forget what IBM and Digital did with Fortran and re-invent the wheel), which underly the need to do all these things.
* As F77 programmers tend to use variable subroutine arguments, you have to set the "Default Calling Convention" (Project>Settings>Fortran>External Procedures) to C, by reference. Otherwise the program may not link - as the compiler appends the number of argument address bytes to the name.
* You cannot use some library routines (e.g. CHANGEDIRQQ) which require the default calling convention if you have set this to C, by reference. The linker will not find them. I have tried forcing just these routines to use the default mechanism (with *DEC$ ATTRIBUTES) without success.
* If passing CHARACTER arguments, you must set the "String Length Arg Passing" to After All Args. Otherwise the string length bytes get pushed into the next argument to corrupt its values (and all subsequent arguments). This is, in fact, the default mechanism for most other compilers, but M$, as usual, have to do it differently.
* As the program will need to know where the DLLs are, it is best to link them into the same folder. You will have to manually change the output file name to point to this folder (Project>Settings>Link>General).
* I found it necessary to specifically exclude (Project>Settings>Link>Input>Ignore Libraries) the following libraries to avoid clashes: libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
* You have to do the preceding operations for EVERY project in your workspace. Service routines which are used generally by the program are best organised in a static library (such as I am used to on mainframe and VAX systems).
You have to tell each project which other projects it depends on (Project>Dependencies) or it will not link. The system will not do this for you.
Later versions of Fortran (currently Intel Fortran 7.0) have improvements, so I am told. There are other issues related to debugging in which PC Fortran is very unfriendly compared to mainframe and VAX systems (such as no trace back, loss of output window and diagnostics, loss of call stack and local variables on abnormal termination). On VAX systems, the program stops at the offending statement, all variables are held, multidimensional arrays are viewed as such (and not as C would have them) and you are not limited to viewing only 300 array elements.
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not going to try to answer all your questions, but I will point out that pretty much all of your complaints in the second part of your message would be resolved by using the current version of Compaq Visual Fortran. However, the one about "variable subroutine arguments" I have to disagree with - this is explicitly prohibited in the Fortran 77 standard - it works on some implementations and not on others. That said, you can change the defaults in Visual Fortran 6.6 to get this and then everything else will fall into place.
I don't know where you're reading that one puts slashes around COMMON block names in DEF files. That's not correct. I don't recommend using blank COMMON if you're trying to share data in DLLs.
Import and export pertains to visibility outside the DLL. Export is a way of specifying which symbols are to be visible to users of the DLL, import says which symbols are from a DLL rather than defined locally. Import attributes can be skipped for routines (with some performance loss), but are required for data.
If nothing else, please download and install the free 5.0D update - it will help you a bit.
Steve
I don't know where you're reading that one puts slashes around COMMON block names in DEF files. That's not correct. I don't recommend using blank COMMON if you're trying to share data in DLLs.
Import and export pertains to visibility outside the DLL. Export is a way of specifying which symbols are to be visible to users of the DLL, import says which symbols are from a DLL rather than defined locally. Import attributes can be skipped for routines (with some performance loss), but are required for data.
If nothing else, please download and install the free 5.0D update - it will help you a bit.
Steve
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Rehi Richard...
Uh, I'll try to answer some of it; I'll let others to comment on the rest.
1) Can all symbols be controlled solely by .DEF files?
Should be so. I can't positively tell is it so.
4) What is the import and export of COMMON data about - it is very poorly explained in your documentation? To my F77 mind, COMMON is simply a memory area shared by subroutines. There are no suppliers and clients so the very concept of "import" and "export" is illogical. If there were just suppliers and clients, you would not have used COMMON in the first place. My COMMON data may be used by the main program and by several DLLs; just internally within a DLL; or between DLLs; I have never had to know before. So precisely which should be "importing" or "exporting" what?
Well, that's the price you pay when you use DLLs. Personally, I like the concept of manual exporting in order to avoid namespace pollution. I understand that COMMONs are this different from "suppliers" and "clients" concept, but DLLs are built on that concept.
6) The code polluting *DEC$ ATTRIBUTES construct has both IMPORT and EXPORT functions, yet .DEF files only have EXPORTS. What is going on here?
IMPORT can be safely ommitted -- IIRC it just speeds up the compilation.
7) There is obviously much more about .DEF files than is described in your documentation - look at your code examples. Why?
I'm lazy now to take a look at DVF 5.0D help, but MSDN is definitely the place to investigate.
--------------------------------------------------------
* As F77 programmers tend to use variable subroutine arguments, you have to set the "Default Calling Convention" (Project>Settings>Fortran>External Procedures) to C, by reference. Otherwise the program may not link - as the compiler appends the number of argument address bytes to the name.
Steve Lionel sighed about it recently -- STDCALL won't be the default calling conventions in the next release, mostly for that very reason. Be aware that this is illegal programming, though.
* You cannot use some library routines (e.g. CHANGEDIRQQ) which require the default calling convention if you have set this to C, by reference. The linker will not find them. I have tried forcing just these routines to use the default mechanism (with *DEC$ ATTRIBUTES) without success.
Fixed in CVF 6.5. Sorry, to put it mildly, it is not practice to ask for fixes to previous releases. Read: you need some $$$ to upgrade :-(.
* If passing CHARACTER arguments, you must set the "String Length Arg Passing" to After All Args. Otherwise the string length bytes get pushed into the next argument to corrupt its values (and all subsequent arguments). This is, in fact, the default mechanism for most other compilers, but M$, as usual, have to do it differently.
It ain't M$, it's Digital/Compaq ;-). Again, it's illegal programming issue.
* As the program will need to know where the DLLs are, it is best to link them into the same folder. You will have to manually change the output file name to point to this folder (Project>Settings>Link>General).
* I found it necessary to specifically exclude (Project>Settings>Link>Input>Ignore Libraries) the following libraries to avoid clashes: libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
* You have to do the preceding operations for EVERY project in your workspace. Service routines which are used generally by the program are best organised in a static library (such as I am used to on mainframe and VAX systems). You have to tell each project which other projects it depends on (Project>Dependencies) or it will not link. The system will not do this for you.
Well, this has to do something with CVF relationship with MS C++/VS. Version 6.5 brings "Save Fortran environment/Manage Fortran environments" options, where you could transfer project settings with two mouse clicks.
Later versions of Fortran (currently Intel Fortran 7.0) have improvements, so I am told. There are other issues related to debugging in which PC Fortran is very unfriendly compared to mainframe and VAX systems (such as no trace back, loss of output window and diagnostics, loss of call stack and local variables on abnormal termination). On VAX systems, the program stops at the offending statement, all variables are held, multidimensional arrays are viewed as such (and not as C would have them) and you are not limited to viewing only 300 array elements.
Free DVF 5.0D update fixes some of it. To enable run-time crash detection, specify environment variable FOR_IGNORE_EXCEPTIONS=TRUE. (This is well hidden in the documentation).
Jugoslav
Uh, I'll try to answer some of it; I'll let others to comment on the rest.
1) Can all symbols be controlled solely by .DEF files?
Should be so. I can't positively tell is it so.
4) What is the import and export of COMMON data about - it is very poorly explained in your documentation? To my F77 mind, COMMON is simply a memory area shared by subroutines. There are no suppliers and clients so the very concept of "import" and "export" is illogical. If there were just suppliers and clients, you would not have used COMMON in the first place. My COMMON data may be used by the main program and by several DLLs; just internally within a DLL; or between DLLs; I have never had to know before. So precisely which should be "importing" or "exporting" what?
Well, that's the price you pay when you use DLLs. Personally, I like the concept of manual exporting in order to avoid namespace pollution. I understand that COMMONs are this different from "suppliers" and "clients" concept, but DLLs are built on that concept.
6) The code polluting *DEC$ ATTRIBUTES construct has both IMPORT and EXPORT functions, yet .DEF files only have EXPORTS. What is going on here?
IMPORT can be safely ommitted -- IIRC it just speeds up the compilation.
7) There is obviously much more about .DEF files than is described in your documentation - look at your code examples. Why?
I'm lazy now to take a look at DVF 5.0D help, but MSDN is definitely the place to investigate.
--------------------------------------------------------
* As F77 programmers tend to use variable subroutine arguments, you have to set the "Default Calling Convention" (Project>Settings>Fortran>External Procedures) to C, by reference. Otherwise the program may not link - as the compiler appends the number of argument address bytes to the name.
Steve Lionel sighed about it recently -- STDCALL won't be the default calling conventions in the next release, mostly for that very reason. Be aware that this is illegal programming, though.
* You cannot use some library routines (e.g. CHANGEDIRQQ) which require the default calling convention if you have set this to C, by reference. The linker will not find them. I have tried forcing just these routines to use the default mechanism (with *DEC$ ATTRIBUTES) without success.
Fixed in CVF 6.5. Sorry, to put it mildly, it is not practice to ask for fixes to previous releases. Read: you need some $$$ to upgrade :-(.
* If passing CHARACTER arguments, you must set the "String Length Arg Passing" to After All Args. Otherwise the string length bytes get pushed into the next argument to corrupt its values (and all subsequent arguments). This is, in fact, the default mechanism for most other compilers, but M$, as usual, have to do it differently.
It ain't M$, it's Digital/Compaq ;-). Again, it's illegal programming issue.
* As the program will need to know where the DLLs are, it is best to link them into the same folder. You will have to manually change the output file name to point to this folder (Project>Settings>Link>General).
* I found it necessary to specifically exclude (Project>Settings>Link>Input>Ignore Libraries) the following libraries to avoid clashes: libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
* You have to do the preceding operations for EVERY project in your workspace. Service routines which are used generally by the program are best organised in a static library (such as I am used to on mainframe and VAX systems). You have to tell each project which other projects it depends on (Project>Dependencies) or it will not link. The system will not do this for you.
Well, this has to do something with CVF relationship with MS C++/VS. Version 6.5 brings "Save Fortran environment/Manage Fortran environments" options, where you could transfer project settings with two mouse clicks.
Later versions of Fortran (currently Intel Fortran 7.0) have improvements, so I am told. There are other issues related to debugging in which PC Fortran is very unfriendly compared to mainframe and VAX systems (such as no trace back, loss of output window and diagnostics, loss of call stack and local variables on abnormal termination). On VAX systems, the program stops at the offending statement, all variables are held, multidimensional arrays are viewed as such (and not as C would have them) and you are not limited to viewing only 300 array elements.
Free DVF 5.0D update fixes some of it. To enable run-time crash detection, specify environment variable FOR_IGNORE_EXCEPTIONS=TRUE. (This is well hidden in the documentation).
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your assistance.
> I don't know where you're reading that one puts
> slashes around COMMON block names in DEF files.
> That's not correct. I don't recommend using blank
> COMMON if you're trying to share data in DLLs.
Sorry, I must have inferred this from the DLLIMPORT syntax. Blank common is heavily used in this program for reasons that date back to mainframe system limitations of 35 years ago - I cannot change it all.
> Import and export pertains to visibility outside the
> DLL. Export is a way of specifying which symbols are
> to be visible to users of the DLL, import says which
> symbols are from a DLL rather than defined locally.
> Import attributes can be skipped for routines (with
> some performance loss), but are required for data.
Is it then OK or necessary for ALL users of the same COMMON symbol to export it (including the main executable)?
> If nothing else, please download and install the free
> 5.0D update - it will help you a bit.
Have done - thanks, but still not getting COMMON data to transfer from main program to DLL. Is it possible to get the absolute address of variables (like in VC++) in the debugger? I might be able to figure out what is going on then by rummaging through the memory.
TIA, Richard
> I don't know where you're reading that one puts
> slashes around COMMON block names in DEF files.
> That's not correct. I don't recommend using blank
> COMMON if you're trying to share data in DLLs.
Sorry, I must have inferred this from the DLLIMPORT syntax. Blank common is heavily used in this program for reasons that date back to mainframe system limitations of 35 years ago - I cannot change it all.
> Import and export pertains to visibility outside the
> DLL. Export is a way of specifying which symbols are
> to be visible to users of the DLL, import says which
> symbols are from a DLL rather than defined locally.
> Import attributes can be skipped for routines (with
> some performance loss), but are required for data.
Is it then OK or necessary for ALL users of the same COMMON symbol to export it (including the main executable)?
> If nothing else, please download and install the free
> 5.0D update - it will help you a bit.
Have done - thanks, but still not getting COMMON data to transfer from main program to DLL. Is it possible to get the absolute address of variables (like in VC++) in the debugger? I might be able to figure out what is going on then by rummaging through the memory.
TIA, Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your comments.
> * As F77 programmers tend to use variable
> subroutine arguments, you have to set the "Default
> Calling Convention"
> (Project>Settings>Fortran>External Procedures) to C,
> by reference. Otherwise the program may not link - as
> the compiler appends the number of argument address
> bytes to the name.
>
> Steve Lionel sighed about it recently -- STDCALL
> won't be the default calling conventions in the next
> release, mostly for that very reason. Be aware that
> this is illegal programming, though.
We had to change F66 code which dimensioned dummy arrays as (say) X(1) to X(*) when we got the F77 compiler. Are you really saying that the use of X(*) is illegal?
> * If passing CHARACTER arguments, you must set the
> "String Length Arg Passing" to After All Args.
> Otherwise the string length bytes get pushed into the
> next argument to corrupt its values (and all
> subsequent arguments). This is, in fact, the default
> mechanism for most other compilers, but M$, as usual,
> have to do it differently.
>
> It ain't M$, it's Digital/Compaq ;-). Again, it's
> illegal programming issue.
OK, it's Digital BUT, the reason it is there dates back to FPS 4.0. Much of our old code is F66 - i.e. no character data - interfacing with newer F77 code. We have to do it, I'm afraid.
> * As F77 programmers tend to use variable
> subroutine arguments, you have to set the "Default
> Calling Convention"
> (Project>Settings>Fortran>External Procedures) to C,
> by reference. Otherwise the program may not link - as
> the compiler appends the number of argument address
> bytes to the name.
>
> Steve Lionel sighed about it recently -- STDCALL
> won't be the default calling conventions in the next
> release, mostly for that very reason. Be aware that
> this is illegal programming, though.
We had to change F66 code which dimensioned dummy arrays as (say) X(1) to X(*) when we got the F77 compiler. Are you really saying that the use of X(*) is illegal?
> * If passing CHARACTER arguments, you must set the
> "String Length Arg Passing" to After All Args.
> Otherwise the string length bytes get pushed into the
> next argument to corrupt its values (and all
> subsequent arguments). This is, in fact, the default
> mechanism for most other compilers, but M$, as usual,
> have to do it differently.
>
> It ain't M$, it's Digital/Compaq ;-). Again, it's
> illegal programming issue.
OK, it's Digital BUT, the reason it is there dates back to FPS 4.0. Much of our old code is F66 - i.e. no character data - interfacing with newer F77 code. We have to do it, I'm afraid.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
We had to change F66 code which dimensioned dummy arrays as (say) X(1) to X(*) when we got the F77 compiler. Are you really saying that the use of X(*) is illegal?
No, it's quite legal -- but it's variable number of elements in array, not variable number of routine arguments. What is illegal is, e.g.
Here, foo is called with different number of actual arguments. This is not allowed per standard, but will pass with compilers which use __cdecl calling convention (e.g. Unix).
Re addresses: you can watch the variables' addresses by typing LOC(variable) in Watch or QuickWatch window. Also, you can type the variable name in "Memory" debug window to see a bigger picture (common block).
Also, let me suggest a method to solve IMPORT/EXPORT common madness :-). Create one Dll which contains just COMMONs (and their BLOCK DATAs, if any); specify DLLEXPORT for common blocks there. In all other dlls/exes, specify DLLIMPORT for common blocks; you could relatively automate it by creating a .fd file which contains only !DEC$ATTRIBUTES DLLIMPORT: "FooCommon" and INCLUDEing it in every routine (non-used symbols will be ignored). (Alternative: move each common to a separate INCLUDE file.) Try to systematically sort and rename all blank commons accross various libraries to avoid clashes. Try it on a small test system first. Lot of job, I know, but at the end you'll have your system well organized, and still even F77-compatible (INCLUDE is a common extension to F77, and !DEC$ will be ignored anyway).
Jugoslav
No, it's quite legal -- but it's variable number of elements in array, not variable number of routine arguments. What is illegal is, e.g.
function foo(method, f, g) if (method.eq.1) then foo = f*g else if (method.eq.2) then foo = f*f end if end ... x = foo(2, 6.) ... x = foo(1, 6., 8.)
Here, foo is called with different number of actual arguments. This is not allowed per standard, but will pass with compilers which use __cdecl calling convention (e.g. Unix).
Re addresses: you can watch the variables' addresses by typing LOC(variable) in Watch or QuickWatch window. Also, you can type the variable name in "Memory" debug window to see a bigger picture (common block).
Also, let me suggest a method to solve IMPORT/EXPORT common madness :-). Create one Dll which contains just COMMONs (and their BLOCK DATAs, if any); specify DLLEXPORT for common blocks there. In all other dlls/exes, specify DLLIMPORT for common blocks; you could relatively automate it by creating a .fd file which contains only !DEC$ATTRIBUTES DLLIMPORT: "FooCommon" and INCLUDEing it in every routine (non-used symbols will be ignored). (Alternative: move each common to a separate INCLUDE file.) Try to systematically sort and rename all blank commons accross various libraries to avoid clashes. Try it on a small test system first. Lot of job, I know, but at the end you'll have your system well organized, and still even F77-compatible (INCLUDE is a common extension to F77, and !DEC$ will be ignored anyway).
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you again.
> We had to change F66 code which dimensioned dummy
> arrays as (say) X(1) to X(*) when we got the F77
> compiler. Are you really saying that the use of X(*)
> is illegal?
>
> No, it's quite legal -- but it's variable number of
> elements in array, not variable number of routine
> arguments.
That is fine, I buy that, although there are some such abuses in our code. What I object to in the following code
SUBROUTINE MOVE( FROM, INTO, LEN, NRPT )
BYTE FROM(*), INTO(*)
DO I = 1, NRPT
DO J = 1, LEN
INTO(J+(I-1)*LEN) = FROM(J)
END DO
END DO
RETURN
END
is that the compiler calls it _MOVE@16, and then thinks that
CALL MOVE (A, B, 8, 1)
where A and B are (say) CHAR*8 requires _MOVE@20. It is this "feature" that forces me to use C by reference calling.
I will try your COMMON suggestion.
Best regards, Richard
> We had to change F66 code which dimensioned dummy
> arrays as (say) X(1) to X(*) when we got the F77
> compiler. Are you really saying that the use of X(*)
> is illegal?
>
> No, it's quite legal -- but it's variable number of
> elements in array, not variable number of routine
> arguments.
That is fine, I buy that, although there are some such abuses in our code. What I object to in the following code
SUBROUTINE MOVE( FROM, INTO, LEN, NRPT )
BYTE FROM(*), INTO(*)
DO I = 1, NRPT
DO J = 1, LEN
INTO(J+(I-1)*LEN) = FROM(J)
END DO
END DO
RETURN
END
is that the compiler calls it _MOVE@16, and then thinks that
CALL MOVE (A, B, 8, 1)
where A and B are (say) CHAR*8 requires _MOVE@20. It is this "feature" that forces me to use C by reference calling.
I will try your COMMON suggestion.
Best regards, Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
OK I am almost there. The general rules that I have deduced by trial and error (and which could well be put in the documentation) are as follows:
1 Only one project may own (i.e. hold in memory) a COMMON area.
2 The programmer must manage the memory used by COMMON for all projects which use it. It does not automatically belong to the active project.
3 For other projects to see the COMMON data, the owner must make it visible with a DLLEXPORT directive and users must reference it with a DLLIMPORT directive. DLLIMPORT is not optional, it must be used to see the data. Consequently, it is not possible to control the build solely with .DEF files.
4 Blank common uses the symbol "BLNK__".
5 DLLEXPORT and DLLIMPORT do not recognise either /BLNK__/ or / /. The compiler indicates (info) a syntax error on the latter format. The former appears to compile, but the symbol is absent from the DLL header. The symbol BLNK__ may be exposed from a .DEF file using the EXPORTS directive. Unfortunately, there is then no way to import it, as there is no equivalent IMPORTS directive.
Blank common is well organised in this program and is used both as a memory pool and as a means to pass large data items from modules to the PL/1 middleware. There is therefore no need to reorganise all the blank common, but I would like to know how I may import blank common into projects.
Any suggestions gratefully received. Otherwise it looks like I shall have to rename all occurrences of blank common and prefix them with DLLIMPORT directives. There would then be non-trivial deviations from the mainframe source, which I wish to avoid.
1 Only one project may own (i.e. hold in memory) a COMMON area.
2 The programmer must manage the memory used by COMMON for all projects which use it. It does not automatically belong to the active project.
3 For other projects to see the COMMON data, the owner must make it visible with a DLLEXPORT directive and users must reference it with a DLLIMPORT directive. DLLIMPORT is not optional, it must be used to see the data. Consequently, it is not possible to control the build solely with .DEF files.
4 Blank common uses the symbol "BLNK__".
5 DLLEXPORT and DLLIMPORT do not recognise either /BLNK__/ or / /. The compiler indicates (info) a syntax error on the latter format. The former appears to compile, but the symbol is absent from the DLL header. The symbol BLNK__ may be exposed from a .DEF file using the EXPORTS directive. Unfortunately, there is then no way to import it, as there is no equivalent IMPORTS directive.
Blank common is well organised in this program and is used both as a memory pool and as a means to pass large data items from modules to the PL/1 middleware. There is therefore no need to reorganise all the blank common, but I would like to know how I may import blank common into projects.
Any suggestions gratefully received. Otherwise it looks like I shall have to rename all occurrences of blank common and prefix them with DLLIMPORT directives. There would then be non-trivial deviations from the mainframe source, which I wish to avoid.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I might be able to shed a little light, from how some of these archaic things evolved. I don't really know what properties a .DLL has, but I understand blank common very well. (They didn't have any other kind when I first learned FORTRAN. And no, my hair is not gray (well, maybe a little).
Thirty-five years ago, a computer appeared to the programmer as linear array of memory and a register called a program counter which contained a number corresponding to the memory location from which the hardware was to load the next binary instruction. Period. The computer "owned" everything and an instruction in a user program was no different from one in the operating system or the floating point value of PI.
When code was generated, there were symbols used internal to the code, called "locals" to specify data storage and a list of a few "external" symbols that told a loader program where, dynamically (i.e. the programmer did have specify the actual address) to load code (e.g. from paper tape) and told code the addresses where subroutines were located, so one routine could call another. Generally, all required data memory was allocated within the subroutine and any data communicated to another subroutine was passed according to a protocol either as the memory address from which to load the data or directly in a hardware register.
"Blank common" was essentially a "subroutine" that only reserved memory for data storage. Its starting address was then communicated to the code just like a subroutine. That why common can overlap, be extended, contain "different" variables in different subroutines becuase the *only* thing that the code knew was the address of the first location of this region of memory. It was used as reusable temporary storage, to pass data to other subroutines and a wide variety of "tricks", such as allowing one subroutine to store a real value and another access it as an integer. Subroutines were completely independent of each other, except for the shared knowledge of the values the loader assigned to the external symbols.
O.K. Long winded preamble. "Blank common" had no conventionally defined symbol associated with its location, unlike a subroutine name. Usually the beginning of the main program didn't either. But the loader needed some "name", to associate with it and so the compiler writer assigned some arbitrary name to it. (When named common blocks were invented, a very common mistake was to use the name "/main/", which the compiler writer often used as, surprise!, the name of the main program and the loader would blighthly assign them the same memory location. (People would often get away with this for a while, because the code at the beginnig of the program was usually only executed once, before data were stored in the common block.)
So, now that I have explained in gory detail, how cavemen could obtain meat with the aid of a rock (pardon the pun) perhaps you can extrapolate how modern man deals with a pile of blank common and gets a DLL (or a beef steak).
Good luck. I can explain the rationale behind ASSGINED GOTO's too.
Regards,
Keith
I might be able to shed a little light, from how some of these archaic things evolved. I don't really know what properties a .DLL has, but I understand blank common very well. (They didn't have any other kind when I first learned FORTRAN. And no, my hair is not gray (well, maybe a little).
Thirty-five years ago, a computer appeared to the programmer as linear array of memory and a register called a program counter which contained a number corresponding to the memory location from which the hardware was to load the next binary instruction. Period. The computer "owned" everything and an instruction in a user program was no different from one in the operating system or the floating point value of PI.
When code was generated, there were symbols used internal to the code, called "locals" to specify data storage and a list of a few "external" symbols that told a loader program where, dynamically (i.e. the programmer did have specify the actual address) to load code (e.g. from paper tape) and told code the addresses where subroutines were located, so one routine could call another. Generally, all required data memory was allocated within the subroutine and any data communicated to another subroutine was passed according to a protocol either as the memory address from which to load the data or directly in a hardware register.
"Blank common" was essentially a "subroutine" that only reserved memory for data storage. Its starting address was then communicated to the code just like a subroutine. That why common can overlap, be extended, contain "different" variables in different subroutines becuase the *only* thing that the code knew was the address of the first location of this region of memory. It was used as reusable temporary storage, to pass data to other subroutines and a wide variety of "tricks", such as allowing one subroutine to store a real value and another access it as an integer. Subroutines were completely independent of each other, except for the shared knowledge of the values the loader assigned to the external symbols.
O.K. Long winded preamble. "Blank common" had no conventionally defined symbol associated with its location, unlike a subroutine name. Usually the beginning of the main program didn't either. But the loader needed some "name", to associate with it and so the compiler writer assigned some arbitrary name to it. (When named common blocks were invented, a very common mistake was to use the name "/main/", which the compiler writer often used as, surprise!, the name of the main program and the loader would blighthly assign them the same memory location. (People would often get away with this for a while, because the code at the beginnig of the program was usually only executed once, before data were stored in the common block.)
So, now that I have explained in gory detail, how cavemen could obtain meat with the aid of a rock (pardon the pun) perhaps you can extrapolate how modern man deals with a pile of blank common and gets a DLL (or a beef steak).
Good luck. I can explain the rationale behind ASSGINED GOTO's too.
Regards,
Keith

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page