0

最近有人让我想起了我小时候(不久前)曾经玩过的一款游戏,我想尝试让它再次运行。它已经有近十年没有开发了,所以没有任何预构建的软件包可以工作。我获取了游戏的源代码和旧版本的 CEGUI 库并开始工作。

我在制作过程中修复了一些问题,但现在我遇到了这个错误消息:

/usr/bin/ld: smc-video.o: in function `SMC::cVideo::Init_CEGUI_Fake() const':
video.cpp:107: undefined reference to `CEGUI::NullRenderer::create()'

我对 C++ 几乎没有经验,但我设法理解这是一个找不到函数声明的链接器问题。所以我查看了应该有声明的文件,确实有一个创建函数:

/*!
\brief
    Create an NullRenderer object 
*/
static NullRenderer& create();

但它不会错过一个声明吗?我检查了链接器是否在正确的文件中查找函数,因为将 {} 添加到代码中确实可以防止错误(它当然会导致不同的错误),这让我相信 make 没有任何问题。我还从 CEGUINullRenderer.h 的包含中查找了声明,但没有找到它们。(没有CEGUINullRenderer.cpp)

我尝试从 create 函数返回一个 NullRenderer 对象,但这并没有真正起作用。我在这里想念什么?

video.cpp(直到抛出错误的部分):

/***************************************************************************
 * video.cpp  -  General video functions
 *
 * Copyright (C) 2005 - 2011 Florian Richter
 ***************************************************************************/
/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "../video/video.h"
#include "../gui/hud.h"
#include "../user/preferences.h"
#include "../core/framerate.h"
#include "../video/font.h"
#include "../core/game_core.h"
#include "../video/img_settings.h"
#include "../input/mouse.h"
#include "../video/renderer.h"
#include "../core/main.h"
#include "../core/math/utilities.h"
#include "../core/i18n.h"
#include "../core/math/size.h"
#include "../core/filesystem/filesystem.h"
#include "../core/filesystem/resource_manager.h"
#include "../gui/spinner.h"
// SDL
#include "SDL_opengl.h"
// CEGUI
#include "CEGUIDefaultResourceProvider.h"
#include "CEGUIDefaultLogger.h"
#include "CEGUIExceptions.h"
#include "CEGUIWindowFactoryManager.h"
#include "CEGUIImagesetManager.h"
#include "CEGUIFontManager.h"
#include "CEGUIWindowManager.h"
#include "CEGUISchemeManager.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "elements/CEGUIProgressBar.h"
#include "RendererModules/Null/CEGUINullRenderer.h"
// png
#include <png.h>
#ifndef PNG_COLOR_TYPE_RGBA
    #define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA
#endif

namespace SMC
{

/* *** *** *** *** *** *** *** Video class *** *** *** *** *** *** *** *** *** *** */

cVideo :: cVideo( void )
{
    m_opengl_version = 0;

    m_double_buffer = 0;

    m_rgb_size[0] = 0;
    m_rgb_size[1] = 0;
    m_rgb_size[2] = 0;

    m_default_buffer = GL_BACK;
    m_max_texture_size = 512;
    
    m_audio_init_failed = 0;
    m_joy_init_failed = 0;
    m_geometry_quality = cPreferences::m_geometry_quality_default;
    m_texture_quality = cPreferences::m_texture_quality_default;

    SDL_VERSION( &wm_info.version );
#ifdef __unix__
    glx_context = NULL;
#endif
    m_render_thread = boost::thread();

    m_initialised = 0;
}

cVideo :: ~cVideo( void )
{

}

void cVideo :: Init_CEGUI_Fake( void ) const
{
    // create fake Resource Provider
    CEGUI::DefaultResourceProvider *rp = new CEGUI::DefaultResourceProvider();
    // set Resource Provider directories
    if( CEGUI::System::getDefaultXMLParserName().compare( "XercesParser" ) == 0 )
    {
        // This is needed for Xerces to specify the schemas location
        rp->setResourceGroupDirectory( "schemas", DATA_DIR "/" GAME_SCHEMA_DIR "/" );
    }
    // get a directory to dump the CEGUI log
#ifdef _WIN32
    // fixme : Workaround for std::string to CEGUI::String utf8 conversion. Check again if CEGUI 0.8 works with std::string utf8
    CEGUI::String log_dump_dir = (const CEGUI::utf8*)((Get_Temp_Directory() + "cegui.log").c_str());
#else
    CEGUI::String log_dump_dir = "/dev/null";
#endif
    // create fake system and renderer
    pGuiSystem = &CEGUI::System::create( CEGUI::NullRenderer::create(), rp, NULL, NULL, NULL, "", log_dump_dir );
}

CEGUINullRenderer.h:

/***********************************************************************
    filename:   CEGUINullRenderer.h
    created:    Fri Jan 15 2010
    author:     Eugene Marcotte
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2010 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#ifndef _CEGUINullRenderer_h_
#define _CEGUINullRenderer_h_

#include "../../CEGUIRenderer.h"
#include "../../CEGUISize.h"
#include "../../CEGUIVector.h"

#include <vector>
#include <map>

#if (defined( __WIN32__ ) || defined( _WIN32 )) && !defined(CEGUI_STATIC)
#   ifdef NULL_GUIRENDERER_EXPORTS
#       define NULL_GUIRENDERER_API __declspec(dllexport)
#   else
#       define NULL_GUIRENDERER_API __declspec(dllimport)
#   endif
#else
#   define NULL_GUIRENDERER_API
#endif

#if defined(_MSC_VER)
#   pragma warning(push)
#   pragma warning(disable : 4251)
#endif


// Start of CEGUI namespace section
namespace CEGUI
{
class NullGeometryBuffer;
class NullTexture;
class NullRenderTarget;

//! CEGUI::Renderer implementation for no particular engine
class NULL_GUIRENDERER_API NullRenderer : public Renderer
{
public:
    /*!
    \brief
        Convenience function that creates all the necessary objects
        then initialises the CEGUI system with them.

        This will create and initialise the following objects for you:
        - CEGUI::NullRenderer
        - CEGUI::DefaultResourceProvider
        - CEGUI::System

    \return
        Reference to the CEGUI::NullRenderer object that was created.

    */
    static NullRenderer& bootstrapSystem();
    
