SCons cross platform build - SDL2 and Imgui example

  • Download SCons
  • "SCons is an Open Source software construction tool—that is, a next-generation build tool. Think of SCons as an improved, cross-platform substitute for the classic Make utility with integrated functionality similar to autoconf/automake and compiler caches such as ccache. In short, SCons is an easier, more reliable and faster way to build software."
  • Read documentation http://scons.org/doc/production/HTML/scons-user/ch02.html
  • SCons is not Python 3 compatible... Let's install a Python 2 environment (I am using conda)
  • conda create --name scons python=2 scons
    activate scons
    
  • Let's try to compile an example
  • int main()
    {
    	printf("Hello, world!\n");
    	return 0;
    }
    
  • Program('hello.c')
    
  • scons: done reading SConscript files.
    scons: Building targets ...
    cl /Fohello.obj /c hello.c /nologo
    "cl" no se reconoce como un comando interno o externo,
    programa o archivo por lotes ejecutable.
    scons: *** [hello.obj] Error 1
    scons: building terminated because of errors.
    
  • Compiler is not in path
  • Get cl in path
  • %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64
    
  • cl is now in path but scons doesn't find it...
  • [scons] C:\Users\micas\Desktop\sconsproject\tutorial>cl
    Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24210 for x64
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    usage: cl [ option... ] filename... [ /link linkoption... ]
    
    [scons] C:\Users\micas\Desktop\sconsproject\tutorial>scons
    scons: done reading SConscript files.
    scons: Building targets ...
    cl /Fohello.obj /c hello.c /nologo
    "cl" no se reconoce como un comando interno o externo,
    programa o archivo por lotes ejecutable.
    scons: *** [hello.obj] Error 1
    scons: building terminated because of errors.
    
  • Scons version was 2.3.0, let's try with 2.5.0
  • pip install scons
    
  • Nice, it works!
  • [scons] C:\Users\micas\Desktop\sconsproject\tutorial>scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    cl /Fohello.obj /c hello.c /nologo
    hello.c
    link /nologo /OUT:hello.exe hello.obj
    scons: done building targets.
    
  • Trying something more complex
  • #include <imgui.h>
    #include "imgui_impl_sdl.h"
    #include <SDL.h>
    #include <SDL_opengl.h>
    
    int main(int argc, char* argv[])
    {
    	int posX = 100, posY = 100, width = 640, height = 480;
    
    	SDL_Init(SDL_INIT_VIDEO);
    
    	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);
    	SDL_DisplayMode current;
    	SDL_GetCurrentDisplayMode(0, &current);
    	SDL_Window *win = SDL_CreateWindow("ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
    	SDL_GLContext glcontext = SDL_GL_CreateContext(win);
    
    	ImGui_ImplSdl_Init(win);
    
    	ImVec4 clear_color = ImColor(114, 144, 154);
    	while (1) {
    		SDL_Event e;
    		if (SDL_PollEvent(&e)) {
    			ImGui_ImplSdl_ProcessEvent(&e);
    			if (e.type == SDL_QUIT) {
    				break;
    			}
    		}
    		ImGui_ImplSdl_NewFrame(win);
    		ImGui::Begin("My window");
    		ImGui::Text("Hello world.");
    		ImGui::End();
    		glViewport(0, 0, (int)ImGui::GetIO().DisplaySize.x, (int)ImGui::GetIO().DisplaySize.y);
    		glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
    		glClear(GL_COLOR_BUFFER_BIT);
    		ImGui::Render();
    		SDL_GL_SwapWindow(win);
    	}
    	ImGui_ImplSdl_Shutdown();
    	SDL_GL_DeleteContext(glcontext);
    	SDL_DestroyWindow(win);
    	SDL_Quit();
    	return 0;
    }
    
  • // ImGui SDL2 binding with OpenGL
    // In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
    
    // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
    // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
    // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
    // https://github.com/ocornut/imgui
    
    #include <SDL.h>
    #include <SDL_syswm.h>
    #include <SDL_opengl.h>
    #include <imgui.h>
    #include "imgui_impl_sdl.h"
    
    // Data
    static double       g_Time = 0.0f;
    static bool         g_MousePressed[3] = { false, false, false };
    static float        g_MouseWheel = 0.0f;
    static GLuint       g_FontTexture = 0;
    
    // This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure)
    // If text or lines are blurry when integrating ImGui in your engine:
    // - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f)
    void ImGui_ImplSdl_RenderDrawLists(ImDrawData* draw_data)
    {
        // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
        ImGuiIO& io = ImGui::GetIO();
        int fb_width = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
        int fb_height = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
        if (fb_width == 0 || fb_height == 0)
            return;
        draw_data->ScaleClipRects(io.DisplayFramebufferScale);
    
        // We are using the OpenGL fixed pipeline to make the example code simpler to read!
        // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers.
        GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
        GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
        glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_SCISSOR_TEST);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);
        glEnable(GL_TEXTURE_2D);
        //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context
    
        // Setup viewport, orthographic projection matrix
        glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();
    
        // Render command lists
        #define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT))
        for (int n = 0; n < draw_data->CmdListsCount; n++)
        {
            const ImDrawList* cmd_list = draw_data->CmdLists[n];
            const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front();
            const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front();
            glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, pos)));
            glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, uv)));
            glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + OFFSETOF(ImDrawVert, col)));
    
            for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++)
            {
                const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
                if (pcmd->UserCallback)
                {
                    pcmd->UserCallback(cmd_list, pcmd);
                }
                else
                {
                    glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
                    glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w), (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
                    glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
                }
                idx_buffer += pcmd->ElemCount;
            }
        }
        #undef OFFSETOF
    
        // Restore modified state
        glDisableClientState(GL_COLOR_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_VERTEX_ARRAY);
        glBindTexture(GL_TEXTURE_2D, (GLuint)last_texture);
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glPopAttrib();
        glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
    }
    
    static const char* ImGui_ImplSdl_GetClipboardText()
    {
        return SDL_GetClipboardText();
    }
    
    static void ImGui_ImplSdl_SetClipboardText(const char* text)
    {
        SDL_SetClipboardText(text);
    }
    
    bool ImGui_ImplSdl_ProcessEvent(SDL_Event* event)
    {
        ImGuiIO& io = ImGui::GetIO();
        switch (event->type)
        {
        case SDL_MOUSEWHEEL:
            {
                if (event->wheel.y > 0)
                    g_MouseWheel = 1;
                if (event->wheel.y < 0)
                    g_MouseWheel = -1;
                return true;
            }
        case SDL_MOUSEBUTTONDOWN:
            {
                if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
                if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
                if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
                return true;
            }
        case SDL_TEXTINPUT:
            {
                ImGuiIO& io = ImGui::GetIO();
                io.AddInputCharactersUTF8(event->text.text);
                return true;
            }
        case SDL_KEYDOWN:
        case SDL_KEYUP:
            {
                int key = event->key.keysym.sym & ~SDLK_SCANCODE_MASK;
                io.KeysDown[key] = (event->type == SDL_KEYDOWN);
                io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
                io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
                io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
                io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
                return true;
            }
        }
        return false;
    }
    
    bool ImGui_ImplSdl_CreateDeviceObjects()
    {
        // Build texture atlas
        ImGuiIO& io = ImGui::GetIO();
        unsigned char* pixels;
        int width, height;
        io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height);
    
        // Upload texture to graphics system
        GLint last_texture;
        glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
        glGenTextures(1, &g_FontTexture);
        glBindTexture(GL_TEXTURE_2D, g_FontTexture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
    
        // Store our identifier
        io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
    
        // Restore state
        glBindTexture(GL_TEXTURE_2D, last_texture);
    
        return true;
    }
    
    void    ImGui_ImplSdl_InvalidateDeviceObjects()
    {
        if (g_FontTexture)
        {
            glDeleteTextures(1, &g_FontTexture);
            ImGui::GetIO().Fonts->TexID = 0;
            g_FontTexture = 0;
        }
    }
    
    bool    ImGui_ImplSdl_Init(SDL_Window* window)
    {
        ImGuiIO& io = ImGui::GetIO();
        io.KeyMap[ImGuiKey_Tab] = SDLK_TAB;                     // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
        io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
        io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
        io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
        io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
        io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
        io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
        io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
        io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
        io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE;
        io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE;
        io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN;
        io.KeyMap[ImGuiKey_Escape] = SDLK_ESCAPE;
        io.KeyMap[ImGuiKey_A] = SDLK_a;
        io.KeyMap[ImGuiKey_C] = SDLK_c;
        io.KeyMap[ImGuiKey_V] = SDLK_v;
        io.KeyMap[ImGuiKey_X] = SDLK_x;
        io.KeyMap[ImGuiKey_Y] = SDLK_y;
        io.KeyMap[ImGuiKey_Z] = SDLK_z;
    
        io.RenderDrawListsFn = ImGui_ImplSdl_RenderDrawLists;   // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer.
        io.SetClipboardTextFn = ImGui_ImplSdl_SetClipboardText;
        io.GetClipboardTextFn = ImGui_ImplSdl_GetClipboardText;
    
    #ifdef _WIN32
        SDL_SysWMinfo wmInfo;
        SDL_VERSION(&wmInfo.version);
        SDL_GetWindowWMInfo(window, &wmInfo);
        io.ImeWindowHandle = wmInfo.info.win.window;
    #else
        (void)window;
    #endif
    
        return true;
    }
    
    void ImGui_ImplSdl_Shutdown()
    {
        ImGui_ImplSdl_InvalidateDeviceObjects();
        ImGui::Shutdown();
    }
    
    void ImGui_ImplSdl_NewFrame(SDL_Window *window)
    {
        if (!g_FontTexture)
            ImGui_ImplSdl_CreateDeviceObjects();
    
        ImGuiIO& io = ImGui::GetIO();
    
        // Setup display size (every frame to accommodate for window resizing)
        int w, h;
        int display_w, display_h;
        SDL_GetWindowSize(window, &w, &h);
        SDL_GL_GetDrawableSize(window, &display_w, &display_h);
        io.DisplaySize = ImVec2((float)w, (float)h);
        io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
    
        // Setup time step
        Uint32	time = SDL_GetTicks();
        double current_time = time / 1000.0;
        io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
        g_Time = current_time;
    
        // Setup inputs
        // (we already got mouse wheel, keyboard keys & characters from SDL_PollEvent())
        int mx, my;
        Uint32 mouseMask = SDL_GetMouseState(&mx, &my);
        if (SDL_GetWindowFlags(window) & SDL_WINDOW_MOUSE_FOCUS)
            io.MousePos = ImVec2((float)mx, (float)my);   // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
        else
            io.MousePos = ImVec2(-1,-1);
    
        io.MouseDown[0] = g_MousePressed[0] || (mouseMask & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0;		// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
        io.MouseDown[1] = g_MousePressed[1] || (mouseMask & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
        io.MouseDown[2] = g_MousePressed[2] || (mouseMask & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
        g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
    
        io.MouseWheel = g_MouseWheel;
        g_MouseWheel = 0.0f;
    
        // Hide OS mouse cursor if ImGui is drawing it
        SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
    
        // Start the frame
        ImGui::NewFrame();
    }
    
  • env = Environment(CPPPATH = ['.'])
    Repository(['C:\\libs\\imgui-1.49','C:\\SDL2-2.0.4\\include'])
    env.Library('imgui',Glob('C:\\libs\\imgui-1.49\\*.cpp'))
    env.Library('imgui_impl_sdl',LIBS=['imgui','SDL2','SDL2main','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64'])
    env.Program('imguiSDL2',LIBS=['imgui_impl_sdl'],LIBPATH=['.'])
    
  • Fails to link .exe with SDL2
  • [scons] C:\Users\micas\Desktop\sconsproject\tutorial\imguiSDL2_example>scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    cl /FoC:\libs\imgui-1.49\imgui.obj /c C:\libs\imgui-1.49\imgui.cpp /TP /nologo /I. /IC:\libs\imgui-1.49 /IC:\SDL2-2.0.4\include
    imgui.cpp
    cl /FoC:\libs\imgui-1.49\imgui_demo.obj /c C:\libs\imgui-1.49\imgui_demo.cpp /TP /nologo /I. /IC:\libs\imgui-1.49 /IC:\SDL2-2.0.4\include
    imgui_demo.cpp
    cl /FoC:\libs\imgui-1.49\imgui_draw.obj /c C:\libs\imgui-1.49\imgui_draw.cpp /TP /nologo /I. /IC:\libs\imgui-1.49 /IC:\SDL2-2.0.4\include
    imgui_draw.cpp
    lib /nologo /OUT:imgui.lib C:\libs\imgui-1.49\imgui.obj C:\libs\imgui-1.49\imgui_demo.obj C:\libs\imgui-1.49\imgui_draw.obj
    cl /FoimguiSDL2.obj /c imguiSDL2.cpp /TP /nologo /I. /IC:\libs\imgui-1.49 /IC:\SDL2-2.0.4\include
    imguiSDL2.cpp
    link /nologo /OUT:imguiSDL2.exe /LIBPATH:. /LIBPATH:C:\libs\imgui-1.49 /LIBPATH:C:\SDL2-2.0.4\include /LIBPATH:C:\SDL2-2.0.4\lib\x64 imgui.lib SDL2main.lib SDL2.lib SDL2test.lib imguiSDL2.obj
    LINK : fatal error LNK1561: entry point must be defined
    scons: *** [imguiSDL2.exe] Error 1561
    scons: building terminated because of errors.
    
  • After specifying /SUBSYSTEM:CONSOLE it works
  • There is an additional problem, compiling everything Glob('*.cpp') and linking opengl 'opengl32'
  • env = Environment(CPPPATH = ['.'])
    env.Append(LINKFLAGS='/SUBSYSTEM:CONSOLE')
    Repository(['C:\\libs\\imgui-1.49','C:\\SDL2-2.0.4\\include'])
    env.Library('imgui',Glob('C:\\libs\\imgui-1.49\\*.cpp'))
    env.Program('imguiSDL2',Glob('*.cpp'),LIBS=['opengl32','imgui','SDL2main','SDL2','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64']
    
  • Ok, it works on Windows 10 with MSVC 14.0
  • Testing in Docker, getting ubuntu image with required prerequisites
  • FROM ubuntu:14.04
    MAINTAINER A test <test@example.com>
    RUN apt-get update && apt-get install -y libvlc-dev libsdl2-dev cmake xorg-dev libglu1-mesa-dev git
    RUN git clone https://github.com/glfw/glfw.git
    RUN cd glfw && cmake . && make && make install
    
  • As I forgot to install scons
  • docker run -t -i test/ubuntu-sdl /bin/bash
    apt-get install -y scons
    exit
    docker commit -m "Added scons" -a "Test User" 03c4e0d0b88d test/ubuntu-sdl
    
  • Copying some example hello.c
  • docker cp ../tutorial/hello.c test/ubuntu-sdl:/hello.c
    
  • Oops error:
  • Error response from daemon: No such container: test/ubuntu-sdl
    
  • Needs to be running, for example
  • docker run -t -i test/ubuntu-sdl /bin/bash
    
  • In another terminal:
  • 
    docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    28f8b2a37e1b        test/ubuntu-sdl     "/bin/bash"         42 seconds ago      Up 6 seconds                            tender_mccarthy
    docker cp ../tutorial/hello.c tender_mccarthy:/hello.c
    docker cp ../tutorial/SConstruct tender_mccarthy:/SConstruct
    
  • Does it work? Yes (Disregard warning, no stdio.h included)
  • root@28f8b2a37e1b:/# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    gcc -o hello.o -c hello.c
    hello.c: In function 'main':
    hello.c:3:2: warning: incompatible implicit declaration of built-in function 'printf' [enabled by default]
      printf("Hello, world!\n");
      ^
    gcc -o hello hello.o
    scons: done building targets.
    
  • Let's try something harder
  • int main()
    {
    	printf("Hello, world!\n");
    	return 0;
    }
    
  • docker cp ../tutorial/SDL2example tender_mccarthy:/SDL2example
    root@28f8b2a37e1b:/SDL2example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    o example.o -c -I. -IC:\SDL2-2.0.4\include example.cpp
    sh: 1: o: not found
    o example /SUBSYSTEM:CONSOLE example.o -L. -LC:\SDL2-2.0.4\include -LC:\SDL2-2.0.4\lib\x64 -LC:\SDL2-2.0.4\include/C:\SDL2-2.0.4\lib\x64 -lSDL2main -lSDL2 -lSDL2test
    sh: 1: o: not found
    scons: done building targets.
    
  • That was the expected result, the SConstruct file was not modified to be compatible with linux
  • Slightly offtopic but trying to modify SConstruct in vi in Windows docker console is kind of a pain, arrows do not work and i am not used to hjkl, let's try something:
  • apt-get install vim
    
  • Nope, but at least I know in which mode I am, that's something I guess
  • Trying :set term=cons25 -> arrows work, but corrupts text...
  • Trying :set nocp, nope
  • Trying :set term=ansi, seems to be working, more or less(End key not working...)
  • Anyways, modified SContruct
  • import platform
    import os
    system = platform.system()
    if system=='Windows':
        env = Environment(CPPPATH = ['.'])
        env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
        Repository(['C:\\SDL2-2.0.4\\include'])
        env.Program('example','example.cpp',LIBS=['SDL2main','SDL2','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64'])
    elif system=='Linux':
        env = Environment(ENV={'PATH': os.environ['PATH']},CPPPATH=['.'])
        env.ParseConfig('sdl2-config --cflags --libs')
        env.Program('example','example.cpp',LIBS=['SDL2main','SDL2','SDL2test'],LIBPATH=['.'])
    
  • With the SConstruct file modified:
  • root@28f8b2a37e1b:/SDL2example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    o example.o -c -D_REENTRANT -I. -I/usr/include/SDL2 example.cpp
    sh: 1: o: not found
    o example example.o -L. -lSDL2main -lSDL2 -lSDL2test
    sh: 1: o: not found
    scons: done building targets.
    
  • Interesting error... http://stackoverflow.com/questions/15878186/unable-to-run-cpp-file-using-scons . I have cc but I need g++, let's install g++
  • apt-get install -y g++
    root@28f8b2a37e1b:/SDL2example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    g++ -o example.o -c -D_REENTRANT -I. -I/usr/include/SDL2 example.cpp
    g++ -o example example.o -L. -lSDL2main -lSDL2 -lSDL2test
    /usr/bin/ld: cannot find -lSDL2test
    collect2: error: ld returned 1 exit status
    scons: *** [example] Error 1
    scons: building terminated because of errors.
    
  • Error, but better. Now the problem is wrong libs. Let's solve it
  • import platform
    import os
    system = platform.system()
    if system=='Windows':
        env = Environment(CPPPATH = ['.'])
        env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
        Repository(['C:\\SDL2-2.0.4\\include'])
        env.Program('example','example.cpp',LIBS=['SDL2main','SDL2','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64'])
    elif system=='Linux':
        env = Environment(ENV={'PATH': os.environ['PATH']},CPPPATH=['.'])
        env.ParseConfig('sdl2-config --cflags --libs')
        env.Program('example','example.cpp',LIBPATH=['.'])
    
  • Done!
  • root@28f8b2a37e1b:/SDL2example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    g++ -o example example.o -L. -lSDL2
    scons: done building targets.
    root@28f8b2a37e1b:/SDL2example# ./example
    Could not create window: Failed to connect to the Mir Server
    
  • The executable can't create a window, obviously. But it compiles and that was the objective.
  • Now it's time for something slightly more complex, let's build with imgui, but first let's save this with a commit
  • $ docker commit -m "Added g++ and some example SConstruct" -a "Test User" 03c4e0d0b88d test/ubuntu-sdl
    sha256:f2abf4aef5396db8ecfddc44e4195ea9df99d708defe39b7d288bcb64632c2c5
    
  • I think at this point I messed up somewhere by closing a docker console before commiting or something.
  • The thing is I didn't have g++ nor the files in the container. At least it was a good opportunity to learn how to rollback :)
  • Let's rollback and add g++ to the Dockerfile and container first
  • $ docker history test/ubuntu-sdl
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    f2abf4aef539        4 hours ago         /bin/bash                                       5.574 MB            Added g++ and some example SConstruct
    8236662d2994        22 hours ago        /bin/sh -c cd glfw && cmake . && make && make   11.02 MB
    da5179b69c23        22 hours ago        /bin/sh -c git clone https://github.com/glfw/   11.35 MB
    f68367557045        22 hours ago        /bin/sh -c apt-get update && apt-get install    357.2 MB
    46bdb43865fc        22 hours ago        /bin/sh -c #(nop)  MAINTAINER A test <test@ex   0 B
    ff6011336327        7 days ago          /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
    <missing>           7 days ago          /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
    <missing>           7 days ago          /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B
    <missing>           7 days ago          /bin/sh -c set -xe   && echo '#!/bin/sh' > /u   194.6 kB
    <missing>           7 days ago          /bin/sh -c #(nop) ADD file:4f5a660d3f5141588d   187.8 MB
    $ docker tag 8236 test/ubuntu-sdl
    $ docker history test/ubuntu-sdl
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    8236662d2994        22 hours ago        /bin/sh -c cd glfw && cmake . && make && make   11.02 MB
    da5179b69c23        22 hours ago        /bin/sh -c git clone https://github.com/glfw/   11.35 MB
    f68367557045        22 hours ago        /bin/sh -c apt-get update && apt-get install    357.2 MB
    46bdb43865fc        22 hours ago        /bin/sh -c #(nop)  MAINTAINER A test <test@ex   0 B
    ff6011336327        7 days ago          /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
    <missing>           7 days ago          /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
    <missing>           7 days ago          /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B
    <missing>           7 days ago          /bin/sh -c set -xe   && echo '#!/bin/sh' > /u   194.6 kB
    <missing>           7 days ago          /bin/sh -c #(nop) ADD file:4f5a660d3f5141588d   187.8 MB
    $ docker run -t -i test/ubuntu-sdl /bin/bash
    root@cd7d839febbc:/# apt-get update && apt-get install -y g++
    $ docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    cd7d839febbc        test/ubuntu-sdl     "/bin/bash"         9 minutes ago       Up 9 minutes                            pedantic_agnesi
    $ docker commit -m "Added g++" -a "Test User" cd7d839febbc test/ubuntu-sdl
    sha256:c21f3367109617f2a04899a9c845f7cbaf78fdfb499834256b9ea741c2c79c39
    $ docker history test/ubuntu-sdl
    IMAGE               CREATED              CREATED BY                                      SIZE                COMMENT
    c21f33671096        About a minute ago   /bin/bash                                       64.14 MB            Added g++
    8236662d2994        22 hours ago         /bin/sh -c cd glfw && cmake . && make && make   11.02 MB
    da5179b69c23        23 hours ago         /bin/sh -c git clone https://github.com/glfw/   11.35 MB
    f68367557045        23 hours ago         /bin/sh -c apt-get update && apt-get install    357.2 MB
    46bdb43865fc        23 hours ago         /bin/sh -c #(nop)  MAINTAINER A test <test@ex   0 B
    ff6011336327        7 days ago           /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
    <missing>           7 days ago           /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
    <missing>           7 days ago           /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B
    <missing>           7 days ago           /bin/sh -c set -xe   && echo '#!/bin/sh' > /u   194.6 kB
    <missing>           7 days ago           /bin/sh -c #(nop) ADD file:4f5a660d3f5141588d   187.8 MB
    
  • Also going to copy the imgui project
  • $ docker cp ../tutorial/imguiSDL2_example/ pedantic_agnesi:/imguiSDL2_example
    $ docker commit -m "Added imguiSDL example files" -a "Test User" cd7d839febbc test/ubuntu-sdl
    
  • Let's change the SConstruct file
  • root@f7733c7c519e:/imguiSDL2_example# scons
    bash: scons: command not found
    
  • Aah when I did the commit I didn't install scons...sigh
  • root@f7733c7c519e:/imguiSDL2_example# apt-get install -y scons
    
  • Ok, next problem
  • root@f7733c7c519e:/imguiSDL2_example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    g++ -o imguiSDL2.o -c -D_REENTRANT -I. -I/usr/include/SDL2 imguiSDL2.cpp
    imguiSDL2.cpp:1:19: fatal error: imgui.h: No such file or directory
     #include <imgui.h>
                       ^
    compilation terminated.
    scons: *** [imguiSDL2.o] Error 1
    scons: building terminated because of errors.
    
  • No imgui include directory, in fact no imgui whatsoever. Let's copy imgui to the container
  • $ docker cp ../imgui tender_hypatia:/imgui
    
  • Ok try with this scons file
  • import platform
    import os
    system = platform.system()
    if system=='Windows':
        env.Append(LINKFLAGS='/SUBSYSTEM:CONSOLE')
        Repository(['C:\\libs\\imgui-1.49','C:\\SDL2-2.0.4\\include'])
        env.Library('imgui',Glob('C:\\libs\\imgui-1.49\\*.cpp'))
        env.Program('imguiSDL2',Glob('*.cpp'),LIBS=['opengl32','imgui','SDL2main','SDL2','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64'])
    elif system=='Linux':
        env = Environment(ENV={'PATH': os.environ['PATH']},CPPPATH=['.'])
        env.Repository(['/imgui/'])
        env.ParseConfig('sdl2-config --cflags --libs')
        env.Library('imgui',Glob('/imgui/*.cpp'))
        env.Program('imguiSDL2',Glob('*.cpp'),LIBS=['imgui'],LIBPATH=['.'])
    
  • root@f7733c7c519e:/imguiSDL2_example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    g++ -o imgui.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui.cpp
    g++ -o imguiSDL2.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 imguiSDL2.cpp
    g++ -o imgui_demo.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui_demo.cpp
    g++ -o imgui_draw.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui_draw.cpp
    g++ -o imgui_impl_sdl.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 imgui_impl_sdl.cpp
    g++ -o /imgui/imgui.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui.cpp
    g++ -o /imgui/imgui_demo.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui_demo.cpp
    g++ -o /imgui/imgui_draw.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 /imgui/imgui_draw.cpp
    ar rc libimgui.a /imgui/imgui.o /imgui/imgui_demo.o /imgui/imgui_draw.o
    ranlib libimgui.a
    g++ -o imguiSDL2 imgui.o imguiSDL2.o imgui_demo.o imgui_draw.o imgui_impl_sdl.o -L. -L/imgui -limgui
    imguiSDL2.o: In function `main':
    imguiSDL2.cpp:(.text+0x56): undefined reference to `SDL_Init'
    imguiSDL2.cpp:(.text+0x65): undefined reference to `SDL_GL_SetAttribute'
    imguiSDL2.cpp:(.text+0x74): undefined reference to `SDL_GL_SetAttribute'
    imguiSDL2.cpp:(.text+0x83): undefined reference to `SDL_GL_SetAttribute'
    imguiSDL2.cpp:(.text+0x92): undefined reference to `SDL_GL_SetAttribute'
    imguiSDL2.cpp:(.text+0xa1): undefined reference to `SDL_GL_SetAttribute'
    imguiSDL2.cpp:(.text+0xb2): undefined reference to `SDL_GetCurrentDisplayMode'
    imguiSDL2.cpp:(.text+0xd7): undefined reference to `SDL_CreateWindow'
    imguiSDL2.cpp:(.text+0xed): undefined reference to `SDL_GL_CreateContext'
    imguiSDL2.cpp:(.text+0x168): undefined reference to `SDL_PollEvent'
    imguiSDL2.cpp:(.text+0x19b): undefined reference to `SDL_GL_DeleteContext'
    imguiSDL2.cpp:(.text+0x1aa): undefined reference to `SDL_DestroyWindow'
    imguiSDL2.cpp:(.text+0x1af): undefined reference to `SDL_Quit'
    imguiSDL2.cpp:(.text+0x231): undefined reference to `glViewport'
    imguiSDL2.cpp:(.text+0x286): undefined reference to `glClearColor'
    imguiSDL2.cpp:(.text+0x290): undefined reference to `glClear'
    imguiSDL2.cpp:(.text+0x2a4): undefined reference to `SDL_GL_SwapWindow'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_RenderDrawLists(ImDrawData*)':
    imgui_impl_sdl.cpp:(.text+0x8f): undefined reference to `glGetIntegerv'
    imgui_impl_sdl.cpp:(.text+0xa0): undefined reference to `glGetIntegerv'
    imgui_impl_sdl.cpp:(.text+0xaa): undefined reference to `glPushAttrib'
    imgui_impl_sdl.cpp:(.text+0xb4): undefined reference to `glEnable'
    imgui_impl_sdl.cpp:(.text+0xc3): undefined reference to `glBlendFunc'
    imgui_impl_sdl.cpp:(.text+0xcd): undefined reference to `glDisable'
    imgui_impl_sdl.cpp:(.text+0xd7): undefined reference to `glDisable'
    imgui_impl_sdl.cpp:(.text+0xe1): undefined reference to `glEnable'
    imgui_impl_sdl.cpp:(.text+0xeb): undefined reference to `glEnableClientState'
    imgui_impl_sdl.cpp:(.text+0xf5): undefined reference to `glEnableClientState'
    imgui_impl_sdl.cpp:(.text+0xff): undefined reference to `glEnableClientState'
    imgui_impl_sdl.cpp:(.text+0x109): undefined reference to `glEnable'
    imgui_impl_sdl.cpp:(.text+0x122): undefined reference to `glViewport'
    imgui_impl_sdl.cpp:(.text+0x12c): undefined reference to `glMatrixMode'
    imgui_impl_sdl.cpp:(.text+0x131): undefined reference to `glPushMatrix'
    imgui_impl_sdl.cpp:(.text+0x136): undefined reference to `glLoadIdentity'
    imgui_impl_sdl.cpp:(.text+0x178): undefined reference to `glOrtho'
    imgui_impl_sdl.cpp:(.text+0x182): undefined reference to `glMatrixMode'
    imgui_impl_sdl.cpp:(.text+0x187): undefined reference to `glPushMatrix'
    imgui_impl_sdl.cpp:(.text+0x18c): undefined reference to `glLoadIdentity'
    imgui_impl_sdl.cpp:(.text+0x1f7): undefined reference to `glVertexPointer'
    imgui_impl_sdl.cpp:(.text+0x216): undefined reference to `glTexCoordPointer'
    imgui_impl_sdl.cpp:(.text+0x235): undefined reference to `glColorPointer'
    imgui_impl_sdl.cpp:(.text+0x294): undefined reference to `glBindTexture'
    imgui_impl_sdl.cpp:(.text+0x2f2): undefined reference to `glScissor'
    imgui_impl_sdl.cpp:(.text+0x30d): undefined reference to `glDrawElements'
    imgui_impl_sdl.cpp:(.text+0x358): undefined reference to `glDisableClientState'
    imgui_impl_sdl.cpp:(.text+0x362): undefined reference to `glDisableClientState'
    imgui_impl_sdl.cpp:(.text+0x36c): undefined reference to `glDisableClientState'
    imgui_impl_sdl.cpp:(.text+0x37b): undefined reference to `glBindTexture'
    imgui_impl_sdl.cpp:(.text+0x385): undefined reference to `glMatrixMode'
    imgui_impl_sdl.cpp:(.text+0x38a): undefined reference to `glPopMatrix'
    imgui_impl_sdl.cpp:(.text+0x394): undefined reference to `glMatrixMode'
    imgui_impl_sdl.cpp:(.text+0x399): undefined reference to `glPopMatrix'
    imgui_impl_sdl.cpp:(.text+0x39e): undefined reference to `glPopAttrib'
    imgui_impl_sdl.cpp:(.text+0x3b1): undefined reference to `glViewport'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_GetClipboardText()':
    imgui_impl_sdl.cpp:(.text+0x3bc): undefined reference to `SDL_GetClipboardText'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_SetClipboardText(char const*)':
    imgui_impl_sdl.cpp:(.text+0x3d6): undefined reference to `SDL_SetClipboardText'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_ProcessEvent(SDL_Event*)':
    imgui_impl_sdl.cpp:(.text+0x501): undefined reference to `SDL_GetModState'
    imgui_impl_sdl.cpp:(.text+0x518): undefined reference to `SDL_GetModState'
    imgui_impl_sdl.cpp:(.text+0x531): undefined reference to `SDL_GetModState'
    imgui_impl_sdl.cpp:(.text+0x54a): undefined reference to `SDL_GetModState'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_CreateDeviceObjects()':
    imgui_impl_sdl.cpp:(.text+0x5b3): undefined reference to `glGetIntegerv'
    imgui_impl_sdl.cpp:(.text+0x5c2): undefined reference to `glGenTextures'
    imgui_impl_sdl.cpp:(.text+0x5d4): undefined reference to `glBindTexture'
    imgui_impl_sdl.cpp:(.text+0x5e8): undefined reference to `glTexParameteri'
    imgui_impl_sdl.cpp:(.text+0x5fc): undefined reference to `glTexParameteri'
    imgui_impl_sdl.cpp:(.text+0x639): undefined reference to `glTexImage2D'
    imgui_impl_sdl.cpp:(.text+0x65e): undefined reference to `glBindTexture'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_InvalidateDeviceObjects()':
    imgui_impl_sdl.cpp:(.text+0x682): undefined reference to `glDeleteTextures'
    imgui_impl_sdl.o: In function `ImGui_ImplSdl_NewFrame(SDL_Window*)':
    imgui_impl_sdl.cpp:(.text+0x806): undefined reference to `SDL_GetWindowSize'
    imgui_impl_sdl.cpp:(.text+0x81d): undefined reference to `SDL_GL_GetDrawableSize'
    imgui_impl_sdl.cpp:(.text+0x8c4): undefined reference to `SDL_GetTicks'
    imgui_impl_sdl.cpp:(.text+0x95c): undefined reference to `SDL_GetMouseState'
    imgui_impl_sdl.cpp:(.text+0x96b): undefined reference to `SDL_GetWindowFlags'
    imgui_impl_sdl.cpp:(.text+0xaaf): undefined reference to `SDL_ShowCursor'
    collect2: error: ld returned 1 exit status
    scons: *** [imguiSDL2] Error 1
    scons: building terminated because of errors.
    
  • At least two problems, opengl and SDL
  • import platform
    import os
    system = platform.system()
    if system=='Windows':
        env.Append(LINKFLAGS='/SUBSYSTEM:CONSOLE')
        Repository(['C:\\libs\\imgui-1.49','C:\\SDL2-2.0.4\\include'])
        env.Library('imgui',Glob('C:\\libs\\imgui-1.49\\*.cpp'))
        env.Program('imguiSDL2',Glob('*.cpp'),LIBS=['opengl32','imgui','SDL2main','SDL2','SDL2test'],LIBPATH=['.','C:\\SDL2-2.0.4\\lib\\x64'])
    elif system=='Linux':
        env = Environment(ENV={'PATH': os.environ['PATH']},CPPPATH=['.'])
        env.Repository(['/imgui/'])
        env.ParseConfig('sdl2-config --cflags --libs')
        env.ParseConfig('pkg-config --cflags --libs gl')
        env.Library('imgui',Glob('/imgui/*.cpp'))
        env.Append(LIBS=['imgui'],LIBPATH=['.'])
        env.Program('imguiSDL2',Glob('*.cpp'))
    
  • root@f7733c7c519e:/imguiSDL2_example# scons -c
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Cleaning targets ...
    Removed imgui.o
    Removed imguiSDL2.o
    Removed imgui_demo.o
    Removed imgui_draw.o
    Removed imgui_impl_sdl.o
    Removed /imgui/imgui.o
    Removed /imgui/imgui_demo.o
    Removed /imgui/imgui_draw.o
    Removed libimgui.a
    scons: done cleaning targets.
    root@f7733c7c519e:/imguiSDL2_example# scons
    scons: Reading SConscript files ...
    scons: done reading SConscript files.
    scons: Building targets ...
    g++ -o imgui.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui.cpp
    g++ -o imguiSDL2.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm imguiSDL2.cpp
    g++ -o imgui_demo.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui_demo.cpp
    g++ -o imgui_draw.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui_draw.cpp
    g++ -o imgui_impl_sdl.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm imgui_impl_sdl.cpp
    g++ -o /imgui/imgui.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui.cpp
    g++ -o /imgui/imgui_demo.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui_demo.cpp
    g++ -o /imgui/imgui_draw.o -c -D_REENTRANT -I. -I/imgui -I/usr/include/SDL2 -I/usr/include/libdrm /imgui/imgui_draw.cpp
    ar rc libimgui.a /imgui/imgui.o /imgui/imgui_demo.o /imgui/imgui_draw.o
    ranlib libimgui.a
    g++ -o imguiSDL2 imgui.o imguiSDL2.o imgui_demo.o imgui_draw.o imgui_impl_sdl.o -L/usr/lib/x86_64-linux-gnu -L. -L/imgui -lSDL2 -lGL -limgui
    scons: done building targets.
    
  • DONE!
  • Now let's commit the changes to the container
  • $ docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    f7733c7c519e        test/ubuntu-sdl     "/bin/bash"         43 minutes ago      Up 43 minutes                           tender_hypatia
    $ docker commit -m "Scons installed again, vim installed, SConstruct file for imguiSDL2 example, all done" -a "Test Use
    r" f7733c7c519e test/ubuntu-sdl
    sha256:3be29a32ac67c6a7a023413d3401410237603177a3a497c90775e875b409fc70
    

links