C++-Fortran mixcompile unresolved externals - c++

I am trying to make a fortran-C++ mix compile project. I use the case to test how the visual studio 2017 compiler link the intel fortran .lib file. Here is the example code:
Fortran code here:
!DEC$ IF DEFINED (_DLL)
!DEC$ ATTRIBUTES DLLEXPORT :: ADD
!DEC$ END IF
REAL*8 FUNCTION ADD (A, B, C, D)
REAL*8 B,D
INTEGER*4 A,C
DIMENSION B(4), D(4)
ADD = B(A) + D(C)
RETURN
END
C++ code here:
#include <iostream>
extern "C" {double add_(int *, double[], int *, double[]); }
double ar1[4] = { 1.0, 2.0, 3.0, 4.0 };
double ar2[4] = { 5.0, 6.0, 7.0, 8.0 };
int main()
{
int x, y;
double z;
x = 3;
y = 3;
z = add_(&x, ar1, &y, ar2); /* Call Fortran add routine */
/* Note: Fortran indexes arrays 1..n */
/* C indexes arrays 0..(n-1) */
std::cout << z << std::endl;
return 0;
}
The project setup procedures are:
Open VS studio, create a c++ empty project, add the c++ code in the source file. Solution will be automatically created as well.
Add a new fortran static library project in the solution. Add the fortran code in the source file.
Fortran project-> properties->Libraries->Runtime Libraries-> Debug multithread dll.
Build the fortran project, find the .lib file directory.
C++ project-> linker -> General -> Additional Library Dependencies -> add the .lib file directory here
C++ project-> linker -> Input -> Additional dependencies -> Add .lib file name here end with ";".
Build C++ project.
And the compiler error message is:
1>------ Build started: Project: Cpp_main, Configuration: Debug Win32 ------
1>Source.obj : error LNK2019: unresolved external symbol _add_ referenced in function _main
1>C:\Users\Documents\TEST_Project\MixCompile_Test\Mix_compile\Debug\Cpp_main.exe : fatal error LNK1120: 1 unresolved externals
1>Done building project "Cpp_main.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
Why the compiler cannot resolve the external function call even if I assign the .lib directory in C++ project?
Thanks a lot!
Update 22-6-24:
Thank you Steve. I followed your instruction and made configuration in VC++ directories to add the ifortran include and lib directory into it. But new problem happened:
1>------ Build started: Project: Cpp_main, Configuration: Debug Win32 ------
1>LINK : fatal error LNK1104: cannot open file 'msvcprtd.lib'
1>Done building project "Cpp_main.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 2 up-to-date, 0 skipped ==========
Update 22-06-24
I solved the issue. I will upload the whole solution tomorrow. It's really special problem for VS2017.
Fortran compiler: Inter ifortran19
Cpp compiler: MSVC 2017
Step:
Create your CPP project and solution.
In the solution, add a fortran static library project with name .
Add your fortran headfile and source code in that project.
For every fortran subroutine that will be called in CPP, do like this:
subroutine_name() BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
end subroutine
For CPP headfile, if the fortran compiler is interl fortran, do not add underscore_ after the function name!! Just declare the function name with extern "C" like this:
extern "C"{void <fortran_subroutine>()}
Remember, all the arguments passed from C code should be reference or pointer. Do not pass value.
In the C compiler, add several dependency directories:
6.1 C project properties-> VC++ Directories -> Include Directries -> add $(IFORT_COMPILER19)\compiler\include;
6.2 C project properties-> VC++ Directories -> Libiary Directries -> add $(IFORT_COMPILER19)\compiler\lib; (+\ia32_win or +\intel64_win depend on win32 or X64 compiler used in VS)
In the C linker, add several dependency directories:
7.1 C project properties-> linker-> General-> Additional Dependency Directories->
add C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\lib
(+\x86 or +\x64 depend on win32 or x64 compiler used in VS)
7.2 C project properties-> linker-> General-> Additional Dependency Directories->
add the fortran static library compiled file directory
7.3 C project properties-> linker->input add .lib
In the source code, include the header file with extern ā€œCā€ keyword declaration and call the function
<fortran_subroutine>()

