Doubts in running an Rcpp example - rcpp

I'm trying to reproduce the examples of "Seamless R and C++ Integration with Rcpp" book, but some codes are not running. Specifically, it is on chapter 5, Section 5.2.3 and the code follows above:
#ifndef _mypackage_RCPP_HELLO_WORLD_H
#define _mypackage_RCPP_HELLO_WORLD_H
#include <Rcpp.h>
/*
* note : RcppExport is an alias to 'extern "C"' defined by Rcpp.
*
* It gives C calling convention to the rcpp_hello_world
* function so that it can be called from .Call in R.
* Otherwise, the C++ compiler mangles the
* name of the functioand .Call can’t find it.
* It is only useful to use RcppExport when the function
* is intended to be called by .Call. See the thread
* http://thread.gmane.org/gmane.comp.lang.r.rcpp/649/focus=672
* on Rcpp-devel for a misuse of RcppExport 19
*/
RcppExport SEXP rcpp_hello_world();
#endif
and the next is
#include "rcpp_hello_world.h"
SEXP rcpp_hello_world() {
using namespace Rcpp;
CharacterVector x = CharacterVector::create( "foo", "bar" ) ;
NumericVector y = NumericVector::create( 0.0, 1.0 ) ;
List z = List::create( x, y ) ;
return z ;
}
The error showed by R is
Error in .Call("rcpp_hello_world", PACKAGE = "mypackage") :
"rcpp_hello_world" not available for .Call() for package "mypackage"
Have anyone faced a problem like this?
Thanks in advance!
When I try to tip
R CMD check mypackage_1.0.tar.gz
I got an error like this
* using log directory ‘/Users/Marcos/Downloads/mypackage.Rcheck’
* using R version 3.0.2 (2013-09-25)
* using platform: x86_64-apple-darwin10.8.0 (64-bit)
* using session charset: UTF-8
* checking for file ‘mypackage/DESCRIPTION’ ... OK
* checking extension type ... Package
* this is package ‘mypackage’ version ‘1.0’
* checking package namespace information ... OK
* checking package dependencies ... OK
* checking if this is a source package ... OK
* checking if there is a namespace ... OK
* checking for executable files ... OK
* checking for hidden files and directories ... OK
* checking for portable file names ... OK
* checking for sufficient/correct file permissions ... OK
* checking whether package ‘mypackage’ can be installed ... ERROR
Installation failed.
See ‘/Users/Marcos/Downloads/mypackage.Rcheck/00install.out’ for details.
In the file 00install.out, the first error is
* installing *source* package ‘mypackage’ ...
** libs
llvm-g++-4.2 -arch x86_64 -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG -I/usr/local/include -I"/Library/Frameworks/R.framework/Versions/3.0/Resources/library/Rcpp/include" -fPIC -mtune=core2 -g -O2 -c RcppExports.cpp -o RcppExports.o
In file included from /Library/Frameworks/R.framework/Versions/3.0/Resources/library/Rcpp/include/RcppCommon.h:28,
from /Library/Frameworks/R.framework/Versions/3.0/Resources/library/Rcpp/include/Rcpp.h:27,
from RcppExports.cpp:4:
/Library/Frameworks/R.framework/Versions/3.0/Resources/library/Rcpp/include/Rcpp/platform/compiler.h:93:17: error: cmath: No such file or directory
And then, I just got error messages.

Go to the terminal:
R CMD build mypackage
R CMD check mypackage_1.0.tar.gz
R CMD install mypackage
and in R:
library(mypackage)
rcpp_hello_world()
[[1]]
[1] "foo" "bar"
[[2]]
[1] 0 1
Now, I don't understand where to use the code written in "Listing 5.4", Do I need to write it or this is created automatically?

