My google-fu's weak regarding this issue… (edit/spoiler: _ isn't the issue after all, see below)
To provide some context, I'm developing a tiny portable program using Nim. At some time, I wanted to use getch() on win32 (using an old windows XP)…
The Nim doc says:
proc getch(): char {.raises: [], tags: [].}
Read a single character from the terminal, blocking until it is entered. The character is not printed to the terminal. This is not available for Windows.
… so eventually I used:
proc getch(): cint {.importc: "_getch", header: "<conio.h>".}
and that works fine for my needs. Later however, I tried using the dynlib pragma instead:
proc getch(): cint {.importc, dynlib: "msvcrt.dll".}
That fails at runtime: could not import: getch. No magic there, the symbol should start with an underscore! But _getch or even `_getch` are illegal in Nim.
(Note: there was allegedly a getch in the CRT but MS tells it's deprecated and we should use _getch instead.)
To make sure, I tried the same thing with a libc symbol Nim doesn't know about:
proc atoi(s: cstring): cint {.importc: "atoi", header: "<stdlib.h>".}
and
proc atoi(s: cstring): cint {.importc, dynlib: "msvcrt.dll".}
That works in both cases; atoi (obviously) doesn't begin with _.
I can do with the header pragma for now in this case, but that's a general issue I'm probably going to face again, hence my question:
How do I get to import symbols that begin with _ with the dynlibpragma?
The best would be an additional pragma in the same {. .}, as opposed to a flag when invoking the toolchain, but at this point any hint is welcome. I'm looking for a solution that doesn't rely on external libs or other languages.
Cheers.
(Nim 0.13.0)
EDIT: (in case others run in the same trouble)
OK, so I was chasing the wrong problem. As commented by #flyx, importc: "symbol" can be used with dynlib in the same way as in the header. The thing is, I had tried before and dismissed this combination for the wrong reasons (since Nim is still under heavy development, sometimes I have to take a guess… unlucky this time).
In fact:
proc getch(): cint {.importc: "_getch", dynlib: "msvcrt.dll".}
proc kbhit(): cint {.importc: "_kbhit", dynlib: "msvcrt.dll".}
didn't work for me. Not at compile time but at run time.
That still doesn't: _getch doesn't return until I Ctrl-C it (perhaps that's why it's not implemented on Windows in the first place!) and with a loop on _kbhit I need to kill the task.
proc getch(): cint {.importc: "_getch", header: "<conio.h>".}
proc kbhit(): cint {.importc: "_kbhit", header: "<conio.h>".}
DO work.
But because now I tested successfully
proc atoi64(s: cstring): clonglong {.importc: "_atoi64", dynlib: "msvcrt.dll".}
I can tell that the underscore is a non-issue.
Use:
proc getch(): cint {.importc: "_getch", dynlib: "msvcrt.dll".}
Related
A snip of Rust code:
pub fn main() {
let a = "hello";
let b = a.len();
let c =b;
println!("len:{}",c)
}
When debugging in CLion, Is it possible to evaluate a function? For example, debug the code step by step, now the code is running to the last line println!... and the current step stops here, by adding the expression a.len() to the watch a variable window, the IDE can't evaluate the a.len(). It says: error: no field named len
This is the same reason you can't make conditional breakpoints for Rust code:
Can't create a conditional breakpoint in VSCode-LLDB with Rust
I hope, I'm not too late to answer this, but with both lldb and gdb, Rust debugging capability is currently rather constrained.
Expressions that are straightforward work; anything complex is likely to produce issues.
My observations from rust-lldb trying this, are that only a small portion of Rust is understood by the expression parser.
There is no support for macros.
Non-used functions are not included in the final binary.
For instance, since that method is not included in the binary, you are unable to execute capacity() on the HashMap in the debugger.
Methods must be named as follows:
struct value.method(&struct value)
There is no technique that I've discovered to call monomorphized functions on generic structs (like HashMap).
For example, "hello" is a const char [5] including the trailing NUL byte. String constants "..." in lldb expressions are produced as C-style string constants.
Therefore, they are not valid functions
While Coding in Python, I often do something like
test.py
x = []
breakpoint()
± |master U:5 ?:4 ✗| → python3 test.py
-> breakpoint()
(Pdb) x
[]
(Pdb) x.append(1)
(Pdb) x
[1]
Is it possible to execute the statement while debugging Rust?
use std::collections::HashMap;
fn main() {
let mut contacts = HashMap::new();
contacts.insert("Daniel", "798-1364");
contacts.insert("Ashley", "645-7689");
//set breakpoint here
}
So far, I can execute p contacts in the debug console, the meaning of this output isn't straight to me. What if I want to know the outcome of println!("{:?}", contacts); without writting this line of code in the source file.
And also I want to know the outcome of contacts.insert("Robert", "956-1742"), If I execute expr contacts.insert("Robert", "956-1742") in the debug console, it says error: no field named insert.
Rust debugging support is currently quite limited with both lldb and gdb. Simple expressions work, anything more complex is likely to cause problems.
My experience while testing this with rust-lldb:
The expression parser only understands a limited subset of Rust. Macros are not supported.
Functions that are not used are not included in the resulting binary. E.g. you cannot call capacity() on the HashMap in the debugger since that function is not included in the binary.
Methods have to be called like this: struct_value.method(&struct_value)
I haven't found a way to call monomorphized methods on generic structs (like HashMap).
String constants "..." in lldb expressions are created as C-style string constants, e.g. "abcdef" is a const char [7] including the trailing NUL byte. Thus they cannot be easily passed to Rust functions expecting &str arguments.
Trying to use a helper function like this:
pub fn print_contacts(contacts: &HashMap<&str, &str>) {
println!("{:?}", contacts);
}
causes lldb to crash:
(lldb) expr print_contacts(&contacts)
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0. Program arguments: [...]
Segmentation fault: 11
So it seems that what you want to do is not possible at this time.
The following code compiles, but I do not think that it should. As you can see, the output is garbage.
This is a minimal failing example of something that bit me hard in a large project I work on.
My question is - why does the compiler not complain? Is this a compiler limitation, or is this somehow "expected behaviour", and I've missed something?
I'm using gfortran 4.6.3.
module dataModule
integer :: datum1 = int(1)
integer :: datum2 = int(2)
end module dataModule
program moduleTest
use dataModule, only: datum1
write(*,*) "datum 1 is", datum1
write(*,*) "datum 2 is", datum2
end program moduleTest
Example output:
datum 1 is 1
datum 2 is 4.58322689E-41
Your code is at fault, not the compiler. If datum2 were use associated despite the only clause and if the explicit initialization of datum2 were ignored, then yes, that would be a naughty compiler.
The answer is much more mundane, though.
datum2 is not use associated: in the absence of implicit none it is an implicitly typed variable in the main program. The "garbage" comes from the fact that it is not defined, by initialization or assignment, before its value is referenced and that it's implicitly (default) real. The compiler isn't required to detect this mistake at compile (or run) time.
I'm very new to Fortran, and for my research I need to get a monster of a model running, so I am learning as I am going along. So I'm sorry if I ask a "stupid" question.
I'm trying to compile (Mac OSX, from the command line) and I've already managed to solve a few things, but now I've come across something I am not sure how to fix. I think I get the idea behind the error, but again, not sure how to fix.
The model is huge, so I will only post the code sections that I think are relevant (though I could be wrong). I have a file with several subroutines, that starts with:
!==========================================================================================!
! This subroutine simply updates the budget variables. !
!------------------------------------------------------------------------------------------!
subroutine update_budget(csite,lsl,ipaa,ipaz)
use ed_state_vars, only : sitetype ! ! structure
implicit none
!----- Arguments -----------------------------------------------------------------------!
type(sitetype) , target :: csite
integer , intent(in) :: lsl
integer , intent(in) :: ipaa
integer , intent(in) :: ipaz
!----- Local variables. ----------------------------------------------------------------!
integer :: ipa
!----- External functions. -------------------------------------------------------------!
real , external :: compute_water_storage
real , external :: compute_energy_storage
real , external :: compute_co2_storage
!---------------------------------------------------------------------------------------!
do ipa=ipaa,ipaz
!------------------------------------------------------------------------------------!
! Computing the storage terms for CO2, energy, and water budgets. !
!------------------------------------------------------------------------------------!
csite%co2budget_initialstorage(ipa) = compute_co2_storage(csite,ipa)
csite%wbudget_initialstorage(ipa) = compute_water_storage(csite,lsl,ipa)
csite%ebudget_initialstorage(ipa) = compute_energy_storage(csite,lsl,ipa)
end do
return
end subroutine update_budget
!==========================================================================================!
!==========================================================================================!
I get error messages along the lines of
budget_utils.f90:20.54:
real , external :: compute_co2_storage
1
Error: Dummy argument 'csite' of procedure 'compute_co2_storage' at (1) has an attribute that requires an explicit interface for this procedure
(I get a bunch of them, but they are essentially all the same). Now, looking at ed_state_vars.f90 (which is "used" in the subroutine), I find
!============================================================================!
!============================================================================!
!---------------------------------------------------------------------------!
! Site type:
! The following are the patch level arrays that populate the current site.
!---------------------------------------------------------------------------!
type sitetype
integer :: npatches
! The global index of the first cohort in all patches
integer,pointer,dimension(:) :: paco_id
! The number of cohorts in each patch
integer,pointer,dimension(:) :: paco_n
! Global index of the first patch in this vector, across all patches
! on the grid
integer :: paglob_id
! The patches containing the cohort arrays
type(patchtype),pointer,dimension(:) :: patch
Etc etc - this goes one for another 500 lines or so.
So to get to the point, it seems like the original subroutine needs an explicit interface for its procedures in order to be able to use the (dummy) argument csite. Again, I am SO NEW to Fortran, but I am really trying to understand how it "thinks". I have been searching what it means to have an explicit interface, when (and how!) to use it etc. But I can't figure out how it applies in my case. Should I maybe use a different compiler (Intel?). Any hints?
Edit: So csite is declared a target in all procedures and from the declaration type(site type) contains a whole bunch of pointers, as specified in sitetype. But sitetype is being properly used from another module (ed_state_vars.f90) in all procedures. So I am still confused why it gives me the explicit interface error?
"explicit interface" means that the interface to the procedure (subroutine or function) is declared to the compiler. This allows the compiler to check consistency of arguments between calls to the procedure and the actual procedure. This can find a lot of programmer mistakes. You can do this writing out the interface with an interface statement but there is a far easier method: place the procedure into a module and use that module from any other entity that calls it -- from the main program or any procedure that is itself not in the module. But you don't use a procedure from another procedure in the same module -- they are automatically known to each other.
Placing a procedure into a module automatically makes its interface known to the compiler and available for cross-checking when it is useed. This is easier and less prone to mistakes than writing an interface. With an interface, you have to duplicate the procedure argument list. Then if you revise the procedure, you also have to revise the calls (of course!) but also the interface.
An explicit interface (interface statement or module) is required when you use "advanced" arguments. Otherwise the compiler doesn't know to generate the correct call
If you have a procedure that is useed, you shouldn't describe it with external. There are very few uses of external in modern Fortran -- so, remove the external attributes, put all of your procedures into a module, and use them.
I ran into the same problems you encountered whilst I was trying to install ED2 on my mac 10.9. I fixed it by including all the subroutines in that file in a module, that is:
module mymodule
contains
subroutine update_budget(csite,lsl,ipaa,ipaz)
other subroutines ecc.
end module mymodule
The same thing had to be done to some 10 to 15 other files in the package.
I have compiled all the files and produced the corresponding object files but now I am getting errors about undefined symbols. However I suspect these are independent of the modifications so if someone has the patience this might be a way to solve at least the interface problem.
I do not understand why the following program segfaults with a SIGSEGV if the bar field is present in containerType, and works without problems if it is commented out. I'm on x86_64, compiling with both gfortran-4.4.6 and gfortran-4.6.3.
As I understand it, using a pointer to containerType should force the allocation of the contained big array to happen on the heap but that doesn't seem to be the case. Running valgrind on the executable gives me
Warning: client switching stacks? SP change: 0x7ff000448 --> 0x7fe0603f8
to suppress, use: --max-stackframe=16384080 or greater
(The rest of the output is IMHO not relevant, but I could edit it in if required). This indicates to me that there's a stack overflow; presumably due to allocating the 8*8*8*4000 * 8(bytes per real) = 16384000 bytes on the stack.
When I comment out the bar field, valgrind is perfectly happy. To make matters even stranger, compiling under gfortran-4.6.3 with '-O' also makes the problem go away (but not under gfortran-4.4.6).
Either I've stumbled on a compiler bug, or (more likely, as I'm pretty new to Fortran) I don't understand where data is allocated. Could someone enlighten me what's going on?
The code in question:
main.f90:
program main
use problematicArray
implicit none
type (containerType),pointer :: container
allocate(container)
container%foo%arrayData = 17.0
write(*,*) container%foo%arrayData(7,7,7,100)
deallocate(container)
write(*,*) 'Program finished'
end program main
problematicArray.f90:
module problematicArray
implicit none
private
integer, parameter, public :: dim1 = 4000
type, public :: typeWith4DArray
real(8), dimension(8,8,8,dim1) :: arrayData
end type typeWith4DArray
type :: typeWithChars
character(4), dimension(:), allocatable :: charData
end type typeWithChars
type, public :: containerType
type(typeWith4DArray) :: foo
type(typeWithChars) :: bar
end type containerType
end module problematicArray
This must be a bug in gfortran. I do not see anything wrong there. It also works in Intel and Oracle compilers. Best to report it to gfortran developers. I tried it with only a 2 days old build of the gfortran 4.8 trunk.
The error has nothing to do with stack/heap difference. It simply crashes during the allocate statement. It does not even work with stat= and errmsg= set.
Just a note, you can have the module and the main program inside a single source file.