Clarification about GUI & compiling ROOT macros in general

Hello,

First of all let me state that I am a complete newbie about compiling and linking any C++ code. “Build” has always been a black magic command to me, which has always worked in a simple and blackbox-y way inside IDEs for other programming languages. Dealing with compiling C++ code has a completely different feeling to it; it seems like it requires some advanced knowledge about how it works in a deeper level, which I surely don’t have.

I have tried very hard (and finally succeeded) to compile a ROOT macro with an external compiler (CMake, g++) and run it as an application, outside the ROOT command line. Never have I been able to do so while making my application show in an effective way any graphics (TCanvas, TBrowser etc), even when using root-config to link all the graphic libraries. I have read on this forum that this is one of the reasons why you shouldn’t use your own main program, and I have read multiple times that writing a main function which uses ROOT code is just something that you shouldn’t do, and you should always write macros that can run on the ROOT command line.

On the other hand, the real reason why I had to compile ROOT code outside ROOT is to be able to use an IDE to get all of its useful features - auto-completion, function templates, debugging, and in general all the coding aids an IDE has to offer. Among the latter, being able to debug and run a program from inside the IDE has many advantages, among which breakpoints, debugging, and also just the possibility to run the code without having to summon a different terminal window and to type the command root -l mymacro.C.

However, it does seem that using the IDE this way (ie using it to debug, compile, and run the ROOT macro) is a very complicated process and, as I said above, it doesn’t offer all the features ROOT has to offer (the GUI doesn’t work properly), and, in general, it is very discouraged by the ROOT developers.

My question is very simple: am I missing something, is my understanding flawed, or else why is all of this so bad?
(Please note that my question has no polemic nuance, I am genuinely interested in what I am doing wrong and how can I improve my ROOT experience.)

Thank you all in advance!

Hi @renyhp,

first of all, you can definitely write your own programs and use Root libraries. You can also use the interpreter, and which one you prefer is really a matter of taste. Depending on your choice, you have to do some things that one or the other method does for you.

  • Compiled application: To have the graphical UI working, you need an instance of TApplication. If you don’t have it, there is nothing that would be able to show windows. So if you go for a compiled executable that you want to start from an IDE, be sure to instantiate the TApplication somewhere, and use TApplication::Run to actually make it react to stuff that you do with the mouse.
    https://root.cern.ch/doc/master/classTApplication.html
  • Interpreter: You can always start root and also gdb from inside an IDE. You have two possibilities:
    • Start root.exe (not root) from the IDE, and make sure that the IDE passes the correct arguments. You should be able to set breakpoints etc if you make the IDE start root.exe with a debugger.
    • Start root.exe from a different shell, and make the IDE or the debugger attach to the PID of the root.exe process.
      Which of the two you choose depends on how you want to set up the IDE.
      Further, you can also edit a macro in your IDE to have code completion etc, but then you start it as root.exe myMacro.C+ to have it (re-)compiled in root. You can still attach the IDE to the running process afterwards, but you don’t need to set up the build system of the IDE when you run it from inside root.

Thank you very much for your insightful answer! I have set up my IDE to launch root.exe -l -q myMacro.C instead of building and launching the application, and that seems to be simple and nicer :slight_smile:

Sorry, I have a follow-up question (I will open another thread if that’s more appropriate).

By passing -q to root.exe, any canvas gets closed as soon as the macro stops being processed. I figured out I can use something like
while (true) gSystem->ProcessEvents();
but that doesn’t make the application stop when the canvases are closed (also, I have the feeling that it is much more intensive on the CPU than needed). I didn’t find any way to check if any ROOT window is open. Is there a way to make ROOT continue running until all windows are closed?

Hi @renyhp,

You can use

root.exe --help

to get some info about the command line options!

I would recommend

root.exe -l macroName.cxx+g

-q means to quit the application after the macro finishes, so that should solve your question :-). Further, use +g after the macro name because it means to compile the macro with debug symbols before calling the function in the macro. This way, your debugger can look even inside the macro, give you line numbers, you can stop inside the macro etc.