This example (and chapter) discusses how to build (and load) an entire package, here called mypackage.
Did you actually create, compile and load mypackage?
This works, as we do this each and every time the unit tests run.
Edit: Here is a full log for you
R> library(Rcpp)
R> Rcpp.package.skeleton("mypackage") ## page 66, Section 5.2.1
Creating directories ...
Creating DESCRIPTION ...
Creating NAMESPACE ...
Creating Read-and-delete-me ...
Saving functions and data ...
Making help files ...
Done.
Further steps are described in './mypackage/Read-and-delete-me'.
Adding Rcpp settings
>> added Depends: Rcpp
>> added LinkingTo: Rcpp
>> added useDynLib directive to NAMESPACE
>> added Makevars file with Rcpp settings
>> added Makevars.win file with Rcpp settings
>> added example src file using Rcpp attributes
>> compiled Rcpp attributes
>> added Rd file for rcpp_hello_world
R>
We can now build the tarball:
R> system("R CMD build mypackage")
* checking for file 'mypackage/DESCRIPTION' ... OK
* preparing 'mypackage':
* checking DESCRIPTION meta-information ... OK
* cleaning src
* checking for LF line-endings in source and make files
* checking for empty or unneeded directories
* building 'mypackage_1.0.tar.gz'
R>
then we can install it: (and I am doing that on a Windows machine for a change)
R> system("R CMD INSTALL mypackage_1.0.tar.gz")
* installing to library 'c:/opt/R-library'
* installing *source* package 'mypackage' ...
** libs
*** arch - i386
g++ -m32 -I"c:/opt/R-CURR~1/include" -DNDEBUG -I"c:/opt/R-library/Rcpp/include" -I"d:/RCompile/CRANpkg/extralibs64/local/include" -O2 -Wall -mtune=core2 -c RcppExports.cpp -o RcppExports.o
g++ -m32 -I"c:/opt/R-CURR~1/include" -DNDEBUG -I"c:/opt/R-library/Rcpp/include" -I"d:/RCompile/CRANpkg/extralibs64/local/include" -O2 -Wall -mtune=core2 -c rcpp_hello_world.cpp -o rcpp_hello_world.o
g++ -m32 -shared -s -static-libgcc -o mypackage.dll tmp.def RcppExports.o rcpp_hello_world.o c:/opt/R-library/Rcpp/lib/i386/libRcpp.a -Ld:/RCompile/CRANpkg/extralibs64/local/lib/i386 -Ld:/RCompile/CRANpkg/extralibs64/local/lib -Lc:/opt/R-CURR~1/bin/i386 -lR
installing to c:/opt/R-library/mypackage/libs/i386
*** arch - x64
g++ -m64 -I"c:/opt/R-CURR~1/include" -DNDEBUG -I"c:/opt/R-library/Rcpp/include" -I"d:/RCompile/CRANpkg/extralibs64/local/include" -O2 -Wall -mtune=core2 -c RcppExports.cpp -o RcppExports.o
g++ -m64 -I"c:/opt/R-CURR~1/include" -DNDEBUG -I"c:/opt/R-library/Rcpp/include" -I"d:/RCompile/CRANpkg/extralibs64/local/include" -O2 -Wall -mtune=core2 -c rcpp_hello_world.cpp -o rcpp_hello_world.o
g++ -m64 -shared -s -static-libgcc -o mypackage.dll tmp.def RcppExports.o rcpp_hello_world.o c:/opt/R-library/Rcpp/lib/x64/libRcpp.a -Ld:/RCompile/CRANpkg/extralibs64/local/lib/x64 -Ld:/RCompile/CRANpkg/extralibs64/local/lib -Lc:/opt/R-CURR~1/bin/x64 -lR
installing to c:/opt/R-library/mypackage/libs/x64
** R
** preparing package for lazy loading
** help
Warning: C:/Users/deddelbuettel/AppData/Local/Temp/RtmpaiaZVk/R.INSTALL65481db46d2b/mypackage/man/mypackage-package.Rd:30: All text must be in a section
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* DONE (mypackage)
R>
after which we can load and run it:
R> library(mypackage)
R> rcpp_hello_world()
[[1]]
[1] "foo" "bar"
[[2]]
[1] 0 1
R>
and finally remove it as it has no real use case besides demonstrating these mechanics:
R> remove.packages("mypackage")
Removing package from ‘c:/opt/R-library’
(as ‘lib’ is unspecified)
R>

Related

application using lttng compile errors with aarch64-xilinx-linux-g++