The linker (not the compiler) can't resolve the reference because the naming conventions don't match. You named the C routine "add_" in lowercase and with a trailing underscore. Neither of those are part of the default Intel Fortran conventions.
A second problem is that your directives to export the name into the DLL are outside the routine - they will be ignored. (Not that this matters if you are building a static library.)
The simplest and most portable way to fix this is:
Remove the trailing underscore from add_ in the C source, wherever it appears.
Add BIND(C) at the end of the SUBROUTINE line in the Fortran source.
Move the directives inside the routine.
This will make the names match, not just in Intel Fortran but any other combination of Fortran and C you may use.
I would also recommend replacing the non-standard Fortran variable declarations and use this instead:
REAL(C_DOUBLE) FUNCTION ADD (A, B, C, D) BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
!DEC$ IF DEFINED (_DLL)
!DEC$ ATTRIBUTES DLLEXPORT :: ADD
!DEC$ END IF
REAL(C_DOUBLE) :: B,D
INTEGER(C_INT) :: A,C
...

Related

Linker error when C++ executable links in Fortran library and main in C++ library

I have a CMake-based project consisting of three targets:
A static library FortLib written in Fortran.
A static library LibWithMain which is written in C++ and contains the definition of int main().
An executable App which links in both of the above libraries.
This is the contents of the CMakeList:
cmake_minimum_required(VERSION 3.7.2)
project(Mcve LANGUAGES C CXX Fortran)
add_library(FortLib STATIC fort.f90)
target_compile_options(FortLib PRIVATE /names:lowercase /assume:underscore /iface:cref)
add_library(LibWithMain STATIC main.cpp)
add_executable(App app.cpp)
target_link_libraries(App PRIVATE FortLib LibWithMain)
(For contents of the source files which can be used to reproduce the issue, see bottom)
My problem is that linking App results in the following linker error:
libifcoremdd.lib(for_main.obj) : error LNK2019: unresolved external symbol MAIN__ referenced in function main
Note that this reference comes from libifcoremdd.lib, an Intel Fortran library which apparently gets implicitly linked in.
This does not happen if the function main is defined directly in App. This can be shown by exchanging the files main.cpp and app.cpp in the CMakeList above (so that main is defined inside the app). Then everything builds and links successfully. It's the fact that the definition of main comes from LibWithMain that somehow gets the linker confused.
In my real code, LibWithMain is Boost.Test, so moving main out from it is not really an option for me.
The order of the static libraries does not matter: the error is present regardless of which lib follows which on the link line.
My toolchain is Visual Studio 2017 and Intel Fortran 18, my platform is Win64 ("x64" in Visual Studio terminology). No other compilers/platforms need to be supported at this point.
I am a C++ developer and know next to nothing about Fotran or the Intel Fortran ecosystem, so I have no idea what could be causing this or how to solve it. That is therefore my question:
What is causing the linker error, and how can I fix it?
These simple files, used in the CMakeList above, are enough to reproduce the issue:
fort.f90
integer function fortfunc
implicit none
fortfunc = 42
end function
main.cpp
#include <iostream>
int work();
int main()
{
std::cout << work() << std::endl;
return 0;
}
app.cpp
extern "C" int fortfunc_();
int work()
{
return fortfunc_();
}
I don't know how cmake works but I'm guessing that you need to do it the other way round. It is possible that main is special function in your toolchain and should not exist in a library.
build the fortran lib
build the c lib without main (app.cpp)
build the main using both c lib and fortran lib.
It probably won't moan about missing externals when building the c lib because it is a library and not everything needs to be resolved.
Also, in app.cpp, what you need to remember is that in Fortran, the callee unstacks the arguments but in C, the caller unstacks.
When the callee unstacks, you need __stdcall as part of the declaration. This used to be extern PASCAL on the older MS compilers. When a caller unstacks, you can optionally add __cdecl.

Connect IMSL library to Intel Fortran in Visual Studios

I try to connect the IMSL library (version 6.0) to Intel Fortran (version 11.1) in Visual Studio (version 2008). The IMSL library is added to the path like this:
$C:\Program Files (x86)\VNI\imsl\fnl600\Intel64\lib
and the "includes" are there as well
$C:\Program Files (x86)\VNI\imsl\fnl600\Intel64\include\dll
$C:\Program Files (x86)\VNI\imsl\fnl600\Intel64\include\static
The program I run to test the installation is:
PROGRAM main
USE RNUN_INT
USE RNSET_INT
IMPLICIT NONE
INTEGER :: ISEED
REAL :: R(5)
ISEED = 123457
CALL RNSET (ISEED)
CALL RNUN (R)
END PROGRAM main
The result I get is Error #7002: Error in opening the compiled module file. Check INCLUDE paths. [RNUN_INT]
What am I missing?

Fortran and C++: Linking error in Visual Studio