    /*!
    \brief
        Convenience function to cleanup the CEGUI system and related objects
        that were created by calling the bootstrapSystem function.

        This function will destroy the following objects for you:
        - CEGUI::System
        - CEGUI::DefaultResourceProvider
        - CEGUI::NullRenderer

    \note
        If you did not initialise CEGUI by calling the bootstrapSystem function,
        you should \e not call this, but rather delete any objects you created
        manually.
    */
    static void destroySystem();

    /*!
    \brief
        Create an NullRenderer object 
    */
    static NullRenderer& create();

    //! destory an NullRenderer object.
    static void destroy(NullRenderer& renderer);

    // implement CEGUI::Renderer interface
    RenderingRoot& getDefaultRenderingRoot();
    GeometryBuffer& createGeometryBuffer();
    void destroyGeometryBuffer(const GeometryBuffer& buffer);
    void destroyAllGeometryBuffers();
    TextureTarget* createTextureTarget();
    void destroyTextureTarget(TextureTarget* target);
    void destroyAllTextureTargets();
    Texture& createTexture();
    Texture& createTexture(const String& filename, const String& resourceGroup);
    Texture& createTexture(const Size& size);
    void destroyTexture(Texture& texture);
    void destroyAllTextures();
    void beginRendering();
    void endRendering();
    void setDisplaySize(const Size& sz);
    const Size& getDisplaySize() const;
    const Vector2& getDisplayDPI() const;
    uint getMaxTextureSize() const;
    const String& getIdentifierString() const;

protected:
    //! default constructor.
    NullRenderer();
    //! common construction things.
    void constructor_impl();
    //! destructor.
    virtual ~NullRenderer();

    //! String holding the renderer identification text.
    static String d_rendererID;
    //! What the renderer considers to be the current display size.
    Size d_displaySize;
    //! What the renderer considers to be the current display DPI resolution.
    Vector2 d_displayDPI;
    //! The default rendering root object
    RenderingRoot* d_defaultRoot;
    //! The default RenderTarget (used by d_defaultRoot)
    NullRenderTarget* d_defaultTarget;
    //! container type used to hold TextureTargets we create.
    typedef std::vector<TextureTarget*> TextureTargetList;
    //! Container used to track texture targets.
    TextureTargetList d_textureTargets;
    //! container type used to hold GeometryBuffers we create.
    typedef std::vector<NullGeometryBuffer*> GeometryBufferList;
    //! Container used to track geometry buffers.
    GeometryBufferList d_geometryBuffers;
    //! container type used to hold Textures we create.
    typedef std::vector<NullTexture*> TextureList;
    //! Container used to track textures.
    TextureList d_textures;
    //! What the renderer thinks the max texture size is.
    uint d_maxTextureSize;
};


} // End of  CEGUI namespace section

#if defined(_MSC_VER)
#   pragma warning(pop)
#endif

#endif  // end of guard _CEGUINullRenderer_h_
4

1 回答 1

1

你已经声明了它,这意味着编译器很乐意编译它。声明就像函数的名称:编译器知道该函数存在并且可以编译调用它的代码。

但是为了链接它,您必须链接该函数的定义(实现)。链接器告诉您它没有您声明的该函数的实际实现。

很可能您的链接行是错误的,几乎可以肯定,您要么根本忘记将库放在链接行上,要么将其放在错误的位置,但是由于您没有向我们提供有关链接命令的任何信息运行以生成该错误消息或您用于链接的 makefile 规则,我们无法提供帮助。

于 2021-04-30T20:33:35.063 回答