Calling C - C++ From Ruby
Calling C - C++ From Ruby
CallingC/C++fromRuby
ThisisablogofAmberBitaRubyonRailswebdevelopmentcompany.Hireusforyourproject!
CallingC/C++fromRuby
2014612
Weoftencometothepoint,whenwehavetowriteenormouslyhugemoduleinRuby.Butwesimply
dontwantto.Maybebecauseweretoolazy/smart,orwedoknowthatsuchlibraryalreadyexists
writteninC/C++.ImplementingpthreadorcryptlibraryinpureRubysoundslikereinventingthe
wheel.TheotherthingiswellwrittenCcodemostlikelywillperformmuchbetterthananyhigher
levelimplementation.Ittakesadvantageofprecompilation,bettergarbagecollectionorstatictyping.
Sowhatshouldwedo?Ifthefunctionalityisrelativelysimple,andwehaveaccesstooriginalsource
code(notonycompled.soor.dllbinaries),firstapproachmaybetogothroughcodelinebylineand
convertit.Whataboutpieceswhichcantbeprocessedinsuchway?Orthealgorithmitselfisvery
complicated?Luckily,thereisafewwaysofcallingCfunctionsfromRubycode.
RubyInline
Itcomesasagem,andrequirestohavegcc/g++compilerinstalled.Afterthatsimplygeminstall
RubyInline.InlineworksbyembeddingpureC/C++codeintoRubycode.Anditdoesntlookcool.
Butwilldothejob,andwilldoitfast.Heresanexampleofcallingpowfunctionfrommathlibrary,as
wellasownimplementationsoffibonacciandfactorialfunctions:
require'inline'
classInlineTest
inlinedo|builder|
builder.include'<math.h>'
builder.c'
intinline_pow(inta,intn){
returnpow(a,n);
}'
builder.c'
longinline_factorial(intmax){
inti=max,result=1;
while(i>=2){result*=i;}
returnresult;
}'
builder.c'
intinline_fibonacci(intn){
inta=1,b=1,c,i;
if(n==0){
return0;
}
for(i=3;i<=n;i++){
c=a+b;
a=b;
b=c;
}
returnb;
}'
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
1/8
7/25/2015
}'
end
end
CallingC/C++fromRuby
putsInlineTest.new.inline_factorial(5)
putsInlineTest.new.inline_fibonacci(9)
putsInlineTest.new.inline_pow(2,10)
Firstthingwhichcomestomymind,isthatyouactuallyNEEDtowritesomeCcode.Atleastdummy
wrapperofexternalfunction.ItsupportsbothCandC++,andaccordingtoauthors,itsextendableto
workwithotherlanguages.Wedontneedtoworryaboutconversionofpassedargumentsandreturned
data.Alsonomanualcompilationisrequired,itwilldetectanycodechangesandadoptthem.
Rice
Anothergreatsoftware,whichtakescomplicatedC++classes,types,methodsandexposestheminto
Ruby.Thistime,separatedimplementationsarerequired,whichgivesusbetterarrangedproject
structureandmakesitalittlebitmorecomplicatedtosetup.Firstofall,eachclassmethodhastobe
wrappedintoCmethodwithcallsintoRubysAPI.AndheresasimpleexampleofexposingC
functionintoRuby:
#include"rice/Class.hpp"
usingnamespaceRice;
intrice_fibonacci(intn){
inta=1,b=1,c,i;
if(n==0){
return0;
}
for(i=3;i<=n;i++){
c=a+b;
a=b;
b=c;
}
returnb;
}
intrice_factorial(intmax){
inti=max,result=1;
while(i>=2){result*=i;}
returnresult;
}
intrice_pow(inta,intn){
returnpow(a,n);
}
extern"C"
voidInit_rice_test()
{
Classrb_c=define_class("RiceTest")
.define_method("fibonacci",&rice_fibonacci)
.define_method("factorial",&rice_factorial)
.define_method("pow",&rice_pow);
}
BeforewejumptotheRubycode,somepreparationsarerequired.Firststep,installingRicegemgem
installrice.Thenweneedtocreateextconf.rbfilecontaining(orsimplyexecutethecode):
require'mkmfrice'
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
2/8
7/25/2015
require'mkmfrice'
create_makefile('rice_test')
CallingC/C++fromRuby
RunningthispieceofcodewillgeneratetemplatedMakefile,readytocompilecoderice_test.cpp
classcode.Andfinally,runningmake,whichwillusepregeneratedMakefiletocompileourgluecode
intosharedlibrary.Wewillendupwithrice_test.o(safetoremove)andrice_test.so.Wecando
anythingwithcompiledbinaries:addittoourprojectvendors,oraddtosystemlibraries.Wejustneed
toincludeitinRubycodecorrectlyandcallexposedmethods:
require'./rice_test'
putsRiceTest.new.fibonacci(5)
UsingRicerequiredmorepreparationsthanRubyInline,butwegotcleanersolution,andprecompiled
librariesreadytodroptoapplicationserver.Itprovidesawaytoexposewholeclasses,withalltheir
methods,constructors,attributesaccessorsandsoon.Sothisapproachwouldbebetterifwewantto
takeOOapproach.AlsoRicewasdesignedwithC++inmind,andbecauseofthatwillworkbestwith
C++,butcanbeusedalsotogluepureC.Anotheradvantageisthatwedontneedtohavecompiler
installedonapplicationserver,whichisnice.
FFI
Andlast,butnotleastlibraryImgoingtofocusonisFFI(ForeignFunctionInterface).Asusual,its
availableinformofagem.Althoughithassimplestandmostintuitivedls,itsnotlackingcomplex
functionalities.Greatadvantage(andmaybedisadvantageforsomebodyatthesametime)isthatwe
dontneedtodigintocrazyC/C++interfaceexposing,gluecodegenerationandcodecompilation.As
simpleasthat.SoletscheckFFIinaction.Afterinstallinggeminstallffianditslibraries:libffi
devorlibffideveldependingonyourOS,theonlythingweneedtodoiswrappingsharedlibrary
callsintoRuby:
require'ffi'
moduleFfiMathTest
extendFFI::Library
ffi_lib'c'
ffi_lib'm'
attach_function:pow,[:double,:double],:double
end
putsFfiMathTest.pow(2.2,10)
Definitionsyntaxisselfexplaining,andallthemagichappensinRuby.Theresnointermediate
methodscallingdesiredone.Werejustincludinglibrarieswewanttouse:libcandlibm(math),and
addressingthemwiththeiroriginalname,parameterslistandtypes.AnothersolidpointforFFIisthat
itsmultiplatformandmultiimplementation.ThesamecodewillrunfineonalldifferentRuby
interpreters:MRI,JRuby,RubiniusandallsupportingFFI.Butontheotherhand,itdoesntsupport
C++becauseofthecomplexitythatC++adds,largelytheprobleminvolvedthenamemangling.FFI
includesmanyusefulcomponents,whichincludesinteractionwithCstructures,unions,allocatingand
accessingmemorywithpointersordatatypesmapping.
Andfromcustomlibrarywhichlookslikethis:
#include<stdlib.h>
#include<math.h>
intffi_pow(inta,intn){
returnpow(a,n);
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
3/8
7/25/2015
CallingC/C++fromRuby
}
intffi_factorial(intmax){
inti=max,result=1;
while(i>=2){result*=i;}
returnresult;
}
intffi_fibonacci(intn){
inta=1,b=1,c,i;
if(n==0){
return0;
}
for(i=3;i<=n;i++){
c=a+b;
a=b;
b=c;
}
returnb;
}
compilation
$gcccfPICffi_test.coffi_test.o
$gccsharedoffi_test.soffi_test.o
Rubybindingandcall:
require'ffi'
moduleFfiCustomTest
extendFFI::Library
ffi_lib'c'
ffi_lib'./ffi_test.so'
attach_function:ffi_pow,[:int,:int],:int
attach_function:ffi_factorial,[:int],:int
attach_function:ffi_fibonacci,[:int],:int
end
putsFfiCustomTest.ffi_factorial(5)
putsFfiCustomTest.ffi_fibonacci(9)
putsFfiCustomTest.ffi_pow(2,10)
Sowhichonetouse?
RubyInlineisextremelyeasytostartwithandallowswrappingCfunctionscallsingluelayer.Itcould
beusefulwhenworkingwithcomplextypes,structuresorclasseswhereasexpectingprimitive
response.RiceinteractsgreatwithC++andallowsOOabstraction.AndFFIbeingabletorunon
variousRubyimplementations.Letslookatsimplebenchmarkofthem,alsowithRubyversion:
defrb_pow(a,n)
a**n
end
defrb_factorial(max)
i=max;result=1
whilei>=2do
result*=i
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
4/8
7/25/2015
result*=i
i=1
end
result
end
CallingC/C++fromRuby
defrb_fibonacci(n)
a=1;b=1
return0ifn==0
foriin3..ndo
c=a+b
a=b
b=c
end
b
end
Andfinallysomenumbers.100000methodcallsof:factorial(10),fibonacci(20),pow(2,20)
Ruby RubyInline
Rice
FFI
factorial 0.044854815 0.026175138 0.197720523 0.014882004
fibonacci 0.152947962 0.026792521 0.202714029 0.018928646
pow
0.01204131 0.03252452 0.211258897 0.023082315
Asmanyofusmightexpect,FFIperformedbest(withsmallexceptioninpowerfunctionastheresnot
muchcodeandexternalfunctioncallstookmostofthetime).RubyInlinewasanicesurprise.Easyto
startwithcombinedwithgoodperformancemakesitgreatcandidatefornotsodemandingproblems.
ButwhosgonnauseembeddedCcodeforsuchtrivialtasks.Inmostofthecasesitwillbe
mathematicalcalculations.Keepingthatinmind,weshouldprobablyconsiderotherfactors:easyof
useandabilitytoadoptinourproject.
References
https://rubygems.org/gems/RubyInline
https://rubygems.org/gems/rice
https://github.com/ffi/ffi
byKamilDziemianowicz
DoyouneedskilledprofessionalstohelpyoubuildRailsapplications?Hireusforyourproject!
AnnouncingElixirCocktails
Fluxvs.Reflux
Sorcery+GoogleCalendarformultipleusers
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
5/8
7/25/2015
CallingC/C++fromRuby
Sorcery+GoogleCalendarformultipleusers
Closures:Elixirvs.Rubyvs.JavaScript
SEObasicsforRailsdevelopers
WhyRails5/Turbolinks3.0/ActionCablematter,andwhy@dhhwasrightallalong
5CoolAngularJSlibraries
10skillsthatwillmakeyouabetterRubyist
SplittingmonolithicRailsapplications
Rubythebadparts
CallingC/C++fromRuby
Rubythegoodparts
BuildinganddocumentingAPIinRails
PuttingRubyonRailsonadiet
AutomatetasksonthewebwithRubyandCapybara
PostgreSQLawesomenessforRailsdevelopers
Torquebox3,Rails4zerodowntimedeploymentsonUbuntu12.04
AngularJStemplatesandRubyonRailsassetspipeline
SimilarimagesdetectioninRubyPart1
BuildingsmallsiteswithLocomotiveCMSanddeployingtoHerokuandGridFS
RenderviewsandpartialsoutsidecontrollersinRails3
RubyFLVpseudostreamingimplementedwithSinatraandRack::Evil
MeasuringcomplexityofRuby1.9codewithmetric_abc
GoTranslateYourselfRailsengineformanagingwebsitetranslations
SocialnetworksapplicationdevelopmentwithRailsandOpenSocial(part1introduction)
GeospatialsearchwithRubyandSphinx
IntroductiontoRackmiddleware
7Comments
AmberBitBlog
Share
Recommend 1
Login
SortbyBest
Jointhediscussion
LOGINWITH
ORSIGNUPWITHDISQUS ?
Name
Theldoria ayearago
Iregularlyusethetoolswig(http://www.swig.org/)togenerateaccessfunctions(wrapper
code)toCfunctions,classes,constantsanddatastructuresfromruby.Itworksreliableand
canprovidesnicemeanstowrapallsortsofspecialcases.Anditcangeneratewrapper
codeformanyothertargetlangueslikeluaorpythonaswell.However,itcannotbeused
easily.
Soitisbestsuitedforlargescaleprojectsasanreplacementforrice.
1
Reply Share
ukaszPeszyski ayearago
Goodpostalsocontroversialone:)IhaveusedRiceandinmyopiniontheperformance
differenceshouldnotbethatbig!AlsofactorialwithRiceis4timesslowerthanRuby.There
mustbesomethingwrong,suchthingsshouldnothappen.Checkthatyouhadthesame
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
6/8
7/25/2015
CallingC/C++fromRuby
mustbesomethingwrong,suchthingsshouldnothappen.Checkthatyouhadthesame
compilerflagsineverycase.Ithinkthatpostbenchmarksthefunctioncallsratherthan
performanceofthefunction.Sometimesfastcallsareneeded,butmostoftenwetryto
delegatesomethingheavylikeaudioprocessing.
WithRice,it'sbiggestadvantageisabilitytowriteobjectorientedcodesoyoucreateaC++
classanditnearlyautomaticallybecomesaclassinRuby.Ithinkyoucanexplorethistopic
inmoredetail,becauseRicetutorialsarenotverypopularontheInternet.
1
Reply Share
KamilDziemianowicz>ukaszPeszyski ayearago
Thanksforthefeedback!WhatiscoolaboutRiceisthatIwasabletopassin/out
complexdatatypeswitharraysetc.Thoughitrequireddefiningbothwaymappingof
allfileds,whichlet'ssayisalittletroublesome...
Reply Share
hubertlepicki ayearago
Cool.Kamil,IhadsometroublebackinthedayswhenIwasforcedtouseC++libraryfrom
FFI.Thetroublewasquiteeasytosolveby...wrappingaroundC++librarycallsintopureC
functions.Didyouexperiencethataswellorwaseverythinggoodinyourcase?
1
Reply Share
KamilDziemianowicz>hubertlepicki ayearago
InfactIdid,triedtouseTopsurfimagedetectionlibraryandhadtowriteRuby
wrapper.AnditendeduponexposingsurfclassmethodsinsimpleCfunctions,
whichwereprettycomplex.SoIgotthatgoinforme,whichisnice:)Probablybetter
examplethanpowerfunction.
Reply Share
CodingMakesYouHappy! 5monthsago
ExcellentwriteuponprettymucheverywaystocallC/C++fromRuby!
Reply Share
RafaelBarbolo ayearago
Thebenchmarksresultsareweird,theyarenotwhatI'dexpect.ButIlikedthecomparisons
intermsofusage.
Reply Share
Wanttogetintouch?Dropusaline!
Yourname...
Youremailaddress...
Yourmessage
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
7/8
7/25/2015
CallingC/C++fromRuby
Sendyourmessage
Hubertepicki
[email protected]
hubert.lepicki
+48694161264
WojciechPiekutowski
[email protected]
w.piekutowski
+48696152570
About
Blog
Workforus
Rubyprogramming
JavaScriptprogramming
Mobileprogramming
ul.Ksawerw302656Warszawa,Poland
ul.Hetmaska3615727Biaystok,Poland
AmberBit
AmberBitSp.zo.o.jestwpisanadoRejestruPrzedsibiorcwKrajowegoRejestruSdowego
prowadzonegoprzezSdRejonowywBiaymstoku,XIIWydziaGospodarczyKrajowegoRejestru
Sdowego.Kapitazakadowy20000,00zopaconywcaoci.
EUVAT:PL5423228204,NIP:5423228204,KRS:0000439100,REGON:200741641
Weusecookiesonthiswebsiteforanalyticsandtoidentifyuserswhopostcommentsonourblog.
2012AmberBitSp.zo.o.
https://www.amberbit.com/blog/2014/6/12/callingccppfromruby/
8/8