simongeilfus / Cinder-Runtime

Runtime-Compiled C++ for Cinder
57 stars 43 forks source link

RT-compilable derived classes? #32

Open mattfelsen opened 6 years ago

mattfelsen commented 6 years ago

Hello! I've been putting some work into getting Runtime working with this scene graph block from Bluecadet. I've got a basic proof of concept working with a simple class (which does not inherit from anything) that returns a ci::ColorA value that I can change at runtime. My goal though is to make custom views which derive from views::BaseView that are rt-compilable, and this is where I'm running into trouble. Are derived classes known to work? Does that parent class need to be rt-compilable as well for this work?

When I try to do this, I get a bunch of unresolved external symbol linker errors for all of the virtual methods in BaseView which don't have an inline implementation, which I've shown below. It seems like the runtime linking step has lost track of a bunch of symbols from BaseView -- maybe it just needs the parent class of whatever class changed to be linked against as well?

When I instead try to make BaseView itself rt-compilable, I get a variety of errors when the app launches which are generally different each time, and seemingly unrelated (e.g. I've gotten issues in GlslProg::link(), somewhere in XmlTree, etc.) so there's some separate weirdness there.

Snippet of the linker errors:

1>------ Runtime Compiler Build started: Project: CentralStandardRuntime, Configuration: Debug_Shared x64 ------
1>  MyView.cpp
1>MyViewFactory.obj : error LNK2019: unresolved external symbol "public: __cdecl bluecadet::views::BaseView::BaseView(void)" (??0BaseView@views@bluecadet@@QEAA@XZ) referenced in function "public: __cdecl MyView::MyView(void)" (??0MyView@@QEAA@XZ)
1>MyViewFactory.obj : error LNK2019: unresolved external symbol "public: virtual __cdecl bluecadet::views::BaseView::~BaseView(void)" (??1BaseView@views@bluecadet@@UEAA@XZ) referenced in function "public: virtual __cdecl MyView::~MyView(void)" (??1MyView@@UEAA@XZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::updateScene(double)" (?updateScene@BaseView@views@bluecadet@@UEAAXN@Z)
1>MyViewFactory.obj : error LNK2019: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::drawScene(class cinder::ColorAT<float> const &)" (?drawScene@BaseView@views@bluecadet@@UEAAXAEBV?$ColorAT@M@cinder@@@Z) referenced in function "protected: virtual void __cdecl bluecadet::views::BaseView::drawChildren(class cinder::ColorAT<float> const &)" (?drawChildren@BaseView@views@bluecadet@@MEAAXAEBV?$ColorAT@M@cinder@@@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::reset(void)" (?reset@BaseView@views@bluecadet@@UEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::cancelAnimations(void)" (?cancelAnimations@BaseView@views@bluecadet@@UEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::addChild(class std::shared_ptr<class bluecadet::views::BaseView>)" (?addChild@BaseView@views@bluecadet@@UEAAXV?$shared_ptr@VBaseView@views@bluecadet@@@std@@@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::addChild(class std::shared_ptr<class bluecadet::views::BaseView>,unsigned __int64)" (?addChild@BaseView@views@bluecadet@@UEAAXV?$shared_ptr@VBaseView@views@bluecadet@@@std@@_K@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::removeChild(class std::shared_ptr<class bluecadet::views::BaseView>)" (?removeChild@BaseView@views@bluecadet@@UEAAXV?$shared_ptr@VBaseView@views@bluecadet@@@std@@@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::removeChild(class bluecadet::views::BaseView *)" (?removeChild@BaseView@views@bluecadet@@UEAAXPEAV123@@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual class std::_List_iterator<class std::_List_val<struct std::_List_simple_types<class std::shared_ptr<class bluecadet::views::BaseView> > > > __cdecl bluecadet::views::BaseView::removeChild(class std::_List_iterator<class std::_List_val<struct std::_List_simple_types<class std::shared_ptr<class bluecadet::views::BaseView> > > >)" (?removeChild@BaseView@views@bluecadet@@UEAA?AV?$_List_iterator@V?$_List_val@U?$_List_simple_types@V?$shared_ptr@VBaseView@views@bluecadet@@@std@@@std@@@std@@@std@@V45@@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::removeAllChildren(void)" (?removeAllChildren@BaseView@views@bluecadet@@UEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::moveToFront(void)" (?moveToFront@BaseView@views@bluecadet@@UEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::moveToBack(void)" (?moveToBack@BaseView@views@bluecadet@@UEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::moveChildToIndex(class bluecadet::views::BaseView *,unsigned __int64)" (?moveChildToIndex@BaseView@views@bluecadet@@UEAAXPEAV123@_K@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::moveChildToIndex(class std::shared_ptr<class bluecadet::views::BaseView>,unsigned __int64)" (?moveChildToIndex@BaseView@views@bluecadet@@UEAAXV?$shared_ptr@VBaseView@views@bluecadet@@@std@@_K@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl bluecadet::views::BaseView::moveChildToIndex(class std::_List_iterator<class std::_List_val<struct std::_List_simple_types<class std::shared_ptr<class bluecadet::views::BaseView> > > >,unsigned __int64)" (?moveChildToIndex@BaseView@views@bluecadet@@UEAAXV?$_List_iterator@V?$_List_val@U?$_List_simple_types@V?$shared_ptr@VBaseView@views@bluecadet@@@std@@@std@@@std@@@std@@_K@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "public: virtual class std::shared_ptr<class cinder::Cue> __cdecl bluecadet::views::BaseView::dispatchAfter(class std::function<void __cdecl(void)>,float)" (?dispatchAfter@BaseView@views@bluecadet@@UEAA?AV?$shared_ptr@VCue@cinder@@@std@@V?$function@$$A6AXXZ@5@M@Z)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "protected: virtual void __cdecl bluecadet::views::BaseView::draw(void)" (?draw@BaseView@views@bluecadet@@MEAAXXZ)
1>MyViewFactory.obj : error LNK2001: unresolved external symbol "protected: virtual void __cdecl bluecadet::views::BaseView::drawDebugInfo(void)" (?drawDebugInfo@BaseView@views@bluecadet@@MEAAXXZ)
1>runtime\MyView\build\MyView.dll : fatal error LNK1120: 20 unresolved externals
========== Runtime Compiler Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
mattfelsen commented 6 years ago

I was reading through the BuildSettings header and noticed BuildSettings::linkObj(), which turned out to be what I needed to resolve these linker errors. The recompilation & linking step works, but I'm seeing unexpected behavior where singleton objects are being recreated, which I detail below. I'm curious about why I needed to pass some of these options though:

RT_IMPL(LocalClock, rt::BuildSettings()
    .vcxproj("MyProject.vcxproj")
    .include("runtime/LocalClock/build")
    .linkObj("x64/Release_Shared/BaseView")
    .linkObj("x64/Release_Shared/CSSettingsManager")
    .linkObj("x64/Release_Shared/FontManager")
    .linkObj("x64/Release_Shared/GradientView")
    .linkObj("x64/Release_Shared/ImageView")
    .linkObj("x64/Release_Shared/SettingsManager")
    .linkObj("x64/Release_Shared/StyleManager")
    .linkObj("x64/Release_Shared/StyledTextLayout")
    .linkObj("x64/Release_Shared/StyledTextParser")
    .linkObj("x64/Release_Shared/ViewEvent")
    .library("Gdi32.lib")
)

I thought that specifying a vcxproj() shouldn't be necessary and that it would default to the current project. However, I was getting include errors for things like Cinder, various blocks, etc., and after adding it these went away.

The include() path for this class's build products (the second option) was necessary since I was getting a missing include for the pch file I believe. This seems like it should be easy to automate using the __FILE__ macro or similar.

The various linkObj() options would be nice to automate somehow, though I'm not sure if it's feasible to detect all the dependencies. Currently I just saved the file, looked at all the missing symbols reported by the linker, and added these. I'll need to go back and wrap them in #ifdefs for the proper build configuration, though I am guessing there's some macro that could be used more directly.

And as mentioned before, I noticed that any singleton class I access from this class seems to have their instance recreated. The singletons I am using are generally implemented like this:

static SingletonRef getInstance() {
    static SingletonRef instance = nullptr;
    if (!instance) instance = SingletonRef(new Singleton());
    return instance;
}

I noticed a comment in the ImGui sample app about how ImGui needs to be built as a DLL since it uses static objects. Is this the same thing I'm seeing here? If so, does that mean I would also need to compile any of these blocks whose singletons I am using as shared libs? Is there some alternative solution where using these classes as non-static instances would workaround the issue?

https://github.com/simongeilfus/Cinder-Runtime/blob/e524fd4e0f60220aeb2e53693aa6406419a5b93e/samples/ImGui/src/ImGuiApp.cpp#L6-L7