I'm interested in calling fortran codes in a Mathematica session. I learn that Mathlink offers a way to do that. But I have little knowledge on C and nothing on C++.
Is anybody willing to give me a detailed example?
I'm using with Mathematica 8, MS Visual Studio 2008 and Intel Fortran 11. The system is Windows 7 Home Premium.
Many thanks!
The following is an explicit example which I succeeded using gfortan and gcc with the Windows system:
I found this blog Adventures in Mathlink.
It is helpful with a specific example. I installed MinGW in order to use gfortran and gcc. After installation, one must set PATH in order to use gfortran and gcc without typing the path each time. A tip for adding PATH without restarting the system: After adding the PATH, open cmd, and run set PATH=C: Then close cmd, whenyou open it again, with echo %PATH%, you will see the new path list. I followed the steps in the linked blog, adapted to Windows, with the tutorial example addtwo:
The Mathematica codes writing a .bat file and running it to generate the executable
(* Write a .bat file to compile the MathLink template *.tm, FORTRAN codes *.f and
C codes *.c files, and run it to create an executable file. *)
CreateExeF[s_String] :=
Module[{dir, libdir, bindir, BatCode, bat}, dir = NotebookDirectory[];
{libdir, bindir} = StringJoin[
"\"", $InstallationDirectory,
"\\SystemFiles\\Links\\MathLink\\DeveloperKit\\Windows\\CompilerAdditions\\mldev32\\",
#] & /# {"lib\\", "bin\\"};
BatCode = StringJoin[
"gfortran -c ", #, ".f -o ", #, "f.o
gcc -c ", #, ".c -o ", #, ".o
",
bindir, "mprep.exe\" ", #, ".tm -o ", #, "tm.c
gcc -c ", #, "tm.c -o ", #, "tm.o
gcc ", #, "tm.o ", #, ".o ", #, "f.o ",
libdir, "ml32i3m.lib\" ",
"-lm -lpthread -mwindows -lstdc++ -o ", #
] &;
(* write the .bat file *)
bat = Export[FileNameJoin[{dir, # <> ".bat"}], BatCode[dir <> #],
"string"] &[s];
(* run the .bat file *)
Run[bat]]
FORTRAN codes addtwo.f
subroutine addtwof(i,j,k)
integer i, j, k
k = i + j
end
C wrapper addtwo.c
#include "mathlink.h"
int addtwo(int i, int j)
{
int res;
addtwof_(&i, &j, &res);
return res;
}
#if WINDOWS_MATHLINK
#if __BORLANDC__
#pragma argsused
#endif
int PASCAL WinMain( HINSTANCE hinstCurrent, HINSTANCE hinstPrevious, LPSTR lpszCmdLine, int nCmdShow)
{
char buff[512];
char FAR * buff_start = buff;
char FAR * argv[32];
char FAR * FAR * argv_end = argv + 32;
hinstPrevious = hinstPrevious; /* suppress warning */
if( !MLInitializeIcon( hinstCurrent, nCmdShow)) return 1;
MLScanString( argv, &argv_end, &lpszCmdLine, &buff_start);
return MLMain( (int)(argv_end - argv), argv);
}
#else
int main(int argc, char* argv[])
{
return MLMain(argc, argv);
}
#endif
The template file addtwo.tm is the same as the one in Todd Gayley's tutorial. For completeness, it is also given here:
:Begin:
:Function: addtwo
:Pattern: AddTwo[i_Integer, j_Integer]
:Arguments: { i, j }
:ArgumentTypes: { Integer, Integer }
:ReturnType: Integer
:End:
:Evaluate: AddTwo::usage = "AddTwo[i, j] gives the sum of two integer numbers i and j."
Related
1.FORTRAN source (main.for)
integer function mysum(a, b)
!DEC$ATTRIBUTES DLLEXPORT,STDCALL :: mysum
!DEC$ATTRIBUTES VALUE :: a, b
integer a,b
mysum = a + b
return
end function mysum
make dll
gfortran main.for -shared -o fordll.dll
call dll
#include <stdio.h>
#include <iostream>
#include <windows.h>
using namespace std;
typedef int(_stdcall * MYSUM)(int a, int b);
int main()
{
int a=10,b=20;
HINSTANCE hLibrary = LoadLibrary("fordll.dll");
if (hLibrary == NULL)
{
cout << "can't find the dll file" << endl;
return -1;
}
MYSUM fact = (MYSUM)GetProcAddress(hLibrary, "mysum");
if (fact == NULL)
{
cout << "can't find the function file." << endl;
return -2;
}
try
{
cout << fact(a,b);
}
catch(...)
{ }
FreeLibrary(hLibrary);
return 0;
}
ERROR
Exception Access Violation reading 0x0000000A
why? if the fortran source file is comppiled by Compad Visual fortran or Inter fortran, it works well. However, it doesn't work with gcc or gfortran. What's wrong?
You are using special directives to alter the calling conventions
!DEC$ATTRIBUTES DLLEXPORT,STDCALL :: mysum
!DEC$ATTRIBUTES VALUE :: a, b
However, these are only valid for the DEC compiler sand its descendant Intel Fortran.
GCC use !GCC$ directives instead. Use them, they are pretty much the same as the DEC ones. See https://gcc.gnu.org/onlinedocs/gfortran/ATTRIBUTES-directive.html#ATTRIBUTES-directive Just change coppy and paste the DEC directives and change DEC to GCC.
Alternatively, change the code to pass-by-reference and ditch the VALUE attribute. The STDCALL attribute is relevant for 32-bit Windows only.
In modern Fortran it is much better to use
integer function mysum(a, b) bind(C,name="mysum")
integer, value :: a, b
(ignoring the stdcall issue, which can be just deleted in the C++ code).
I'm trying to get started working with Intel's Array Building Blocks, and there seems to only be one tutorial on "Hello World", at http://www.hpc.lsu.edu/training/tutorials/sc10/tutorials/SC10Tutorials/docs/M07/M07.pdf . And I'm not really getting it.
I'm using Visual Studio 2010 and this is the code I got from the above link, kinda.
#include <C:/Program Files/intel/arbb/Beta6/include/arbb.hpp>
//What do I have to do to make just "#include <arbb.hpp>" work?
using namespace arbb;
void my_function(f32& result, f32 input){
std::cout << "Hello, world!" << std::endl;
result = input + 1.0f; //"Error: no operator "+" matches these operands
}
int main(){
typedef closure<void (f32&, f32)> mfc;
mfc a = capture(my_function);
mfc b = call(my_function);
mfc c = call(my_function);
}
What else do I need to do to get "Hello World" working?
There are many samples available in arbb installation path. You can use the visual studio solution files to start with any of the sample. That is the easiest way.
In order to compile and run your own application from scratch, you have to have the include and dependencies set.
On Linux, you can add the path ~/(whatever)/intel/arbb/Beta6/include in the compile option using -I
On Windows, you can do:
set INCLUDE=C:/Program Files/intel/arbb/Beta6/include/arbb.hpp;
Or have a batch script that will ensure all the environment variables are set by default.
--- contents of the batch file ---
SET ARBB_OPT_LEVEL=O3
SET PATH=%ARBB_ROOT%\bin\ia32;%ARBB_ROOT%\bin\ia32\vs%MSVS_VERSION%;%OPENCV_ROOT%\bin;%FFTW_ROOT%;%FREEGLUT_ROOT%;%PTHREADS_ROOT%\lib;%PATH%
---- here is hello world program in arbb ---
#include <arbb.hpp>
void arbb_hello_map(arbb::i32& val)
{
val = val * 2;
}
void arbb_hello(arbb::dense<arbb::i32>& data)
{
using namespace arbb;
map(arbb_hello_map)(data);
}
int main()
{
using namespace arbb;
int size = 5;
dense<i32> data = dense<i32>(size);
range<i32> write_data = data.write_only_range();
for (int i = 0; i < size; ++i)
write_data[i] = i;
arbb::call(arbb_hello)(data);
std::cout << "hello: " << std::endl;
const_range<i32> read_data = data.read_only_range();
for (int i = 0; i < size; ++i)
std::cout <<"data["<<i<<"] = " << read_data[i] <<"\n";
return 0;
}
And compile it using
g++ -m64 -I/home/YOUR_NAME/arbb/install//include -Wall -Werror -O3 -W -Wshadow temp.cpp -o temp -L/home/YOUR_NAME/arbb/install/lib/intel64 -larbb_dev -ltbb -littnotify
Run it using
./temp
As this is my first post to stackoverflow I want to thank you all for your valuable posts that helped me a lot in the past.
I use MinGW (gcc 4.4.0) on Windows-7(64) - more specifically I use Nokia Qt + MinGW but Qt is not involved in my Question.
I need to find the address and -more important- the length of specific functions of my application at runtime, in order to encode/decode these functions and implement a software protection system.
I already found a solution on how to compute the length of a function, by assuming that static functions placed one after each other in a source-file, it is logical to be also sequentially placed in the compiled object file and subsequently in memory.
Unfortunately this is true only if the whole CPP file is compiled with option: "g++ -O0" (optimization level = 0).
If I compile it with "g++ -O2" (which is the default for my project) the compiler seems to relocate some of the functions and as a result the computed function length seems to be both incorrect and negative(!).
This is happening even if I put a "#pragma GCC optimize 0" line in the source file,
which is supposed to be the equivalent of a "g++ -O0" command line option.
I suppose that "g++ -O2" instructs the compiler to perform some global file-level optimization (some function relocation?) which is not avoided by using the #pragma directive.
Do you have any idea how to prevent this, without having to compile the whole file with -O0 option?
OR: Do you know of any other method to find the length of a function at runtime?
I prepare a small example for you, and the results with different compilation options, to highlight the case.
The Source:
// ===================================================================
// test.cpp
//
// Intention: To find the addr and length of a function at runtime
// Problem: The application output is correct when compiled with: "g++ -O0"
// but it's erroneous when compiled with "g++ -O2"
// (although a directive "#pragma GCC optimize 0" is present)
// ===================================================================
#include <stdio.h>
#include <math.h>
#pragma GCC optimize 0
static int test_01(int p1)
{
putchar('a');
putchar('\n');
return 1;
}
static int test_02(int p1)
{
putchar('b');
putchar('b');
putchar('\n');
return 2;
}
static int test_03(int p1)
{
putchar('c');
putchar('\n');
return 3;
}
static int test_04(int p1)
{
putchar('d');
putchar('\n');
return 4;
}
// Print a HexDump of a specific address and length
void HexDump(void *startAddr, long len)
{
unsigned char *buf = (unsigned char *)startAddr;
printf("addr:%ld, len:%ld\n", (long )startAddr, len);
len = (long )fabs(len);
while (len)
{
printf("%02x.", *buf);
buf++;
len--;
}
printf("\n");
}
int main(int argc, char *argv[])
{
printf("======================\n");
long fun_len = (long )test_02 - (long )test_01;
HexDump((void *)test_01, fun_len);
printf("======================\n");
fun_len = (long )test_03 - (long )test_02;
HexDump((void *)test_02, fun_len);
printf("======================\n");
fun_len = (long )test_04 - (long )test_03;
HexDump((void *)test_03, fun_len);
printf("Test End\n");
getchar();
// Just a trick to block optimizer from eliminating test_xx() functions as unused
if (argc > 1)
{
test_01(1);
test_02(2);
test_03(3);
test_04(4);
}
}
The (correct) Output when compiled with "g++ -O0":
[note the 'c3' byte (= assembly 'ret') at the end of all functions]
======================
addr:4199344, len:37
55.89.e5.83.ec.18.c7.04.24.61.00.00.00.e8.4e.62.00.00.c7.04.24.0a.00.00.00.e8.42
.62.00.00.b8.01.00.00.00.c9.c3.
======================
addr:4199381, len:49
55.89.e5.83.ec.18.c7.04.24.62.00.00.00.e8.29.62.00.00.c7.04.24.62.00.00.00.e8.1d
.62.00.00.c7.04.24.0a.00.00.00.e8.11.62.00.00.b8.02.00.00.00.c9.c3.
======================
addr:4199430, len:37
55.89.e5.83.ec.18.c7.04.24.63.00.00.00.e8.f8.61.00.00.c7.04.24.0a.00.00.00.e8.ec
.61.00.00.b8.03.00.00.00.c9.c3.
Test End
The erroneous Output when compiled with "g++ -O2":
(a) function test_01 addr & len seem correct
(b) functions test_02, test_03 have negative lengths,
and fun. test_02 length is also incorrect.
======================
addr:4199416, len:36
83.ec.1c.c7.04.24.61.00.00.00.e8.c5.61.00.00.c7.04.24.0a.00.00.00.e8.b9.61.00.00
.b8.01.00.00.00.83.c4.1c.c3.
======================
addr:4199452, len:-72
83.ec.1c.c7.04.24.62.00.00.00.e8.a1.61.00.00.c7.04.24.62.00.00.00.e8.95.61.00.00
.c7.04.24.0a.00.00.00.e8.89.61.00.00.b8.02.00.00.00.83.c4.1c.c3.57.56.53.83.ec.2
0.8b.5c.24.34.8b.7c.24.30.89.5c.24.08.89.7c.24.04.c7.04.
======================
addr:4199380, len:-36
83.ec.1c.c7.04.24.63.00.00.00.e8.e9.61.00.00.c7.04.24.0a.00.00.00.e8.dd.61.00.00
.b8.03.00.00.00.83.c4.1c.c3.
Test End
This is happening even if I put a "#pragma GCC optimize 0" line in the source file, which is supposed to be the equivalent of a "g++ -O0" command line option.
I don't believe this is true: it is supposed to be the equivalent of attaching __attribute__((optimize(0))) to subsequently defined functions, which causes those functions to be compiled with a different optimisation level. But this does not affect what goes on at the top level, whereas the command line option does.
If you really must do horrible things that rely on top level ordering, try the -fno-toplevel-reorder option. And I suspect that it would be a good idea to add __attribute__((noinline)) to the functions in question as well.
I'm having a really hard time getting an R library installed that requires some compilation in C. I'm using a Mac OSX Snow Leopard machine and trying to install this R package (here).
I've looked at the thread talking about getline on macs and have tried a few of these fixes, but nothing is working! I'm a newbie and don't know any C, so that may be why! Can anyone give me some tips on how I could modify files in this package to get it to install?? Anyhelp would be pathetically appreciated! Here's the error I'm getting:
** libs
** arch - i386
g++ -arch i386 -I/Library/Frameworks/R.framework/Resources/include -I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include -D_FASTMAP -DMAQ_LONGREADS -fPIC -g -O2 -c bed2vector.C -o bed2vector.o
In file included from /usr/include/c++/4.2.1/backward/strstream:51,
from bed2vector.C:8:
/usr/include/c++/4.2.1/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <iostream> instead of the deprecated header <iostream.h>. To disable this warning use -Wno-deprecated.
bed2vector.C: In function ‘int get_a_line(FILE*, BZFILE*, int, std::string&)’:
bed2vector.C:74: error: no matching function for call to ‘getline(char**, size_t*, FILE*&)’
make: *** [bed2vector.o] Error 1
chmod: /Library/Frameworks/R.framework/Resources/library/spp/libs/i386/*: No such file or directory
ERROR: compilation failed for package 'spp'
The easiest solution is probably to add a static definition for getline() to bed2vector.c. This might be good enough:
/* PASTE AT TOP OF FILE */
#include <stdio.h> /* flockfile, getc_unlocked, funlockfile */
#include <stdlib.h> /* malloc, realloc */
#include <errno.h> /* errno */
#include <unistd.h> /* ssize_t */
extern "C" ssize_t getline(char **lineptr, size_t *n, FILE *stream);
/* PASTE REMAINDER AT BOTTOM OF FILE */
ssize_t
getline(char **linep, size_t *np, FILE *stream)
{
char *p = NULL;
size_t i = 0;
if (!linep || !np) {
errno = EINVAL;
return -1;
}
if (!(*linep) || !(*np)) {
*np = 120;
*linep = (char *)malloc(*np);
if (!(*linep)) {
return -1;
}
}
flockfile(stream);
p = *linep;
for (int ch = 0; (ch = getc_unlocked(stream)) != EOF;) {
if (i > *np) {
/* Grow *linep. */
size_t m = *np * 2;
char *s = (char *)realloc(*linep, m);
if (!s) {
int error = errno;
funlockfile(stream);
errno = error;
return -1;
}
*linep = s;
*np = m;
}
p[i] = ch;
if ('\n' == ch) break;
i += 1;
}
funlockfile(stream);
/* Null-terminate the string. */
if (i > *np) {
/* Grow *linep. */
size_t m = *np * 2;
char *s = (char *)realloc(*linep, m);
if (!s) {
return -1;
}
*linep = s;
*np = m;
}
p[i + 1] = '\0';
return ((i > 0)? i : -1);
}
This doesn't handle the case where the line is longer than the maximum value that ssize_t can represent. If you run into that case, you've likely got other problems.
Zeroth question: Have you considered using a package manager like fink or MacPorts rather than compiling yourself? I know that fink has an R package.
First question: How is the R build managed? Is there a ./configure? If so have you looked at the options to it? Does it use make? Scons? Some other dependency manager?
Second question: Have you told the build system that you are working on a Mac? Can you specify that you don't have a libc with native getline?
If the build system doesn't support Mac OS---but I image that R's does---you are probably going to have to download the standalone version, and hack the build to include it. How exactly you do that depends on the build system. And you may need to hack the source some.
-- All of the revised code still refuses to run well, please help --
When I compile my code in Windows, I get memory errors. However on the Mac, where I initially coded this code, it works fine. I need to get this working on Windows.
It's something to do with the way I handle my char strings using strcpy that the Mac seems to be fine with (I guess it's related to gcc vs. Microsoft's way of doing things).
Here's the code for the complainers:
main.cpp
#include "Cust.h"
using namespace std;
int main (int argc, char * const argv[]) {
Cust customers[500];
char tmpString[70] = " ";
char * pch = new char[255];
string tmpAcctFN = " ";
string tmpAcctLN = " ";
ifstream input("P3_custData.txt");
for (int idx = 0; idx < 130; idx++){
input.getline(tmpString, 70, '\n');
strcpy(pch,strtok(tmpString," "),255);
customers[idx].setAcctNum(pch);
cout << pch << endl;
strcpy(pch, strtok(NULL," "));;
customers[idx].setAcctFN(pch);
cout << pch << endl;
strcpy(pch, strtok(NULL," "));;
customers[idx].setAcctLN(pch);
cout << pch << endl;
strcpy(pch, strtok(NULL," "));;
customers[idx].setCurrBalance(atol(pch));
cout << pch << endl;
strcpy(pch, strtok(NULL," "));;
customers[idx].setPIN(atoi(pch));
cout << pch << endl;
}
input.close();
return 0;
}
Cust.h
/*
* Cust.h
* Project 3
*
* Created by Anthony Glyadchenko on 11/17/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
#include <iostream>
#include <string>
using namespace std;
#ifndef CUST_H
#define CUST_H
class Cust{
public:
char * getAcctNum();
void setAcctNum(char num[]);
double getCurrBalance();
void setCurrBalance(double balance);
void addToCurrBalance(double amount);
void subFromCurrBalance(double amount);
void setAcctFN(char firstName[]);
void setAcctLN(char lastName[]);
char * getAcctFN();
char * getAcctLN();
void setPIN(int pin);
int getPIN();
private:
char acctNum[255];
char acctFN[255];
char acctLN[255];
double currBalance;
int pin;
char fileName[255];
};
#endif
Cust.cpp
/*
* Cust.cpp
* Project 3
*
* Created by Anthony Glyadchenko on 11/17/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
#include <fstream>
#include <string>
#include <sstream>
#include "Cust.h"
using namespace std;
char * Cust::getAcctNum(){
return acctNum;
}
void Cust::setAcctNum(char num[]){
strcpy(acctNum,num);
}
double Cust::getCurrBalance(){
return currBalance;
}
void Cust::setCurrBalance(double balance){
currBalance = balance;
}
void Cust::addToCurrBalance(double amount){
currBalance += amount;
}
void Cust::subFromCurrBalance(double amount){
currBalance -= amount;
}
void Cust::setAcctFN(char firstName[]){
strcpy(acctFN,firstName);
}
void Cust::setAcctLN(char lastName[]){
strcpy(acctLN,lastName);
}
char * Cust::getAcctFN(){
return acctFN;
}
char * Cust::getAcctLN(){
return acctLN;
}
void Cust::setPIN(int pin){
Cust::pin = pin;
}
int Cust::getPIN(){
return pin;
}
Here is my stack trace:
Index Function
--------------------------------------------------------------------------------
1 msvcr90d.dll!68d7f693()
2 [Frames below may be incorrect and/or missing, no symbols loaded for msvcr90d.dll]
*3 P3.exe!main(int argc=0, char * const * argv=0x0036fcd0)
4 P3.exe!_FreeLibrary#4()
5 P3.exe!#ILT+170(__except_handler4)()
6 kernel32.dll!75eb3677()
7 ntdll.dll!77b29d72()
8 ntdll.dll!77b29d45()
A few things to check (sorry not going to download the code):
does g++ *.c have warnings? If so fix them.
does g++ -W have warnings? If so fix them.
does g++ -W -Wall have warnings? If so fix them.
does g++ -W -Wall -Wextra have warnings? If so fix them.
does g++ -W -Wall -Wextra -ansi have warnings? If so fix them.
does g++ -W -Wall -Wextra -ansi -pedantic have warnings? If so fix them.
On microsoft try adding /W4 to the command line to turn the warning up, again fix any issues.
Odds are you are doing something "silly" and chances are that the compiler can help you catch what it is.
Edit:
From compiling your code with the flags above you will see:
Cust.h:33: error: ISO C++ forbids zero-size array ‘acctNum’
Cust.h:34: error: ISO C++ forbids zero-size array ‘acctFN’
Cust.h:35: error: ISO C++ forbids zero-size array ‘acctLN’
Cust.h:38: error: ISO C++ forbids zero-size array ‘fileName’
Cust.h:33: error: ISO C++ forbids zero-size array ‘acctNum’
Cust.h:34: error: ISO C++ forbids zero-size array ‘acctFN’
Cust.h:35: error: ISO C++ forbids zero-size array ‘acctLN’
Cust.h:38: error: ISO C++ forbids zero-size array ‘fileName’
So your code is not valid C++. You are copying a name into an array that is too small - the array has 0 elements. What you really need to do is give the arrays a size when you declare them or declare them as pointers and then use "new" to allocate the right amount of memroy.
Passing invalid buffers, buffers that are too small, etc., to strcpy results in undefined behavior - just about anything can happen. On the Mac, the problems happen but aren't apparent, while on Windows it results in a crash.
char acctNum[];
char acctFN[];
char acctLN[];
There's your problem right there. You never seem to allocate any space for these strings anywhere. The strcpy() in setAcctNum() is overflowing the bounds of that unsized array, and overwriting something else. It's pretty amazing that this compiles at all, actually.
You probably ought to be using std::string, instead - that'll make the memory management easier, at least.
Probably is your implementation of the strcpy function, which could have differences between how it is coded on the mac and how it's coded on Windows.