I would like to think about a strategy to remove the  UI dependent code.
Obfuscated used a 
BaseClass -
          |- UI Class
          |- Non UI Class
How do you think you want to remove ui code? Simply with
if(!BatchBuild)
   show message box
else
   log to console
			
			
			
				It gets a bit more complex as the more I understand it the more things have to be taken care of.
My current thinking is below at a high level, which has changed a few times as I find things and get more familiar with the code in the area that needs mods or I have looked at.
if(!IsBatchBuild)
   show C::B normal IDE
else
{
    if(IsHeadlessBuild)
   {
     log to console or log to file
   }
   else
      show batch build dialog 
}
NOTE: for a Headless build then both IsBatchBuild & IsHeadlessBuild are true.
The change to remove the GUI is painless and relatively easy, but other parts of the code need to be modded to not try and use the GUI. The following is my WIP SetupGUILogging() in main.cpp to that removed the GUI. The main change was to add another if check in the else code ("if (!Manager::IsHeadlessBuild())"). The call to m_pInfoPane->SetDropTarget(...) now has protection around is m_pInfoPane does not exist in a headless build.
void MainFrame::SetupGUILogging(int uiSize16)
{
    // allow new docked windows to use be 3/4 of the available space, the default (0.3) is sometimes too small, especially for "Logs & others"
    m_LayoutManager.SetDockSizeConstraint(0.75,0.75);
    int bottomH = Manager::Get()->GetConfigManager(_T("app"))->ReadInt(_T("/main_frame/layout/bottom_block_height"), 150);
    wxSize clientsize = GetClientSize();
    LogManager* mgr = Manager::Get()->GetLogManager();
    Manager::Get()->SetImageSize(uiSize16, Manager::UIComponent::InfoPaneNotebooks);
    Manager::Get()->SetUIScaleFactor(cbGetContentScaleFactor(*this),
                                     Manager::UIComponent::InfoPaneNotebooks);
    if (!Manager::IsBatchBuild())
    {
        m_pInfoPane = new InfoPane(this);
        m_LayoutManager.AddPane(m_pInfoPane, wxAuiPaneInfo().
                                  Name(wxT("MessagesPane")).Caption(_("Logs & others")).
                                  BestSize(wxSize(clientsize.GetWidth(), bottomH)).//MinSize(wxSize(50,50)).
                                  Bottom());
        wxWindow* log;
        for (size_t i = LogManager::app_log; i < LogManager::max_logs; ++i)
        {
            if ((log = mgr->Slot(i).GetLogger()->CreateControl(m_pInfoPane)))
                m_pInfoPane->AddLogger(mgr->Slot(i).GetLogger(), log, mgr->Slot(i).title, mgr->Slot(i).icon);
        }
        m_findReplace.CreateSearchLog();
    }
    else
    {
        if (!Manager::IsHeadlessBuild())
        {
            m_pBatchBuildDialog = new BatchLogWindow(this, _("Code::Blocks - Batch build"));
            wxSizer* s = new wxBoxSizer(wxVERTICAL);
            m_pInfoPane = new InfoPane(m_pBatchBuildDialog);
            s->Add(m_pInfoPane, 1, wxEXPAND);
            m_pBatchBuildDialog->SetSizer(s);
            // setting &g_null_log causes the app to crash on exit for some reason...
            mgr->SetLog(new NullLogger, LogManager::app_log);
            mgr->SetLog(new NullLogger, LogManager::debug_log);
        }
    }
    mgr->NotifyUpdate();
    if (m_pInfoPane)
        m_pInfoPane->SetDropTarget(new cbFileDropTarget(this));
}