Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Fortran called by C

JohnNichols
Valued Contributor III
2,224 Views

I am playing, for a valid reason, with the grammar checker program LINK developed at Carn Mellon in about 2005. There is a later version but it does not play well with INTEL C or VS and the 2005 does what I want it to do for the moment.  

The program runs quite nicely and well give me a 1 for a valid sentence and a 0 otherwise. 

However, I want to add a Fortran subroutine to do a lot of hard lifting in a language I know how to code in - somewhat - and I have no desire to push my C knowledge beyond what it currently is - about Miss Scotman's first grade class level. 

I have used the INTEL sample, but it is CPP, and the CM code is just pure old fashioned C. 

I get a two  errors, Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol _for_CFI_establish referenced in function _main Baker C:\Users\macne\Documents\Visual Studio 2017\Projects\Program111 - Baker\Baker\Baker\AMain.obj : 1

and 

Severity Code Description Project File Line Suppression State
Error LNK1120 1 unresolved externals Baker C:\Users\macne\Documents\Visual Studio 2017\Projects\Program111 - Baker\Baker\Debug\Baker.exe : 1

---------------------------------------------------------------------------------------------------------

from calling the Fortran subroutine, which in the Intel sample is in a CPP file. 

I tried several alternatives Fortran calling C and it basically always breaks down on the use of C files, but I do not want to stuff with the things that are working. 

I enclose the complete solution - but here is the main code for the C code calling the Fortran subroutine.  

 



 

/********************************************************************************/
/* Copyright (c) 2004                                                           */
/* Daniel Sleator, David Temperley, and John Lafferty                           */
/* All rights reserved                                                          */
/*                                                                              */
/* Use of the link grammar parsing system is subject to the terms of the        */
/* license set forth in the LICENSE file included with this software,           */ 
/* and also available at http://www.link.cs.cmu.edu/link/license.html           */
/* This license allows free redistribution and use in source and binary         */
/* forms, with or without modification, subject to certain conditions.          */
/*                                                                              */
/********************************************************************************/

#include "link-includes.h"
#include "ISO_Fortran_binding.h"

void fsub
(int INT_ARG,
	CFI_cdesc_t *STR_IN,
	CFI_cdesc_t *STR_OUT
);

int main() {

    Dictionary    dict;
    Parse_Options opts;
    Sentence      sent;
    Linkage       linkage;
    char *        diagram;
    int           i, num_linkages;
    char *        input_string[] = {
       "Grammar is useless because there, is nothing to say -- Gertrude Stein.",
       "Computers are useless; they can only give you answers -- Pablo Picasso."};

	char instring[40];
	char outstring[40];
	int intarg;
	CFI_CDESC_T(0) instring_desc, outstring_desc; // Ignore warning for zero-sized array
	int status;

    opts  = parse_options_create();
    dict  = dictionary_create("4.0.dict", "4.0.knowledge", NULL, "4.0.affix");

    for (i=0; i<2; ++i) {
	sent = sentence_create(input_string[i], dict);
	num_linkages = sentence_parse(sent, opts);
	if (num_linkages > 0) {
	    linkage = linkage_create(0, sent, opts);
	    printf("%s\n", diagram = linkage_print_diagram(linkage));
	    string_delete(diagram);
	    linkage_delete(linkage);
	}
	sentence_delete(sent);
    }

    dictionary_delete(dict);
    parse_options_delete(opts);

	strcpy(instring, "Testing...");
	intarg = 123;
	/*
   Initialize descriptors. We'll set the length of the input string to the NUL-terminated length,
   which will be picked up by Fortran.
*/

	status = CFI_establish(
		(CFI_cdesc_t *)&instring_desc, // Descriptor
		&instring, // Base address
		CFI_attribute_other, // Not allocatable or pointer
		CFI_type_char, // Character type
		strlen(instring), // Element size
		0, // Number of dimensions (0 = scalar)
		NULL // Extents (not used here)
	);
	status = CFI_establish((CFI_cdesc_t *)&outstring_desc, &outstring, CFI_attribute_other, CFI_type_char, sizeof(outstring), 0, NULL);

	/* Call Fortran routine, passing descriptors. Note that intarg is passed by value */

	fsub(intarg, (CFI_cdesc_t *)&instring_desc, (CFI_cdesc_t *)&outstring_desc); 

	printf("%s\n", outstring); // Should print "Testing...0123"
    return 0;
}

 

 

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
2,219 Views

Baker (the C++ project) doesn't link to the Fortran project's output library, so it's not pulling in the ifort run-time library. Ordinarily I would tell you to make FortranLib a dependent of Baker (which you should anyway), but Visual Studio won't pick up a Fortran output in a C++ project. Put the path to the .lib in Baker's Linker > Input > Additional Dependencies.

View solution in original post

9 Replies
Steve_Lionel
Honored Contributor III
2,220 Views

Baker (the C++ project) doesn't link to the Fortran project's output library, so it's not pulling in the ifort run-time library. Ordinarily I would tell you to make FortranLib a dependent of Baker (which you should anyway), but Visual Studio won't pick up a Fortran output in a C++ project. Put the path to the .lib in Baker's Linker > Input > Additional Dependencies.

JohnNichols
Valued Contributor III
2,207 Views

It took a minute to work out to include the file name in the path. 

Thanks it works a treat. 

Just one wonders why we need to take that step. 

 

0 Kudos
Steve_Lionel
Honored Contributor III
2,193 Views

