我准备了一个用于遗留Fortran库的C++接口(interface)。
旧版库中的某些子例程遵循丑陋但可用的状态代码约定来报告错误,并且我使用此类状态代码从C++代码中抛出可读的异常:它很好用。
另一方面,有时旧版库会调用STOP
(终止程序)。即使条件是可恢复的,它也经常这样做。
我想从C++中捕获此STOP
,到目前为止,我一直没有成功。
以下代码很简单,但恰好代表了手头的问题:
Fortran旧版库fmodule.f90
:
module fmodule
use iso_c_binding
contains
subroutine fsub(x) bind(c, name="fsub")
real(c_double) x
if(x>=5) then
stop 'x >=5 : this kills the program'
else
print*, x
end if
end subroutine fsub
end module fmodule
C++接口(interface)
main.cpp
:#include<iostream>
// prototype for the external Fortran subroutine
extern "C" {
void fsub(double& x);
}
int main() {
double x;
while(std::cin >> x) {
fsub(x);
}
return 0;
}
编译行(GCC 4.8.1/OS X 10.7.4;
$
表示命令提示符):$ gfortran -o libfmodule.so fmodule.f90 -shared -fPIC -Wall
$ g++ main.cpp -L. -lfmodule -std=c++11
运行:
$ ./a.out
1
1.0000000000000000
2
2.0000000000000000
3
3.0000000000000000
4
4.0000000000000000
5
STOP x >=5 : this kills the program
我如何捕获
STOP
并要求另一个号码。请注意,我不想触摸Fortran代码。我尝试过的是:
std::atexit
:一旦我输入了std::signal
:STOP
似乎没有发出可以捕获最佳答案
您可以通过拦截Fortran运行时对exit
函数的调用来解决您的问题。见下文。 a.out
是使用您的代码和您提供的编译行创建的。
步骤1.找出要调用的函数。启动gdb
$ gdb ./a.out
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
[...]
(gdb) break fsub
Breakpoint 1 at 0x400888
(gdb) run
Starting program: a.out
5
Breakpoint 1, 0x00007ffff7dfc7e4 in fsub () from ./libfmodule.so
(gdb) step
Single stepping until exit from function fsub,
which has no line number information.
stop_string (string=0x7ffff7dfc8d8 "x >=5 : this kills the programfmodule.f90", len=30) at /usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c:67
因此
stop_string
被调用。我们需要知道该功能对应于哪个符号。步骤2.找到
stop_string
函数的确切名称。它必须在共享库之一中。$ ldd ./a.out
linux-vdso.so.1 => (0x00007fff54095000)
libfmodule.so => ./libfmodule.so (0x00007fa31ab7d000)
libstdc++.so.6 => /usr/local/gcc/4.7.2/lib64/libstdc++.so.6 (0x00007fa31a875000)
libm.so.6 => /lib64/libm.so.6 (0x0000003da4000000)
libgcc_s.so.1 => /usr/local/gcc/4.7.2/lib64/libgcc_s.so.1 (0x00007fa31a643000)
libc.so.6 => /lib64/libc.so.6 (0x0000003da3c00000)
libgfortran.so.3 => /usr/local/gcc/4.7.2/lib64/libgfortran.so.3 (0x00007fa31a32f000)
libquadmath.so.0 => /usr/local/gcc/4.7.2/lib64/libquadmath.so.0 (0x00007fa31a0fa000)
/lib64/ld-linux-x86-64.so.2 (0x0000003da3800000)
我在fortran运行时中发现了它(毫不奇怪)。
$ readelf -s /usr/local/gcc/4.7.2/lib64/libgfortran.so.3|grep stop_string
1121: 000000000001b320 63 FUNC GLOBAL DEFAULT 11 _gfortran_stop_string@@GFORTRAN_1.0
2417: 000000000001b320 63 FUNC GLOBAL DEFAULT 11 _gfortran_stop_string
步骤3.编写一个将替换该函数的函数
我在源代码中寻找函数的精确签名(
/usr/local/src/gcc-4.7.2/libgfortran/runtime/stop.c
请参见gdb
session )$ cat my_exit.c
#define _GNU_SOURCE
#include <stdio.h>
void _gfortran_stop_string (const char *string, int len)
{
printf("Let's keep on");
}
步骤4.编译导出该符号的共享库。
gcc -Wall -fPIC -c -o my_exit.o my_exit.c
gcc -shared -fPIC -Wl,-soname -Wl,libmy_exit.so -o libmy_exit.so my_exit.o
步骤5.使用LD_PRELOAD运行程序,以便我们的新函数优先于运行时的函数
$ LD_PRELOAD=./libmy_exit.so ./a.out
1
1.0000000000000000
2
2.0000000000000000
3
3.0000000000000000
4
4.0000000000000000
5
Let's keep on 5.0000000000000000
6
Let's keep on 6.0000000000000000
7
Let's keep on 7.0000000000000000
妳去
关于c++ - 从C++截取Fortran STOP,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19596375/