I am trying to compile a fairly modern fortran code on a Mac with gfortran. Lines like this one ...
allocate(sce, mold=sct)
get errors like this:
Error: Array specification or array-valued SOURCE= expression required in ALLOCATE statement
It seems, then, that gfortran understands SOURCE but not MOLD. However, my gfortran is recent:
gcc version 8.2.0 (MacPorts gcc8 8.2.0_3)
I have seen web pages claiming that gfortran has been able to support MOLD since version 7.something. So surely it should be able to do it with 8.2.0. Is this not true? Is something funny about the Mac version? Can anyone suggest what some other problem might be?
EDIT: If anyone's still there, this toy code works fine:
program awm
integer, dimension(:), allocatable :: sct,sce
integer :: nspec = 100
allocate(sct(nspec))
allocate(sce, mold=sct)
end program
But when sct and sce are derived types, it falls apart:
program awm
type :: r1d
real, allocatable :: a(:)
end type
type(r1d), dimension(:), allocatable :: sct,sce
integer :: nspec = 100
allocate(sct(nspec))
do i = 1,nspec
allocate(sct(i)%a(10))
enddo
allocate(sce, mold=sct)
end program
This returns the error I was having above. You might think the definition of the derived type is kind of weird, even unnecessary. Well, the original code from which this is taken is not my code and I'm not in a position to change it much, and actually, this structuring does have its uses for reasons I don't have time to go into. Thanks.
I am convinced this is a duplicate of this GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80708 or is very closely related. You have to wait for a fix. I will put your code in the comment for this bug and not open a new one.
Related
I'm writing my own programming language, and am wanting to compile it to native binaries by compiling to LLVM IR, then letting the rest of the LLVM toolchain take over. Eventually, I will target multiple platforms, but for now I'm just focusing on Windows.
For starters, I have the empty program compiling, which implies that in general my toolchain is set up and working, and I get a no op executable out of it. The next logical step is doing "Hello World", but after looking at the LLVM IR output of clang of the C program that simply calls puts("Hello World!") it looks like a slightly easier first step is to simply _exit();. When reviewing the clang output of that C program, it looks like the relevant line is to do call void #_exit(i32 0). I've distilled it down to what I think is the bare minimum program which calls exit:
define i64* #main() {
%1 = alloca i32, align 4
store i32 0, i32* %1, align 4
call void #_exit(i32 0)
unreachable
}
declare dso_local void #_exit(i32)
When trying to run the equivalent C program directly, of course it works when I use clang directly, but the steps after creation of the LLVM IR are opaque to me, and I believe I'm using the wrong linker options or something, as I get lld-link: error: undefined symbol: _exit during the lld-link step. (Actually, this also occurs when I try to manually link the output of clang -S --emit-llvm, so I have no reason to believe my IR is the problem). The current invocation I'm using for lld-link is lld-link /out:"exit.exe" /entry:main exit.obj. I've tried playing around with adding various flavors of the /defaultlib switch, including manually linking to libcmt both libucrt which I do believe contain _exit after looking through the symbols with dumpbin, but that doesn't seem to help. Looking at the IR output of the clang program, it doesn't seem like there's any particular reference to <stdlib.h>, so I guess that information is lost after the IR generation stage, so I don't think I'm missing anything in my IR.
This appears to be a general Windows linker problem, rather than anything to do with LLVM, since if I do link /out:exit.exe /entry:main exit.obj I get basically the same error.
Anyways, there's clearly some step here during the linking that I don't understand, around how to find the actual library that a given external call lives in, so if anyone could point me in the right direction of how to figure this out for any given C runtime call, that would be great. Particularly in this case, I guess I need to find the library which contains the _exit function. Thanks!
Turns out the libcmt has been replaced. The replacement is ucrt, and so doing /defaultlib:ucrt seems to fix the problem!
While attempting to use fftw3 libraries in VS2008 with Intel Fortran, I encountered a problem with the data types defined by the iso_c_binding.
Considering that fftw3 defines in fftw3.f03:
integer, parameter :: C_FFTW_R2R_KIND = C_INT32_T
When compiling a code with the line
integer(C_FFTW_R2R_KIND), dimension(*), intent(in) :: kind
I get the following error:
error #6684: This is an incorrect value for a kind type parameter in this context. [C_FFTW_R2R_KIND]
To understand the problem, I tried the following code
program test
implicit none
call sub()
contains
subroutine sub()
use, intrinsic :: iso_c_binding
implicit none
write(*,*) C_INT, C_DOUBLE , C_INT32_T, C_INT_FAST32_T, C_INT_LEAST32_T
end subroutine sub
end program test
After running, the following result is displayed:
4 8 -2 -2 -2
As -2 is not a valid data type, I assumed that was the problem and looking in https://software.intel.com/en-us/node/678431, I replaced the line in fftw3.f03 by this:
integer, parameter :: C_FFTW_R2R_KIND = 4 !C_INT32_T
And I can run the program without errors.
If anybody could confirm that this alternative is correct or how to solve the original problem I would appreciate it.
Your approach will work fine for Intel Fortran, although using SELECTED_INT_KIND(8) instead of 4 would be safer and more portable.
Intel Visual Fortran apparently uses Visual C++ as a companion C compiler. And apparently a version that does not supports these C99 types yet. AFAIK Visual C++ is more oriented towards C++ than C and does not bring new C standard features too fast. They are supported in recent versions though https://msdn.microsoft.com/en-us/library/323b6b3k.aspx
In my opinion it would be more useful for Intel Fortran to define the c_ kind values anyway even if the C compiler does not define those constants, but maybe it is not completely standard conforming. But I think it would be a useful extension.
You simply need a newer version of Intel Fortran. If you are using VS2008, you would be at most using version 14; the current version is 18 and your test program there produces the result:
4 8 4 4 4
I'm using Fortran for my research and sometimes, for debugging purposes, someone will insert in the code something like this:
write(*,*) 'Variable x:', varx
The problem is that sometimes it happens that we forget to remove that statement from the code and it becomes difficult to find where it is being printed. I usually can get a good idea where it is by the name 'Variable x' but it sometimes happens that that information might no be present and I just see random numbers showing up.
One can imagine that doing a grep for write(*,*) is basically useless so I was wondering if there is an efficient way of finding my culprit, like forcing every call of write(*,*) to print a file and line number, or tracking stdout.
Thank you.
Intel's Fortran preprocessor defines a number of macros, such as __file__ and __line__ which will be replaced by, respectively, the file name (as a string) and line number (as an integer) when the pre-processor runs. For more details consult the documentation.
GFortran offers similar facilities, consult the documentation.
Perhaps your compiler offers similar capabilities.
As has been previously implied, there's no Fortran--although there may be a compiler approach---way to change the behaviour of the write statement as you want. However, as your problem is more to do with handling (unintentionally produced) bad code there are options.
If you can't easily find an unwanted write(*,*) in your code that suggests that you have many legitimate such statements. One solution is to reduce the count:
use an explicit format, rather than list-directed output (* as the format);
instead of * as the output unit, use output_unit from the intrinsic module iso_fortran_env.
[Having an explicit format for "proper" output is a good idea, anyway.]
If that fails, use your version control system to compare an old "good" version against the new "bad" version. Perhaps even have your version control system flag/block commits with new write(*,*)s.
And if all that still doesn't help, then the pre-processor macros previously mentioned could be a final resort.
I have a big, old, FORTRAN 77 code that has worked for many, many years with no problems.
Double-precision is not enough anymore, so to convert to quadruple-precision I have:
Replaced all occurrences of REAL*8 to REAL*16
Replaced all functions like DCOS() into functions like COS()
Replaced all built-in numbers like 0.d0 to 0.q0 , and 1D+01 to 1Q+01
The program compiles with no errors or warnings with the gcc-4.6 compiler on
operating system: openSUSE 11.3 x86_64 (a 64-bit operating system)
hardware: Intel Xeon E5-2650 (Sandy Bridge)
My LD_LIBRARY_PATH variable is set to the 64-bit library folder:
/gcc-4.6/lib64
The program reads an input file that has numbers in it.
Those numbers used to be of the form 1.234D+02 (for the double-precision version of the code, which works).
I have changed them so now that number is 1.234Q+02 , however I get the runtime error:
Bad real number in item 1 of list input
Indicating that the subroutine that reads in the data from the input file (called read.f) does not find the first number in the inputfile, to be compatible with what it expected.
Strangely, the quadruple-precision version of the code does not complain when the input file contains numbers like 1.234D+02 or 123.4 (which, based on the output seems to automatically be converted to the form 1.234D+02 rather than Q+02), it just does not like the Q+02 , so it seems that gcc-4.6 does not allow quadruple-precision numbers to be read in from input files in scientific notation !
Has anyone ever been able to read from an input file a quadruple-precision number in scientific notation (ie, like 1234Q+02) in FORTRAN with a gcc compiler, and if so how did you get it to work ? (or did you need a different compiler/operating system/hardware to get it to work ?)
Almost all of this is already in comments by #IanH and #Vladimi.
I suggest mixing in a little Fortran 90 into your FORTRAN 77 code.
Write all of your numbers with "E". Change your other program to write the data this way. Don't bother with "D" and don't try to use the infrequently supported "Q". (Using "Q" in constants in source code is an extension of gfortran -- see 6.1.8 in manual.)
Since you want the same source code to support two precisions, at the top of the program, have:
use ISO_FORTRAN_ENV
WP = real128
or
use ISO_FORTRAN_ENV
WP = real64
as the variation that changes whether your code is using double or quadruple precision. This is using the ISO Fortran Environment to select the types by their number of bits. (use needs to between program and implicit none; the assignment statement after implicit none.)
Then declare your real variables via:
real (WP) :: MyVar
In source code, write real constants as 1.23456789012345E+12_WP. The _type is the Fortran 90 way of specifying the type of a constant. This way you can go back and forth between double and quadruple precision by only changing the single line defining WP
WP == Working Precision.
Just use "E" in input files. Fortran will read according to the type of the variable.
Why not write a tiny test program to try it out?
I'm working on some old source code for an embedded system on an m68k target, and I'm seeing massive memory allocation requests sometimes when calling gcvtf to format a floating point number for display. I can probably work around this by writing my own substitute routine, but the nature of the error has me very curious, because it only occurs when the heap starts at or above a certain address, and it goes away if I hack the .ld linker script or remove any set of global variables (which are placed before the heap in my memory map) that add up to enough byte size so that the heap starts below the mysterious critical address.
So, I thought I'd look in the gcc source code for the compiler version I'm using (m68k-elf-gcc 3.3.2). I downloaded what appears to be the source for this version at http://gcc.petsads.us/releases/gcc-3.3.2/, but I can't find the definition for gcvt or gcvtf anywhere in there. When I search for it, grep only finds some documentation and .h references, but not the definition:
$ find | xargs grep gcvt
./gcc/doc/gcc.info: C library functions `ecvt', `fcvt' and `gcvt'. Given va
lid
./gcc/doc/trouble.texi:library functions #code{ecvt}, #code{fcvt} and #code{gcvt
}. Given valid
./gcc/sys-protos.h:extern char * gcvt(double, int, char *);
So, where is this function actually defined in the source code? Or did I download the entirely wrong thing?
I don't want to change this project to use the most recent gcc, due to project stability and testing considerations, and like I said, I can work around this by writing my own formatting routine, but this behavior is very confusing to me, and it will grind my brain if I don't find out why it's acting so weird.
Wallyk is correct that this is defined in the C library rather than the compiler. However, the GNU C library is (nearly always) only used with Linux compilers and distributions. Your compiler, being a "bare-metal" compiler, almost certainly uses the Newlib C library instead.
The main website for Newlib is here: http://sourceware.org/newlib/, and this particular function is defined in the newlib/libc/stdlib/efgcvt.c file. The sources have been quite stable for a long time, so (unless this is a result of a bug) chances are pretty good that the current sources are not too different from what your compiler is using.
As with the GNU C source, I don't see anything in there that would obviously cause this weirdness that you're seeing, but it's all eventually a bunch of wrappers around the basic sprintf routines.
It is in the GNU C library as glibc/misc/efgcvt.c. To save you some trouble, the code for the function is:
char *
__APPEND (FUNC_PREFIX, gcvt) (value, ndigit, buf)
FLOAT_TYPE value;
int ndigit;
char *buf;
{
sprintf (buf, "%.*" FLOAT_FMT_FLAG "g", MIN (ndigit, NDIGIT_MAX), value);
return buf;
}
The directions for obtain glibc are here.