Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of...

75
1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.4.3 1.5 1.5.1 1.5.2 1.6 1.6.1 1.6.2 1.6.3 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.5.3 Table of Contents An Introduction to M odern CM ake Installing CM ake Running CM ake Dos and Don'ts What's new in CMake Introduction to the Basics Variables and the Cache Programming in CM ake Communicating with your code How to Structure Your Project Running Other Programs A Simp le Examp le Adding Features C++11 and Beyond Small but common needs Utilities Useful modules IDEs Debugging Including Projects Submodule DownloadProject Fetch (CM ake 3.11) Testing GoogleTest Catch Exporting and Installing Installing Exporting Packaging Looking for libraries CUDA OpenMP Boost MPI ROOT UseFile Examp le Simp le Examp le Dictionary Example 1

Transcript of Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of...

Page 1: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

1.1

1.1.1

1.1.2

1.1.3

1.1.4

1.2

1.2.1

1.2.2

1.2.3

1.2.4

1.2.5

1.2.6

1.3

1.3.1

1.3.2

1.3.3

1.3.4

1.3.5

1.3.6

1.4

1.4.1

1.4.2

1.4.3

1.5

1.5.1

1.5.2

1.6

1.6.1

1.6.2

1.6.3

1.7

1.7.1

1.7.2

1.7.3

1.7.4

1.7.5

1.7.5.1

1.7.5.2

1.7.5.3

TableofContentsAnIntroductiontoModernCMake

InstallingCMake

RunningCMake

DosandDon'ts

What'snewinCMake

IntroductiontotheBasics

VariablesandtheCache

ProgramminginCMake

Communicatingwithyourcode

HowtoStructureYourProject

RunningOtherPrograms

ASimpleExample

AddingFeatures

C++11andBeyond

Smallbutcommonneeds

Utilities

Usefulmodules

IDEs

Debugging

IncludingProjects

Submodule

DownloadProject

Fetch(CMake3.11)

Testing

GoogleTest

Catch

ExportingandInstalling

Installing

Exporting

Packaging

Lookingforlibraries

CUDA

OpenMP

Boost

MPI

ROOT

UseFileExample

SimpleExample

DictionaryExample

1

Page 2: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

1.7.6Minuit2

2

Page 3: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

AnIntroductiontoModernCMakePeoplelovetohatebuildsystems.JustwatchthetalksfromCppCon17toseeexamplesofdevelopersmakingthestateofbuildsystemsthebruntofjokes.Thisraisesthequestion:Why?Certainlytherearenoshortageofproblemswhenbuilding.ButIthinkthat,in2020,wehaveaverygoodsolutiontoquiteafewofthoseproblems.It'sCMake.NotCMake2.8though;thatwasreleasedbeforeC++11evenexisted!NorthehorribleexamplesoutthereforCMake(eventhosepostedonKitWare'sowntutorialslist).I'mtalkingaboutModernCMake.CMake3.1+,maybeevenCMake3.17+!It'sclean,powerful,andelegant,soyoucanspendmostofyourtimecoding,notaddinglinestoanunreadable,unmaintainableMake(OrCMake2)file.AndCMake3.11+issupposedtobesignificantlyfaster,aswell!

Thisbookismeanttobealivingdocument.YoucanraiseanissueorputinamergerequestonGitLab.YoucanalsodownloadacopyasaPDF.

Inshort,herearethemostlikelyquestionsinyourmindifyouareconsideringModernCMake:

WhydoIneedagoodbuildsystem?Doanyofthefollowingapplytoyou?

Youwanttoavoidhard-codingpathsYouneedtobuildapackageonmorethanonecomputerYouwanttouseCI(continuousintegration)YouneedtosupportdifferentOSs(maybeevenjustflavorsofUnix)YouwanttosupportmultiplecompilersYouwanttouseanIDE,butmaybenotallofthetimeYouwanttodescribehowyourprogramisstructuredlogically,notflagsandcommandsYouwanttousealibraryYouwanttousetools,likeClang-Tidy,tohelpyoucodeYouwanttouseadebugger

Ifso,you'llbenefitfromaCMake-likebuildsystem.

WhymusttheanswerbeCMake?Buildsystemsisahottopic.Ofcoursetherearemanyoptions.Butevenareallygoodone,oronethatre-usesafamiliarsyntax,can'tcomeclosetoCMake.Why?Support.EveryIDEsupportsCMake(orCMakesupportsthatIDE).MorepackagesuseCMakethananyothersystem.So,ifyouusealibrarythatisdesignedtobeincludedinyourcode,youhaveachoice:Makeyourownbuildsystem,oruseoneofoftheprovidedones,andthatwillalmostalwaysincludeCMake.Andthatwillquicklybethecommondenominatorifyouincludemultipleprojects.And,ifyouneedalibrarythat'spreinstalled,thechancesofithavingafindCMakescriptorconfigCMakescriptareexcellent.

WhyuseaModernCMake?AroundCMake2.6-2.8,CMakestartedtakingover.ItwasinmostofthepackagemanagersforLinuxOS's,andwasbeingusedinlotsofpackages.

ThenPython3cameout.

Iknow,thisshouldhavenothingwhatsoevertodowithCMake.

AnIntroductiontoModernCMake

3

Page 4: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Butithada3.Anditfollowed2.Anditwasahard,ugly,transitionthatisstillongoinginsomeplaces,eventoday.

IbelievethatCMake3hadthebadlucktofollowPython3. EventhougheveryversionofCMakeisinsanelybackwardcompatible,the3serieswastreatedasifitwassomethingnew.Andso,you'llfindOS'slikeCentOS7withGCC4.8,withalmost-completeC++14support,andCMake2.8,whichcameoutbeforeC++11.

YoureallyshouldatleastuseaversionofCMakethatcameoutafteryourcompiler,sinceitneedstoknowcompilerflags,etc,forthatversion.And,sinceCMakewilldumbitselfdowntotheminimumrequiredversioninyourCMakefile,installinganewCMake,evensystemwide,isprettysafe.Youshouldatleastinstallitlocally.It'seasy(1-2linesinmanycases),andyou'llfindthat5minutesofworkwillsaveyouhundredsoflinesandhoursofCMakeLists.txtwriting,andwillbemucheasiertomaintaininthelongrun.

Thisbooktriestosolvetheproblemofthepoorexamplesandbestpracticesthatyou'llfindproliferatingtheweb.

Othersources

Othermaterialfromtheoriginalauthorofthisbook:

CMakeWorkshopInteractiveModernCMaketalk

Therearesomeotherplacestofindgoodinformationontheweb.Herearesomeofthem:

Theofficialhelp:Reallyamazingdocumentation.Nicelyorganized,greatsearch,andyoucantoggleversionsatthetop.Itjustdoesn'thaveagreat"bestpracticestutorial",whichiswhatthisbooktriestofillin.EffectiveModernCMake:Agreatlistofdo'sanddon'ts.EmbracingModernCMake:ApostwithgooddescriptionofthetermIt'stimetodoCMakeRight:AnicesetofbestpracticesforModernCMakeprojects.TheUltimateGuidetoModernCMake:Aslightlydatedpostwithsimilarintent.MoreModernCMake:AgreatpresentationfromMeetingC++2018thatrecommendsCMake3.12+.ThistalkmakescallsCMake3.0+"ModernCMake"andCMake3.12+"MoreModernCMake".OhNo!MoreModernCMake:ThesequeltoMoreModernCMake.toeb/moderncmake:AnicepresentationandexamplesaboutCMake3.5+,withintrotosyntaxthroughprojectorganization

Credits

ModernCMakewasoriginallywrittenbyHenrySchreiner.OthercontributorscanbefoundlistedonGitLab.

.CMake3.0alsoremovedseverallongdeprecatedfeaturesfromveryoldversionsofCMakeandmakeoneverytinybackwardsincompatiblechangetosyntaxrelatedtosquarebrackets,sothisisnotentirelyfair;theremightbesomevery,veryoldCMakefilesthatwouldstopworkingwith3.I'veneverseenone,though.↩

1

1

AnIntroductiontoModernCMake

4

Page 5: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

InstallingCMake

YourCMakeversionshouldbenewerthanyourcompiler.Itshouldbenewerthanthelibrariesyouareusing(especiallyBoost).Newversionsworkbetterforeveryone.

IfyouhaveabuiltincopyofCMake,itisn'tspecialorcustomizedforyoursystem.Youcaneasilyinstallanewoneinstead,eitheronthesystemlevelortheuserlevel.FeelfreetoinstructyourusershereiftheycomplainaboutaCMakerequirementbeingsettoohigh.Especiallyiftheywant<3.1support.MaybeeveniftheywantCMake<3.17support...

Quicklist(moreinfooneachmethodbelow)

Orderedbyauthorpreference:

AllPip(official,sometimesdelayedslightly)Anaconda/Conda-Forge

WindowsChocolateyScoopMSYS2Downloadbinary(official)

MacOSHomebrewMacPortsDownloadbinary(official)

LinuxSnapcraft(official)APTrepository(Ubuntu/Debianonly)(official)Downloadbinary(official)

OfficialpackageYoucandownloadCMakefromKitWare.ThisishowyouwillprobablygetCMakeifyouareonWindows.It'snotabadwaytogetitonmacOSeither,butusingbrewinstallcmakeismuchnicerifyouuseHomebrew(andyoushould).Youcanalsogetitonmostotherpackagemanagers,suchasChocolateyforWindowsorMacPortsformacOS.

OnLinux,thereareseveraloptions.KitwareprovidesaDebian/Ubunutuaptrepository,aswellassnappackages.ThereareuniversalLinuxbinariesprovided,butyou'llneedtopickaninstalllocation.Ifyoualreadyuse~/.localforuser-spacepackages,thefollowingsinglelinecommand willgetCMakeforyou :

IfyoujustwantalocalfolderwithCMakeonly:

1 2

~$wget-qO-"https://cmake.org/files/v3.17/cmake-3.17.0-Linux-x86_64.tar.gz"|tar--

strip-components=1-xz-C~/.local

~$mkdir-pcmake-3.17&&wget-qO-"https://cmake.org/files/v3.17/cmake-3.17.0-Linux-

x86_64.tar.gz"|tar--strip-components=1-xz-Ccmake-3.17

~$exportPATH=`pwd`/cmake-3.17/bin:$PATH

InstallingCMake

5

Page 6: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

You'llobviouslywanttoappendtothePATHeverytimeyoustartanewterminal,oraddittoyour.bashrcortoanLModsystem.

And,ifyouwantasysteminstall,installto/usr/local;thisisanexcellentchoiceinaDockercontainer,forexampleonGitLabCI.Donottryitonanon-containerizedsystem.

Ifyouareonasystemwithoutwget,replacewget-qO-withcurl-s.

YoucanalsobuildCMakeonanysystem,it'sprettyeasy,butbinariesarefaster.

CMakeDefaultVersions

HerearesomecommonbuildenvironmentsandtheCMakeversionyou'llfindonthem.FeelfreetoinstallCMakeyourself,it's1-2linesandthere'snothing"special"aboutthebuiltinversion.It'salsoverybackwardcompatible.

Windows

AlsoScoopisgenerallyuptodate.ThenormalinstallersfromCMake.orgarecommononWindows,too.

MacOS

HomebrewisquiteabitmorepopularnowadaysonmacOS,atleastaccordingtoGoogleTrends.

Linux

RHEL/CentOS

Thedefaulton8isnottoobad,butyoushouldnotusethedefaulton7.UsetheEPELpackageinstead.

Ubuntu

YoushouldonlyusethedefaultCMakeon18.04+;it'sanLTSreleasewithaprettydecentminimumversion!

Other

Generaltools

docker$wget-qO-"https://cmake.org/files/v3.17/cmake-3.17.0-Linux-x86_64.tar.gz"|tar

--strip-components=1-xz-C/usr/local

InstallingCMake

6

Page 8: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

InstallingCMake

8

Page 9: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Alsoseepkgs.org/download/cmake.

Pip

