I'm looking to use the LAPACKE library to make C/C++ calls to the LAPACK library. On multiple devices, I have tried to compile a simple program, but it appears LAPACKE is not linking correctly.
Here is my code, slightly modified from this example:
#include <cstdio>
extern "C"
{
#include "lapacke.h"
}
// extern "C" {
// // LU decomoposition of a general matrix
// void LAPACK_dgetrf(int* M, int *N, double* A, int* lda, int* IPIV, int* INFO);
// // generate inverse of a matrix given its LU decomposition
// void LAPACK_dgetri(int* N, double* A, int* lda, int* IPIV, double* WORK, int* lwork, int* INFO);
// }
extern "C"
{
#include <lapacke.h>
}
void inverse(double* A, int N)
{
int *IPIV = new int[N];
int LWORK = N*N;
double *WORK = new double[LWORK];
int INFO;
dgetrf_(&N,&N,A,&N,IPIV,&INFO);
dgetri_(&N,A,&N,IPIV,WORK,&LWORK,&INFO);
delete[] IPIV;
delete[] WORK;
}
int main(){
double A [2*2] = {
1,2,
3,4
};
inverse(A, 2);
printf("%f %f\n", A[0], A[1]);
printf("%f %f\n", A[2], A[3]);
return 0;
}
I have installed blas, lapack and lapacke using the apt package manager:
sudo apt-get install libblas-dev liblapack-dev liblapacke-dev
I am compiling with:
g++ -lblas -llapack -llapacke -I /usr/include main.cpp
the -I shouldn't be neccisary as far as I know, but I put it in anyway to be sure. I get the following error:
'/usr/bin/ld: /tmp/ccJSTpTf.o: in function `inverse(double*, int)':
main.cpp:(.text+0x9f): undefined reference to `dgetrf_'
/usr/bin/ld: main.cpp:(.text+0xc8): undefined reference to `dgetri_'
collect2: error: ld returned 1 exit status
This problem persists regardless if I compile lapacke from source, import the entire header, declare the functions themselves as extern, or change the names of the function to any of the following: dgetrf(), dgetrf_(), or LAPACK_dgetrf(), all common names I have seen for LAPACK-sytle calls.
Looking through the Lapacke header, it looks like LAPACK_dgetrf() translates to a lapack function call dgetrf_(). Unwrapping the static archives to look for dgetrf, I can find that liblapack.a has a function object dgetrf.o, and liblapacke.a has a function lapack_dgetrf.o. I'm thinking the root of the problem is that LAPACK_dgetrf() is basically dgetrf_(), and the linker cannot find dgetrf_(), because LAPACK has the function called dgetrf(), not dgetrf_(). I'm very confused though, as the compiler did not complain that any of the linked libraries didn't exist, and nobody else seems to have this issue on their devices, while I've had it now on 3 separate ones (all ubuntu based).
What do I need to do to get LAPACKE to compile, not just for C, but for C++?
I am compiling with: g++ -lblas -llapack -llapacke -I /usr/include main.cpp
That command line is wrong. Do this instead:
g++ main.cpp -llapacke -llapack -lblas
To understand why the order of sources and libraries matters, read this.
Related
One colleague did send me a Fortran function to include in my C++ program.
So far, everything in my program is coded in C++.
To keep things simple (especially dependencies and installation) I thought I'll just re-code it in C++.
Unfortunately, the code is very complex with many goto statements and other stuff I'm not very familiar with. (I have never worked with Fortran and this is from an old scientific Fortran 77 program)
Thus, I would like to call the Fortran function directly in C++.
A prerequisite is, that I'm using CMake for my program and everything (like linking) has to be done in the CMake file. Additionally, the CMake file should be as simple as possible since only scientists work and extend the program with no sophisticated programming background.
I found many approaches and solutions on the internet - however, most are very complex dealing with modules and libraries - I only need to call one function, we are not working with libraries or such.
Unfortunately, I get a lot of errors when executing my code:
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.dll.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0\libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.dll.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
skipping incompatible C:/MinGW/lib/gcc/mingw32/6.3.0/libgfortran.a
when searching for -lgfortran
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe:
cannot find -lgfortran
My main question is: Are these errors due to a problem in my code or are they related to a problem with my environment?
This is what my code looks like:
main.cpp
#include <iostream>
extern double f_add(double *, double *, double *);
int main() {
double a = 1.;
double b = 2.;
double c;
f_add(&a, &b, &c);
std::cout << c << std::endl;
}
f_add.f
real function f_add(a, b, c)
real a,b,c
c = a+b
end
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(test_cpp)
set(CMAKE_CXX_STANDARD 14)
SET (CMAKE_Fortran_COMPILER gfortran)
ENABLE_LANGUAGE(Fortran)
set(SOURCE_FILES
main.cpp
f_add.f
)
add_executable(test_cpp ${SOURCE_FILES})
I think your C++ code is missing extern "C" and some additional corrections to the Fortran code. For example, the following would work:
#include <iostream>
extern "C" {
double f_add(double, double);
}
int main() {
double a = 1.;
double b = 2.;
double c;
c = f_add(a, b);
std::cout << c << std::endl;
}
and,
function f_add(a, b) result(c) bind(C, name = "f_add")
use iso_c_binding, only: c_double
implicit none ! remove this line if your F77 code has implicitly-declared variables.
real(c_double), intent(in), value :: a, b
real(c_double) :: c
c = a + b
end function f_add
Then compile, link, and run (via MinGW GNU 10.1 that I am using),
gfortran -c f_add.f90
g++ -c main.cpp
g++ *.o -o main.exe
./main.exe
The output is,
3
I do not have CMake installed in MinGW, but setting it up should be straightforward with the above modifications. Your CMake file is fully functional in a Linux environment if that helps.
This question already has an answer here:
External calls are not supported - CUDA
(1 answer)
Closed 7 years ago.
I am trying to understand how to decouple CUDA __device__ codes in separate header files.
I have three files.
File: 1: int2.cuh
#ifndef INT2_H_
#define INT2_H_
#include "cuda.h"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
__global__ void kernel();
__device__ int k2(int k);
int launchKernel(int dim);
#endif /* INT2_H_ */
File 2: int2.cu
#include "int2.cuh"
#include "cstdio"
__global__ void kernel() {
int tid = threadIdx.x;
printf("%d\n", k2(tid));
}
__device__ int k2(int i) {
return i * i;
}
int launchKernel(int dim) {
kernel<<<1, dim>>>();
cudaDeviceReset();
return 0;
}
File 3: CUDASample.cu
include <stdio.h>
#include <stdlib.h>
#include "int2.cuh"
#include "iostream"
using namespace std;
static const int WORK_SIZE = 256;
__global__ void sampleCuda() {
int tid = threadIdx.x;
// printf("%d\n", k2(tid)); //Can not call k2
printf("%d\n", tid * tid);
}
int main(void) {
int var;
var = launchKernel(16);
kernel<<<1, 16>>>();
cudaDeviceReset();
sampleCuda<<<1, 16>>>();
cudaDeviceReset();
return 0;
}
The code works fine. I can call the sampleCuda() kernel (in same file), call the C function launchKernel() (in other file), and call kernel() directly (in other file).
However, I get the following error when calling the __device__ function from the sampleCuda() kernel. The same function is callable in kernel().
10:58:11 **** Incremental Build of configuration Debug for project CUDASample ****
make all
Building file: ../src/CUDASample.cu
Invoking: NVCC Compiler
/Developer/NVIDIA/CUDA-6.5/bin/nvcc -G -g -O0 -gencode arch=compute_20,code=sm_20 -odir "src" -M -o "src/CUDASample.d" "../src/CUDASample.cu"
/Developer/NVIDIA/CUDA-6.5/bin/nvcc -G -g -O0 --compile --relocatable-device-code=false -gencode arch=compute_20,code=compute_20 -gencode arch=compute_20,code=sm_20 -x cu -o "src/CUDASample.o" "../src/CUDASample.cu"
../src/CUDASample.cu(18): warning: variable "var" was set but never used
../src/CUDASample.cu(8): warning: variable "WORK_SIZE" was declared but never referenced
../src/CUDASample.cu(18): warning: variable "var" was set but never used
../src/CUDASample.cu(8): warning: variable "WORK_SIZE" was declared but never referenced
ptxas fatal : Unresolved extern function '_Z2k2i'
make: *** [src/CUDASample.o] Error 255
10:58:14 Build Finished (took 2s.388ms)
How do I call the __device__ function from the sampleCuda() kernel ?
The issue is that you defined a __device__ function in separate compilation unit from __global__ that calls it. You need to either explicitely enable relocatable device code mode by adding -dc flag or move your definition to the same unit.
From nvcc documentation:
--device-c|-dc Compile each .c/.cc/.cpp/.cxx/.cu input file into an object file that contains relocatable device code. It is equivalent to
--relocatable-device-code=true --compile.
See Separate Compilation and Linking of CUDA C++ Device Code for more information.
I have been using a FORTRAN code, main.f90, to send an array to func.cpp which would call a C++ code, addition.cpp & addition.h. The code was working properly on a CentOS 4 platform, but when I moved it to a CentOS 6 one, it is giving me errors. I have tried using the same version of gcc (4.3.0) on both machines or a newer version 4.4.7 in CentOS 6, but the issue is not resolved. I am attaching the over-simplified version of the code as
main.f90:
program main
use iso_c_binding
implicit none
interface
function func (a) bind (C, name="func")
import
integer(c_int):: func
real(c_double), dimension(1:4), intent(in):: a
end function func
end interface
real(c_double), dimension(1:4):: a = [ 2.3, 3.4, 4.5, 5.6 ]
integer(c_int):: result
result = func(a)
write (*,*) result
end program main
func.cpp:
#include <iostream>
#include "addition.h"
using namespace std;
#ifdef __cplusplus
extern"C" {
#endif
void *__gxx_personality_v0;
int func(double a[]) {
int i;
for(i=0; i<4; i++) {
cout << a[i] << endl;
}
int z;
z = addition (5,3);
cout << z << endl;
return 0;
}
#ifdef __cplusplus
}
#endif
addition.cpp:
#include <iostream>
#include "addition.h"
using namespace std;
int addition (int a, int b)
{
int r;
r = a + b;
return r;
}
addition.h:
#ifndef ADDITION_H
#define ADDITION_H
int addition (int a, int b);
#endif /* ADDITION_H */
CMakeLists.txt:
PROJECT(test)
cmake_minimum_required(VERSION 2.6)
enable_language(C Fortran)
# Setting the compilers
set (CMAKE_Fortran_COMPILER /usr/bin/gfortran)
set (CMAKE_CXX_COMPILER /usr/bin/g++)
# Setting the flags
set (CMAKE_CXX_FLAGS "-lgfortran")
set_source_files_properties(main.f90 func.cpp PROPERTIES COMPILE_FLAGS -c)
# Making the executable
ADD_EXECUTABLE(test.exe main.f90 func.cpp addition.cpp addition.h)
The error I am getting now is:
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: ld returned 1 exit status
make[2]: *** [test.exe] Error 1
make[1]: *** [CMakeFiles/test.exe.dir/all] Error 2
make: *** [all] Error 2
I appreciate any help on solving the issue.
Why do you link with g++ when your main program is in Fortran? Do it the other way, link with gfortran and add -lstdc++.
Just add line: SET_TARGET_PROPERTIES(test.exe PROPERTIES LINKER_LANGUAGE Fortran)
Or use more recent GCC. All versions of GCC which are still supported work even with your original settings.
I tried the following code in C as well as C++ .file1 is a c file .file2 is a c++ file and file3 is a header file for name magling.
file1.c
#include<stdio.h>
#include<stdlib.h>
#include "file3.hpp"
int main(int argc,char **argv)
{
int a[5];
int i;
for(i=0;i<5;i++)
a[i] = i;
printf("%d",a[17]);
return 0;
}
file2.cpp
#include "file3.hpp"
int printtrial(int number)
{
return number;
}
file3.hpp
#ifdef __cplusplus
extern "C"
{
#endif
extern int printtrial(int number);
#ifdef __cplusplus
}
#endif
I compile it using the following commands:
gcc -c file1.c
g++ -c file2.cpp
gcc -o output file1.o file2.o
On this it gives the error:
file2.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
Can anyone tell me what's going on!
As one of your files is compiled as c++ use g++ for linking phase.
See: What is __gxx_personality_v0 for?
C and C++ executables require the presence of some libraries, which are included during the linking stage:
gcc -o output file1.o file2.o
The problem here is that you are trying to link a C++ file using a C linker. gcc simply fails to locate some libraries required by the C++ runtime. To solve this you must use g++, like yi_H said.
I'm relatively new to C & C++ and stuck at compiling (or should I say linking) for the whole 2 days. Anyone gives me an idea would be appreciated.
Error message and 3 code files are below. These are what I cut down to minimum from I'm actually working on so that you guys can take a better glimpse at.
Env: Ubuntu 10.10, Eclipse Indigo CDT, g++ (Ubuntu/Linaro 4.4.4-14ubuntu5) 4.4.5
Error message:
**** Build of configuration Debug for project SceneRec2 ****
make all
Building file: ../src/AdaBoost.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Includes" -I/usr/src/linux-headers-2.6.35-30/arch/um/include/shared -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/AdaBoost.d" -MT"src/AdaBoost.d" -o "src/AdaBoost.o" "../src/AdaBoost.cpp"
Finished building: ../src/AdaBoost.cpp
Building file: ../src/AdaMain.cpp
Invoking: GCC C++ Compiler
g++ -I"/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Includes" -I/usr/src/linux-headers-2.6.35-30/arch/um/include/shared -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/AdaMain.d" -MT"src/AdaMain.d" -o "src/AdaMain.o" "../src/AdaMain.cpp"
../src/AdaMain.cpp: In function ‘int main(int, char**)’:
../src/AdaMain.cpp:6: warning: deprecated conversion from string constant to ‘char*’
Finished building: ../src/AdaMain.cpp
Building target: SceneRec2
Invoking: GCC C++ Linker
g++ -o "SceneRec2" ./src/AdaBoost.o ./src/AdaMain.o
./src/AdaMain.o: In function `main':
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:5: undefined reference to `AdaBoost<double>::AdaBoost()'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:6: undefined reference to `AdaBoost<double>::readFromFile(char*)'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:8: undefined reference to `AdaBoost<double>::~AdaBoost()'
/home/ubuntuLove/Documents/workspace_eclipse/SceneRec2/Debug/../src/AdaMain.cpp:8: undefined reference to `AdaBoost<double>::~AdaBoost()'
collect2: ld returned 1 exit status
make: *** [SceneRec2] Error 1
**** Build Finished ****
Note-1. I receive the same result when I execute g++ on terminal.
Note-2. The path of .o files in the argument for linker should be correct (./src/###.o).
AdaBoost.h
#ifndef _ADABOOST_H
#define _ADABOOST_H
#include <iostream>
const double eps = 2.2204e-16;
template<class T>
class AdaBoost
{
int N; //Number of Instances
int D; //Number of Dimensions
int nL; //Number of Learners / Classifiers / Rules
T** fVectors;
int* labels;
void learnRule(int t, double* dist);
double genRule(int t, int* L, double* dist);
public:
//Default Constructor
AdaBoost();
//Constructor
AdaBoost(T** data, int* labels, int n, int d, int nL);
//Train function
void train();
//Test function
void test(double** data, double* pMap);
void test(double** data, double* pMap, int n);
int writeToFile(char* fName);
int readFromFile(char* fName);
//Destructor
~AdaBoost();
};
#endif
AdaBoost.cpp
#include "AdaBoost.h"
#include <fstream>
using namespace std;
template class AdaBoost<double> ;
template<class T>
int AdaBoost<T>::readFromFile(char* fName) {
ifstream inFile;
int temp;
int d, dir;
float thr, wt;
inFile.open(fName);
if (!inFile)
return 0;
inFile >> temp;
this->nL = temp;
int k = 0;
while (!inFile.eof() && k < nL) {
inFile >> d;
inFile >> thr;
inFile >> dir;
inFile >> wt;
k++;
}
inFile.close();
return 1;
}
AdaMain.cpp
#include "AdaBoost.h"
using namespace std;
int main(int argc, char** argv)
{
AdaBoost<double> rdClass;
rdClass.readFromFile("Naerer");
return 0;
}
If you are using explicit instantiation, you have to define the generic version of the member function before instantiating the class:
template<class T>
int AdaBoost<T>::readFromFile(char* fName) {
// ...
}
template class AdaBoost<double>;
However, if you don't have a specific or pressing reason to use explicit instantiation in the first place, go with the other recommendations and define the templates in the header.
You cannot separate template class definition and implementation in different compilation units. In other words, AdaBoost<T> complete implementation should be linked in the same compilation unit that main (where it is used) is.
This is typically fixed by either #including the .cpp file at the end of your .hpp file (if you want to maintain them separate), or just using only the .hpp file implementing the whole class there.
You have multiple problems.
First, you use the unconventional technique of explicit instantiation in a CPP file. As others have pointed out, convention (but nothing more) requires that you put the implementation in the .H file to allow for generic instantiation. You don't have to do this, but if you did, the readfile() error would go away. (As an alternative, put your AdaBoost<double> instantiation after the definition of AdaBoost::readfile.)
Next, you have declared, but not defined, your constructor and destructor. If you wish to use the compiler-provided constructor and destructor you should delete the declarations. If you wish to use your own constructor and dstructor, you should define them.
Best practice is to get rid of AdaBoost.cpp, and modify AdaBoost.h to include the implementation inline in the header. (Note that this best practice is for templated classes; other advice may apply to non-templated classes.)
You need to put the definition of template<class T>
int AdaBoost<T>::readFromFile(char* fName) into AdaBoost.h, and remove AdaBoost.cpp from your build.
It's best to put all template code into the header. C++ linkers are required to eliminate duplicate instantiations of template code so you won't get "multiply defined symbol" errors.
P.S. You should declare the function as template<class T>
int AdaBoost<T>::readFromFile(const char* fName) to get rid of the deprecated conversion from string constant to ‘char*’ warning. The function does not need to alter the filename.