System: Windows-7-64-bit/Visual-Studio-2010/Intel-Visual-Fortran-11.
I am creating 32-bit executables.
Fortran routine declaration
SUBROUTINE LA01BD(N,M,L,A,B,C,X,F,IA,IPRINT,IND,WK,IER)
!DEC$ ATTRIBUTES DLLEXPORT::LA01BD
!DEC$ ATTRIBUTES STDCALL,REFERENCE,ALIAS:"LA01BD"::LA01BD
use, intrinsic :: ISO_C_BINDING
C++ function signature declaration
extern "C" {void __stdcall LA01BD(int *N, int *M, int *L, double *A, double *B, double *C, double *X, double *F, int *IA, int *IPRINT, int *IND, double *WK, int *IER); }
I created the dll from fortran code using Visual Studio 2010 and Intel Visual Fortran compiler 11. I checked the exported symobol in dependency walker and the Function is "LA01BD".
When using the same dll (the .lib file during linking) in my C++ project, I get the following linker error.
lpwrap.obj : error LNK2001: unresolved external symbol _LA01BD#52
I am unable to resolve this issue. What does suffix "#52" does? How to fix the linking issue?
Thanks.
The C++ compiler applies name decoration to the identifier. The __stdcall decoration is a leading _underscore and a trailing #n where n is the size of the activation frame.
The ALIAS directive in your Fortran code caused this problem, you forced it to be exported as "LA01BD" instead of "_LA01BD#52". You should first try to remove it so the normal name decoration is applied. If that's not an option then you'll need to either create an import library with lib.exe /def from a properly crafted .def file or fallback to late binding with GetProcAddress().
If you must use the STDCALL calling convention, then add the DECORATE attribute to the Fortran side to instruct the compiler to decorate the specified alias.
SUBROUTINE LA01BD(N,M,L,A,B,C,X,F,IA,IPRINT,IND,WK,IER)
!DEC$ ATTRIBUTES DLLEXPORT::LA01BD
!DEC$ ATTRIBUTES STDCALL,REFERENCE,ALIAS:"LA01BD"::LA01BD
!DEC$ ATTRIBUTES DECORATE :: LA01BD
it is caused by name mangling, please ref this for details. I guess you missed the extern "c" in your C++ project.

How to run c++ and c together in WinRT project

I have a file name as sqlite3.c and some c++ file use to work with the function write in sqlite3.c. But I face a problem to compile the file using visual studio 2012. I create a WindowsRuntimeComponent project for the c++ file and c file. When I set Properties -> C/C++ -> Advanced -> Compile As -> "Compile as C++ Code (/TP)", I get an error which is error D8045: cannot compile C file 'xxx.c' with the /clr option.
After that, I change Properties -> C/C++ -> Advanced -> Compile As -> "Compile as C Code (/TC)", I get an error which is error D8045: cannot compile C file 'xxx.cpp' with the /clr option.
I don't have an idea to solve this problem. Can anyone give me a help? Thank you.

C++; eclipse linker error

So working on getting my eclipse IDE going so I can develop my arduino uno in eclipse.
My C++ is weak so this is probably a nube error on my part.
I have a blink program that looks for an arduino library I compiled from the arduino IDE's library.
My code points to the header file and my code find it fine; meaning I can click on:
#include <arduino.h>
and go view the header
this: "C:/programs/arduino-1.0/hardware/arduino/cores/328p_lib/libuno_library.a"
is a valid path... but I get the following error:
>****** Build of configuration Debug for project project1 ****
>make all
>Building target: project1.elf
>Invoking: AVR C++ Linker
>avr-g++ -Wl,-Map,project1.map,--cref -L"C:\programs\arduino->1.0\hardware\arduino\cores\328p_lib" -mmcu=atmega328p -o "project1.elf" ./code/code1.o >-l"C:/programs/arduino-1.0/hardware/arduino/cores/328p_lib/libuno_library.a"
>c:/programs/winavr/bin/../lib/gcc/avr/4.3.3/../../../../avr/bin/ld.exe: cannot find ->lC:/programs/arduino-1.0/hardware/arduino/cores/328p_lib/libuno_library.a
>make: *** [project1.elf] Error 1
>**** Build Finished ******
Well after wasting 2 days or so of fun time I finally found the problem.
http://sourceforge.net/projects/avr-eclipse/forums/forum/664382/topic/4640554
When adding the static library to the linker you have to remove the lib prefix and the .a suffix. not sure what that is about.
Right click on the project>Click on C/C++ BUild> Settings > GCC C++ Linker> Libraries
Click the first icon Add> Add the library name ( without the .a suffix, the suffix will be added automatically)
This will ensure that the library is added to the project.
If the library is part of another project >Go to GCC C Compiler> directories >Add the directory
This will ensure that the library is there for getting the compilation done.