Thisisalsoprovidedasanofficialpackage,maintainedbytheauthorsofCMakeatKitWare.It'sarathernewmethod,andmightfailonsomesystems(Alpineisn'tsupportedlastIchecked,butthathasCMake3.8),butworksreallywellwhenitworks(likeonTravisCI).Ifyouhavepip(Python'spackageinstaller),youcando:

Andaslongasabinaryexistsforyoursystem,you'llbeup-and-runningalmostimmediately.Ifabinarydoesn'texist,itwilltrytouseKitWare'sscikit-buildpackagetobuild,whichcurrentlycan'tbelistedasadependencyinthepackagingsystem,andmightevenrequire(anolder)copyofCMaketobuild.Soonlyusethissystemifbinariesexist,whichismostofthetime.

Thishasthebenefitofrespectingyourcurrentvirtualenvironment,aswell.

Personally,onLinux,IputversionsofCMakeinfolders,like/opt/cmake312or~/opt/cmake312,andthenaddthemto[LMod].Seeenvmodule_setupforhelpsettingupanLModsystemonmacOSorLinux.Ittakesabittolearn,butisagreatwaytomanagepackageandcompilerversions.

.Iassumethisisobvious,butyouaredownloadingandrunningcode,whichexposesyoutoamaninthemiddleattack.Ifyouareinacriticalenvironment,youshoulddownloadthefileandcheckthechecksum.(And,no,simplydoingthisintwostepsdoesnotmakeyouanysafer,onlyachecksumissafer).↩

.Ifyoudon'thavea.localinyourhomedirectory,it'seasytostart.Justmakethefolder,thenaddexportPATH="$HOME/.local/bin:$PATH"toyour.bashrcor.bash_profileor.profilefileinyourhomedirectory.Nowyoucaninstallanypackagesyoubuildto-DCMAKE_INSTALL_PREFIX=~/.localinsteadof/usr/local!↩

gitbook$pipinstallcmake

1

2

InstallingCMake

9

Page 10: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

RunningCMakeBeforewritingCMake,let'smakesureyouknowhowtorunittomakethings.ThisistrueforalmostallCMakeprojects,whichisalmosteverything.

Buildingaproject

Unlessotherwisenoted,youshouldalwaysmakeabuilddirectoryandbuildfromthere.Youcantechnicallydoanin-sourcebuild,butyou'llhavetobecarefulnottooverwritefilesoraddthemtogit,sojustdon't.

Here'stheClassicCMakeBuildProcedure(TM):

Youcanreplacethemakelinewithcmake--build.ifyou'dlike,anditwillcallmakeorwhateverbuildtoolyouareusing.IfyouareusinganewerversionofCMake(whichyouusuallyshouldbe,exceptforcheckingcompatibilitywitholderCMake),youcaninsteaddothis:

Anyoneofthesecommandswillinstall:

Sosetofmethodsshouldyouuse?Aslongasyoudonotforgettotypethebuilddirectoryastheargument,stayingoutofthebuilddirectoryisshorter,andmakingsourcechangesiseasierfromthesourcedirectory.Youshouldtrytogetusedtousing--build,asthatwillfreeyoufromusingonlymaketobuild.Notethatworkingfromthebuilddirectoryishistoricallymuchmorecommon,andsometoolsandcommands(includingCTest)stillrequirerunningfromthebuilddirectory.

Justtoclarify,youcanpointCMakeateitherthesourcedirectoryfromthebuilddirectory,oratanexistingbuilddirectoryfromanywhere.

Ifyouusecmake--buildinsteadofdirectlycallingtheunderlyingbuildsystem,youcanuse-vforverbosebuilds(CMake3.14+),-jNforparallelbuildsonNcores(CMake3.12+),and--target(anyversionofCMake)or-t(CMake3.15+)topickatarget.Otherwise,thesecommandsvarybetweenbuildsystems,suchasVERBOSE=1makeandninja-v.

Pickingacompiler

~/package$mkdirbuild

~/package$cdbuild

~/package/build$cmake..

~/package/build$make

~/package$cmake-S.-Bbuild

~/package$cmake--buildbuild

#Fromthebuilddirectory(pickone)

~/package/build$makeinstall

~/package/build$cmake--build.--targetinstall

~/package/build$cmake--install.#CMake3.15+only

#Fromthesourcedirectory(pickone)

~/package$cmake--buildbuild--targetinstall

~/package$cmake--installbuild#CMake3.15+only

RunningCMake

10

Page 11: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Selectingacompilermustbedoneonthefirstruninanemptydirectory.It'snotCMakesyntaxperse,butyoumightnotbefamiliarwithit.TopickClang:

ThatsetstheenvironmentvariablesinbashforCCandCXX,andCMakewillrespectthosevariables.Thissetsitjustforthatoneline,butthat'stheonlytimeyou'llneedthose;afterwardsCMakecontinuestousethepathsitdeducesfromthosevalues.

PickingageneratorYoucanbuildwithavarietyoftools;makeisusuallythedefault.ToseeallthetoolsCMakeknowsaboutonyoursystem,run

Andyoucanpickatoolwith-G"MyTool"(quotesonlyneededifspacesareinthetoolname).YoushouldpickatoolonyourfirstCMakecallinadirectory,justlikethecompiler.Feelfreetohaveseveralbuilddirectories,likebuild/andbuildXcode.YoucansettheenvironmentvariableCMAKE_GENERATORtocontrolthedefaultgenerator(CMake3.15+).Notethatmakefileswillonlyruninparallelifyouexpliciltypassanumberofthreads,suchasmake-j2,whileNinjawillautomaticallyruninparallel.Youcandirectlypassaparallelizationoptionsuchas-j2tothecmake--build.commandinrecentversionsofCMake.

Settingoptions

YousetoptionsinCMakewith-D.Youcanseealistofoptionswith-L,oralistwithhuman-readablehelpwith-LH.Ifyoudon'tlistthesource/builddirectory,thelistingwillnotrerunCMake(cmake-Linsteadofcmake-L.).

Verboseandpartialbuilds

Again,notreallyCMake,butifyouareusingacommandlinebuildtoollikemake,youcangetverbosebuilds:

YoucanactuallywritemakeVERBOSE=1,andmakewillalsodotherightthing,thoughthat'safeatureofmakeandnotthecommandlineingeneral.

Youcanalsobuildjustapartofabuildbyspecifyingatarget,suchasthenameofalibraryorexecutableyou'vedefinedinCMake,andmakewilljustbuildthattarget.

Options

CMakehassupportforcachedoptions.AVariableinCMakecanbemarkedas"cached",whichmeansitwillbewrittentothecache(afilecalledCMakeCache.txtinthebuilddirectory)whenitisencountered.Youcanpreset(orchange)thevalueofacachedoptiononthecommandlinewith-D.WhenCMakelooksforacachedvariable,itwillusetheexistingvalueandwillnotoverwriteit.

Standardoptions

ThesearecommonCMakeoptionstomostpackages:

-DCMAKE_BUILD_TYPE=PickfromRelease,RelWithDebInfo,Debug,orsometimesmore.-DCMAKE_INSTALL_PREFIX=Thelocationtoinstallto.SysteminstallonUNIXwouldoftenbe/usr/local(thedefault),userdirectoriesareoften~/.local,oryoucanpickafolder.

~/package/build$CC=clangCXX=clang++cmake..

~/package/build$cmake--help

~/package/build$VERBOSE=1make

RunningCMake

11

Page 12: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

-DBUILD_SHARED_LIBS=YoucansetthisONorOFFtocontrolthedefaultforsharedlibraries(theauthorcanpickonevs.theotherexplicitlyinsteadofusingthedefault,though)-DBUILD_TESTING=Thisisacommonnameforenablingtests,notallpackagesuseit,though,sometimeswithgoodreason.

DebuggingyourCMakefiles

We'vealreadymentionedverboseoutputforthebuild,butyoucanalsoseeverboseCMakeconfigureoutputtoo.The--traceoptionwillprinteverylineofCMakethatisrun.Sincethisisveryverbose,CMake3.7added--trace-source="filename",whichwillprintouteveryexecutedlineofjustthefileyouareinterestedinwhenitruns.Ifyouselectthenameofthefileyouareinterestedindebugging(usuallybyselectingtheparentdirectorywhendebuggingaCMakeLists.txt,sinceallofthosehavethesamename),youcanjustseethelinesthatruninthatfile.Veryuseful!

RunningCMake

12

Page 13: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Do'sandDon'ts

CMakeAntipatterns

ThenexttwolistsareheavilybasedontheexcellentgistEffectiveModernCMake.Thatlistismuchlongerandmoredetailed,feelfreetoreaditaswell.

Donotuseglobalfunctions:Thisincludeslink_directories,include_libraries,andsimilar.Don'taddunneededPUBLICrequirements:Youshouldavoidforcingsomethingonusersthatisnotrequired(-Wall).MakethesePRIVATEinstead.Don'tGLOBfiles:MakeoranothertoolwillnotknowifyouaddfileswithoutrerunningCMake.NotethatCMake3.12addsaCONFIGURE_DEPENDSflagthatmakesthisfarbetterifyouneedtouseit.Linktobuiltfilesdirectly:Alwayslinktotargetsifavailable.NeverskipPUBLIC/PRIVATEwhenlinking:Thiscausesallfuturelinkingtobekeyword-less.

CMakePatternsTreatCMakeascode:Itiscode.Itshouldbeascleanandreadableasallothercode.Thinkintargets:Yourtargetsshouldrepresentconcepts.Makean(IMPORTED)INTERFACEtargetforanythingthatshouldstaytogetherandlinktothat.Exportyourinterface:Youshouldbeabletorunfrombuildorinstall.WriteaConfig.cmakefile:Thisiswhatalibraryauthorshoulddotosupportclients.MakeALIAStargetstokeepusageconsistent:Usingadd_subdirectoryandfind_packageshouldprovidethesametargetsandnamespaces.Combinecommonfunctionalityintoclearlydocumentedfunctionsormacros:Functionsarebetterusually.Uselowercasefunctionnames:CMakefunctionsandmacroscanbecalledloweroruppercase.Alwaysuserlowercase.Uppercaseisforvariables.Usecmake_policyand/orrangeofversions:Policieschangeforareason.OnlypiecemealsetOLDpoliciesifyouhaveto.

DosandDon'ts

13

Page 14: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

What'snewininCMakeThisisanabbreviatedversionoftheCMakechanglogwithjustthehighlightsforauthors.Namesforeachreleasearearbitrarilypickedbytheauthor.

CMake3.0:Interfacelibraries

TherewereatonofadditionstothisversionofCMake,primarilytofilloutthetargetinterface.SomebitsofneededfunctionalityweremissedandimplementedinCMake3.1instead.

NewdocumentationINTERFACElibrariesProjectVERSIONsupportExportingbuildtreeseasilyBracketargumentsandcommentsavailable(notwidelyused)Lotsofimprovements

CMake3.1:C++11andcompilefeatures

ThisisthefirstreleaseofCMaketosupportC++11.CombinedwithfixestothenewfeaturesofCMake3.0,thisiscurrentlyacommonminimumversionofCMakeforlibrariesthatwanttosupportoldCMakebuilds.

C++11SupportCompilefeaturessupportSourcescanbeaddedlaterwithtarget_sourcesBettersupportforgeneratorexpressionsandINTERFACEtargets

CMake3.2:UTF8Thisisasmallerrelease,withmostlysmallfeaturesandfixes.Internalchanges,likebetterWindowsandUTF8support,werethefocus.

continue()insideloopsFileanddirectorylocksadded

CMake3.3:ifIN_LIST

ThisisnotablefortheusefulIN_LISToptionforif,butitalsoaddedbetterlibrarysearchusing$PATH(SeeCMake3.6),dependenciesforINTERFACElibraries,andseveralotherusefulimprovements.TheadditionofaCOMPILE_LANGUAGEgeneratorexpressionwouldproveveryusefulinthefutureasmorelanguagesareadded.Makefilesnowproducebetteroutputinparallel.

IN_LISTaddedtoif*_INCLUDE_WHAT_YOU_USEpropertyaddedCOMPILE_LANGUAGEgeneratorexpression(limitedsupportinsomegenerators)

CMake3.4:Swift&CCacheThisreleaseaddslotsofusefultools,supportfortheSwiftlanguage,andtheusualimprovements.Italsostartedsupportingcompilerlaunchers,likeCCache.

AddedSwiftlanguage

What'snewinCMake

14

Page 15: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

AddedBASE_DIRtoget_filename_componentif(TEST...)addedstring(APPEND...)addedCMAKE_*_COMPILER_LAUNCHERaddedformakeandninjaTARGET_MESSAGESallowmakefilestoprintmessagesaftertargetiscompletedImportedtargetsarebeginningtoshowupintheofficialFind*.cmakefiles

CMake3.5:ARM

ThisreleaseexpandedCMaketomoreplatforms,andmakewarningseasiertocontrolfromthecommandline.

Multipleinputfilessupportedforseveralofthecmake-Ecommands.cmake_parse_argumentsnowbuiltinBoost,GTest,andmorenowsupportimportedtargetsARMCCnowsupported,bettersupportforiOSXCodebackslashfix

CMake3.6:Clang-Tidy

ThisreleaseaddedClang-Tidysupport,alongwithmoreutilitiesandimprovements.Italsoremovedthesearchof$PATHonUnixsystemsduetoproblems,insteadusersshoulduse$CMAKE_PREFIX_PATH.

EXCLUDE_FROM_ALLforinstalllist(FILTERaddedCMAKE_*_STANDARD_INCLUDE_DIRECTORIESandCMAKE_*_STANDARD_LIBRARIESaddedfortoolchainsTry-compileimprovements*_CLANG_TIDYpropertyaddedExternalprojectscannowbeshallowclones,andotherimprovements

CMake3.7:Android&CMakeServerYoucannowcross-compiletoAndroid.Usefulnewifstatementoptionsreallyhelpclarifycode.AndthenewservermodewassupposedtoimproveintegrationwithIDEs(butisbeingreplacedbyadifferentsysteminCMake3.14+).SupportfortheVIMeditorwasalsoimproved.

PARSE_ARGVmodeforcmake_parse_argumentsBetter32-bitsupporton64-bitmachinesLotsofusefulnewifcomparisons,likeVERSION_GREATER_EQUAL(really,whydidittakethislong?)LINK_WHAT_YOU_USEaddedLotsofcustompropertiesrelatedtofilesanddirectoriesCMakeServeraddedAdded--trace-source="filename"tomonitorcertainfilesonly

CMake3.8:C#&CUDA

ThisaddsCUDAasalanguage,aswellascxx_std_11asacompilermeta-feature.ThenewgeneratorexpressioncouldbereallyusefulifyoucanrequireCMake3.8+!

NativesupportforC#asalanguageNativesupportforCUDAasalanguageMetafeaturescxx_std_11(and14,17)addedtry_compilehasbetterlanguagesupport

What'snewinCMake

15

Page 16: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

BUILD_RPATHpropertyaddedCOMPILE_FLAGSnowsupportsgeneratorexpression*_CPPLINTadded$<IF:cond,true-value,false-value>added(wow!)source_group(TREEadded(finallyallowingIDE'storeflecttheprojectfolderstructure!)

CMake3.9:IPO

LotsoffixestoCUDAsupportwentintothisrelease,includingPTXsupportandMSVCgenerators.InterproceduralOptimizationsarenowsupportedproperly.Evenmoremodulesprovideimportedtargets,includingMPI.

CUDAsupportedforWindowsBetterobjectlibrarysupportinseveralsituationsDESCRIPTIONaddedtoprojectseparate_argumentsgetsNATIVE_COMMANDINTERPROCEDURAL_OPTIMIZATIONenforced(andCMAKE_*initializeradded,CheckIPOSupportedadded,ClangandGCCsupport)NewGoogleTestmoduleFindDoxygendrasticallyimproved

CMake3.10:CppCheck

CMakenowisbuiltwithC++11compilers.Lotsofusefulimprovementshelpwritecleanercode.

SupportforflangFortrancompilerCompilerlauncheraddedtoCUDAIndented#cmakedefinesnowsupportedforconfigure_fileinclude_guard()addedtoensureafilegetsincludedonlyoncestring(PREPENDadded*_CPPCHECKpropertyaddedLABELSaddedtodirectoriesFindMPIvastlyexpandedFindOpenMPimprovedDynamictestdiscoveryforGoogleTest

CMake3.11:Faster&IMPORTEDINTERFACEThisreleaseissupposedtobemuchfaster.YoucanalsofinallydirectlyaddINTERFACEtargetstoIMPORTEDlibraries(theinternalFind*.cmakescriptsshouldbecomemuchcleanereventually).

FortransupportscompilerlaunchersXcodeandVisualStudiosupportCOMPILE_LANGUAGEgeneratorexpressionsfinallyYoucannowaddINTERFACEtargetsdirectlytoIMPORTEDINTERFACElibraries(Wow!)SourcefilepropertieshavebeenexpandedFetchContentmodulenowallowsdownloadstohappenatconfiguretime(Wow)

CMake3.12:VersionrangesandCONFIGURE_DEPENDS

Verypowerfulrelease,containinglotsofsmallerlong-requestedfeatures.Oneofthesmallerbutimmediatelynoticeablechangesistheadditionofversionranges;youcannowsetboththeminimumandmaximumknownCMakeversioneasily.YoucanalsosetCONFIGURE_DEPENDSonaGLOBedsetoffiles,andthebuildsystemwillcheckthosefilesandrerunifneeded!YoucanusethegeneralPackageName_ROOTforallfind_packagesearches.Lotsofadditionstostringsandlists,moduleupdates,shinynewPythonfindmodule(2and3versionstoo),andmanymore.

What'snewinCMake

16

Page 17: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Supportforcmake_minimum_requiredranges(backwardcompatible)Supportfor-j,--parallelin--buildmode(passedontobuildtool)SupportforSHELL:stringsincompileoptions(notdeduplicated)NewFindPythonmodulestring(JOINandlist(JOIN,andlist(TRANSFORMfile(TOUCHandfile(GLOBCONFIGURE_DEPENDSC++20supportCUDAasalanguageimprovements:CUDA7and7.5nowsupportedSupportforOpenMPonmacOS(commandlineonly)SeveralnewpropertiesandpropertyinitializersCPackfinallyreadsCMAKE_PROJECT_VERSIONvariables

CMake3.13:Linkingcontrol

YoucannowmakesymboliclinksonWindows!LotsofnewfunctionsthatfilloutthepopularrequestsforCMake,suchasadd_link_options,target_link_directories,andtarget_link_options.Youcannowdoquiteabitmoremodificationtotargetsoutsideofthesourcedirectory,forbetterfileseparation.And,target_sourcesfinallyhandlesrelativepathsproperly(policy76).

Newctest--progressoptionforliveoutputtarget_link_optionsandadd_link_optionsaddedtarget_link_directoriesaddedSymboliclinkcreation,-Ecreate_symlink,supportedonWindowsIPOsupportedonWindowsYoucanuse-Sand-Bforsourceandbuilddirectoriestarget_link_librariesandinstallworkoutsidethecurrenttargetdirectorySTATIC_LIBRARY_OPTIONSpropertyaddedtarget_sourcesisnowrelativetothecurrentsourcedirectory(CMP0076)IfyouuseXcode,younowcanexperimentallysetschemafields

CMake3.14:Fileutilities(AKACMakeπ)

Thisreleasehaslotsofsmallcleanups,includingseveralutilitiesforfiles.Generatorexpressionsworkinafewmoreplaces,andlisthandlingisbetterwithemptyvariables.Quiteafewmorefindpackagesproducetargets.ThenewVisualStudio162019generatorisabitdifferentthanolderversions.WindowsXPandVistasupporthasbeendropped.

Thecmake--buildcommandgained-v/--verbose,touseverbosebuildsifyourbuildtoolsupportsitTheFILEcommandgainedCREATE_LINK,READ_SYMLINK,andSIZEget_filename_componentgainedLAST_EXTandNAME_WLEtoaccessjustthelastextensiononafile,whichwouldget.ziponafilesuchasversion.1.2.zip(veryhandy!)YoucanseeifavariableisdefinedintheCACHEwithDEFINEDCACHE{VAR}inanifstatement.BUILD_RPATH_USE_ORIGINandCMakeversionwereaddedtoimprovehandlingofRPathinthebuilddirectory.TheCMakeservermodeisnowbeingreplacedwithafileAPI,startinginthisrelease.WillaffectIDEsinthelongrun.

CMake3.15:CLIupgradeThisreleasehasmanysmallerpolishingchanges,includeseveralofimprovementstotheCMakecommandline,suchascontroloverthedefaultgeneratorthroughenvironmentvariables(sonowit'seasytochangethedefaultgeneratortoNinja).Multipletargetsaresupportedin--buildmode,and--installmodeadded.CMakefinallysupportsmultiplelevelsoflogging.Generatorexpressionsgainedafewhandytools.ThestillverynewFindPythonmodulecontinuestoimprove,andFindBoostisnowmoreinlinewithBoost1.70'snewCONFIGmodule.export(PACKAGE)hasdrasticallychanged;itnownolongertouches$HOME/.cmakebydefault(ifCMakeMinimumversionis3.15orhigher),andrequiresanextrastepifauserwantstouseit.Thisisgenerallylesssurprising.

What'snewinCMake

17

Page 18: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

CMAKE_GENERATORenvironmentvariableaddedtocontroldefaultgeneratorMultipletargetsupportinbuildmode,cmake.--build--targetabShortcut-tfor--targetInstallsupport,cmake.--install,doesnotinvokethebuildsystemSupportfor--loglevelandNOTICE,VERBOSE,DEBUG,andTRACEformessageThelistcommandgainedPREPEND,POP_FRONT,andPOP_BACKexecute_processgainedCOMMAND_ECHOoption(CMAKE_EXECUTE_PROCESS_COMMAND_ECHO)allowsyoutoautomaticallyechocommandsbeforerunningthemSeveralNinjaimprovements,includeSWIFTlanguagesupportCompilerandlistimprovementstogeneratorexpressions

CMake3.16:Unitybuilds

Anewunitybuildmodewasadded,allowingsourcefilestobemergedintoasinglebuildfile.Supportforprecompiledheaders(possiblypreparingforC++20modules,perhaps?)wasadded.Lotsofothersmallerfixeswereimplemented,especiallytonewerfeatures,suchastoFindPython,FindDoxygen,andothers.

AddedsupportforObjectiveCandObjectiveC++languagesSupportforprecompilingheaders,withtarget_precompile_headersSupportfor"Unity"or"Jumbo"builds(mergingsourcefiles)withCMAKE_UNITY_BUILDCTest:Cannowskipbasedonregex,expandlistsSeveralnewfeaturestocontrolRPath.Generatorexpressionsworkinmoreplaces,likebuildandinstallpathsFindlocationscannowbeexplicitlycontrolledthroughnewvariables

CMake3.17:MoreCUDA

AFindCUDAToolkitwasfinallyadded,whichallowsfindingandusingtheCUDAtoolkitwithoutenablingtheCUDAlanguage!CUDAnowisabitmoreconfigurable,suchaslinkingtosharedlibraries.Quiteabitmorepolishintheexpectedareas,aswell,likeFindPython.Finally,youcannowiterateovermultiplelistsatatime.

CUDA_RUNTIME_LIBRARYcanfinallybesettoShared!FindCUDAToolkitfinallyaddedcmake-ErmreplacesolderremovecommandsCUDAhasmetafeatureslikecuda_std_03,etc.Youcantrackthesearchesforpackageswith--debug-findExternalProjectcannowdisablerecursivecheckoutsFindPythonbetterintegrationwithCondaDEPRECATIONcanbeappliedtotargetsCMakegainedarmcommandSeveralnewenvironmentvariablesforeachcannowdoZIP_LISTS(multiplelistsatatime)

What'snewinCMake

18

Page 19: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Introductiontothebasics

MinimumVersion

Here'sthefirstlineofeveryCMakeLists.txt,whichistherequirednameofthefileCMakelooksfor:

cmake_minimum_required(VERSION3.1)

Let'smentionabitofCMakesyntax.Thecommandnamecmake_minimum_requirediscaseinsensitive,sothecommonpracticeistouselowercase. TheVERSIONisaspecialkeywordforthisfunction.Andthevalueoftheversionfollowsthekeyword.Likeeverywhereinthisbook,justclickonthecommandnametoseetheofficialdocumentation,andusethedropdowntoswitchdocumentationbetweenCMakeversions.

Thislineisspecial! TheversionofCMakewillalsodictatethepolicies,whichdefinebehaviorchanges.So,ifyousetminimum_requiredtoVERSION2.8,you'llgetthewronglinkingbehavioronmacOS,forexample,eveninthenewestCMakeversions.Ifyousetitto3.3orless,you'llgetthewronghiddensymbolsbehaviour,etc.Alistofpoliciesandversionsisavailableatpolicies.

InCMake3.12,thiswillsupportarange,suchasVERSION3.1...3.12;thismeansyousupportaslowas3.1buthavealsotesteditwiththenewpolicysettingsupto3.12.Thisismuchniceronusersthatneedthebettersettings,andduetoatrickinthesyntax,it'sbackwardcompatiblewitholderversionsofCMake(thoughactuallyrunningCMake3.2-3.11willonlysetthe3.1versionofthepoliciesinthisexample).NewversionsofpoliciestendtobemostimportantformacOSandWindowsusers,whoalsousuallyhaveaveryrecentversionofCMake.

Thisiswhatnewprojectsshoulddo:

cmake_minimum_required(VERSION3.1...3.15)

if(${CMAKE_VERSION}VERSION_LESS3.12)

cmake_policy(VERSION${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})

endif()

IfCMakeversionislessthan3.12,theifblockwillbetrue,andthepolicywillbesettothecurrentCMakeversion.IfCMakeis3.12orhigher,theifblockwillbefalse,butthenewsyntaxincmake_minimum_requiredwillberespectedandthiswillcontinuetoworkproperly!

WARNING:MSVC'sCMakeservermodeoriginallyhadabuginreadingthisformat,soifyouneedtosupportnon-commandlineWindowsbuildsforolderMSVCversions,youwillwanttodothisinstead:

cmake_minimum_required(VERSION3.1)

if(${CMAKE_VERSION}VERSION_LESS3.15)

cmake_policy(VERSION${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})

else()

cmake_policy(VERSION3.15)

endif()

Ifyoureallyneedtosettoalowvaluehere,youcanusecmake_policytoconditionallyincreasethepolicylevelorsetaspecificpolicy.PleaseatleastdothisforyourmacOSusers!

Settingaproject

Now,everytop-levelCMakefilewillhavethenextline:

1

2

IntroductiontotheBasics

19

Page 20: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

project(MyProjectVERSION1.0

DESCRIPTION"Veryniceproject"

LANGUAGESCXX)

Nowweseeevenmoresyntax.Stringsarequoted,whitespacedoesn'tmatter,andthenameoftheprojectisthefirstargument(positional).Allthekeywordargumentshereareoptional.Theversionsetsabunchofvariables,likeMyProject_VERSIONandPROJECT_VERSION.ThelanguagesareC,CXX,Fortran,ASM,CUDA(CMake3.8+),CSharp(3.8+),andSWIFT(CMake3.15+experimental).CCXXisthedefault.InCMake3.9,DESCRIPTIONwasaddedtosetaprojectdescription,aswell.Thedocumentationforprojectmaybehelpful.

Youcanaddcommentswiththe#character.CMakedoeshaveaninlinesyntaxforcommentstoo,butitisrarelyneeded,aswhitespacedoesn'tmatter.

There'sreallynothingspecialabouttheprojectname.Notargetsareaddedatthispoint.

Makinganexecutable

Althoughlibrariesaremuchmoreinteresting,andwe'llspendmostofourtimewiththem,let'sstartwithasimpleexecutable.

add_executable(onetwo.cppthree.h)

Thereareseveralthingstounpackhere.oneisboththenameoftheexecutablefilegenerated,andthenameoftheCMaketargetcreated(you'llhearalotmoreabouttargetssoon,Ipromise).Thesourcefilelistcomesnext,andyoucanlistasmanyasyou'dlike.CMakeissmart,andwillonlycompilesourcefileextensions.Theheaderswillbe,formostintentsandpurposes,ignored;theonlyreasontolistthemistogetthemtoshowupinIDEs.TargetsshowupasfoldersinmanyIDEs.Moreaboutthegeneralbuildsystemandtargetsisavailableatbuildsystem.

MakingalibraryMakingalibraryisdonewithadd_library,andisjustaboutassimple:

add_library(oneSTATICtwo.cppthree.h)

Yougettopickatypeoflibrary,STATIC,SHARED,orMODULE.Ifyouleavethischoiceoff,thevalueofBUILD_SHARED_LIBSwillbeusedtopickbetweenSTATICandSHARED.

Asyou'llseeinthefollowingsections,oftenyou'llneedtomakeafictionaltarget,thatis,onewherenothingneedstobecompiled,forexample,foraheader-onlylibrary.ThatiscalledanINTERFACElibrary,andisanotherchoice;theonlydifferenceisitcannotbefollowedbyfilenames.

YoucanalsomakeanALIASlibrarywithanexistinglibrary,whichsimplygivesyouanewnameforatarget.Theonebenefittothisisthatyoucanmakelibrarieswith::inthename(whichyou'llseelater).

Targetsareyourfriend

Nowwe'vespecifiedatarget,howdoweaddinformationaboutit?Forexample,maybeitneedsanincludedirectory:

target_include_directories(onePUBLICinclude)

3

IntroductiontotheBasics

20

Page 21: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

target_include_directoriesaddsanincludedirectorytoatarget.PUBLICdoesn'tmeanmuchforanexecutable;foralibraryitletsCMakeknowthatanytargetsthatlinktothistargetmustalsoneedthatincludedirectory.OtheroptionsarePRIVATE(onlyaffectthecurrenttarget,notdependencies),andINTERFACE(onlyneededfordependencies).

Wecanthenchaintargets:

add_library(anotherSTATICanother.cppanother.h)

target_link_libraries(anotherPUBLICone)

target_link_librariesisprobablythemostusefulandconfusingcommandinCMake.Ittakesatarget(another)andaddsadependencyifatargetisgiven.Ifnotargetofthatname(one)exists,thenitaddsalinktoalibrarycalledoneonyourpath(hencethenameofthecommand).Oryoucangiveitafullpathtoalibrary.Oralinkerflag.Justtoaddafinalbitofconfusion,classicCMakeallowedyoutoskipthekeywordselectionofPUBLIC,etc.Ifthiswasdoneonatarget,you'llgetanerrorifyoutrytomixstylesfurtherdownthechain.

Focusonusingtargetseverywhere,andkeywordseverywhere,andyou'llbefine.

Targetscanhaveincludedirectories,linkedlibraries(orlinkedtargets),compileoptions,compiledefinitions,compilefeatures(seetheC++11chapter),andmore.Asyou'llseeinthetwoincludingprojectschapters,youcanoftengettargets(andalwaysmaketargets)torepresentallthelibrariesyouuse.Eventhingsthatarenottruelibraries,likeOpenMP,canberepresentedwithtargets.ThisiswhyModernCMakeisgreat!

DiveinSeeifyoucanfollowthefollowingfile.ItmakesasimpleC++11libraryandaprogramusingit.Nodependencies.I'lldiscussmoreC++standardoptionslater,usingtheCMake3.8systemfornow.

cmake_minimum_required(VERSION3.8)

project(CalculatorLANGUAGESCXX)

add_library(calclibSTATICsrc/calclib.cppinclude/calc/lib.hpp)

target_include_directories(calclibPUBLICinclude)

target_compile_features(calclibPUBLICcxx_std_11)

add_executable(calcapps/calc.cpp)

target_link_libraries(calcPUBLICcalclib)

.Inthisbook,I'llmostlyavoidshowingyouthewrongwaytodothings;youcanfindplentyofexamplesofthatonline.I'llmentionalternativesoccasionally,butthesearenotrecommendedunlesstheyareabsolutelynecessary;oftentheyarejusttheretohelpyoureadolderCMakecode.↩

.YouwillsometimesseeFATAL_ERRORhere,thatwasneededtosupportnicefailureswhenrunningthisinCMake<2.6,whichshouldnotbeaproblemanymore.↩

.The::syntaxwasoriginallyintendedforINTERFACEIMPORTEDlibraries,whichwereexplicitlysupposedtobelibrariesdefinedoutsidethecurrentproject.But,becauseofthis,mostofthetarget_*commandsdon'tworkonIMPORTEDlibraries,makingthemhardtosetupyourself.Sodon'tusetheIMPORTEDkeywordfornow,anduseanALIAStargetinstead;itwillbefineuntilyoustartexportingtargets.ThislimitationwasfixedinCMake3.11.↩

1

2

3

IntroductiontotheBasics

21

Page 22: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

VariablesandtheCache

LocalVariables

Wewillcovervariablesfirst.Alocalvariableissetlikethis:

set(MY_VARIABLE"value")

Thenamesofvariablesareusuallyallcaps,andthevaluefollows.Youaccessavariablebyusing${},suchas${MY_VARIABLE}.CMakehastheconceptofscope;youcanaccessthevalueofthevariableafteryousetitaslongasyouareinthesamescope.Ifyouleaveafunctionorafileinasubdirectory,thevariablewillnolongerbedefined.YoucansetavariableinthescopeimmediatelyaboveyourcurrentonewithPARENT_SCOPEattheend.

Listsaresimplyaseriesofvalueswhenyousetthem:

set(MY_LIST"one""two")

whichinternallybecome;separatedvalues.Sothisisanidenticalstatement:

set(MY_LIST"one;two")

Thelist(commandhasutilitiesforworkingwithlists,andseparate_argumentswillturnaspaceseparatedstringintoalist(inplace).NotethatanunquotedvalueinCMakeisthesameasaquotedoneiftherearenospacesinit;thisallowsyoutoskipthequotesmostofthetimewhenworkingwithvaluethatyouknowcouldnotcontainspaces.

Whenavariableisexpandedusing${}syntax,allthesamerulesaboutspacesapply.Beespeciallycarefulwithpaths;pathsmaycontainaspaceatanytimeandshouldalwaysbequotedwhentheyareavariable(neverwrite${MY_PATH},alwaysshouldbe"${MY_PATH}").

CacheVariables

Ifyouwanttosetavariablefromthecommandline,CMakeoffersavariablecache.Somevariablesarealreadyhere,likeCMAKE_BUILD_TYPE.Thesyntaxfordeclaringavariableandsettingitifitisnotalreadysetis:

set(MY_CACHE_VARIABLE"VALUE"CACHESTRING"Description")

Thiswillnotreplaceanexistingvalue.ThisissothatyoucansettheseonthecommandlineandnothavethemoverriddenwhentheCMakefileexecutes.Ifyouwanttousethesevariablesasamake-shiftglobalvariable,thenyoucando:

set(MY_CACHE_VARIABLE"VALUE"CACHESTRING""FORCE)

mark_as_advanced(MY_CACHE_VARIABLE)

Thefirstlinewillcausethevaluetobesetnomatterwhat,andthesecondlinewillkeepthevariablefromshowingupinthelistofvariablesifyouruncmake-L..oruseaGUI.Thisissocommon,youcanalsousetheINTERNALtypetodothesamething(thoughtechnicallyitforcestheSTRINGtype,thiswon'taffectanyCMakecodethatdependsonthevariable):

set(MY_CACHE_VARIABLE"VALUE"CACHEINTERNAL"")

SinceBOOLissuchacommonvariabletype,youcansetitmoresuccinctlywiththeshortcut:

option(MY_OPTION"Thisissettablefromthecommandline"OFF)

1

VariablesandtheCache

22

Page 23: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

FortheBOOLdatatype,thereareseveraldifferentwordingsforONandOFF.

Seecmake-variablesforalistingofknownvariablesinCMake.

Environmentvariables

Youcanalsoset(ENV{variable_name}value)andget$ENV{variable_name}environmentvariables,thoughitisgenerallyaverygoodideatoavoidthem.

TheCache

Thecacheisactuallyjustatextfile,CMakeCache.txt,thatgetscreatedinthebuilddirectorywhenyourunCMake.ThisishowCMakeremembersanythingyouset,soyoudon'thavetore-listyouroptionseverytimeyourerunCMake.

Properties

TheotherwayCMakestoresinformationisinproperties.Thisislikeavariable,butitisattachedtosomeotheritem,likeadirectoryoratarget.Aglobalpropertycanbeausefuluncachedglobalvariable.ManytargetpropertiesareinitializedfromamatchingvariablewithCMAKE_atthefront.SosettingCMAKE_CXX_STANDARD,forexample,willmeanthatallnewtargetscreatedwillhaveCXX_STANDARDsettothatwhentheyarecreated.Therearetwowaystosetproperties:

set_property(TARGETTargetName

PROPERTYCXX_STANDARD11)

set_target_properties(TargetNamePROPERTIES

CXX_STANDARD11)

Thefirstformismoregeneral,andcansetmultipletargets/files/testsatonce,andhasusefuloptions.Thesecondisashortcutforsettingseveralpropertiesononetarget.Andyoucangetpropertiessimilarly:

get_property(ResultVariableTARGETTargetNamePROPERTYCXX_STANDARD)

Seecmake-propertiesforalistingofallknownproperties.Youcanalsomakeyourowninsomecases.

.ifstatementsareabitoddinthattheycantakethevariablewithorwithoutthesurroundingsyntax;thisisthereforhistoricalreasons:ifpredatesthe${}syntax.↩

.Interfacetargets,forexample,mayhavelimitsoncustompropertiesthatareallowed.↩

2

1

2

VariablesandtheCache

23

Page 24: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

ProgramminginCMake

Controlflow

CMakehasanifstatement,thoughovertheyearsithasbecomerathercomplex.Thereareaseriesofallcapskeywordsyoucanuseinsideanifstatement,andyoucanoftenrefertovariablesbyeitherdirectlybynameorusingthe${}syntax(theifstatementhistoricallypredatesvariableexpansion).Anexampleifstatement:

if(variable)

#Ifvariableis`ON`,`YES`,`TRUE`,`Y`,ornonzeronumber

else()

#Ifvariableis`0`,`OFF`,`NO`,`FALSE`,`N`,`IGNORE`,`NOTFOUND`,`""`,orendsin`-NOTFOUND`

endif()

#Ifvariabledoesnotexpandtooneoftheabove,CMakewillexpanditthentryagain

Sincethiscanbealittleconfusingifyouexplicitlyputavariableexpansion,like${variable},duetothepotentialexpansionofanexpansion,apolicy(CMP0054)wasaddedinCMake3.1+thatkeepsaquotedexpansionfrombeingexpandedyetagain.So,aslongastheminimumversionofCMakeis3.1+,youcando:

if("${variable}")

#Trueifvariableisnotfalse-like

else()

#Notethatundefinedvariableswouldbe`""`thusfalse

endif()

Thereareavarietyofkeywordsaswell,suchas:

Unary:NOT,TARGET,EXISTS(file),DEFINED,etc.Binary:STREQUAL,AND,OR,MATCHES(regularexpression),VERSION_LESS,VERSION_LESS_EQUAL(CMake3.7+),etc.Parenthesescanbeusedtogroup

generator-expressions

generator-expressionsarereallypowerful,butabitoddandspecialized.MostCMakecommandshappenatconfiguretime,includetheifstatementsseenabove.Butwhatifyouneedlogictooccuratbuildtimeoreveninstalltime?Generatorexpressionswereaddedforthispurpose. Theyareevaluatedintargetproperties.

Thesimplestgeneratorexpressionsareinformationalexpressions,andareoftheform$<KEYWORD>;theyevaluatetoapieceofinformationrelevantforthecurrentconfiguration.Theotherformis$<KEYWORD:value>,whereKEYWORDisakeywordthatcontrolstheevaluation,andvalueistheitemtoevaluate(aninformationalexpressionkeywordisallowedhere,too).IfKEYWORDisageneratorexpressionorvariablethatevaluatesto0or1,valueissubstitutedif1andnotif0.Youcannestgeneratorexpressions,andyoucanusevariablestomakereadingnestedvariablesbearable.Someexpressionsallowmultiplevalues,separatedbycommas.

IfyouwanttoputacompileflagonlyfortheDEBUGconfiguration,forexample,youcoulddo:

target_compile_options(MyTargetPRIVATE"$<$<CONFIG:Debug>:--my-flag>")

Thisisanewer,betterwaytoaddthingsthanusingspecialized*_DEBUGvariables,andgeneralizedtoallthethingsgeneratorexpressionssupport.Notethatyoushouldnever,neverusetheconfiguretimevalueforthecurrentconfiguration,becausemulti-configurationgeneratorslikeIDEsdonothavea"current"configurationatconfiguretime,onlyatbuildtimethroughgeneratorexpressionsandcustom*_<CONFIG>variables.

Othercommonusesforgeneratorexpressions:

1

2

ProgramminginCMake

24

Page 25: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Limitinganitemtoacertainlanguageonly,suchasCXX,toavoiditmixingwithsomethinglikeCUDA,orwrappingitsothatitisdifferentdependingontargetlanguage.Accessingconfigurationdependentproperties,liketargetfilelocation.Givingadifferentlocationforbuildandinstalldirectories.

Thatlastoneisverycommon.You'llseesomethinglikethisinalmosteverypackagethatsupportsinstalling:

target_include_directories(

MyTarget

PUBLIC

$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>

$<INSTALL_INTERFACE:include>

)

MacrosandFunctions

YoucandefineyourownCMakefunctionormacroeasily.Theonlydifferencebetweenafunctionandamacroisscope;macrosdon'thaveone.So,ifyousetavariableinafunctionandwantittobevisibleoutside,you'llneedPARENT_SCOPE.Nestingfunctionsthereforeisabittricky,sinceyou'llhavetoexplicitlysetthevariablesyouwantvisibletotheoutsideworldtoPARENT_SCOPEineachfunction.But,functionsdon't"leak"alltheirvariableslikemacrosdo.Forthefollowingexamples,I'llusefunctions.

Anexampleofasimplefunctionisasfollows:

function(SIMPLEREQUIRED_ARG)

message(STATUS"Simplearguments:${REQUIRED_ARG},followedby${ARGV}")

set(${REQUIRED_ARG}"FromSIMPLE"PARENT_SCOPE)

endfunction()

simple(This)

message("Output:${This}")

Ifyouwantpositionalarguments,theyarelistedexplicitly,andallotherargumentsarecollectedinARGN(ARGVholdsallarguments,eventheonesyoulist).YouhavetoworkaroundthefactthatCMakedoesnothavereturnvaluesbysettingvariables.Intheexampleabove,youcanexplicitlygiveavariablenametoset.

ArgumentsCMakehasanamedvariablesystemthatyou'vealreadyseeninmostofthebuildinCMakefunctions.Youcanuseitwiththecmake_parse_argumentsfunction.IfyouwanttosupportaversionofCMakelessthan3.5,you'llwanttoalsoincludetheCMakeParseArgumentsmodule,whichiswhereitusedtolivebeforebecomingabuiltincommand.Hereisanexampleofhowtouseit:

function(COMPLEX)

cmake_parse_arguments(

COMPLEX_PREFIX

"SINGLE;ANOTHER"

"ONE_VALUE;ALSO_ONE_VALUE"

"MULTI_VALUES"

${ARGN}

)

endfunction()

complex(SINGLEONE_VALUEvalueMULTI_VALUESsomeothervalues)

Insidethefunctionafterthiscall,you'llfind:

COMPLEX_PREFIX_SINGLE=TRUE

COMPLEX_PREFIX_ANOTHER=FALSE

COMPLEX_PREFIX_ONE_VALUE="value"

COMPLEX_PREFIX_ALSO_ONE_VALUE=<UNDEFINED>

ProgramminginCMake

25

Page 26: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

COMPLEX_PREFIX_MULTI_VALUES="some;other;values"

Ifyoulookattheofficialpage,you'llseeaslightlydifferentmethodusingsettoavoidexplicitlywritingthesemicolonsinthelist;feelfreetousethestructureyoulikebest.Youcanmixitwiththepositionalargumentslistedabove;anyremainingarguments(thereforeoptionalpositionalarguments)areinCOMPLEX_PREFIX_UNPARSED_ARGUMENTS.

.Theyactasiftheyareevaluatedatbuild/installtime,thoughactuallytheyareevaluatedforeachbuildconfiguration.↩

.TheCMakedocssplitsexpressionsintoInformational,Logical,andOutput.↩

1

2

ProgramminginCMake

26

Page 27: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Communicationwithyourcode

ConfigureFile

CMakeallowsyoutoaccessCMakevariablesfromyourcodeusingconfigure_file.Thiscommandcopiesafile(traditionallyendingin.infromoneplacetoanother,substitutingallCMakevariablesitfinds.Ifyouwanttoavoidreplacingexisting${}syntaxinyourinputfile,[email protected]'salsoaCOPY_ONLYkeywordifyouarejustusingthisasareplacementforfile(COPY.

Thisfunctionalityisusedquitefrequently;forexample,onVersion.h.in:

Version.h.in

#pragmaonce

#defineMY_VERSION_MAJOR@PROJECT_VERSION_MAJOR@

#defineMY_VERSION_MINOR@PROJECT_VERSION_MINOR@

#defineMY_VERSION_PATCH@PROJECT_VERSION_PATCH@

#defineMY_VERSION_TWEAK@PROJECT_VERSION_TWEAK@

#defineMY_VERSION"@PROJECT_VERSION@"

CMakelines:

configure_file(

"${PROJECT_SOURCE_DIR}/include/My/Version.h.in"

"${PROJECT_BINARY_DIR}/include/My/Version.h"

)

Youshouldincludethebinaryincludedirectoryaswellwhenbuildingyourproject.Ifyouwanttoputanytrue/falsevariablesinaheader,CMakehasCspecific#cmakedefineand#cmakedefine01replacementstomakeappropriatedefinelines.

Youcanalso(andoftendo)usethistoproduce.cmakefiles,suchastheconfigurefiles(seeinstalling).

Readingfiles

Theotherdirectioncanbedonetoo;youcanreadinsomething(likeaversion)fromyoursourcefiles.Ifyouhaveaheaderonlylibrarythatyou'dliketomakeavailablewithorwithoutCMake,forexample,thenthiswouldbethebestwaytohandleaversion.Thiswouldlooksomethinglikethis:

#Assumingthecanonicalversionislistedinasingleline

#ThiswouldbeinseveralpartsifpickingupfromMAJOR,MINOR,etc.

set(VERSION_REGEX"#defineMY_VERSION[\t]+\"(.+)\"")

#Readinthelinecontainingtheversion

file(STRINGS"${CMAKE_CURRENT_SOURCE_DIR}/include/My/Version.hpp"

VERSION_STRINGREGEX${VERSION_REGEX})

#Pickoutjusttheversion

string(REGEXREPLACE${VERSION_REGEX}"\\1"VERSION_STRING"${VERSION_STRING}")

#AutomaticallygettingPROJECT_VERSION_MAJOR,My_VERSION_MAJOR,etc.

project(MyLANGUAGESCXXVERSION${VERSION_STRING})

Above,file(STRINGSfile_namevariable_nameREGEXregex)pickslinesthatmatcharegex;andthesameregexisusedtothenpickouttheparenthesescapturegroupwiththeversionpart.Replaceisusedwithbacksubstitutiontooutputonlythatonegroup.

Communicatingwithyourcode

27

Page 28: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Communicatingwithyourcode

28

Page 29: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

HowtostructureyourprojectThefollowinginformationisbiased.Butinagoodway,Ithink.I'mgoingtotellyouhowtostructurethedirectoriesinyourproject.Thisisbasedonconvention,butwillhelpyou:

Easilyreadotherprojectsfollowingthesamepatters,Avoidapatternthatcausesconflicts,Keepfrommuddlingandcomplicatingyourbuild.

First,thisiswhatyourfilesshouldlooklikewhenyoustartifyourprojectiscreativelycalledproject,withalibrarycalledlib,andaexecutablecalledapp:

-project

-.gitignore

-README.md

-LICENCE.md

-CMakeLists.txt

-cmake

-FindSomeLib.cmake

-something_else.cmake

-include

-project

-lib.hpp

-src

-CMakeLists.txt

-lib.cpp

-apps

-CMakeLists.txt

-app.cpp

-tests

-CMakeLists.txt

-testlib.cpp

-docs

-CMakeLists.txt

-extern

-googletest

-scripts

-helper.py

Thenamesarenotabsolute;you'llseecontentionabouttest/vs.tests/,andtheapplicationfoldermaybecalledsomethingelse(ornotexistforalibrary-onlyproject).You'llalsosometimeseeapythonfolderforpythonbindings,oracmakefolderforhelperCMakefiles,likeFind<library>.cmakefiles.Butthebasicsarethere.

Noticeafewthingsalreadyapparent;theCMakeLists.txtfilesaresplitupoverallsourcedirectories,andarenotintheincludedirectories.Thisisbecauseyoushouldbeabletocopythecontentsoftheincludedirectoryto/usr/includeorsimilardirectly(exceptforconfigurationheaders,whichIgooverinanotherchapter),andnothaveanyextrafilesorcauseanyconflicts.That'salsowhythereisadirectoryforyourprojectinsidetheincludedirectory.Useadd_subdirectorytoaddasubdirectorycontainingaCMakeLists.txt.

Youoftenwantacmakefolder,withallofyourhelpermodules.ThisiswhereyourFind*.cmakefilesgo.Ansetofsomecommonhelpersisatgithub.com/CLIUtils/cmake.ToaddthisfoldertoyourCMakepath:

set(CMAKE_MODULE_PATH"${PROJECT_SOURCE_DIR}/cmake"${CMAKE_MODULE_PATH})

Yourexternfoldershouldcontaingitsubmodulesalmostexclusively.Thatway,youcancontroltheversionofthedependenciesexplicitly,butstillupgradeeasily.SeetheTestingchapterforanexampleofaddingasubmodule.

Youshouldhavesomethinglike/build*inyour.gitignore,sothatuserscanmakebuilddirectoriesinthesourcedirectoryandusethosetobuild.Afewpackagesprohibitthis,butit'smuchbetterthandoingatrueout-of-sourcebuildandhavingtotypesomethingdifferentforeachpackageyoubuild.

HowtoStructureYourProject

29

Page 30: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Ifyouwanttoavoidthebuilddirectorybeinginavalidsourcedirectory,addthisnearthetopofyourCMakeLists:

###Requireout-of-sourcebuilds

file(TO_CMAKE_PATH"${PROJECT_BINARY_DIR}/CMakeLists.txt"LOC_PATH)

if(EXISTS"${LOC_PATH}")

message(FATAL_ERROR"Youcannotbuildinasourcedirectory(oranydirectorywithaCMakeLists.txtfile).Pleasemakeab

uildsubdirectory.FeelfreetoremoveCMakeCache.txtandCMakeFiles.")

endif()

Seetheextendedcodeexamplehere.

HowtoStructureYourProject

30

Page 31: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Runningotherprograms

Runningacommandatconfiguretime

Runningacommandatconfiguretimeisrelativelyeasy.Useexecute_processtorunaprocessandaccesstheresults.ItisgenerallyagoodideatoavoidhardcodingaprogrampathintoyourCMake;youcanuse${CMAKE_COMMAND},find_package(Git),orfind_programtogetaccesstoacommandtorun.UseRESULT_VARIABLEtocheckthereturncodeandOUTPUT_VARIABLEtogettheoutput.

Hereisanexamplethatupdatesallgitsubmodules:

find_package(GitQUIET)

if(GIT_FOUNDANDEXISTS"${PROJECT_SOURCE_DIR}/.git")

execute_process(COMMAND${GIT_EXECUTABLE}submoduleupdate--init--recursive

WORKING_DIRECTORY${CMAKE_CURRENT_SOURCE_DIR}

RESULT_VARIABLEGIT_SUBMOD_RESULT)

if(NOTGIT_SUBMOD_RESULTEQUAL"0")

message(FATAL_ERROR"gitsubmoduleupdate--initfailedwith${GIT_SUBMOD_RESULT},pleasecheckoutsubmodules")

endif()

endif()

RunningacommandatbuildtimeBuildtimecommandsareabittricker.Themaincomplicationcomesfromthetargetsystem;whendoyouwantyourcommandtorun?Doesitproduceanoutputthatanothertargetneeds?Withthisinmind,hereisanexamplethatcallsaPythonscripttogenerateaheaderfile:

find_package(PythonInterpREQUIRED)

add_custom_command(OUTPUT"${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp"

COMMAND"${PYTHON_EXECUTABLE}""${CMAKE_CURRENT_SOURCE_DIR}/scripts/GenerateHeader.py"--argument

DEPENDSsome_target)

add_custom_target(generate_headerALL

DEPENDS"${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hpp")

install(FILES${CMAKE_CURRENT_BINARY_DIR}/include/Generated.hppDESTINATIONinclude)

Here,thegenerationhappensaftersome_targetiscomplete,andhappenswhenyourunmakewithoutatarget(ALL).Ifyoumakethisadependencyofanothertargetwithadd_dependencies,youcouldavoidtheALLkeyword.Or,youcouldrequirethatauserexplicitlybuildsthegenerate_headertargetwhenmaking.

Includedcommonutilities

AusefultoolinwritingCMakebuildsthatworkcross-platformiscmake-E<mode>(seeninCMakefilesas${CMAKE_COMMAND}-E).ThismodeallowsCMaketodoavarietyofthingswithoutcallingsystemtoolsexplicitly,likecopy,make_directory,andremove.Itismostlyusedforthebuildtimecommands.Notethattheveryusefulcreate_symlinkmodeusedtobeUnixonly,butwasaddedforWindowsinCMake3.13.Seethedocs.

RunningOtherPrograms

31

Page 32: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

AsimpleexampleThisisasimpleyetcompleteexampleofaproperCMakeLists.Forthisprogram,wehaveonelibrary(MyLibExample)withaheaderfileandasourcefile,andoneapplication,MyExample,withonesourcefile.

#AlmostallCMakefilesshouldstartwiththis

#Youshouldalwaysspecifyarangewiththenewest

#andoldesttestedversionsofCMake.Thiswillensure

#youpickupthebestpolicies.

cmake_minimum_required(VERSION3.1...3.16)

#Thisisyourprojectstatement.Youshouldalwayslistlanguages;

#Listingtheversionisniceheresinceitsetslotsofusefulvariables

project(ModernCMakeExampleVERSION1.0LANGUAGESCXX)

#IfyousetanyCMAKE_variables,thatcangohere.

#(Butusuallydon'tdothis,exceptmaybeforC++standard)

#Findpackagesgohere.

#Youshouldusuallysplitthisintofolders,butthisisasimpleexample

#Thisisa"default"library,andwillmatchthe***variablesetting.

#OthercommonchoicesareSTATIC,SHARED,andMODULE

#IncludingheaderfilesherehelpsIDEsbutisnotrequired.

#Outputlibnamematchestargetname,withtheusualextensionsonyoursystem

add_library(MyLibExamplesimple_lib.cppsimple_lib.hpp)

#Linkeachtargetwithothertargetsoraddoptions,etc.

#Addingsomethingwecanrun-Outputnamematchestargetname

add_executable(MyExamplesimple_example.cpp)

#Makesureyoulinkyourtargetswiththiscommand.Itcanalsolinklibrariesand

#evenflags,solinkingatargetthatdoesnotexistwillnotgiveaconfigure-timeerror.

target_link_libraries(MyExamplePRIVATEMyLibExample)

Thecompleteexampleisavailableinexamplesfolder.

Alarger,multi-fileexampleisalsoavailable.

ASimpleExample

32

Page 33: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

AddingfeaturesThissectioncoversaddingcommonfeaturestoyourCMakeproject.You'lllearnhowtoaddavarietyofoptionscommonlyneededinC++projects,likeC++11support,aswellashowtosupportIDEsandmore.

Defaultbuildtype

CMakenormallydoesa"non-release,nondebug"emptybuildtype;ifyouprefertosetthedefaultbuildtypeyourself,youcanfollowthisrecipeforthedefaultbuildtypemodifiedfromtheKitwareblog:

set(default_build_type"Release")

if(NOTCMAKE_BUILD_TYPEANDNOTCMAKE_CONFIGURATION_TYPES)

message(STATUS"Settingbuildtypeto'${default_build_type}'asnonewasspecified.")

set(CMAKE_BUILD_TYPE"${default_build_type}"CACHE

STRING"Choosethetypeofbuild."FORCE)

#Setthepossiblevaluesofbuildtypeforcmake-gui

set_property(CACHECMAKE_BUILD_TYPEPROPERTYSTRINGS

"Debug""Release""MinSizeRel""RelWithDebInfo")

endif()

AddingFeatures

33

Page 34: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

C++11andbeyondC++11issupportedbyCMake.Really.JustnotinCMake2.8,because,guesswhat,C++11didn'texistin2009when2.0wasreleased.AslongasyouareusingCMake3.1ornewer,youshouldbefine,therearetwodifferentwaystoenablesupport.Andasyou'llsoonsee,there'sevenbettersupportinCMake3.8+.I'llstartwiththat,sincethisisModernCMake.

CMake3.8+:Metacompilerfeatures

AslongasyoucanrequirethatauserinstallCMake,you'llhaveaccesstothenewestwaytoenableC++standards.Thisisthemostpowerfulway,withthenicestsyntaxandthebestsupportfornewstandards,andthebesttargetbehaviorformixingstandardsandoptions.AssumingyouhaveatargetnamedmyTarget,itlookslikethis:

target_compile_features(myTargetPUBLICcxx_std_11)

set_target_properties(myTargetPROPERTIESCXX_EXTENSIONSOFF)

Forthefirstline,wegettopickbetweencxx_std_11,cxx_std_14,andcxx_std_17.Thesecondlineisoptional,butwillavoidextensionsbeingadded;withoutityou'dgetthingslike-std=g++11replacing-std=c++11.ThefirstlineevenworksonINTERFACEtargets;onlyactualcompiledtargetscanusethesecondline.

IfatargetfurtherdownthedependencychainspecifiesahigherC++level,thisinteractsnicely.It'sreallyjustamoreadvancedversionofthefollowingmethod,soitinteractsnicelywiththat,too.

CMake3.1+:Compilerfeatures

Youcanaskforspecificcompilerfeaturestobeavailable.ThiswasmoregranularthanaskingforaC++version,thoughit'sabittrickytopickoutjustthefeaturesapackageisusingunlessyouwrotethepackageandhaveagoodmemory.SincethisultimatelychecksagainstalistofoptionsCMakeknowsyourcompilersupportsandpicksthehighestflagindicatedinthatlist,youdon'thavetospecifyalltheoptionsyouneed,justtherarestones.Thesyntaxisidenticaltothesectionabove,youjusthavealistofoptionstopickinsteadofcxx_std_*options.Seethewholelisthere.

Ifyouhaveoptionalfeatures,youcanusethelistCMAKE_CXX_COMPILE_FEATURESanduseif(...IN_LIST...)fromCMake3.3+toseeifthatfeatureissupported,andadditconditionally.Seethedocshereforotherusecases.

Arelatedfeature,WriteCompilerDetectionHeader,isworthcheckingout.Itisamodulethatletsyoumakeafilewithmacrosallowingyoutocheckandsupportoptionalfeaturesforspecificcompilers.Likeanyheadergenerator,thiswillrequirethatyoubuildwithCMakesothatyourheadercanbegeneratedaspartofthebuildprocess(onlyimportantifyoucareaboutsupportingmultiplebuildsystems,orifyouaremakingano-buildheader-onlylibrary).

CMake3.1+:Globalandpropertysettings

ThereisanotherwaythatC++standardsaresupported;aspecificsetofthreeproperties(bothglobalandtargetlevel).Theglobalpropertiesare:

set(CMAKE_CXX_STANDARD11)

set(CMAKE_CXX_STANDARD_REQUIREDON)

set(CMAKE_CXX_EXTENSIONSOFF)

ThefirstlinesetsaC++standardlevel,andthesecondtellsCMaketouseit,andthefinallineisoptionalandensures-std=c++11vs.somethinglike-std=g++11.Thismethodisn'tbadforafinalpackage,butshouldn'tbeusedbyalibrary.Youcanalsosetthesevaluesonatarget:

C++11andBeyond

34

Page 35: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

set_target_properties(myTargetPROPERTIES

CXX_STANDARD11

CXX_STANDARD_REQUIREDYES

CXX_EXTENSIONSNO

)

Whichisbetter,butstilldoesn'thavethesortofexplicitcontrolthatcompilerfeatureshaveforpopulatingPRIVATEandINTERFACEproperties.

YoucanfindmoreinformationaboutthefinaltwomethodsonCraigScott'susefulblogpost.

Don'tsetmanualflagsyourself.You'llthenbecomeresponsibleformaintingcorrectflagsforeveryreleaseofeverycompiler,errormessagesforunsupportedcompilerswon'tbeuseful,andsomeIDEsmightnotpickupthemanualflags.

C++11andBeyond

35

Page 36: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

AddingFeaturesTherearelotsofcompilerandlinkersettings.Whenyouneedtoaddsomethingspecial,youcouldcheckfirsttoseeifCMakesupportsit;ifitdoes,youcanavoidexplicitlytyingyourselftoacompilerversion.And,betteryet,youexplainwhatyoumeaninyourCMakeLists,ratherthanspewingflags.

ThefirstandmostcommonfeaturewasC++standardssupport,whichgotit'sownchapter.

Positionindependentcode

Thisisbestknownasthe-fPICflag.Muchofthetime,youdon'tneedtodoanything.CMakewillincludetheflagforSHAREDorMODULElibraries.Ifyoudoexplicitlyneedit:

set(CMAKE_POSITION_INDEPENDENT_CODEON)

willdoitglobally,or:

set_target_properties(lib1PROPERTIESPOSITION_INDEPENDENT_CODEON)

toexplicitlyturnitON(orOFF)foratarget.

LittlelibrariesIfyouneedtolinktothedllibrary,with-ldlonLinux,justusethebuilt-inCMakevariable${CMAKE_DL_LIBS}inatarget_link_librariescommand.Nomoduleorfind_packageneeded.(Thisaddswhateverisneededtogetdlopenanddlclose)

Unfortunately,themathlibraryisnotsolucky.Ifyouneedtoexplicitlylinktoit,youcanalwaysdotarget_link_libraries(MyTargetPUBLICm),butitmightbebettertouseCMake'sgenericfind_library:

find_library(MATH_LIBRARYm)

if(MATH_LIBRARY)

target_link_libraries(MyTargetPUBLIC${MATH_LIBRARY})

endif()

YoucanprettyeasilyfindFind*.cmake'sforthisandotherlibrariesthatyouneedwithaquicksearch;mostmajorpackageshaveahelperlibraryofCMakemodules.Seethechapteronexistingpackageinclusionformore.

InterproceduraloptimizationINTERPROCEDURAL_OPTIMIZATION,bestknownaslinktimeoptimizationandthe-fltoflag,isavailableonveryrecentversionsofCMake.YoucanturnthisonwithCMAKE_INTERPROCEDURAL_OPTIMIZATION(CMake3.9+only)ortheINTERPROCEDURAL_OPTIMIZATIONpropertyontargets.SupportforGCCandClangwasaddedinCMake3.8.Ifyousetcmake_minimum_required(VERSION3.9)orbetter(seeCMP0069),settingthistoONonatargetisanerrorifthecompilerdoesn'tsupportit.Youcanusecheck_ipo_supported(),fromthebuilt-inCheckIPOSupportedmodule,toseeifsupportisavailablebeforehand.Anexampleof3.9styleusage:

include(CheckIPOSupported)

check_ipo_supported(RESULTresult)

if(result)

set_target_properties(fooPROPERTIESINTERPROCEDURAL_OPTIMIZATIONTRUE)

endif()

Smallbutcommonneeds

36

Page 37: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Smallbutcommonneeds

37

Page 38: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

CCacheandUtilitiesOvertheversions,commonutilitiesthathelpyouwritegoodcodehavehadsupportaddedtoCMake.ThisisusuallyintheformofapropertyandmatchingCMAKE_*initializationvariable.Thefeatureisnotmeanttobetiedtoonespecialprogram,butratheranyprogramthatissomewhatsimilarinbehavior.

Allofthesetake;separatedvalues(astandardlistinCMake)thatdescribetheprogramandoptionsthatyoushouldrunonthesourcefilesofthistarget.

CCache

SettheCMAKE_<LANG>_COMPILER_LAUNCHERvariableorthe<LANG>_COMPILER_LAUNCHERpropertyonatargettousesomethinglikeCCacheto"wrap"thecompilationofthetarget.SupportforCCachehasbeenexpandinginthelatestversionsofCMake.Inpractice,thistendstolooklikethis:

find_program(CCACHE_PROGRAMccache)

if(CCACHE_PROGRAM)

set(CMAKE_CXX_COMPILER_LAUNCHER"${CCACHE_PROGRAM}")

set(CMAKE_CUDA_COMPILER_LAUNCHER"${CCACHE_PROGRAM}")#CMake3.9+

endif()

Utilities

SetthefollowingpropertiesorCMAKE_*initializervariablestothecommandlineforthetools.MostofthemarelimitedtoCorCXXwithmakeorninjagenerators.

<LANG>_CLANG_TIDY:CMake3.6+<LANG>_CPPCHECK

<LANG>_CPPLINT

<LANG>_INCLUDE_WHAT_YOU_USE

ClangtidyHereisasimpleexampleofusingClang-Tidy:

if(CMAKE_VERSIONVERSION_GREATER3.6)

#Addclang-tidyifavailable

option(CLANG_TIDY_FIX"PerformfixesforClang-Tidy"OFF)

find_program(

CLANG_TIDY_EXE

NAMES"clang-tidy"

DOC"Pathtoclang-tidyexecutable"

)

if(CLANG_TIDY_EXE)

if(CLANG_TIDY_FIX)

set(CMAKE_CXX_CLANG_TIDY"${CLANG_TIDY_EXE}""-fix")

else()

set(CMAKE_CXX_CLANG_TIDY"${CLANG_TIDY_EXE}")

endif()

endif()

endif()

Utilities

38

Page 39: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

The-fixpartisoptional,andwillmodifyyoursourcefilestotrytofixthetidywarningissued.Ifyouareworkinginagitrepository,thisisfairlysafeasyoucanseewhathaschanged.However,makesureyoudonotrunyourmakefile/ninjabuildinparallel!Thiswillnotworkverywellatallifittriestofixthesameheadertwice.

Ifyouwanttoexplicitlyusethetargetformtoensureyouonlycallthisonyourlocaltargets,youcansetavariable(IusuallychoseDO_CLANG_TIDY)insteadoftheCMAKE_CXX_CLANG_TIDYvariable,thenaddittoyourtargetpropertiesasyoucreatethem.

Includewhatyouuse

Thisisanexampleforusingincludewhatyouuse.First,you'llneedtohavethetool,suchasinadockercontainer:

Then,youcanpassthisintoyourbuildwithoutmodifyingthesource:

Finally,youcancollecttheoutputandapplythefixes:

LinkwhatyouuseThereisabooleantargetproperty,LINK_WHAT_YOU_USE,thatwillcheckforextraneousfileswhenlinking.

Clang-formatClang-formatdoesn'treallyhaveanintegrationwithCMake,unfortunately.Youcouldmakeacustomtarget(Seethispost,oryoucanrunitmanually.AninterestingprojectthatIhavenotreallytriedishere;itaddsaformattargetandevenmakessurethatyoucan'tcommitunformattedfiles.

Thefollowingtwolinewoulddothatinagitrepositoryinbash(assumingyouhavea.clang-formatfile):

gitbook$dockerrun--rm-ittuxity/include-what-you-use:clang_4.0

build#cmake..-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE=include-what-you-use

build#make2>iwyu.out

build#fix_includes.py<iwyu.out

gitbook$gitls-files--'*.cpp''*.h'|xargsclang-format-i-style=file

gitbook$gitdiff--exit-code--color

Utilities

39

Page 40: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

UsefulModulesThereareatonofusefulmodulesinCMake'smodulescollection;butsomeofthemaremoreusefulthanothers.Hereareafewhighlights.

CMakeDependentOption

Thisaddsacommandcmake_dependent_optionthatsetsanoptionbasedonanothersetofvariablesbeingtrue.Itlookslikethis:

include(CMakeDependentOption)

cmake_dependent_option(BUILD_TESTS"Buildyourtests"ON"VAL1;VAL2"OFF)

whichisjustashortcutforthis:

if(VAL1ANDVAL2)

set(BUILD_TESTS_DEFAULTON)

else()

set(BUILD_TESTS_DEFAULTOFF)

endif()

option(BUILD_TESTS"Buildyourtests"${BUILD_TESTS_DEFAULT})

if(NOTBUILD_TESTS_DEFAULT)

mark_as_advanced(BUILD_TESTS)

endif()

NotethatBUILD_TESTINGisabetterwaytocheckfortestingbeingenabledifyouuseinclude(CTest),sinceitisdefinedforyou.ThisisjustanexampleofCMakeDependentOption.

CMakePrintHelpers

Thismodulehasacoupleofhandyoutputfunctions.cmake_print_propertiesletsyoueasilyprintproperties.Andcmake_print_variableswillprintthenamesandvaluesofanyvariablesyougiveit.

CheckCXXCompilerFlag

Thischeckstoseeifaflagissupported.Forexample:

include(CheckCXXCompilerFlag)

check_cxx_compiler_flag(-someflagOUTPUT_VARIABLE)

NotethatOUTPUT_VARIABLEwillalsoappearintheconfigurationprintout,sochooseagoodname.

Thisisjustoneofmanysimilarmodules,suchasCheckIncludeFileCXX,CheckStructHasMember,TestBigEndian,andCheckTypeSizethatallowyoutocheckforinformationaboutthesystem(andyoucancommunicatethattoyoursourcecode).

WriteCompilerDetectionHeader

Thisisanamazingmodulesimilartotheoneslistedabove,butspecialenoughtodeserveitsownsection.Itallowsyoutolookforalistoffeaturesthatsomecompilerssupport,andwriteoutaC++headerfilethatletsyouknowwhetherthatfeatureisavailable.Itevencanprovidecompatibilitymacrosforfeaturesthathavechangednames!

Usefulmodules

40

Page 41: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Touse:

write_compiler_detection_header(

FILEmyoutput.h

PREFIXMy

COMPILERSGNUClangMSVCIntel

FEATUREScxx_variadic_templates

)

Thissupportscompilerfeatures(definedto0or1),symbols(definedtoemptyorthesymbol),andmacrosthatsupportdifferentnames.TheywillbeprefixedwiththePREFIXyouprovide.YoucanseparatecompilersintodifferentfilesusingOUTPUT_FILES_DIR.

Thedownsideisthatyoudohavetolistthecompilersyouexpecttosupport.IfyouusetheALLOW_UNKNOWN_COMPILERSflag(s),youcankeepthisfromerroringonunknowncompilers,butitwillstillleaveallfeaturesempty.

try_compile/try_run

Thisisnotexactlyamodule,butiscrucialtomanyofthemoduleslistedabove.Youcanattempttocompile(andpossiblyrun)abitofcodeatconfiguretime.Thiscanallowyoutogetinformationaboutthecapabilitiesofyoursystem.Thebasicsyntaxis:

try_compile(

RESULT_VAR

bindir

SOURCES

source.cpp

)

Therearelotsofoptionsyoucanadd,likeCOMPILE_DEFINITIONS.InCMake3.8+,thiswillhonortheCMakeC/C++/CUDAstandardsettings.Ifyouusetry_runinstead,itwillruntheresultingprogramandgiveyoutheoutputinRUN_OUTPUT_VARIABLE.

FeatureSummaryThisisafairlyusefulbutratheroddmodule.Itallowsyoutoprintoutalistofpackageswhatweresearchedfor,aswellasanyoptionsyouexplicitymark.It'spartiallybutnotcompletelytiedintofind_package.Youfirstincludethemodule,asalways:

include(FeatureSummary)

Then,foranyfindpackagesyouhaverunorwillrun,youcanextendthedefaultinformation:

set_package_properties(OpenMPPROPERTIES

URL"http://www.openmp.org"

DESCRIPTION"Parallelcompilerdirectives"

PURPOSE"Thisiswhatitdoesinmypackage")

YoucanalsosettheTYPEofapackagetoRUNTIME,OPTIONAL,RECOMMENDED,orREQUIRED;youcan't,however,lowerthetypeofapackage;ifyouhavealreadyaddedaREQUIREDpackagethroughfind_packagebasedonanoption,you'llseeitlistedasREQUIRED.

And,youcanmarkanyoptionsaspartofthefeaturesummary.Ifyouchoosethesamenameasapackage,thetwointeractwitheachother.

add_feature_info(WITH_OPENMPOpenMP_CXX_FOUND"OpenMP(ThreadsafeFCNsonly)")

Then,youcanprintoutthesummaryoffeatures,eithertothescreenoralogfile:

if(CMAKE_PROJECT_NAMESTREQUALPROJECT_NAME)

feature_summary(WHATENABLED_FEATURESDISABLED_FEATURESPACKAGES_FOUND)

Usefulmodules

41

Page 42: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

feature_summary(FILENAME${CMAKE_CURRENT_BINARY_DIR}/features.logWHATALL)

endif()

YoucanbuildanycollectionofWHATitemsthatyoulike,orjustuseALL.

Usefulmodules

42

Page 43: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

SupportingIDEsIngeneral,IDEsarealreadysupportedbyastandardCMakeproject.TherearejustafewextrathingsthatcanhelpIDEsperformevenbetter.

Foldersfortargets

SomeIDEs,likeXcode,supportfolders.YouhavetomanuallyenabletheUSE_FOLDERSglobalpropertytoallowCMaketoorganizeyourfilesbyfolders:

set_property(GLOBALPROPERTYUSE_FOLDERSON)

Then,youcanaddtargetstofoldersafteryoucreatethem:

set_property(TARGETMyFilePROPERTYFOLDER"Scripts")

Folderscanbenestedwith/.

Youcancontrolhowfilesshowupineachfolderwithregularexpressionsorexplicitlistingsinsource_group:

FoldersforfilesYoucanalsocontrolhowthefoldersinsidetargetsappear.Therearetwoways,bothusingthesource_groupcommand.Thetraditionalwayis

source_group("SourceFiles\\NewDirectory"REGULAR_EXPRESSION".*\\.c[ucp]p?")

YoucanexplicitlylistfileswithFILES,oruseaREGULAR_EXPRESSION.Thiswayyouhavecompletecontroloverthefolderstructure.However,ifyouron-disklayoutiswelldesigned,youmightjustwanttomimicthat.InCMake3.8+,youcandosoveryeasilywithanewversionofthesource_groupcommand:

source_group(TREE"${CMAKE_CURRENT_SOURCE_DIR}/base/dir"PREFIX"HeaderFiles"FILES${FILE_LIST})

FortheTREEoption,youshouldusuallygiveafullpathstartingwithsomethinglike${CMAKE_CURRENT_SOURCE_DIR}/(becausethecommandinterpretspathsrelativetothebuilddirectory).TheprefixtellsyouwhereitputsitintotheIDEstructure,andtheFILESoptiontakesalistoffiles.CMakewillstriptheTREEpathfromtheFILE_LISTpath,itwilladdPREFIX,andthatwillbetheIDEfolderstructure.

Note:IfyouneedtosupportCMake<3.8,Iwouldrecommendjustprotectingtheabovecommand,andonlysupportingnicefolderlayoutonCMake3.8+.Foroldermethodstodothisfolderlayout,seethisblogpost.

RunningwithanIDE

TouseanIDE,eitherpass-G"nameofIDE"ifCMakecanproducethatIDE'sfiles(likeXcode,VisualStudio),oropentheCMakeLists.txtfilefromyourIDEifthatIDEhasbuiltinsupportforCMake(CLion,QtCreator,manyothers).

IDEs

43

Page 44: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

DebuggingcodeYoumightneedtodebugyourCMakebuild,ordebugyourC++code.Botharecoveredhere.

CMakedebugging

First,let'slookatwaystodebugaCMakeListsorotherCMakefile.

Printingvariables

ThetimehonoredmethodofprintstatementslookslikethisinCMake:

message(STATUS"MY_VARIABLE=${MY_VARIABLE}")

However,abuiltinmodulemakesthiseveneasier:

include(CMakePrintHelpers)

cmake_print_variables(MY_VARIABLE)

Ifyouwanttoprintoutaproperty,thisismuch,muchnicer!Insteadofgettingthepropertiesonebyoneofofeachtarget(orotheritemwithproperties,suchasSOURCES,DIRECTORIES,TESTS,orCACHE_ENTRIES-globalpropertiesseemtobemissingforsomereason),youcansimplylistthemandgetthemprinteddirectly:

cmake_print_properties(

TARGETSmy_target

PROPERTIESPOSITION_INDEPENDENT_CODE

)

Tracingarun

HaveyouwantedtowatchexactlywhathappensinyourCMakefile,andwhen?The--trace-source="filename"featureisfantastic.Everylineruninthefilethatyougivewillbeechoedtothescreenwhenitisrun,lettingyoufollowexactlywhatishappening.Therearerelatedoptionsaswell,buttheytendtoburyyouinoutput.

Forexample:

cmake-S.-Bbuild--trace-source=CMakeLists.txt

Ifyouadd--trace-expand,thevariableswillbeexpandedintotheirvalues.

Buildingindebugmode

Forsingle-configurationgenerators,youcanbuildyourcodewith-DCMAKE_BUILD_TYPE=Debugtogetdebuggingflags.Inmulti-configurationgenerators,likemanyIDEs,youcanpicktheconfigurationintheIDE.Therearedistinctflagsforthismode(variablesendingin_DEBUGasopposedto_RELEASE),aswellasageneratorexpressionvalueCONFIG:DebugorCONFIG:Release.

Onceyoumakeadebugbuild,youcanrunadebugger,suchasgdborlldbonit.

Debugging

44

Page 45: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

IncludingSmallProjectsThisiswhereagoodGitsystemplusCMakeshines.Youmightnotbeabletosolvealltheworld'sproblems,butthisisprettycloseforC++!

Thereareseveralmethodslistedinthechaptersinthissection.

IncludingProjects

45

Page 46: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

GitSubmoduleMethodIfyouwanttoaddaGitrepositoryonthesameservice(GitHub,GitLab,BitBucket,etc),thefollowingisthecorrectGitcommandtosetthatupasasubmoduleintheexterndirectory:

Therelativepathtotherepoisimportant;itallowsyoutokeepthesameaccessmethod(sshorhttps)astheparentrepository.Thisworksverywellinmostways.Whenyouareinsidethesubmodule,youcantreatitjustlikeanormalrepo,andwhenyouareintheparentrepository,youcan"add"tochangethecurrentcommitpointer.

Butthetraditionaldownsideisthatyoueitherhavetohaveyourusersknowgitsubmodulecommands,sotheycaninitandupdatetherepo,ortheyhavetoadd--recursivewhentheyinitiallycloneyourrepo.CMakecanofferasolution:

find_package(GitQUIET)

if(GIT_FOUNDANDEXISTS"${PROJECT_SOURCE_DIR}/.git")

#Updatesubmodulesasneeded

option(GIT_SUBMODULE"Checksubmodulesduringbuild"ON)

if(GIT_SUBMODULE)

message(STATUS"Submoduleupdate")

execute_process(COMMAND${GIT_EXECUTABLE}submoduleupdate--init--recursive

WORKING_DIRECTORY${CMAKE_CURRENT_SOURCE_DIR}

RESULT_VARIABLEGIT_SUBMOD_RESULT)

if(NOTGIT_SUBMOD_RESULTEQUAL"0")

message(FATAL_ERROR"gitsubmoduleupdate--initfailedwith${GIT_SUBMOD_RESULT},pleasecheckoutsubmodules")

endif()

endif()

endif()

if(NOTEXISTS"${PROJECT_SOURCE_DIR}/extern/repo/CMakeLists.txt")

message(FATAL_ERROR"Thesubmoduleswerenotdownloaded!GIT_SUBMODULEwasturnedofforfailed.Pleaseupdatesubmodules

andtryagain.")

endif()

ThefirstlinechecksforGitusingCMake'sbuiltinFindGit.cmake.Then,ifyouareinagitcheckoutofyoursource,addanoption(defaultingtoON)thatallowsdeveloperstoturnoffthefeatureiftheyneedto.Wethenrunthecommandtogetallrepositories,andfailifthatcommandfails,withaniceerrormessage.Finally,weverifythattherepositoriesexistbeforecontinuing,regardlessofthemethodusedtoobtainthem.YoucanuseORtolistseveral.

Now,youruserscanbecompletelyoblivioustotheexistenceofthesubmodules,andyoucanstillkeepupgooddevelopmentpractices!Theonlythingtowatchoutforisfordevelopers;youwillresetthesubmodulewhenyourerunCMakeifyouaredevelopinginsidethesubmodule.Justaddnewcommitstotheparentstagingarea,andyou'llbefine.

YoucanthenincludeprojectsthatprovidegoodCMakesupport:

add_subdirectory(extern/repo)

Or,youcanbuildaninterfacelibrarytargetyourselfifitisaheaderonlyproject.Or,youcanusefind_packageifthatissupported,probablypreparingtheinitialsearchdirectorytobetheoneyou'veadded(checkthedocsorthefilefortheFind*.cmakefileyouareusing).YoucanalsoincludeaCMakehelperfiledirectoryifyouappendtoyourCMAKE_MODULE_PATH,forexampletoaddpybind11'simprovedFindPython*.cmakefiles.

Bonus:Gitversionnumber

MovethistoGitsection:

execute_process(COMMAND${GIT_EXECUTABLE}rev-parse--shortHEAD

WORKING_DIRECTORY"${CMAKE_CURRENT_SOURCE_DIR}"

gitbook$gitsubmoduleadd../../owner/repo.gitextern/repo

Submodule

46

Page 47: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

OUTPUT_VARIABLEPACKAGE_GIT_VERSION

ERROR_QUIET

OUTPUT_STRIP_TRAILING_WHITESPACE)

Submodule

47

Page 48: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

GoogleTest:Downloadmethod

DownloadingMethod:buildtime

UntilCMake3.11,theprimarydownloadmethodforpackageswasdoneatbuildtime.Thiscausesseveralissues;mostimportantofwhichisthatadd_subdirectorydoesn'tworkonafilethatdoesn'texistyet!Thetoolforthis,ExternalProject,hastoworkaroundthisbydoingthebuilditself.(Itcan,however,buildnon-CMakepackagesaswell).

.NotethatExternalDataisthetoolfornon-packagedata.↩

DownloadingMethod:configuretimeIfyoupreferconfiguretime,seetheCrascit/DownloadProjectrepositoryforadrop-insolution.Submodulesworksowell,though,thatI'vediscontinuedmostofthedownloadsforthingslikeGoogleTestandmovedthemtosubmodules.Autodownloadsarehardertomimicifyoudon'thaveinternetaccess,andtheyareoftenimplementedinthebuilddirectory,wastingtimeandspaceifyouhavemultiplebuilddirectories.

1

1

DownloadProject

48

Page 49: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

FetchContent(CMake3.11+)Often,youwouldliketodoyourdownloadofdataorpackagesaspartoftheconfigureinsteadofthebuild.Thiswasinventedseveraltimesinthirdpartymodules,butwasfinallyaddedtoCMakeitselfaspartofCMake3.11astheFetchContentmodule.

TheFetchContentmodulehasexcellentdocumentationthatIwon'ttrytorepeat.Thekeyideasare:

UseFetchContent_Declare(MyName)togetdataorapackage.YoucansetURLs,Gitrepositories,andmore.UseFetchContent_GetProperties(MyName)onthenameyoupickedinthefirststeptogetMyName_*variables.CheckMyName_POPULATED,andifnotpopulated,useFetchContent_Populate(MyName)(andifapackage,add_subdirectory("${MyName_SOURCE_DIR}""${MyName_BINARY_DIR}"))

Forexample,todownloadCatch2:

FetchContent_Declare(

catch

GIT_REPOSITORYhttps://github.com/catchorg/Catch2.git

GIT_TAGv2.9.1

)

#CMake3.14+

FetchContent_MakeAvailable(catch)

Ifyoucan'tuseCMake3.14+,theclassicwaytopreparecodewas:

#CMake3.11+

FetchContent_GetProperties(catch)

if(NOTcatch_POPULATED)

FetchContent_Populate(catch)

add_subdirectory(${catch_SOURCE_DIR}${catch_BINARY_DIR})

endif()

Ofcourse,youcouldbundledthisupintoamacro:

if(${CMAKE_VERSION}VERSION_LESS3.14)

macro(FetchContent_MakeAvailableNAME)

FetchContent_GetProperties(${NAME})

if(NOT${NAME}_POPULATED)

FetchContent_Populate(${NAME})

add_subdirectory(${${NAME}_SOURCE_DIR}${${NAME}_BINARY_DIR})

endif()

endmacro()

endif()

NowyouhavetheCMake3.14+syntaxinCMake3.11+.

Fetch(CMake3.11)

49

Page 50: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Testing

GeneralTestingInformation

InyourmainCMakeLists.txtyouneedtoaddthefollowingfunctioncall(notinasubfolder):

if(CMAKE_PROJECT_NAMESTREQUALPROJECT_NAME)

include(CTest)

endif()

WhichwillenabletestingandsetaBUILD_TESTINGoptionsouserscanturntestingonandoff(Alongwithafewotherthings).Oryoucandothisyourselfbydirectlycallingenable_testing().

Whenyouaddyourtestfolder,youshoulddosomethinglikethis:

if(CMAKE_PROJECT_NAMESTREQUALPROJECT_NAMEANDBUILD_TESTING)

add_subdirectory(tests)

endif()

Thereasonforthisisthatifsomeoneelseincludesyourpackage,andtheyuseBUILD_TESTING,theyprobablydonotwantyourteststobuild.Intherarecasethatyoureallydowanttoenabletestingonbothpackages,youcanprovideanoverride:

if((CMAKE_PROJECT_NAMESTREQUALPROJECT_NAMEORMYPROJECT_BUILD_TESTING)ANDBUILD_TESTING)

add_subdirectory(tests)

endif()

Themainusecasefortheoverrideaboveisactuallyinthisbook'sownexamples,asthemasterCMakeprojectreallydoeswanttorunallthesubprojecttests.

Youcanregistertargetswith:

add_test(NAMETestNameCOMMANDTargetName)

IfyouputsomethingelsebesidesatargetnameafterCOMMAND,itwillregisterasacommandlinetorun.Itwouldalsobevalidtoputthegeneratorexpression:

add_test(NAMETestNameCOMMAND$<TARGET_FILE:${TESTNAME}>)

whichwouldusetheoutputlocation(thus,theexecutable)oftheproducedtarget.

Buildingaspartofatest

IfyouwanttorunCMaketobuildaprojectaspartofatest,youcandothattoo(infact,thisishowCMaketestsitself).Forexample,ifyourmasterprojectwascalledMyProjectandyouhadanexamples/simpleprojectthatcouldbuildbyitself,thiswouldlooklike:

add_test(

NAME

ExampleCMakeBuild

COMMAND

"${CMAKE_CTEST_COMMAND}"

--build-and-test"${My_SOURCE_DIR}/examples/simple"

"${CMAKE_CURRENT_BINARY_DIR}/simple"

--build-generator"${CMAKE_GENERATOR}"

--test-command"${CMAKE_CTEST_COMMAND}"

Testing

50

Page 51: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

)

TestingFrameworksLookatthesubchaptersforrecipesforpopularframeworks.

GoogleTest:ApopularoptionfromGoogle.Developmentcanbeabitslow.Catch2:Amodern,PyTest-likeframeworkwithclevermacros.DocTest:AreplacementforCatch2thatissupposedtocompilemuchfasterandbecleaner.SeeCatch2chapterandreplacewithDocTest.

Testing

51

Page 52: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

GoogleTest

Submodulemethod(preferred)

Tousethismethod,justcheckoutGoogleTestasasubmodule:

gitsubmoduleadd--branch=release-1.8.0../../google/googletest.gitextern/googletest

Then,inyourmainCMakeLists.txt:

option(PACKAGE_TESTS"Buildthetests"ON)

if(PACKAGE_TESTS)

enable_testing()

include(GoogleTest)

add_subdirectory(tests)

endif()

IwouldrecommendusingsomethinglikePROJECT_NAMESTREQUALCMAKE_PROJECT_NAMEtosetthedefaultforthePACKAGE_TESTSoption,sincethisshouldonlybuildbydefaultifthisisthecurrentproject.Asmentionedbefore,youhavetodotheenable_testinginyourmainCMakeLists.

Now,inyourtestsdirectory:

add_subdirectory("${PROJECT_SOURCE_DIR}/extern/googletest""extern/googletest")

IfyoudidthisinyourmainCMakeLists,youcoulduseanormaladd_subdirectory;theextrapathhereisneededtocorrectthebuildpathbecausewearecallingitfromasubdirectory.

Thenextlineisoptional,butkeepsyourCACHEcleaner:

mark_as_advanced(

BUILD_GMOCKBUILD_GTESTBUILD_SHARED_LIBS

gmock_build_testsgtest_build_samplesgtest_build_tests

gtest_disable_pthreadsgtest_force_shared_crtgtest_hide_internal_symbols

)

IfyouareinterestedinkeepingIDEsthatsupportfoldersclean,Iwouldalsoaddtheselines:

set_target_properties(gtestPROPERTIESFOLDERextern)

set_target_properties(gtest_mainPROPERTIESFOLDERextern)

set_target_properties(gmockPROPERTIESFOLDERextern)

set_target_properties(gmock_mainPROPERTIESFOLDERextern)

Then,toaddatest,I'drecommendthefollowingmacro:

macro(package_add_testTESTNAME)

#createanexectuableinwhichthetestswillbestored

add_executable(${TESTNAME}${ARGN})

#linktheGoogletestinfrastructure,mockinglibrary,andadefaultmainfuctionto

#thetestexecutable.Removeg_test_mainifwritingyourownmainfunction.

target_link_libraries(${TESTNAME}gtestgmockgtest_main)

#gtest_discover_testsreplacesgtest_add_tests,

#seehttps://cmake.org/cmake/help/v3.10/module/GoogleTest.htmlformoreoptionstopasstoit

gtest_discover_tests(${TESTNAME}

#setaworkingdirectorysoyourprojectrootsothatyoucanfindtestdataviapathsrelativetotheprojectroot

WORKING_DIRECTORY${PROJECT_DIR}

PROPERTIESVS_DEBUGGER_WORKING_DIRECTORY"${PROJECT_DIR}"

1

GoogleTest

52

Page 53: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

)

set_target_properties(${TESTNAME}PROPERTIESFOLDERtests)

endmacro()

package_add_test(test1test1.cpp)

Thiswillallowyoutoquicklyandsimplyaddtests.Feelfreetoadjusttosuityourneeds.Ifyouhaven'tseenitbefore,ARGNis"everyargumentafterthelistedones".Modifythemacrotomeetyourneeds.Forexample,ifyou'retestinglibrariesandneedtolinkindifferentlibrariesfordifferenttests,youmightusethis:

macro(package_add_test_with_librariesTESTNAMEFILESLIBRARIESTEST_WORKING_DIRECTORY)

add_executable(${TESTNAME}${FILES})

target_link_libraries(${TESTNAME}gtestgmockgtest_main${LIBRARIES})

gtest_discover_tests(${TESTNAME}

WORKING_DIRECTORY${TEST_WORKING_DIRECTORY}

PROPERTIESVS_DEBUGGER_WORKING_DIRECTORY"${TEST_WORKING_DIRECTORY}"

)

set_target_properties(${TESTNAME}PROPERTIESFOLDERtests)

endmacro()

package_add_test_with_libraries(test1test1.cpplib_to_test"${PROJECT_DIR}/european-test-data/")

Downloadmethod

YoucanusethedownloaderinmyCMakehelperrepository,usingCMake'sincludecommand.

ThisisadownloaderforGoogleTest,basedontheexcellentDownloadProjecttool.DownloadingacopyforeachprojectistherecommendedwaytouseGoogleTest(somuchso,infact,thattheyhavedisabledtheautomaticCMakeinstalltarget),sothisrespectsthatdesigndecision.Thismethoddownloadstheprojectatconfiguretime,sothatIDE'scorrectlyfindthelibraries.Usingitissimple:

cmake_minimum_required(VERSION3.10)

project(MyProjectCXX)

list(APPENDCMAKE_MODULE_PATH${PROJECT_SOURCE_DIR}/cmake)

enable_testing()#Mustbeinmainfile

include(AddGoogleTest)#Couldbein/tests/CMakeLists.txt

add_executable(SimpleTestSimpleTest.cu)

add_gtest(SimpleTest)

Note:add_gtestisjustamacrothataddsgtest,gmock,andgtest_main,andthenrunsadd_testtocreateatestwiththesamename:

target_link_libraries(SimpleTestgtestgmockgtest_main)

add_test(SimpleTestSimpleTest)

FetchContent:CMake3.11TheexamplefortheFetchContentmoduleisGoogleTest:

include(FetchContent)

FetchContent_Declare(

googletest

GIT_REPOSITORYhttps://github.com/google/googletest.git

GIT_TAGrelease-1.8.0

)

FetchContent_GetProperties(googletest)

if(NOTgoogletest_POPULATED)

GoogleTest

53

Page 54: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

FetchContent_Populate(googletest)

add_subdirectory(${googletest_SOURCE_DIR}${googletest_BINARY_DIR})

endif()

.HereI'veassumedthatyouareworkingonaGitHubrepositorybyusingtherelativepathtogoogletest.↩1

GoogleTest

54

Page 55: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

CatchCatchandCatch2(C++11onlyversion)arepowerful,idomatictestingsolutionssimilarinphilosophytoPyTestforPython.TouseCatchinaCMakeproject,thereareseveraloptions.

Vendoring

IfyousimplydropinthesingleincludereleaseofCatchintoyourproject,thisiswhatyouwouldneedtoaddCatch:

#Prepare"Catch"libraryforotherexecutables

set(CATCH_INCLUDE_DIR${CMAKE_CURRENT_SOURCE_DIR}/extern/catch)

add_library(Catch2::CatchIMPORTEDINTERFACE)

set_property(Catch2::CatchPROPERTYINTERFACE_INCLUDE_DIRECTORIES"${CATCH_INCLUDE_DIR}")

Then,youwouldlinktoCatch2::Catch.ThiswouldhavebeenokayasanINTERFACEtargetsinceyouwon'tbeexportingyourtests.

DirectinclusionIfyouaddthelibraryusingExternalProject,FetchContent,orgitsubmodules,youcanalsoadd_subdirectoryCatch(CMake3.1+).

CatchalsoprovidestwoCMakemodulesthatyoucanusetoregistertheindividualtestswithCMake.

Catch

55

Page 56: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

ExportingandInstallingTherearethreegoodwaysandonebadwaytoallowothersuseyourlibrary:

Findmodule(thebadway)

Ifyouarethelibraryauthor,don'tmakeaFind<mypackage>.cmakescript!TheseweredesignedforlibrarieswhoseauthorsdidnotsupportCMake.UseaConfig<mypackage>.cmakeinsteadaslistedbelow.

AddSubproject

Apackagecanincludeyourprojectinasubdirectory,andthenuseadd_directoryonthesubdirectory.Thisusefulforheader-onlyandquick-to-compilelibraries.Notethattheinstallcommandsmayinterferewiththeparentproject,soyoucanaddEXCLUDE_FROM_ALLtotheadd_subdirectorycommand;thetargetsyouexplicitlyusewillstillbebuilt.

Inordertosupportthisasalibraryauthor,makesureyouuseCMAKE_CURRENT_SOURCE_DIRinsteadofPROJECT_SOURCE_DIR(andlikewiseforothervariables,likebinarydirs).YoucancheckCMAKE_PROJECT_NAMESTREQUALPROJECT_NAMEtoonlyaddoptionsordefaultsthatmakesenseifthisisaproject.

Also,sincenamespacesareagoodidea,andtheusageofyourlibraryshouldbeconsistentwiththeothermethodsbelow,youshouldadd

add_library(MyLib::MyLibALIASMyLib)

tostandardisetheusageacrossallmethods.ThisALIAStargetwillnotbeexportedbelow.

ExportingThethirdwayis*Config.cmakescripts;thatwillbethetopicofthenextchapterinthissession.

ExportingandInstalling

56

Page 57: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

InstallingInstallcommandscauseafileortargettobe"installed"intotheinstalltreewhenyoumakeinstall.Yourbasictargetinstallcommandlookslikethis:

install(TARGETSMyLib

EXPORTMyLibTargets

LIBRARYDESTINATIONlib

ARCHIVEDESTINATIONlib

RUNTIMEDESTINATIONbin

INCLUDESDESTINATIONinclude

)

Thevariousdestinationsareonlyneededifyouhavealibrary,staticlibrary,orprogramtoinstall.Theincludesdestinationisspecial;sinceatargetdoesnotinstallincludes.Itonlysetstheincludesdestinationontheexportedtarget(whichisoftenalreadysetbytarget_include_directories,sochecktheMyLibTargetsfileandmakesureyoudon'thavetheincludedirectoryincludedtwiceifyouwantcleancmakefiles).

It'susuallyagoodideatogiveCMakeaccesstotheversion,sothatfind_packagecanhaveaversionspecified.Thatlookslikethis:

include(CMakePackageConfigHelpers)

write_basic_package_version_file(

MyLibConfigVersion.cmake

VERSION${PACKAGE_VERSION}

COMPATIBILITYAnyNewerVersion

)

Youhavetwochoicesnext.YouneedtomakeaMyLibConfig.cmake,butyoucandoiteitherbyexportingyourtargetsdirectlytoit,orbywritingitbyhand,thenincludingthetargetsfile.Thelateroptioniswhatyou'llneedifyouhaveanydependencies,evenjustOpenMP,soI'llillustratethatmethod.

First,makeaninstalltargetsfile(verysimilartotheoneyoumadeinthebuilddirectory):

install(EXPORTMyLibTargets

FILEMyLibTargets.cmake

NAMESPACEMyLib::

DESTINATIONlib/cmake/MyLib

)

Thisfilewilltakethetargetsyouexportedandputtheminafile.Ifyouhavenodependencies,justuseMyLibConfig.cmakeinsteadofMyLibTargets.cmakehere.ThenwriteacustomMyLibConfig.cmakefileinyoursourcetreesomewhere.Ifyouwanttocaptureconfiguretimevariables,youcanusea.infile,andyouwillwanttousethe@[email protected]:

include(CMakeFindDependencyMacro)

#Capturingvaluesfromconfigure(optional)

set(my-config-var@my-config-var@)

#Samesyntaxasfind_package

find_dependency(MYDEPREQUIRED)

#Anyextrasetup

#Addthetargetsfile

include("${CMAKE_CURRENT_LIST_DIR}/MyLibTargets.cmake")

Now,youcanuseconfigurefile(ifyouuseda.infile)andtheninstalltheresultingfile.Sincewe'vemadeaConfigVersionfile,thisisagoodplacetoinstallittoo.

Installing

57

Page 58: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

configure_file(MyLibConfig.cmake.inMyLibConfig.cmake@ONLY)

install(FILES"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfig.cmake"

"${CMAKE_CURRENT_BINARY_DIR}/MyLibConfigVersion.cmake"

DESTINATIONlib/cmake/MyLib

)

That'sit!Nowonceyouinstallapackage,therewillbefilesinlib/cmake/MyLibthatCMakewillsearchfor(specifically,MyLibConfig.cmakeandMyLibConfigVersion.cmake),andthetargetsfilethatconfigusesshouldbethereaswell.

WhenCMakesearchesforapackage,itwilllookinthecurrentinstallprefixandseveralstandardplaces.Youcanalsoaddthistoyoursearchpathmanually,includingMyLib_PATH,andCMakegivestheusernicehelpoutputiftheconfigurefileisnotfound.

Installing

58

Page 59: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Exporting

ThedefaultbehaviorforexportingchangedinCMake3.15.Sincechangingfilesinauser'shomedirectoryisconsidered"surprising"(anditis,whichiswhythischapterexists),itisnolongerthedefaultbehavior.IfyousetaminimumormaximumCMakeversionof3.15orbetter,thiswillnolongerhappenunlessyousetCMAKE_EXPORT_PACKAGE_REGISTRY,asmentionedbelow.

Therearethreewaystoaccessaprojectfromanotherproject:subdirectory,exportedbuilddirectories,andinstalling.Tousethebuilddirectoryofoneprojectinanotherproject,youwillneedtoexporttargets.Exportingtargetsisneededforaproperinstall,allowingthebuilddirectorytobeusedaswellisjusttwoaddedlines.ItisnotgenerallyawaytoworkthatIwouldrecommend,butcanbeusefulfordevelopmentandaswaytopreparetheinstallationprocedurediscussedlater.

Youshouldmakeanexportset,probablyneartheendofyourmainCMakeLists.txt:

export(TARGETSMyLib1MyLib2NAMESPACEMyLib::FILEMyLibTargets.cmake)

Thisputsthetargetsyouhavelistedintoafileinthebuilddirectory,andoptionallyprefixesthemwithanamespace.Now,toallowCMaketofindthispackage,exportthepackageintothe$HOME/.cmake/packagesfolder:

set(CMAKE_EXPORT_PACKAGE_REGISTRYON)

export(PACKAGEMyLib)

Now,ifyoufind_package(MyLib),CMakecanfindthebuildfolder.LookatthegeneratedMyLibTargets.cmakefiletohelpyouunderstandexactlywhatiscreated;it'sjustanormalCMakefile,withtheexportedtargets.

Notethatthere'sadownside:ifyouhaveimporteddependencies,theywillneedtobeimportedbeforeyoufind_package.Thatwillbefixedinthenextmethod.

Exporting

59

Page 60: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

PackagingTherearetwowaystoinstructCMaketobuildyourpackage;oneistouseaCPackConfig.cmakefile,andtheotheristointegratetheCPackvariablesintoyourCMakeLists.txtfile.Sinceyouwantvariablesfromyourmainbuildtobeincluded,likeversionnumber,you'llwanttomakeaconfigurefileifyougothatroute.I'llshowyoutheintegratedversion:

#Packagingsupport

set(CPACK_PACKAGE_VENDOR"Vendorname")

set(CPACK_PACKAGE_DESCRIPTION_SUMMARY"Somesummary")

set(CPACK_PACKAGE_VERSION_MAJOR${PROJECT_VERSION_MAJOR})

set(CPACK_PACKAGE_VERSION_MINOR${PROJECT_VERSION_MINOR})

set(CPACK_PACKAGE_VERSION_PATCH${PROJECT_VERSION_PATCH})

set(CPACK_RESOURCE_FILE_LICENSE"${CMAKE_CURRENT_SOURCE_DIR}/LICENCE")

set(CPACK_RESOURCE_FILE_README"${CMAKE_CURRENT_SOURCE_DIR}/README.md")

Thesearethemostcommonvariablesyou'llneedtomakeabinarypackage.AbinarypackageusestheinstallmechanismofCMake,soanythingthatisinstalledwillbepresent.

Youcanalsomakeasourcepackage.YoushouldsetCMAKE_SOUCE_IGNORE_FILEStoregularexpressionsthatensureyoudon'tpickupanyextrafiles(likethebuilddirectoryorgitdetails);otherwisemakepackage_sourcewillbundleupliterallyeverythinginthesourcedirectory.Youcanalsosetthesourcegeneratortomakeyourfavoritetypesoffilesforsourcepackages:

set(CPACK_SOURCE_GENERATOR"TGZ;ZIP")

set(CPACK_SOURCE_IGNORE_FILES

/.git

/dist

/.*build.*

/\\\\.DS_Store

)

NotethatthiswillnotworkonWindows,butthegeneratedsourcepackagesworkonWindows.

Finally,youneedtoincludetheCPackmodule:

include(CPack)

Packaging

60

Page 61: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

FindingPackageTherearetwowaystofindpackagesinCMake.

Lookingforlibraries

61

Page 62: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

CUDA(inprogress)CUDAsupportisavailableintwoflavors.Thenewmethod,introducedinCMake3.8(3.9forWindows),willbewhatIfocusonfirst.Theoldmethodwillbecoveredafterwards,butasyou'llsee,it'suglierandhardertogetright.I'dsticktorequiringCMake3.8or3.9forCUDA(andCMake3.11forIDEslikeXcodeandVisualStudio).

AgoodresourceforCUDAandModernCMakeisthistalkbyCMakedeveloperRobertMaynardatGTC2017.

Method1:CUDAasaFirstClassLanguage

Thismethodisquitenew,anddoesn'tseemtohavemuchdocumentation.Thereareseveralissuesyouneedtowatchoutforwhenusingit,butoverallisshouldbeamuchnicerandcleanerwaytouseCUDA.

AddingtheCUDALanguage

TherearetwowaystoenableCUDAsupport.IfCUDAisnotoptional:

project(MY_PROJECTLANGUAGESCUDACXX)

You'llprobablywantCXXlistedherealso.And,ifCUDAisoptional,you'llwanttoputthisinsomewhereconditionally:

enable_language(CUDA)

TochecktoseeifCUDAisavailable,useCheckLanuage:

include(CheckLanguage)

check_language(CUDA)

YoucanchecktheversionoftheNVCCtoolkitwithCMAKE_CUDA_COMPILER_VERSION(fornow,onlyNVCCissupported,butjusttobesure,checkCMAKE_CUDA_COMPILER_IDSTREQUAL"NVIDIA").

VariablesforCUDA

ManyvariableswithCXXinthenamehaveaCUDAversionwithCUDAinstead.Forexample,tosettheC++standardrequiredforCUDA,

if(NOTDEFINEDCMAKE_CUDA_STANDARD)

set(CMAKE_CUDA_STANDARD11)

set(CMAKE_CUDA_STANDARD_REQUIREDON)

endif()

Addingalibrary

Thisistheeasypart;aslongasyouuse.cuforCUDAfiles,youcanjustaddlibrarieslikeyounormallywould.

Youcanalsouseseparablecompilation:

set_target_properties(mylibPROPERTIES

CUDA_SEPERABLE_COMPILATIONON)

YoucanalsodirecltymakeaPTXfilewiththeCUDA_PTX_COMPILATIONproperty.

CUDA

62

Page 63: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Workingwithtargets

UsingtargetsshouldworksimilarlytoCXX,butthere'saproblem.Ifyouincludeatargetthatincludescompileroptions(flags),mostofthetime,theoptionswillnotbeprotectedbythecorrectincludes(andthechancesofthemhavingthecorrectCUDAwrapperisevensmaller).Here'swhatacorrectcompileroptionslineshouldlooklike:

"$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CXX>>:-fopenmp>$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CUDA>>:-Xcompiler=-fopenmp>"

However,ifyouusingalmostanyfind_package,andusingtheModernCMakemethodsoftargetsandinheritance,everythingwillbreak.I'velearnedthatthehardway.

Fornow,here'saprettyreasonablesolution,aslongasyouknowtheun-aliasedtargetname.It'safunctionthatwillfixaC++onlytargetbywrappingtheflagsifusingaCUDAcompiler:

function(CUDA_CONVERT_FLAGSEXISTING_TARGET)

get_property(old_flagsTARGET${EXISTING_TARGET}PROPERTYINTERFACE_COMPILE_OPTIONS)

if(NOT"${old_flags}"STREQUAL"")

string(REPLACE";"","CUDA_flags"${old_flags}")

set_property(TARGET${EXISTING_TARGET}PROPERTYINTERFACE_COMPILE_OPTIONS

"$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CXX>>:${old_flags}>$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CUDA>>:-Xcompile

r=${CUDA_flags}>"

)

endif()

endfunction()

Usefulvariables

CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES:Placeforbuilt-inThrust,etcCMAKE_CUDA_COMPILER:NVCCwithlocation

NotethatFindCUDAisdeprecated,butfornow,thefollowingfunctionsrequireFindCUDA:

CUDAversionchecks/pickingaversionArchitecturedetection(Note:3.12fixesthispartially)LinkingtoCUDAlibrariesfromnon-.cufiles

Method2:FindCUDAIfyouwanttosupportanolderversionofCMake,IrecommendatleastincludingtheFindCUDAfromCMakeversion3.9inyourcmakefolder(seetheCLIUtilsgithuborganizationforagitrepository).You'llwanttwofeaturesthatwereadded:CUDA_LINK_LIBRARIES_KEYWORDandcuda_select_nvcc_arch_flags,alongwiththenewerarchitecturesandCUDAversions.

TousetheoldCUDAsupport,youusefind_package:

find_package(CUDA7.0REQUIRED)

message(STATUS"FoundCUDA${CUDA_VERSION_STRING}at${CUDA_TOOLKIT_ROOT_DIR}")

YoucancontroltheCUDAflagswithCUDA_NVCC_FLAGS(listappend)andyoucancontrolseparablecompilationwithCUDA_SEPARABLE_COMPILATION.You'llalsowanttomakesureCUDAplaysniceandaddskeywordstothetargets(CMake3.9+):

set(CUDA_LINK_LIBRARIES_KEYWORDPUBLIC)

You'llalsomightwanttoallowausertocheckforthearchflagsoftheircurrenthardware:

cuda_select_nvcc_arch_flags(ARCH_FLAGS)#optionalargumentforarchtoadd

CUDA

63

Page 64: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

CUDA

64

Page 65: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

OpenMPOpenMPsupportwasdrasticallyimprovedinCMake3.9+.TheModern(TM)waytoaddOpenMPtoatargetis:

find_package(OpenMP)

if(OpenMP_CXX_FOUND)

target_link_libraries(MyTargetPUBLICOpenMP::OpenMP_CXX)

endif()

Thisnotonlyiscleanerthantheoldmethod,itwillalsocorrectlysetthelibrarylinklinedifferentlyfromthecompilelineifneeded.InCMake3.12+,thiswillevensupportOpenMPonmacOS(ifthelibraryisavailable,suchaswithbrewinstalllibomp).However,ifyouneedtosupportolderCMake,thefollowingworksonCMake3.1+:

#ForCMake<3.9,weneedtomakethetargetourselves

if(NOTTARGETOpenMP::OpenMP_CXX)

find_package(ThreadsREQUIRED)

add_library(OpenMP::OpenMP_CXXIMPORTEDINTERFACE)

set_property(TARGETOpenMP::OpenMP_CXX

PROPERTYINTERFACE_COMPILE_OPTIONS${OpenMP_CXX_FLAGS})

#Onlyworksifthesameflagispassedtothelinker;useCMake3.9+otherwise(Intel,AppleClang)

set_property(TARGETOpenMP::OpenMP_CXX

PROPERTYINTERFACE_LINK_LIBRARIES${OpenMP_CXX_FLAGS}Threads::Threads)

endif()

target_link_libraries(MyTargetPUBLICOpenMP::OpenMP_CXX)

Warning:CMake<3.4hasabugintheThreadspackagethatrequiresyoutohavetheClanguageenabled.

OpenMP

65

Page 66: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

BoostlibraryTheBoostlibraryisincludedinthefindpackagesthatCMakeprovides,butithasacoupleofodditiesinhowitworks.SeeFindBoostforafulldescription;thiswilljustgiveaquickoverviewandprovidearecipe.BesuretocheckthepagefortheminimumrequiredversionofCMakeyouareusingandseewhatoptionsyouhave.

First,youcancustomizethebehavioroftheBoostlibrariesselectedusingasetofvariablesthatyousetbeforesearchingforBoost.Thereareagrowingnumberofsettings,butherearethethreemostcommonones:

set(Boost_USE_STATIC_LIBSOFF)

set(Boost_USE_MULTITHREADEDON)

set(Boost_USE_STATIC_RUNTIMEOFF)

InCMake3.5,importedtargetswereadded.Thesetargetshandledependenciesforyouaswell,sotheyareaverynicewaytoaddBoostlibraries.However,CMakehasthedependencyinformationbakedintoitforallknownversionsofBoost,soCMakemustbenewerthanBoostforthesetowork.Inarecentmergerequest,CMakestartedassumingthatthedependenciesholdfromthelastversionitknowsabout,andwillusethat(alongwithgivingawarning).ThisfunctionalitywasbackportedintoCMake3.9.

TheimporttargetsareintheBoost::namespace.Boost::boostistheheaderonlypart.Theothercompiledlibrariesareavailable,andincludedependenciesasneeded.

HereisanexampleforusingtheBoost::filesystemlibrary:

set(Boost_USE_STATIC_LIBSOFF)

set(Boost_USE_MULTITHREADEDON)

set(Boost_USE_STATIC_RUNTIMEOFF)

find_package(Boost1.50REQUIREDCOMPONENTSfilesystem)

message(STATUS"Boostversion:${Boost_VERSION}")

#ThisisneededifyourBoostversionisnewerthanyourCMakeversion

#orifyouhaveanoldversionofCMake(<3.5)

if(NOTTARGETBoost::filesystem)

add_library(Boost::filesystemIMPORTEDINTERFACE)

set_property(TARGETBoost::filesystemPROPERTY

INTERFACE_INCLUDE_DIRECTORIES${Boost_INCLUDE_DIR})

set_property(TARGETBoost::filesystemPROPERTY

INTERFACE_LINK_LIBRARIES${Boost_LIBRARIES})

endif()

target_link_libraries(MyExeOrLibraryPUBLICBoost::filesystem)

Boost

66

Page 67: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

MPIToaddMPI,likeOpenMP,you'llbebestoffwithCMake3.9+.

find_package(MPIREQUIRED)

message(STATUS"Run:${MPIEXEC}${MPIEXEC_NUMPROC_FLAG}${MPIEXEC_MAX_NUMPROCS}${MPIEXEC_PREFLAGS}EXECUTABLE${MPIEXEC_POSTF

LAGS}ARGS")

target_link_libraries(MyTargetPUBLICMPI::MPI_CXX)

However,youcanimitatethisonCMake3.1+with:

find_package(MPIREQUIRED)

#ForsupportingCMake<3.9:

if(NOTTARGETMPI::MPI_CXX)

add_library(MPI::MPI_CXXIMPORTEDINTERFACE)

set_property(TARGETMPI::MPI_CXX

PROPERTYINTERFACE_COMPILE_OPTIONS${MPI_CXX_COMPILE_FLAGS})

set_property(TARGETMPI::MPI_CXX

PROPERTYINTERFACE_INCLUDE_DIRECTORIES"${MPI_CXX_INCLUDE_PATH}")

set_property(TARGETMPI::MPI_CXX

PROPERTYINTERFACE_LINK_LIBRARIES${MPI_CXX_LINK_FLAGS}${MPI_CXX_LIBRARIES})

endif()

message(STATUS"Run:${MPIEXEC}${MPIEXEC_NUMPROC_FLAG}${MPIEXEC_MAX_NUMPROCS}${MPIEXEC_PREFLAGS}EXECUTABLE${MPIEXEC_POSTF

LAGS}ARGS")

target_link_libraries(MyTargetPUBLICMPI::MPI_CXX)

MPI

67

Page 68: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

ROOTROOTisaC++ToolkitforHighEnergyPhysics.Itishuge.TherearereallyalotofwaystouseitinCMake,thoughmany/mostoftheexamplesyou'llfindareprobablywrong.Here'smyrecommendation.

Mostimportantly,therearelotsofimprovementsinCMakesupportinmorerecentversionsofROOT-Using6.16+ismuch,mucheasier!Ifyoureallymustsupport6.14orearlier,seethesectionattheend.

FindingROOT

ROOT6.10+supportsconfigfilediscovery,soyoucanjustdo:

find_package(ROOT6.16CONFIGREQUIRED)

toattempttofindROOT.Ifyoudon'thaveyourpathssetup,youcanpass-DROOT_DIR=$ROOTSYS/cmaketofindROOT.(But,really,youshouldsourcethisroot.sh).

Therightway(Targets)

ROOT6.12andearlierdonotaddtheincludedirectoryforimportedtargets.ROOT6.14+hascorrectedthiserror,andrequiredtargetpropertieshavebeengettingbetter.Thismethodisrapidlybecomingeasiertouse(seetheexampleattheendofthispagefortheolderROOTdetails).

Tolink,justpickthelibrariesyouwanttouse:

add_executable(RootSimpleExampleSimpleExample.cxx)

target_link_libraries(RootSimpleExamplePUBLICROOT::Physics)

Ifyou'dliketoseethedefaultlist,runroot-config--libsonthecommandline.InHomebrewROOT6.18thiswouldbe:

ROOT::Core

ROOT::Gpad

ROOT::Graf3d

ROOT::Graf

ROOT::Hist

ROOT::Imt

ROOT::MathCore

ROOT::Matrix

ROOT::MultiProc

ROOT::Net

ROOT::Physics

ROOT::Postscript

ROOT::RIO

ROOT::ROOTDataFrame

ROOT::ROOTVecOps

ROOT::Rint

ROOT::Thread

ROOT::TreePlayer

ROOT::Tree

ROOT

68

Page 69: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Theoldglobalway

ROOTprovidesautilitytosetupaROOTproject,whichyoucanactivateusinginclude("${ROOT_USE_FILE}").Thiswillautomaticallymakeuglydirectorylevelandglobalvariablesforyou.Itwillsaveyoualittletimesettingup,andwillwastemassiveamountsoftimelaterifyoutrytodoanythingtricky.Aslongasyouaren'tmakingalibrary,it'sprobablyfineforsimplescripts.Includesandflagsaresetglobally,butyou'llstillneedtolinkto${ROOT_LIBRARIES}yourself,alongwithpossiblyROOT_EXE_LINKER_FLAGS(Youwillhavetoseparate_argumentsfirstbeforelinkingoryouwillgetanerroriftherearemultipleflags,likeonmacOS).Also,before6.16,youhavetomanuallyfixabuginthespacing.

Here'swhatitwouldlooklike:

#Setsupglobalsettings

include("${ROOT_USE_FILE}")

#ThisisrequiredforROOT<6.16

#string(REPLACE"-L""-L"ROOT_EXE_LINKER_FLAGS"${ROOT_EXE_LINKER_FLAGS}")

#Thisisrequiredonifthereismorethanoneflag(likeonmacOS)

separate_arguments(ROOT_EXE_LINKER_FLAGS)

add_executable(RootUseFileExampleSimpleExample.cxx)

target_link_libraries(RootUseFileExamplePUBLIC${ROOT_LIBRARIES}${ROOT_EXE_LINKER_FLAGS})

ComponentsFindROOTallowsyoutospecifycomponents.Itwilladdanythingyoulistto${ROOT_LIBRARIES},soyoumightwanttobuildyourowntargetusingthattoavoidlistingthecomponentstwice.Thisdidnotsolvedependencies;itwasanerrortolistRooFitbutnotRooFitCore.IfyoulinktoROOT::RooFitinsteadof${ROOT_LIBRARIES},thenRooFitCoreisnotrequired.

DictionarygenerationDictionarygenerationisROOT'swayofworkingaroundthemissingreflectionfeatureinC++.ItallowsROOTtolearnthedetailsofyourclasssoitcansaveit,showmethodsintheClinginterpreter,etc.You'llneedthreethingsinyoursourcecodetomakeitworkforclasses:

YourclassdefinitionshouldendwithClassDef(MyClassName,1)YourclassimplementationshouldhaveClassImp(MyClassName)initYoushouldhaveafilewithanamethatendswithLinkDef.h

TheLinkDef.hfilefollowsaspecificformulaandtellsROOTwhatpartstogeneratedictionariesfor.

Togenerate,youshouldincludethefollowinginyourCMakeLists:

include("${ROOT_DIR}/modules/RootNewMacros.cmake")

#UncommentforROOTversionsthan6.16

#Theybreakifnothingisintheglobalincludelist!

#include_directories(ROOT_BUG)

ThesecondlineisduetoabugintheNewMacrosfilethatcausesdictionarygenerationtofailifthereisnotatleastoneglobalincludedirectoryoraincfolder.HereI'mincludinganon-existentdirectoryjusttomakeitwork.ThereisnoROOT_BUGdirectory.

Togenerateafile:

root_generate_dictionary(G__ExampleExample.hLINKDEFExampleLinkDef.h)

ROOT

69

Page 70: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Thefinalargument,listedafterLINKDEF,musthaveanamethatendsinLinkDef.h.Thiscommandwillcreatethreefiles.IfyoustartedoutputnamewithG__,thatwillberemovedfromthename,otherwiseitwillusethenamegiven;thismustmatchthefinaloutputlibrarynameyouwillsoonbecreating.Assumingthisis${NAME}:

${NAME}.cxx:Thisfileshouldbeincludedinyoursourceswhenyoumakethelibrary.lib{NAME}.rootmap(G__prefixremoved):Therootmapfileinplaintextlib{NAME}_rdict.pcm(G__prefixremoved):AROOTfile

Thefinaltwooutputfilesmustsitnexttothelibraryoutput.ThisisdonebycheckingCMAKE_LIBRARY_OUTPUT_DIRECTORY(itwillnotpickuplocaltargetsettings).Ifyouhavealibdirsetbutyoudon'thave(global)installlocationsset,you'llalsoneedtosetARG_NOINSTALLtoTRUE.

UsingOldROOTIfyoureallyhavetouseolderROOT,you'llneedsomethinglikethis:

#ROOTtargetsaremissingincludesandflagsinROOT6.10and6.12

set_property(TARGETROOT::CorePROPERTY

INTERFACE_INCLUDE_DIRECTORIES"${ROOT_INCLUDE_DIRS}")

#EarlyROOTdoesnotincludetheflagsrequiredontargets

add_library(ROOT::Flags_CXXIMPORTEDINTERFACE)

#ROOT6.14andearlierhaveaspacingbuginthelinkerflags

string(REPLACE"-L""-L"ROOT_EXE_LINKER_FLAGS"${ROOT_EXE_LINKER_FLAGS}")

#FixforROOT_CXX_FLAGSnotactuallybeingaCMakelist

separate_arguments(ROOT_CXX_FLAGS)

set_property(TARGETROOT::Flags_CXXAPPENDPROPERTY

INTERFACE_COMPILE_OPTIONS${ROOT_CXX_FLAGS})

#Adddefinitions

separate_arguments(ROOT_DEFINITIONS)

foreach(_flag${ROOT_EXE_LINKER_FLAG_LIST})

#Remove-Dor/Difpresent

string(REGEXREPLACE[=[^[-//]D]=]""_flag${_flag})

set_property(TARGETROOT::FlagsAPPENDPROPERTYINTERFACE_LINK_LIBRARIES${_flag})

endforeach()

#Thisalsofixesabuginthelinkerflags

separate_arguments(ROOT_EXE_LINKER_FLAGS)

set_property(TARGETROOT::Flags_CXXAPPENDPROPERTY

INTERFACE_LINK_LIBRARIES${ROOT_EXE_LINKER_FLAGS})

#MakesureyoulinkwithROOT::Flags_CXXtoo!

ROOT

70

Page 71: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

ASimpleROOTProjectThisisaminimalexampleofaROOTprojectusingtheUseFilesystemandwithoutadictionary.

examples/root-usefile/CMakeLists.txt

cmake_minimum_required(VERSION3.1...3.16)

project(RootUseFileExampleLANGUAGESCXX)

find_package(ROOT6.16CONFIGREQUIRED)

#Setsupglobalsettings

include("${ROOT_USE_FILE}")

#ThisisrequiredforROOT<6.16

#string(REPLACE"-L""-L"ROOT_EXE_LINKER_FLAGS"${ROOT_EXE_LINKER_FLAGS}")

#Thisisrequiredonifthereismorethanoneflag(likeonmacOS)

separate_arguments(ROOT_EXE_LINKER_FLAGS)

add_executable(RootUseFileExampleSimpleExample.cxx)

target_link_libraries(RootUseFileExamplePUBLIC${ROOT_LIBRARIES}${ROOT_EXE_LINKER_FLAGS})

examples/root-usefile/SimpleExample.cxx

#include<TLorentzVector.h>

intmain(){

TLorentzVectorv(1,2,3,4);

v.Print();

return0;

}

UseFileExample

71

Page 72: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

ASimpleROOTProjectThisisaminimalexampleofaROOTprojectusingthetargetsystemandwithoutadictionary.

examples/root-simple/CMakeLists.txt

cmake_minimum_required(VERSION3.1...3.16)

project(RootSimpleExampleLANGUAGESCXX)

#FindingtheROOTpackage

find_package(ROOT6.16CONFIGREQUIRED)

#AddinganexecutableprogramandlinkingtoneededROOTlibraries

add_executable(RootSimpleExampleSimpleExample.cxx)

target_link_libraries(RootSimpleExamplePUBLICROOT::Physics)

examples/root-simple/SimpleExample.cxx

#include<TLorentzVector.h>

intmain(){

TLorentzVectorv(1,2,3,4);

v.Print();

return0;

}

SimpleExample

72

Page 73: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

DictionaryExampleThisisanexampleofbuildingamodulethatincludesadictionaryinCMake.InsteadofusingtheROOTsuggestedflags,wewillmanuallyaddthreadingviafind_package,whichistheonlyimportantflaginthelistonmostsystems.

examples/root-dict/CMakeLists.txt

cmake_minimum_required(VERSION3.4...3.16)

project(RootDictExampleLANGUAGESCXX)

set(CMAKE_CXX_STANDARD11)

set(CMAKE_CXX_STANDARD_REQUIREDON)

set(CMAKE_CXX_EXTENSIONSOFF)

set(CMAKE_PLATFORM_INDEPENDENT_CODEON)

find_package(ROOTCONFIGREQUIRED)

include("${ROOT_DIR}/modules/RootNewMacros.cmake")

root_generate_dictionary(G__DictExampleDictExample.hLINKDEFDictLinkDef.h)

add_library(DictExampleSHAREDDictExample.cxxDictExample.hG__DictExample.cxx)

target_include_directories(DictExamplePUBLIC"${CMAKE_CURRENT_SOURCE_DIR}")

target_link_libraries(DictExamplePUBLICROOT::Core)

SupportingfilesThisisjustasimple-as-possibleclassdefinition,withonemethod:

examples/root-dict/DictExample.cxx

#include"DictExample.h"

Double_tSimple::GetX()const{returnx;}

ClassImp(Simple)

examples/root-dict/DictExample.h

#pragmaonce

#include<TROOT.h>

classSimple{

Double_tx;

public:

Simple():x(2.5){}

Double_tGetX()const;

ClassDef(Simple,1)

};

WeneedaLinkDef.h,aswell.

examples/root-dict/DictLinkDef.h

DictionaryExample

73

Page 74: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

//See:https://root.cern.ch/selecting-dictionary-entries-linkdefh

#ifdef__CINT__

#pragmalinkoffallglobals;

#pragmalinkoffallclasses;

#pragmalinkoffallfunctions;

#pragmalinkC++nestedclasses;

#pragmalinkC++classSimple+;

#endif

TestingitThisisanexampleofamacrothatteststhecorrectgenerationfromthefileslistedabove.

examples/root-dict/CheckLoad.C

{

gSystem->Load("libDictExample");

Simples;

cout<<s.GetX()<<endl;

TFile*_file=TFile::Open("tmp.root","RECREATE");

gDirectory->WriteObject(&s,"MyS");

Simple*MyS=nullptr;

gDirectory->GetObject("MyS",MyS);

cout<<MyS->GetX()<<endl;

_file->Close();

}

DictionaryExample

74

Page 75: Table of Contents · 2020-03-30 · work will save you hundreds of lines and hours of CMakeLists.txt writing, and will be much easier to maintain in the long run. This book tries

Minuit2Minuit2isavailableinstandalonemode,foruseincaseswhereROOTiseithernotavailableornotbuiltwithMinuit2enabled.Thiswillcoverrecommendedusages,aswellassomeaspectsofthedesign.

Usage

Minuit2canbeusedinanyofthestandardCMakeways,eitherfromtheROOTsourceorfromastandalonesourcedistribution:

#CheckforMinuit2inROOTifyouwant

#andthenlinktoROOT::Minuit2instead

add_subdirectory(minuit2)#orroot/math/minuit2

#OR

find_package(Minuit2CONFIG)#Eitherbuildorinstall

target_link_libraries(MyProgramPRIVATEMinuit2::Minuit2)

Development

Minuit2isagoodexampleofpotentialsolutionstotheproblemofintegratingamodern(CMake3.1+)buildintoanexistingframework.

TohandlethetwodifferentCMakesystems,themainCMakeLists.txtdefinescommonoptions,thencallsaStandalone.cmakefileifthisisnotbuildingaspartofROOT.

ThehardestpartintheROOTcaseisthatMinuit2requiresfilesthatareoutsidethemath/minuit2directory.Thiswassolvedbyaddingacopy_standalone.cmakefilewithafunctionthattakesafilenamelistandtheneitherreturnsalistoffilenamesinplaceintheoriginalsource,orcopiesfilesintothelocalsourceandreturnsalistofthenewlocations,orreturnsjustthelistofnewlocationsiftheoriginalsourcedoesnotexist(standalone).

#Copiesfilesintosourcedirectory

cmake/root/math/minuit2-Dminuit2-standalone=ON

#Makes.tar.gzfromsourcedirectory

makepackage_source

#Optional,cleanthesourcedirectory

makepurge

Thisisonlyintendedfordeveloperswantingtoproducesourcepackages-anormaluserdoesnotpassthisoptionandwillnotcreatesourcecopies.

Youcanusemakeinstallormakepackage(binarypackages)withoutaddingthisstandaloneoption,eitherfrominsidetheROOTsourceorfromastandalonepackage.

Minuit2

75