Home > Archive > Fortran > May 2005 > strange linking problem
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
strange linking problem
|
|
| nicolasbock@gmail.com 2005-04-28, 4:01 am |
| Hello,
the problem I have is a little complicated to describe, well, I wil
give it a try. I wrote a module in f90 (MAC OS X 10.3, IBM XLF
compiler) which defines a character array and assigns a literal string
to it. In another file I use this array. I build my program such that I
make an object file out of the module and link that into the program. I
tried this two ways, first by linking the module by listing the object
file directly on the compiler command line, and second by using a
static library and linking it that way. In the first case, everything
works as I expect it, in the second case the array is empty. Here are
the files:
in file Parameters.F90:
MODULE Parameters
IMPLICIT NONE
Character (len=100) :: test = "This is a test"
END MODULE
in file Main.F90:
PROGRAM Main
USE Parameters
IMPLICIT NONE
write (*, *) "printing test: ", test
END PROGRAM Main
The Makefile which produces both versions of the program is
..PHONY : all
all : Main1 Main2
Main1 : Main.o libtest.a
xlf95 -o $@ $< -L. -ltest
Main2 : Main.o Parameters.o
xlf95 -o $@ $^
libtest.a : Parameters.o
ar -rcv libtest.a $^
ranlib libtest.a
Main.o : Parameters.o
%.o : %.F90
xlf95 -qsuffix=f=F90 -o $@ -c $^
Could someone shed some light on this strange problem? Is that
something that is to be expected?
Thanks already, nick
| |
| nicolasbock@gmail.com 2005-04-28, 4:01 am |
| To make this even stranger, I found that the following modifications to
Parameters.F90 and Main.F90 make both version of the program work
in file Parameters.F90:
MODULE Parameters
IMPLICIT NONE
Character (len=100) :: test = "This is a test"
CONTAINS
subroutine nop ()
return
end subroutine nop
END MODULE
in file Main.F90:
PROGRAM Main
USE Parameters
IMPLICIT NONE
write (*, *) "printing test: ", test
END PROGRAM Main
subroutine nopMain ()
use Parameters
implicit none
call nop ()
return
end subroutine nopMain
| |
| Michel OLAGNON 2005-04-28, 8:58 am |
|
nicolasbock@gmail.com wrote:
> To make this even stranger, I found that the following modifications to
> Parameters.F90 and Main.F90 make both version of the program work
>
>
> in file Parameters.F90:
>
> MODULE Parameters
> IMPLICIT NONE
> Character (len=100) :: test = "This is a test"
> CONTAINS
> subroutine nop ()
> return
> end subroutine nop
> END MODULE
>
>
> in file Main.F90:
>
> PROGRAM Main
> USE Parameters
> IMPLICIT NONE
>
> write (*, *) "printing test: ", test
>
> END PROGRAM Main
>
> subroutine nopMain ()
>
> use Parameters
> implicit none
>
> call nop ()
> return
>
> end subroutine nopMain
>
No executable code in the module results in no reference from
the program to the module object file, so the linker does not
bring it in.
The "problem" has been known for decades by some who couldn't
get their block data to be linked into the program.
| |
| nicolasbock@gmail.com 2005-05-01, 9:08 pm |
| If I understand you correctly, then the linker doesn't pull in the
string although I reference it in the main program? How come it doesn't
complain at link time that it can't satisfy the reference to the
variable test?
| |
| Richard E Maine 2005-05-01, 9:08 pm |
| In article <1114645565.383875.105010@l41g2000cwc.googlegroups.com>,
nicolasbock@gmail.com wrote:
>... character array...
....
> Character (len=100) :: test = "This is a test"
Michel answered your question. Allow me to just help you avoid a
completely different problem in the future.
What you have is *NOT* a character array. It is a scalar character
string. One can have character arrays in Fortran, but they are not the
same thing. For example
character :: test_array(100)
is an array of characters (of length 1 by default, since the length is
not otherwise specified), and
character(len=42) :: array_of_strings(100)
is an array of character strings, each of which is 42 characters long.
(There are other syntaxes for declaring both of these).
If you refer to character strings as arrays, it is highly likely that
you will eventually make mistakes because of it; the difference does
matter. It is perhaps even more likely that you will get wrong answers
from some future question because someone will answer the question that
you actually ask instead of the one you meant - and the answers might
not be the same.
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
| nicolasbock@gmail.com 2005-05-01, 9:08 pm |
| Thanks Richard, I didn't know that. I usually use C, and since strings
don't exist there I sort of assumed that to be similar in f90.
I hope I don't sound like a complete moron now, but I still don't quite
understand this. As far as I know, the linker goes through the object
files and looks for unsatisfied references to functions and variables.
Then it looks through the libraries and tries to satisfy those
references by linking code from the libraries into the executable. If
that's correct, then I don't understand how the linker does not either
1) find a reference to "test", link that in from the library and
everyone's happy, or 2) see that "test" is not satisfied and give me an
error. The fact that it does not complain suggests that the linker
indeed is linking something into the executable from the library. But
apparently something that does not contain the literal string that I
assigned to "test".
Could someone explain this to me?
Thanks, nick
| |
| Richard E Maine 2005-05-01, 9:08 pm |
| In article <1114703379.735008.294480@f14g2000cwb.googlegroups.com>,
nicolasbock@gmail.com wrote:
> Thanks Richard, I didn't know that. I usually use C, and since strings
> don't exist there I sort of assumed that to be similar in f90.
Fortran arrays of characters are pretty direct analogues to those of C.
In fact, it is sometimes more convenient to use arrays of characters
instead of strings when interfacing to C. But many character operations
in Fortran are more "naturally" done with character strings instead of
arrays. So most commonly, you'll see character strings instead of
character arrays in Fortran (like your example was using) unless there
are special circumstances.
> As far as I know, the linker goes through the object
> files and looks for unsatisfied references to functions and variables.
> Then it looks through the libraries and tries to satisfy those
> references by linking code from the libraries into the executable. If
> that's correct, then I don't understand how the linker does not either
> 1) find a reference to "test", link that in from the library and
> everyone's happy, or 2) see that "test" is not satisfied and give me an
> error. The fact that it does not complain suggests that the linker
> indeed is linking something into the executable from the library. But
> apparently something that does not contain the literal string that I
> assigned to "test".
>
> Could someone explain this to me?
I'll try. For procedures (both functions and subroutines), you are
right, but variables are different. For a procedure, things are
relatively simple (in this regard). The linker sees 2 kinds of things:
there are references to a procedure and there is a separate thing is the
procedure itself. If you have references with no corresponding
procedure, that is an error.
For data, however, it is possible to have multiple references to a data
area, with nothing that actually is uniquely the data area itself. This
is typical of non-initialized data areas. All that the linker sees is
that there should be a data area of a certain size and a certain name.
If something defines the area, then fine, that definition gets used. But
if nothing otherwise defines the data area, the linker will allocate an
an appropriate chunk of memory. This is not an error, and indeed is
quite typical for COMMON blocks.
I forget all the right terminology, but the "references" that the linker
sees for the variable "test" here are probably of this type, where you
won't get an error for a lack of other definition. The linker doesn't
tend to look in libraries for this kind of reference.
As alluded to by others, this used to be quite a widespread problem with
COMMON in f77 and earlier days. Modules are less prone to the problem,
but it can still happen (only when the modules have no referenced
procedures).
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
| glen herrmannsfeldt 2005-05-01, 9:08 pm |
| Richard E Maine wrote:
> In article <1114703379.735008.294480@f14g2000cwb.googlegroups.com>,
> nicolasbock@gmail.com wrote:
(snip)
(snip)
[color=darkred]
> I'll try. For procedures (both functions and subroutines), you are
> right, but variables are different. For a procedure, things are
> relatively simple (in this regard). The linker sees 2 kinds of things:
> there are references to a procedure and there is a separate thing is the
> procedure itself. If you have references with no corresponding
> procedure, that is an error.
There might also be a difference between initialized data (as in BLOCK
DATA), and uninitialized data (COMMON not in BLOCK DATA).
> For data, however, it is possible to have multiple references to a data
> area, with nothing that actually is uniquely the data area itself. This
> is typical of non-initialized data areas. All that the linker sees is
> that there should be a data area of a certain size and a certain name.
> If something defines the area, then fine, that definition gets used. But
> if nothing otherwise defines the data area, the linker will allocate an
> an appropriate chunk of memory. This is not an error, and indeed is
> quite typical for COMMON blocks.
and static external variables in other languages that don't have COMMON.
> I forget all the right terminology, but the "references" that the linker
> sees for the variable "test" here are probably of this type, where you
> won't get an error for a lack of other definition. The linker doesn't
> tend to look in libraries for this kind of reference.
As far as I know, it was Fortran's COMMON that historically started that
type of reference. It is used for external variables in other
languages. The OS/360 linkers have one called SD, used for functions
and subroutines, and one called CM used for COMMON. There is another
type used for ENTRY, but has most of the same properties as SD.
OS/360 also has a reference type called weak, where it will be resolved
to point to an otherwise already loaded module, but won't cause it to
be loaded from the library.
> As alluded to by others, this used to be quite a widespread problem with
> COMMON in f77 and earlier days. Modules are less prone to the problem,
> but it can still happen (only when the modules have no referenced
> procedures).
For OS/360 (and successors) initialized data (from BLOCK DATA) is SD,
just as subroutines and functions are. This can cause some interesting
effects if you accidentally (or not) name COMMON the same as a
subroutine. OS/360 also requires that the initialized data be at least
as long as the uninitialized data block with the same name. That was
once a limitation on a trick for specifying array sizes at link time
for already compiled subroutines.
-- glen
| |
| Richard E Maine 2005-05-01, 9:08 pm |
| In article <D8ydneYJcsMupOzfRVn-qw@comcast.com>,
glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:
> This can cause some interesting
> effects if you accidentally (or not) name COMMON the same as a
> subroutine.
Been there. Was no fun. :-( Accidentally.
--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
| glen herrmannsfeldt 2005-05-01, 9:08 pm |
| Richard E Maine wrote:
> In article <D8ydneYJcsMupOzfRVn-qw@comcast.com>,
> glen herrmannsfeldt <gah@ugcs.caltech.edu> wrote:
[color=darkred]
> Been there. Was no fun. :-( Accidentally.
I did see one once that coded the OS/360 system call to return
the time, along with appropriate initialization and return
instruction into an eight byte floating point constant.
It was then used to initialize a COMMON variable, and called
to return the time. That is the only non-accidental
one I remember.
-- glen
|
|
|
|
|