I am trying to porting lttng on xilinx mpsoc with linux OS, I have write a demo as same as lttng "Record user application events", it runs on Ubuntu perfectly
g++ -c -I. hello-tp.c
g++ -c hello.c
g++ -o hello hello-tp.o hello.o -llttng-ust -ldl
but when I compile it on arm linux platform I got errors:
aarch64-xilinx-linux-g++ -mcpu=cortex-a72.cortex-a53 -march=armv8-a+crc -fstack-protector-strong -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/david/project/zcu102/images/linux/sdk/sysroots/cortexa72-cortexa53-xilinx-linux -O2 -pipe -g -feliminate-unused-debug-types -c -I. hello-tp.c
In file included from hello-tp.c:4:
hello-tp.h:16:27: error: expected constructor, destructor, or type conversion before ‘(’ token
16 | LTTNG_UST_TRACEPOINT_EVENT(hello_world, my_first_tracepoint, LTTNG_ARGS, LTTNG_FIELDS)
| ^
make: *** [Makefile:14: hello-tp.o] Error 1
here is the code
hello-tp.h:
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER hello_world
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./hello-tp.h"
#if !defined(_HELLO_TP_H) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define _HELLO_TP_H
#include <lttng/tracepoint.h>
#define LTTNG_ARGS LTTNG_UST_TP_ARGS(int, my_integer_arg, char *, my_string_arg)
#define LTTNG_FIELDS LTTNG_UST_TP_FIELDS(lttng_ust_field_string(my_string_field, my_string_arg) lttng_ust_field_integer(int, my_integer_field, my_integer_arg))
LTTNG_UST_TRACEPOINT_EVENT(hello_world, my_first_tracepoint, LTTNG_ARGS, LTTNG_FIELDS)
#endif /* _HELLO_TP_H */
#include <lttng/tracepoint-event.h>
hello-tp.c
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "hello-tp.h"
hello.c
#include <stdio.h>
#include "hello-tp.h"
int main(int argc, char *argv[])
{
unsigned int i;
puts("Hello, World!\nPress Enter to continue...");
/*
* The following getchar() call only exists for the purpose of this
* demonstration, to pause the application in order for you to have
* time to list its tracepoints. You don't need it otherwise.
*/
getchar();
/*
* An lttng_ust_tracepoint() call.
*
* Arguments, as defined in `hello-tp.h`:
*
* 1. Tracepoint provider name (required)
* 2. Tracepoint name (required)
* 3. `my_integer_arg` (first user-defined argument)
* 4. `my_string_arg` (second user-defined argument)
*
* Notice the tracepoint provider and tracepoint names are
* C identifiers, NOT strings: they're in fact parts of variables
* that the macros in `hello-tp.h` create.
*/
lttng_ust_tracepoint(hello_world, my_first_tracepoint, 23,
"hi there!");
for (i = 0; i < argc; i++) {
lttng_ust_tracepoint(hello_world, my_first_tracepoint,
i, argv[i]);
}
puts("Quitting now!");
lttng_ust_tracepoint(hello_world, my_first_tracepoint,
i * i, "i^2");
return 0;
}
Makefile
APP = hello
# Add any other object files to this list below
APP_OBJS = hello-tp.o hello.o
all: build
build: $(APP)
$(APP): $(APP_OBJS)
$(CXX) -o $# $(APP_OBJS) $(LDFLAGS) -llttng -ldl
hello-tp.o : hello-tp.c hello-tp.h
$(CXX) $(CXXFLAGS) -c -I. $<
hello.o : hello.c
$(CXX) $(CXXFLAGS) -c $<
clean:
rm -f $(APP) *.o
Is there anyone met such issue? I guess the problem is caused by complier but I don't find any clue...
I just ran into this problem. Check your LTTNG version. The 2.13 release (current) uses LTTNG_UST_TRACEPOINT_PROVIDER. However, older releases uses TRACEPOINT_PROVIDER. The prefix LTTNG_UST has been added all over the place. See https://lttng.org/man/3/lttng-ust/v2.13/#doc-_compatibility_with_previous_apis

How to execute C++11 with makefile

I have a problem when I execute commmand "make" in terminal ubuntu.
My code of makefile is:
all: temp p1
%: %.cc g++ -lm -lcrypt -O2 -std=c++11 -pipe $< -o $#
Of course, my files are temp.cc and p1.cc, but my problem is in p1.cc, where the code is:
#include <bits/stdc++.h>
using namespace std;
int main(){
vector<int> vec = {4,6,8,9,8,7,1,3,4,5,0,1};
for(auto i : vec)
cout<<i<<" ";
cout<<endl;
return 0;}
My error using 'make' is:
eabg97#EABG:~/P$ make
g++ p1.cc -o p1
p1.cc: In function ‘int main()’:
p1.cc:7:44: error: in C++98 ‘vec’ must be initialized by constructor, not by ‘{...}’
vector<int> vec = {4,6,8,9,8,7,1,3,4,5,0,1};
^
p1.cc:7:44: error: could not convert ‘{4, 6, 8, 9, 8, 7, 1, 3, 4, 5, 0, 1}’ from ‘<brace-enclosed initializer list>’ to ‘std::vector<int>’
p1.cc:9:11: error: ‘i’ does not name a type
for(auto i : vec)
^
p1.cc:11:2: error: expected ‘;’ before ‘cout’
cout<<endl;
^
p1.cc:12:2: error: expected primary-expression before ‘return’
return 0;
^
p1.cc:12:2: error: expected ‘)’ before ‘return’
make: *** [p1] Error 1
Using the next command lines, compile:
g++ --std=c++11 p1.cc -o p1
and executing is okay:
eabg97#EABG:~/P$ ./p1
4 6 8 9 8 7 1 3 4 5 0 1
Please help me, I don't understand why there is a problem, thanks for your support :)
This is wrong:
all: temp p1
%: %.cc g++ -lm -lcrypt -O2 -std=c++11 -pipe $< -o $#
You should either add a newline and an initial TAB, like this:
all: temp p1
%: %.cc
g++ -lm -lcrypt -O2 -std=c++11 -pipe $< -o $#
(the first char on the third line must be a TAB character) or you need to insert a semicolon like this:
all: temp p1
%: %.cc ; g++ -lm -lcrypt -O2 -std=c++11 -pipe $< -o $#
What is your makefile doing? First, that statement all in one line without any newline/TAB or semicolon is considered by make to be a single pattern rule with a target % and prerequisites %.cc, g++, -lm, -lcrypt, etc. And, since there's no recipe, you're basically deleting that pattern rule (which doesn't exist anyway) since a pattern rule with no recipe deletes the pattern rule. So that line is essentially a no-op and does nothing.
So what happens? Make has a bunch of built-in rules that it uses to create things if you don't tell it how to do so, and there's a built-in rule that knows how to create a program from a .cc file, so make uses that. But of course, that built-in rule doesn't have any of your customizations.
It's simpler to use make's built-in rule and use the standard make variables to control it:
CXX := g++
CXXFLAGS := -std=c++11 -pipe
LDLIBS := -lm -lcrypt
all: temp p1
That's all you need, if you don't want to write your own rule.

dylib dynamic library calling a dylib : Undefined symbols for architecture i386

Under mac os x with g++ from gcc-5.2 I am trying to do the following : create a dylib exporting a class defined by header tmp8bis_dylib.h and source tmp8bis_dylib.cpp, and then create another dylib out of a source file tmp8bis.cpp using and linking to the previous dylib. Header and sources are in the same directory. I compile as follows :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis_dylib.o -o ./tmp8bis_dylib.dylib
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib
and get this :
Undefined symbols for architecture i386:
"complex::cmodule(double, double)", referenced from:
_mymodule in tmp8bis.o
"complex::complex(double, double)", referenced from:
_mymodule in tmp8bis.o
"complex::~complex()", referenced from:
_mymodule in tmp8bis.o
ld: symbol(s) not found for architecture i386
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
Obviously, I tried to pass various include and library paths with -I and -L flags respectively, with the very same result... Any idea ?
Files are below :
For tmp8bis_dylib.h :
#ifndef TMP_8_BIS_DYLIB_H
#define TMP_8_BIS_DYLIB_H
class complex
{
public:
double real;
double imag;
public:
complex();
complex(double x);
complex(double x,double y);
double cmodule(double x, double y);
~complex();
};
#endif
For tmp8bis_dylib.cpp :
#include "./tmp8bis_dylib.h"
#include <math.h>
extern "C"
{
complex::complex()
{
real = 0.0 ;
imag = 0.0 ;
}
complex::complex(double x)
{
real = x ;
imag = 0.0 ;
}
complex::complex(double x,double y)
{
real = x ;
imag = y ;
}
double complex::cmodule(double x, double y)
{
double res = sqrt(x*x+y*y);
return res ;
}
complex::~complex()
{
}
}
For tmp8bis.cpp :
#include <math.h>
#include "./tmp8bis_dylib.h"
extern "C"
{
double mymodule(double x, double y)
{
complex z(x,y);
double ret = z.cmodule(x,y);
return ret;
}
}
Precision. -m32 is because I need 32 bits dylib because the final dylib will be plugged into excel 2011's (for mac) VBA, which is 32 bits.
EDIT. Following Brett Hale's comment about Apple's advises about dylibs, I added
#define EXPORT __attribute__((visibility("default")))
after the #include's from tmp8bis.cpp, and EXPORT's for all its member functions, and compiled as follows :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis_dylib.o -fvisibility=hidden -o ./tmp8bis_dylib.dylib
did a sudo cp ./tmp8bis_dylib.dylib /opt/lib/libtmp8bis_dylib.dylib and then compiled :
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib -L/opt/lib
and got the same result as before... Nor did
g++-5.2.0 -m32 -dynamiclib ./tmp8bis.o -o ./tmp8bis.dylib -ltmp8bis_dylib.dylib
make my day.
Without resorting to #define EXPORT __attribute__((visibility("default"))) or any -fvisibility=hidden
g++-5.2.0 -m32 -Wall -fpic -g -c ./tmp8bis_dylib.cpp
g++-5.2.0 -m32 -shared ./tmp8bis_dylib.o -o ./libtmp8bis_dylib.dylib
g++-5.2.0 -m32 -Wall -g -c ./tmp8bis.cpp
g++-5.2.0 -m32 -shared ./tmp8bis.o -o ./tmp8bis.dylib -L. -ltmp8bis_dylib
finally worked. I did not managed to succeed without -fpic, naming libtmp8bis_dylib.dylib and using -ltmp8bis_dylib.

Link error undefined reference to `dgels_' in Lapack

I followed this below webpage to install ATLAS + Lapack in linux :
http://math-atlas.sourceforge.net/atlas_install/node6.html
bunzip2 -c atlas3.10.1.tar.bz2 | tar xfm - # create SRCdir
mv ATLAS ATLAS3.10.1 # get unique dir name
cd ATLAS3.10.1 # enter SRCdir
mkdir Linux_C2D64SSE3 # create BLDdir
cd Linux_C2D64SSE3 # enter BLDdir
../configure -b 64 -D c -DPentiumCPS=2400 \ # configure command
--prefix=/home/whaley/lib/atlas \ # install dir
--with-netlib-lapack-tarfile=/home/whaley/dload/lapack-3.4.2.tgz
make build # tune & build lib
make check # sanity check correct answer
make ptcheck # sanity check parallel
make time # check if lib is fast
make install # copy libs to install dir
After that , I try to run an sample in
http://www.netlib.org/lapack/lapacke.html
the sample code :
#include <stdio.h>
#include <lapacke.h>
int main (int argc, const char * argv[])
{
double a[5*3] = {1,2,3,4,5,1,3,5,2,4,1,4,2,5,3};
double b[5*2] = {-10,12,14,16,18,-3,14,12,16,16};
lapack_int info,m,n,lda,ldb,nrhs;
int i,j;
m = 5;
n = 3;
nrhs = 2;
lda = 5;
ldb = 5;
info = LAPACKE_dgels(LAPACK_COL_MAJOR,'N',m,n,nrhs,a,lda,b,ldb);
for(i=0;i<n;i++)
{
for(j=0;j<nrhs;j++)
{
printf("%lf ",b[i+ldb*j]);
}
printf("\n");
}
return(info);
}
I have found out the build library has no iblapacke.a , so I build this library by myslef
cd lapack-3.4.2
cp make.inc.example make.inc
cd lapacke
make
Then , finally I have the iblapacke.a now , so I compile the sample above by :
g++ test3.cpp liblapacke.a -o test3.exe
I get the following errors :
liblapacke.a(lapacke_dgels_work.o): In function `LAPACKE_dgels_work':
lapacke_dgels_work.c:(.text+0x1dd): undefined reference to `dgels_'
lapacke_dgels_work.c:(.text+0x2b7): undefined reference to `dgels_'
After I google , I have found :
http://www.netlib.org/lapack/explore-html/d7/d3b/group__double_g_esolve.html
Functions/Subroutines
subroutine dgels (TRANS, M, N, NRHS, A, LDA, B, LDB, WORK, LWORK, INFO)
DGELS solves overdetermined or underdetermined systems for GE matrices
There is a function dgels , without underline , and in
http://shtools.ipgp.fr/www/faq.html#l4
I think the underline is added for accident ,
nm -A liblapacke.a |grep "dgels_"
liblapacke.a:lapacke_dgels.o: U LAPACKE_dgels_work
liblapacke.a:lapacke_dgels_work.o: U LAPACKE_dge_trans
liblapacke.a:lapacke_dgels_work.o:0000000000000000 T LAPACKE_dgels_work
liblapacke.a:lapacke_dgels_work.o: U LAPACKE_xerbla
liblapacke.a:lapacke_dgels_work.o: U dgels_
liblapacke.a:lapacke_dgels_work.o: U free
liblapacke.a:lapacke_dgels_work.o: U malloc
I think I should try to not avoid underline like build "dgels" not to "dgels" while build liblapack.a ,means I should change something build Lapack and ATLAS ,
just don't know how to do it ....Any suggestion is appreciated !!
Update : http://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/c_bindings.htm
I have no idea if related , -Ddgels=dgels_ is added , the same link error !!
see:
http://icl.cs.utk.edu/lapack-forum/viewtopic.php?f=12&t=3336
for example:
gcc LinearEquation.c -Ilapack-3.5.0/lapacke/include/ -Llapack-3.5.0 -llapacke -llapack -lrefblas -lgfortran -o LinearEquation
the order of lapacke > lapack > refblas is important... also if you don't want to use the double step gcc gfortran, use -lgfortran
I had the exact same problem. You need to do it as follows:
gcc(or g++) -c -O3 -I ../include -o test.o test.c
and then
gfortran test.o ../liblapacke.a ../liblapack.a ../blas.a -o test.exe
You can then run it like so:
./test.exe
Basically, you need to follow the gcc compile with a gfortran compile. The -c option in the first command forces gcc to skip the linker. gfortran is then used to link the libraries.
You can learn more by looking at the makefile for the examples provided with LAPACKE.
I had the same problem (using g++), but fixed my problems by adding a -lblas and -lgfortran.
To resolve the issue, here are the steps I have done.
sudo apt-get install libblas-dev liblapack-dev gfortran
linking a -lblas and -lgfortran when it runs

Linking cuda object file

I have one .cu file that contains my cuda kernel, and a wrapper function that calls the kernel. I have a bunch of .c files as well, one of which contains the main function. One of these .c files calls the wrapper function from the .cu to invoke the kernel.
I compile these files as follows:
LIBS=-lcuda -lcudart
LIBDIR=-L/usr/local/cuda/lib64
CFLAGS = -g -c -Wall -Iinclude -Ioflib
NVCCFLAGS =-g -c -Iinclude -Ioflib
CFLAGSEXE =-g -O2 -Wall -Iinclude -Ioflib
CC=gcc
NVCC=nvcc
objects := $(patsubst oflib/%.c,oflib/%.o,$(wildcard oflib/*.c))
table-hash-gpu.o: table-hash.cu table-hash.h
$(NVCC) $(NVCCFLAGS) table-hash.cu -o table-hash-gpu.o
main: main.c $(objects) table-hash-gpu.o
$(CC) $(CFLAGSEXE) $(objects) table-hash-gpu.o -o udatapath udatapath.c $(LIBS) $(LIBDIR)
So far everything is fine. table-hash-gpu.cu calls a function from one of the .c files. When linking for main, I get the error that the function is not present. Can someone please tell me what is going on?
nvcc compiles both device and host code using the host C++ compiler, which implies name mangling. If you need to call a function compiled with a C compiler in C++, you must tell the C++ compiler that it uses C calling conventions. I presume that the errors you are seeing are analogous to this:
$ cat cfunc.c
float adder(float a, float b, float c)
{
return a + 2.f*b + 3.f*c;
}
$ cat cumain.cu
#include <cstdio>
float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ gcc -m32 -c cfunc.c
$ nvcc -o app cumain.cu cfunc.o
Undefined symbols:
"adder(float, float, float)", referenced from:
_main in tmpxft_0000b928_00000000-13_cumain.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Here we have code compiled with nvcc (so the host C++ compiler) trying to call a C function and getting a link error, because the C++ code expects a mangled name for adder in the supplied object file. If the main is changed like this:
$ cat cumain.cu
#include <cstdio>
extern "C" float adder(float, float, float);
int main(void)
{
float result = adder(1.f, 2.f, 3.f);
printf("%f\n", result);
return 0;
}
$ nvcc -o app cumain.cu cfunc.o
$ ./app
14.000000
It works. Using extern "C" to qualify the declaration of the function to the C++ compiler, it will not use C++ mangling and linkage rules when referencing adder and the resulting code links correctly.

Resources