As I wrote above, if you had made the Fortran_Lib project a dependent of Baker, then VS should have included the .lib in the link of Baker. But a few releases ago, Microsoft changed VS so that C++ projects dependent on non-C++ projects didn't do this. In addition, a C++ DLL project won't automatically link into a Fortran project (but a C++ LIB will.)

I'm surprised you didn't also get an error for the Fortran routine not being found.

0 Kudos
JohnNichols
Valued Contributor III
2,175 Views

I used the sample from Intel and worked backwards slowly, it took quite a few starts to get close. 

How do I make the Fortan lib a dependence on the C++ program, I have no idea, I just followed the Intel example. 

The C++ print function takes the 123 string and prints 00123 - which is interesting. 

The idea is simple - construct a sentence from English words and see if it is a acceptable sentence then we do some other stuff. 

it may work and it may not. 

But it is fun just trying. 

0 Kudos
Steve_Lionel
Honored Contributor III
2,169 Views

In a solution with more than one project, right click on the project you want to be the "parent" and select Build Dependencies > Project Dependencies. Check the box for the dependent project.

I don't see leading zeroes in the output when I try it. I would not expect those from the %i specifier.

0 Kudos
JohnNichols
Valued Contributor III
2,164 Views

Thanks, that worked. 

Two leading zeros after Testing...

Capture.GIF

0 Kudos
JohnNichols
Valued Contributor III
2,162 Views

The programmer wrote 

printf("%s\n", outstring); // Should print "Testing...0123"

 

next question - why does the VS IDE give errors on the standard strcpy type C functions.  

I know this is Fortran -- but I think I have a better chance here than the C++ Forum. They are not as busy and the answers tend to terse.  

0 Kudos
Steve_Lionel
Honored Contributor III
2,154 Views

You must be working from a different sample than I see, and I wrote this sample!

The C code in the Fortran_Calls_C sample has:

sprintf_s(output_text,output_text_len,"%s%i ",input_text,int_arg);

There is no comment about what the output should be.

The reason that the compiler warns you about printf is that it is subject to buffer overflow safety issues. Therefore I put in sprintf_s, which passes the size of the output buffer rather than relying on the variables and formats to be the correct size.

0 Kudos
JohnNichols
Valued Contributor III
2,148 Views

I just downloaded the zip file with Baker in it.  The main c routine has the following form and the last lines show the printout of the results from the fsub routine. 

/********************************************************************************/
/* Copyright (c) 2004                                                           */
/* Daniel Sleator, David Temperley, and John Lafferty                           */
/* All rights reserved                                                          */
/*                                                                              */
/* Use of the link grammar parsing system is subject to the terms of the        */
/* license set forth in the LICENSE file included with this software,           */ 
/* and also available at http://www.link.cs.cmu.edu/link/license.html           */
/* This license allows free redistribution and use in source and binary         */
/* forms, with or without modification, subject to certain conditions.          */
/*                                                                              */
/********************************************************************************/

#include "link-includes.h"
#include "ISO_Fortran_binding.h"

void fsub
(int INT_ARG,
	CFI_cdesc_t *STR_IN,
	CFI_cdesc_t *STR_OUT
);

int main() {

    Dictionary    dict;
    Parse_Options opts;
    Sentence      sent;
    Linkage       linkage;
    char *        diagram;
    int           i, num_linkages;
    char *        input_string[] = {
       "Grammar is useless because there, is nothing to say -- Gertrude Stein.",
       "Computers are useless; they can only give you answers -- Pablo Picasso."};

	char instring[40];
	char outstring[40];
	int intarg;
	CFI_CDESC_T(0) instring_desc, outstring_desc; // Ignore warning for zero-sized array
	int status;

    opts  = parse_options_create();
    dict  = dictionary_create("4.0.dict", "4.0.knowledge", NULL, "4.0.affix");

    for (i=0; i<2; ++i) {
	sent = sentence_create(input_string[i], dict);
	num_linkages = sentence_parse(sent, opts);
	if (num_linkages > 0) {
	    linkage = linkage_create(0, sent, opts);
	    printf("%s\n", diagram = linkage_print_diagram(linkage));
	    string_delete(diagram);
	    linkage_delete(linkage);
	}
	sentence_delete(sent);
    }

    dictionary_delete(dict);
    parse_options_delete(opts);

	strcpy(instring, "Testing...");
	intarg = 123;
	/*
   Initialize descriptors. We'll set the length of the input string to the NUL-terminated length,
   which will be picked up by Fortran.
*/

	status = CFI_establish(
		(CFI_cdesc_t *)&instring_desc, // Descriptor
		&instring, // Base address
		CFI_attribute_other, // Not allocatable or pointer
		CFI_type_char, // Character type
		strlen(instring), // Element size
		0, // Number of dimensions (0 = scalar)
		NULL // Extents (not used here)
	);
	status = CFI_establish((CFI_cdesc_t *)&outstring_desc, &outstring, CFI_attribute_other, CFI_type_char, sizeof(outstring), 0, NULL);

	/* Call Fortran routine, passing descriptors. Note that intarg is passed by value */

	fsub(intarg, (CFI_cdesc_t *)&instring_desc, (CFI_cdesc_t *)&outstring_desc); 

	printf("%s\n", outstring); // Should print "Testing...0123"
    return 0;
}

 I have not changed it - whilst you showed me how to fix the problem.  

0 Kudos
Reply