I want to set up ROOT from CERN in my Xcode IDE but I'm having problems linking the libraries. I'm using root 6.04.14 and xcode 7.3.
I created a mock up project where I simply have a .cpp where I include a basic class from root (#include "TFile.h"). This I can compile from command line by:
clang++ -std=c++11 -I/opt/root/root-6.04.14/include/root -L/opt/root/root-6.04.14/lib/root -lCore main.cpp
Now it comes to setting up everything in the Xcode IDE. I included "/opt/root/root-6.04.14/include/root" in the header search path and Xcode is not complaining, so I guess it finds the header files. I tried adding "/opt/root/root-6.04.14/lib/root -lCore" to the library search path but I get errors:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/cmath:301:
/opt/root/root-6.04.14/include/root/Math/math.h:65:11: error: no member named 'log1p' in the global namespace; did you mean simply 'log1p'?
return ::log1p(x);
^~
/opt/root/root-6.04.14/include/root/Math/math.h:63:15: note: 'log1p' declared here
inline double log1p( double x) {
^
/opt/root/root-6.04.14/include/root/Math/math.h:76:11: error: no member named 'expm1' in the global namespace; did you mean simply 'expm1'?
return ::expm1(x);
^~
/opt/root/root-6.04.14/include/root/Math/math.h:74:15: note: 'expm1' declared here
inline double expm1( double x) {
and so on...
Furthermore when I look at the terminal command Xcode is running(at least that is what I think it does) there is no "-L/opt/root/root-6.04.14/lib/root -lCore" included. I then tried to put "-L/opt/root/root-6.04.14/lib/root -lCore" into other linker flags. Now it is included in the terminal command but still giving me the same error.
Question1:
I noticed Xcode is running "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" while I have been using clang++, where is the difference and how can I change it?
Question2:
What is the difference between adding the directory to the library search path and putting it in via the linker flag?
Question3:
The big one, where do I mess up?
You've probably already figured this out, but just in case someone else stumbles on this issue here's how I've setup my ROOT (v6.06.04) in xcode. To demonstrate, lets start from scratch with a fresh xcode project.
Say we want to run the following program in xcode (note that it uses ROOT classes)
#include <iostream>
#include "TApplication.h"
#include "TCanvas.h"
#include "TGraph.h"
#include <vector>
int main(int argc, const char * argv[]) {
// Create a TApplication so that we can get plot the histogram
TApplication* myApp = new TApplication("myApp", 0, 0) ;
// Create some vector information
std::vector<double> x(100), y(100) ;
for (int i=0; i<x.size(); i++) {
x[i] = i * (10.0/x.size()) ;
y[i] = std::cos(x[i]) ;
}
// Create a TGraph
TGraph* graph = new TGraph(x.size(), &x[0], &y[0]) ;
// Create a canvas and draw the graph
TCanvas* canvas = new TCanvas("canvas","canvas") ;
graph->Draw("ap0") ;
canvas->Update() ;
// Run the TApplication to produce all of the plots
myApp->Run() ;
return 0;
}
If you just copy and paste this program into xcode you'll see that the ROOT headers arent recognized by xcode and you get the error 'XXX.h' file not found
. This is obviously because we need to tell xcode where to find the headers.
- Click on your project in the left-side menu
- Under "Build Settings" click the "+" -> "Add User-Defined Settings".
This will add a parameter under the "User-Defined" section. Call the new parameter "ROOTSYS" and point it to the top directory of your ROOT installation. For me this is /Users/user/root_cern/root_v6.06.04/
. (Note: This step isnt absolutely necessary but makes the rest less painful and allows you to update your ROOT installation without having to change the header and library paths below)
Now (still in "Build Settings") go to "Search Paths" -> "User Header Search Paths". In this field add the path "$(ROOTSYS)/include"
- Set the "Search Paths" -> "Always Search User Paths" field to Yes
At this point the nasty errors on our headers have gone away! Unfortunately, the program wont build. A look at the build errors shows that there are TONS of linking errors! Clearly we need to update our linker flags to include all the ROOT libraries we want to compile against.
Open a terminal and run $ROOTSYS/bin/root-config --libs
. For me the output is:
-L/Users/user/root_cern/root_v6.06.04/lib -lCore -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lMultiProc -lpthread -Wl,-rpath,/Users/user/root_cern/root_v6.06.04/lib -stdlib=libc++ -lm -ldl
Copy the output from the above root-config
and paste it under "Build Settings" -> "Linking" -> "Other Linker Flags". Note that you can replace all instances of the path to your ROOT install directory with $(ROOTSYS)
and you wont have to update them in the future when you update your ROOT version.
Now the program should build just fine! If you're STILL getting the linking errors, make sure that the TARGET you're trying to build inherits it's linking information from the project. Do this by going to "Other Linker Flags" for the target you are building and set it to $(inherited)
. You'll get the handy plot of a cos(x) function.
A few notes:
- If you dont use a TApplication, the program will end before you get a chance to look at your plot.
- You can end the program either through the xcode GUI or by selecting "File" -> "Quit Root" in the plot's menu bar.
- Things get a bit more complicated if you're trying to write a class that you want ROOT to be able to stream out to the file. It's possible to do it by adding in an additional "Run Script" build phase to your target. For now though, this should get you started.