Is there any possibility to launch an external program from Fortran and write something to this programs standard input?
I know e.g. of gfortran's SYSTEM but there is no such option.
As you have noticed, GFortran does not have anything like the pipe()/fork()/exec() functions builtin.
If you're on Linux or some other Unix-like system you could do something like
execute_command_line("mkfifo /path/to/fifo")
The mkfifo command creates a named pipe, that is, a pipe that also has a name in the filesystem.
open(newunit=plot_unit, file="/path/to/fifo", access="stream", format="formatted")
execute_command_line("gnuplot < /path/to/fifo")
So the idea is that you can then open the FIFO like a normal external unit in GFortran, then execute gnuplot with standard input connected to the FIFO.
You might need to exchange the order of #2 and #3 in case this deadlocks. But some minor variation of the above should work (I've used it to connect to one Fortran program from another).
Firstly, if you're using a relatively recent compiler you should be able to use execute_command_line (part of the f2008 spec) instead of system (compiler extension). This launches a command using the C library's system call which uses the sh shell on nix and cmd.exe on Windows (see here). As such you can use standard input redirection type approaches to connect to stdin of the launched program, but it may not be suitable for more complicated use.
The following example shows a simple example
program stdIn
implicit none
character(len=20) :: cmd, args
character(len=50) :: fullcmd
cmd = "bc"
args = "1+2"
fullcmd = cmd//" <<< "//args
print*,"Running ",fullcmd
call execute_command_line(fullcmd)
end program stdIn
Which should output
Running bc <<< 1+2
3
Related
What I'd like to do is have my C++ code open up Mplus (statistical program that I've downloaded on my computer) and run it. Is it possible?
You may be able to do what you want with std::system() calls like:
std::system("program -e input_commands.txt"); // Assuming it accepts some sort of command line args
std::system("program < input_commands.txt"); // Assuming it responds to stdin
It depends on the program if this approach will work.
This one's going to take a bit of explaining. Please bear with me.
What I Have
I have in my possession some Fortran source code and some binaries that have been compiled from that code. I did not do the compilation, but there is a build script that suggests G77 was used to do it.
As well as the Fortran stuff, there is also some Java code that provides users with a GUI "wrapper" around the binaries. It passes information between itself and the binaries via their input/output/error pipes. The Java code is very messy, and this way of doing things adds a lot of boilerplate and redundancy, but it does the job and I know it works.
What I Need
Unfortunately, I'd like to make some changes:
I want to create a new Python wrapper for the binaries (or, more precisely, extend an existing Python program to become the new wrapper).
I want to be able to compile the Fortran code as part of this existing program's build process. I would like to use gfortran for this, since MinGW is used elsewhere in the build and so it will be readily available.
The Problem
When I compile the Fortran code myself using gfortran, I cannot get the resulting binaries to "talk" to either the current Java wrapper or my new Python wrapper.
Here are the various ways of printing to the console that I have tried in the Fortran code:
subroutine printA(message)
write(6,*) message
end
subroutine printB(message)
write(*,*) message
end
subroutine printC(message)
use iso_fortran_env
write(output_unit,*) message
end
There are also read commands as well, but the code doesn't even get a change to execute that part so I'm not worrying about it yet.
Extra Info
I have to call gfortran with the -ffixed-line-length-132 flag so that the code compiles, but apart from that I don't use anything else. I have tried using the -ff2c flag in the vague hope that it will make a difference. It doesn't.
This stackoverflow post is informative, but doesn't offer me anything that works.
The relavant manual page suggests that printA should work just fine.
I'm working on Windows, but will need this to be multi-platform.
Juse in case you're intested, the Java code uses Runtime.getRuntime().exec("prog.exe") to call the binaries and then the various "stream" methods of the resulting Process object to communicate with them. The Python code uses equivalents of this provided by the Popen object of the subprocess module.
I should also say that I am aware there are alternatives. Rewriting the code in Python (or something else like C++), or making amendments so that is it can be called via F2Py have been ruled out as options. Using g77 is also a no-go; we have enough dependencies as it is. I'd like to be able to write to / read from the console properly with gfortran, or know that it's just not possible.
Hard to say without seeing more details from your Fortran and Python codes. The following pair of code works for me (at least under Linux):
Fortran program repeating its input line by line prefixed with line number:
program test_communication
use iso_fortran_env, stdout => output_unit, stdin => input_unit
implicit none
character(100) :: buffer
integer :: ii
ii = 1
do while (.true.)
read(stdin, *) buffer
write(stdout, "(I0,A,A)") ii, "|", trim(buffer)
flush(stdout)
ii = ii + 1
end do
end program test_communication
Python program invoking the Fortran binary. You can feed it with arbitrary strings from the console.
import subprocess as sub
print "Starting child"
proc = sub.Popen("./a.out", stdin=sub.PIPE, stdout=sub.PIPE)
while True:
send = raw_input("Enter a string: ")
if not send:
print "Exiting loop"
break
proc.stdin.write(send)
proc.stdin.write("\n")
proc.stdin.flush()
print "Sent:", send
recv = proc.stdout.readline()
print "Received:", recv.rstrip()
print "Killing child"
proc.kill()
I'm in the process of adding an option to a Fortran program to run it using multiple processors using MPI. If the user is going to run it in parallel, the user needs to specify different input files---one file for each domain (processor) of the problem. The program will look for a specific filename by default (a file called "serial.inp"). So I need the program to know when it is being run in parallel so that it can instead look for the other filenames instead (e.g. "parallel_1.inp", "parallel_2.inp", "parallel_3.inp", etc.). My first thought is to have the user pass an argument to the program when they execute it, e.g.:
mpiexec -n 4 myprogram.exe -parallel
This way, it will look for the parallel files when that argument is present. But it seems kind of redundant. If the program is being called with mpiexec, there is no question that the user is attempting to run it in parallel. Is there any way that my program will know it was started using mpiexec? Or is the command line argument my best bet?
Alex Leach is right in that you can do this with MPI-implementation-specific environment variable lookups, but there's no portable way to do this.
But as I understand, I don't think you really need to; you can get most of what you want with just checking to see if it was run with one rank:
program filenames
use mpi
implicit none
integer :: comsize, rank, ierr
character(len=128) :: inputfilename
call MPI_Init(ierr)
call MPI_Comm_size(MPI_COMM_WORLD,comsize,ierr)
call MPI_Comm_rank(MPI_COMM_WORLD,rank,ierr)
if (comsize == 1) then
inputfilename = 'serial.inp'
else
write(inputfilename, '(A,I0,A)'), 'parallel_',rank,'.imp'
endif
write(*,'(I,1X,A)'), rank, trim(inputfilename)
call MPI_Finalize(ierr)
end program filenames
Running gives
$ mpirun -np 4 ./filenames
0 parallel_0.imp
1 parallel_1.imp
2 parallel_2.imp
3 parallel_3.imp
$ ./filenames
0 serial.inp
That's not perfect; it'll give the serial result if you run using mpirun -np 1 filenames, but depending on your use case that may not be a terrible thing in exchange for having something portable.
Processes run with mpiexec will have various environment variables set, indicating to the subprocesses whether they are the master process or slaves, amongst other things.
Look in your mpiexec's documentation for specific details. Microsoft have some documentation online too.
Why not do it programmatically? This is how I do it in my program:
#ifdef MPI
CALL MPI_Init(ierr) ! Initialize MPI
CALL MPI_Comm_rank(mpicomm,nproc,ierr) ! Who am I?
CALL MPI_Comm_size(mpicomm,size,ierr) ! How many processes?
#else
nproc = 0
size = 1
#endif
After this point in the program, you can inquire whether the program is serial or parallel by inquiring the value of size.
i have an interface where i use to execute the mml command in my solaris unix like below:
> eaw 0004
<RLTYP;
BSC SYSTEM TYPE DATA
GSYSTYPE
GSM1800
END
<
As soon as i do eaw <name> on the command line.It will start an interface where in i can execute mml commands and i can see the output of those commands executed.
My idea here is to parse the command output in c++.
I can do away with some logic for parsing.But to start with How can get the command to be executed inside c++ ? Is there any predefined way to do this.
This should be similar to executing sql queries inside c++.But we use other libraries to execute sql queries.I also donot want to run a shell script or create temporary files in between.
what i want is to execute the command inside c++ and get the output and even that in c++.
could anybody give me the right directions?
You have several options. From easiest and simplest to hardest and most complex to use:
Use the system() call to spawn a shell to run a command
Use the popen() call to spawn a subprocess and either write to its standard input stream or read from its standard output stream (but not both)
Use a combination of pipe(), fork(), dup()/dup2(), and exec*() to spawn a child process and set up pipes for a child process's standard input and output.
The below code is done with the sh command. This redirects stdout to a file named "out" which can be read later to process the output. Each command to the process can be written through the pipe.
#include <stdio.h>
int main()
{
FILE *fp;
fp = popen("sh > out", "w");
if (fp) {
fprintf(fp, "date\n");
fprintf(fp, "exit\n");
fclose(fp);
}
return 0;
}
It seems that input redirection in gdb does not work in Cygwin e.g
(gdb) run < input.txt
Is there other way to redirect input in gdb of Cygwin??
Unfortunately this is not possible when running gdb in cygwin. The bug exists for a quote long time, but apparently it's a hard one to fix - and probably the gdb devs prefer spending time on features/issues relevant to more common environments (such as Linux).
There are various possible workarounds; I'd prefer the first one since it's the cleanest and also useful while not debugging / running on cygwin:
Add a command line argument, e.g. -f whatever with whatever being the filename to read from. If the argument is not present or set to -, read from stdin. The -f - option is optional of course but for arguments accepting filenames it's a common standard (as long as it makes sense) to handle - as "use stdin/out".
Use the gdb hack mentioned here to remap stdin to a manually opened file inside the application:
> gdb yourexecutable
(gdb) break main
(gdb) run
(gdb) call dup2(open("input.txt", 0), 0)
(gdb) continue
This sets a breakpoint on the main function, then executes the program which will break right after entering main. Then dup2 is used to replace the stdin fd (0) with a file descriptor of the input file.