I would like to write a standalone C++ program based on ROOT v6.30.02 in Windows 10 with Visual Studio 2022 and CMake. When we run this program, I would like to show a window with left part a button and the right part a TCanvas, and when I click the button, it will print a message in terminal.
The code has been tested on Mac/Linux systems. However, on Windows, it can be compiled correctly, but with a run-time error on the generated file “G__MyMainFrame.cxx” L176:
Unhandled exception at 0x00007FFA7B90CF19 in root_cmake.exe: Microsoft C++ exception: std::length_error at memory location 0x00000097F5FDFB50.
If I use x64_release to compile the project, it will give me the errors in the terminal:
IncrementalExecutor::executeFunction: symbol '?GeneratorConfig@MyMainFrame@@QEAAXXZ' unresolved while linking symbol '__cf_3'!
You are probably missing the definition of public: void __cdecl MyMainFrame::GeneratorConfig(void) __ptr64
Maybe you need to load the corresponding shared library?
Error in <TClingCallFunc::make_wrapper>: Failed to compile
==== SOURCE BEGIN ====
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-security"
__attribute__((used)) __attribute__((annotate("__cling__ptrcheck(off)")))
extern "C" void __cf_3(void* obj, int nargs, void** args, void* ret)
{
((MyMainFrame*)obj)->GeneratorConfig();
return;
}
#pragma clang diagnostic pop
==== SOURCE END ====
Error in <TClingCallFunc::Exec(address, interpVal)>: Called with no wrapper, not implemented!
Could anyone give me some hints?
Many thanks.
Zhihong Shen
The following is my project:
CMakelist.txt:
cmake_minimum_required(VERSION 3.16)
project("root_cmake")
# Find the ROOT package
find_package(ROOT REQUIRED COMPONENTS Gui)
# Include directories
include_directories(${ROOT_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/include)
# Specify C++ Standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# ROOT dictionary generation
ROOT_GENERATE_DICTIONARY(G__MyMainFrame ${CMAKE_SOURCE_DIR}/include/MyMainFrame.h LINKDEF ${CMAKE_SOURCE_DIR}/include/LinkDef.h)
# Add executable
add_executable(root_cmake "src/main.cpp" "src/MyMainFrame.cpp" "G__MyMainFrame.cxx") # Add the generated dictionary to the list of source files
# Link ROOT libraries
target_link_libraries(root_cmake PUBLIC ${ROOT_LIBRARIES})
include/LinkDef.h:
#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class MyMainFrame+;
#endif
include/MyMainFrame.h:
#endif // MY_MAIN_FRAME_H
#ifndef MY_MAIN_FRAME_H
#define MY_MAIN_FRAME_H
#include <TGFrame.h>
#include <TGButton.h>
#include <TRootEmbeddedCanvas.h>
#include <iostream>
class MyMainFrame {
private:
TGMainFrame* fMain;
TRootEmbeddedCanvas* fEmbeddedCanvas;
TGHorizontalFrame* fHFrame;
TGVerticalFrame* fLeftFrame;
TGTextButton* fButton;
void SetupGUI(int width, int height);
public:
MyMainFrame(const TGWindow* p, int width, int height);
virtual ~MyMainFrame();
void GeneratorConfig();
ClassDef(MyMainFrame, 0)
};
src/main.cpp:
#include "MyMainFrame.h"
#include "TApplication.h"
int main(int argc, char** argv) {
TApplication theApp("App", &argc, argv);
MyMainFrame* mainFrame = new MyMainFrame(gClient->GetRoot(), 2000, 900);
theApp.Run();
delete mainFrame;
return 0;
}
src/MyMainFrame.cpp:
#include "MyMainFrame.h"
#include <TCanvas.h>
#include <TH1D.h>
#include <TRandom.h>
MyMainFrame::MyMainFrame(const TGWindow* p, int width, int height) {
fMain = new TGMainFrame(p, width, height);
SetupGUI(width, height);
}
MyMainFrame::~MyMainFrame() {
fMain->Cleanup();
delete fMain;
}
void MyMainFrame::SetupGUI(int width, int height) {
fHFrame = new TGHorizontalFrame(fMain, width, height);
fLeftFrame = new TGVerticalFrame(fHFrame, width / 2, height);
fButton = new TGTextButton(fLeftFrame, "Generator Config");
fButton->Connect("Clicked()", "MyMainFrame", this, "GeneratorConfig()");
fLeftFrame->AddFrame(fButton, new TGLayoutHints(kLHintsCenterX | kLHintsTop, 200, 200, 5, 5));
fHFrame->AddFrame(fLeftFrame, new TGLayoutHints(kLHintsLeft | kLHintsExpandY));
fEmbeddedCanvas = new TRootEmbeddedCanvas("EmbeddedCanvas", fHFrame, width / 2, height);
fHFrame->AddFrame(fEmbeddedCanvas, new TGLayoutHints(kLHintsRight | kLHintsExpandX | kLHintsExpandY));
TCanvas* canvas = fEmbeddedCanvas->GetCanvas();
TH1D* h1 = new TH1D("h1", "Example histogram", 100, -4, 4);
for (int i = 0; i < 10000; i++) {
h1->Fill(gRandom->Gaus(0, 1));
}
h1->Draw();
canvas->Update();
fMain->AddFrame(fHFrame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
fMain->MapSubwindows();
fMain->Resize(fMain->GetDefaultSize());
fMain->MapWindow();
// fButton->Connect("Clicked()", "MyMainFrame", this, "GeneratorConfig()");
// ...
}
void MyMainFrame::GeneratorConfig() {
std::cout << "Generator Config button pressed!" <<std::endl;
// MyGuiHandler::GeneratorConfig 中的代码
// ...
}
_ROOT Version: 6.30.02
_Platform: Windows10
_Compiler: visual studio 2022