Thank you very much! In fact, had encountered some problems about debugging and +g will probably solve those!

However, I knew about -q: I tried removing it but in that case simple hello world programs will seemingly run indefinitely, which is bad for code that doesn’t give any output (including ROOT windows). So I was trying to search for a way to decide for -q inside the actual macro, rather than from the launch command. Alternatively, I will settle for creating two launch configurations, one with -q to be used when the macro doesn’t output any window, and one without. However, if I understand correctly, if I remove -q, after closing the windows I will have to stop the process manually.

Yes. You can either type .q in the root prompt (the thing that keeps running when the macro finishes) or when you have a window, you can click “quit root”.
You can manually start the interpreter from your program to keep the program running, but I would have to look up how to do that.

In fact, my problem boils down to the fact that VSCode doesn’t show the ROOT command prompt when launching root.exe (with or without debugging). If I remove -q from the launch command, I can type ROOT commands and use the console as a ROOT console, but I have no root [] prompt. Just having that one would be okay for me: I would immediately know if my macro has finished running, and the ROOT interpreter can always come handy after finishing the execution of a macro. But I don’t know if anyone in this forum can help me with this VSCode issue…

EDIT: the problem is that VSCode launches gdb with the option --tty=tty (I don’t know how to escape backticks here). In other words, launching
gdb root.exe --interpreter=mi --tty=tty
doesn’t make the ROOT prompt appear, while with
gdb root.exe --interpreter=mi
the ROOT prompt is there.
Now I have to figure out how to tell VSCode what I want (and this option is pure Greek to me…)
This behavior is strange, though, it does seem to be related to ROOT, as gdb'ing python with the tty option does make the prompt show up…

I have no experience with VSCode, but on linux the prompt appears only after you start the process.

@bellenot might know more in case you run this on windows.

Well, sorry, I only use the VS Code Editor as a code editor…

For the record, I am running VSCode on linux. But anyway, apart from VSCode, is it normal that this shows the prompt:

$ gdb root.exe
[...]
Reading symbols from root.exe...(no debugging symbols found)...done.
(gdb) run
Starting program: root.exe 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
   ------------------------------------------------------------
  | Welcome to ROOT 6.16/00                  https://root.cern |
  |                               (c) 1995-2018, The ROOT Team |
  | Built for linuxx8664gcc on Jan 23 2019, 09:06:13           |
  | From tags/v6-16-00@v6-16-00                                |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
   ------------------------------------------------------------

root [0] 1
(int) 1
root [1] .q
[Inferior 1 (process 6498) exited normally]

and this doesn’t?

$ gdb root.exe --tty=`tty`
[...]
Reading symbols from root.exe...(no debugging symbols found)...done.
(gdb) run
Starting program: root.exe 
warning: GDB: Failed to set controlling terminal: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
   ------------------------------------------------------------
  | Welcome to ROOT 6.16/00                  https://root.cern |
  |                               (c) 1995-2018, The ROOT Team |
  | Built for linuxx8664gcc on Jan 23 2019, 09:06:13           |
  | From tags/v6-16-00@v6-16-00                                |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q' |
   ------------------------------------------------------------

1
(int) 1
.q
[Inferior 1 (process 6540) exited normally]

In my understanding, setting the tty to the current tty should have pretty much no effect…

EDIT: In fact, the prompt isn’t shown even if I set the tty to be another terminal. Also, running
((TRint*)gROOT->GetApplication())->SetPrompt("test> ") has no effect if the --tty option is passed to gdb. The prompt is set, though: in a new run,

((TRint*)gROOT->GetApplication())->GetPrompt()            
(char *) "root [2] "

Sorry, I never found the time to debug this. What I can recommend is start ROOT on a terminal, then attach gdb with gdb -p <pid> where <pid> is the process id of root.exe .

Axel.

So is this behavior a known ROOT bug, or is gdb (or even me!) to blame?

Unfortunately starting ROOT and attaching every time I want to debug a program does make the workflow be quite longer, so I’ll stick with the missing prompt, waiting for it to be fixed. Thank you so much!