Problem trying to bind C++ files to compile

141 views
Skip to first unread message

Luke Selman

unread,
Mar 4, 2017, 11:02:23 AM3/4/17
to Haxe
I am currently in the process of binding 'dear imgui' to Haxe so that it can be used with linc SDL and OpenGL. To make things easier for myself, I used the imgui example test code found here.

There are some subtle changes in the example code. See below.

//inside the header

#include <hxcpp.h>

struct SDL_Window;
typedef union SDL_Event SDL_Event;

IMGUI_API ImVec2      ImGui_GetDisplaySize(); // CHANGED
IMGUI_API bool        ImGui_ImplSdl_Init(SDL_Window* window);
IMGUI_API void        ImGui_ImplSdl_Shutdown();
IMGUI_API void        ImGui_ImplSdl_NewFrame(SDL_Window* window);
IMGUI_API bool        ImGui_ImplSdl_ProcessEvent(cpp::Struct<SDL_Event> value); // CHANGED

// Use if you want to reset your rendering device without losing ImGui state.
IMGUI_API void        ImGui_ImplSdl_InvalidateDeviceObjects();
IMGUI_API bool        ImGui_ImplSdl_CreateDeviceObjects();

//inside the cpp file

ImVec2 ImGui_GetDisplaySize()
{
    ImVec2 size = ImGui::GetIO().DisplaySize;
    return size;
}

bool ImGui_ImplSdl_ProcessEvent(cpp::Struct<SDL_Event> value)
{
    SDL_Event *event = &value.value;

...

I am using the following Haxe class to bind the implementation above:

@:include("hx/imgui_impl_sdl.h")
extern class Gui
{

    @:native("ImGui_GetDisplaySize")
    public static function ImGui_GetDisplaySize():ImVec2;

    @:native("ImGui_ImplSdl_RenderDrawLists")
    public static function ImGui_ImplSdl_RenderDrawLists(draw_data:cpp.Pointer<ImDrawData>):Void;

    @:native("ImGui_ImplSdl_GetClipboardText")
    public static function ImGui_ImplSdl_GetClipboardText():cpp.ConstCharStar;

    @:native("ImGui_ImplSdl_SetClipboardText")
    public static function ImGui_ImplSdl_SetClipboardText(text:cpp.ConstCharStar):Void;

    @:native("ImGui_ImplSdl_ProcessEvent")
    public static function ImGui_ImplSdl_ProcessEvent(e:EventRef):Void;

    @:native("ImGui_ImplSdl_CreateDeviceObjects")
    public static function ImGui_ImplSdl_CreateDeviceObjects():Bool;

    @:native("ImGui_ImplSdl_InvalidateDeviceObjects")
    public static function ImGui_ImplSdl_InvalidateDeviceObjects():Void;

    @:native("ImGui_ImplSdl_Init")
    public static function ImGui_ImplSdl_Init(window:Window):Bool;

    @:native("ImGui_ImplSdl_Shutdown")
    public static function ImGui_ImplSdl_Shutdown():Void;

    @:native("ImGui_ImplSdl_NewFrame")
    public static function ImGui_ImplSdl_NewFrame(window:Window):Void;
}

And then using this in my main class (no actual IMGUI calls) to get things up and running before I go ahead and start creating the 'dear imgui' binding.

using hximgui.ImGuiTypes;
import hximgui.ImGui;
import hximgui.Gui;

using opengl.GL;

import sdl.SDL;
import sdl.Window.Window;
import sdl.Event.Event;
import sdl.Renderer.Renderer;

@:buildXml("<include name=\"${haxelib:hximgui}/build.xml\" />")
class Main
{

    public static function main()
    {
        if (SDL.init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
        {
            Sys.print("Error: " + SDL.getError());
            return;
        }

        SDL.GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        SDL.GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
        SDL.GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
        SDL.GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
        SDL.GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
        var current = SDL.getCurrentDisplayMode(0);
        var window = SDL.createWindow("Example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
        var glcontext = SDL.GL_CreateContext(window);

        Gui.ImGui_ImplSdl_Init(window);
        
        var clear_color = ImVec4.create(114, 144, 154, 255);

        var running = true;
        while (running)
        {
            while (SDL.hasAnEvent())
            {
                var e = SDL.pollEvent();
                Gui.ImGui_ImplSdl_ProcessEvent(e);
                if (e.type == SDL_QUIT)
                    running = false;
            }

            var size = Gui.ImGui_GetDisplaySize();
            GL.glViewport(0, 0, cast size.x, cast size.y);
            GL.glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
            GL.glClear(GL.GL_COLOR_BUFFER_BIT);
            SDL.GL_SwapWindow(window);
        }

        SDL.GL_DeleteContext(glcontext);
        SDL.destroyWindow(window);
        SDL.quit();
    }

}

However, when trying to compile this code, I am getting unresolved external symbol errors, which relate to the very first code example in C++. It relates to the functions ImGui_GetDisplaySize(void), ImGui_ImplSdl_Init(struct SDL_Window *), and ImGui_ImplSdl_ProcessEvent(class cpp::Struct<union SDL_Event,class cpp::DefaultStructHandler>).

I have checked main.cpp in the generated code, and the includes appear to be generated in the correct order. I can't figure out what's causing the issue.

The functions are declared and defined in their respective places, they are being included in the generated C++ main file, and they are part of the same code base. I just don't see the culprit... anywhere. Does anyone have a clue what's happening here? Any help would be appreciated.

Hugh

unread,
Mar 6, 2017, 11:31:37 PM3/6/17
to Haxe
unresolved external symbols points to a link error, rather than a compile error.
It would appear your "inside the cpp file" code is not getting linked into the final exe.
Hxcpp generates a file call "all_objs" - you can inspect this file to see if it contains the implementation cpp file.

If you have only 1 cpp file, it can be easier to directly include the cpp inside an hxcpp generated file using the @:cppInclude("./myImplementation.cpp") class meta.
This ensures all the correct headers/flags are used when compiling.

Generally, if you can avoid "#include <hxcpp.h>" in your non-hxcpp-gen code you will be more robust to changes in compiler flags, and you will get a nicer separation between generated and library code.

Hugh
Reply all
Reply to author
Forward
0 new messages