windows平台vs2019编译Luabind小记

前言

  • 写这篇文章的目的是Luabind这个库比较老旧,对于新编译器需要做一些代码上的兼容,参考资料又都有点过时,所以特写此篇,记录踩坑过程;
  • Luabind库使用了大量boost header-only相关的头文件,导致你的工程如果带上这个库,就需要在源码中附带上整个boost全家桶,且版本最好与你编译此工程(LuaBind)时使用的保持相同
  • 如果不想使用这个库的可以出门右转sol2库,也是一个优秀的C++&Lua绑定库,而且是完全steand-alone + header-only的;

参考资料

编译前准备

准备相关前置组件

  • 基本编译依赖
Desktop Development with C++
C++ ATL for Latest v142 Build Tools (x86 & x64)
C++ MFC for Latest v142 Build Tools (x86 & x64)
Windows 10 SDK(建议16299之后支持vs2019的全装上)
luabind-0.9
lua-5.3.6 (5.4.x应该也行)
boost_1_70_0 (其他版本也可以,但是兼容性代码可能会略有不同,有概率踩坑)

编译开始

  1. 下载lua5.3luabind-0.9boost_1_70_0,分别解压到文件夹;

  2. 打开vs2019新建静态库工程

  • luabind-0.9/luabind文件夹下的文件添加到Header虚拟目录树;

  • luabind-0.9/luabind/detail添加到Header/detail虚拟目录树;

  • luabind-0.9/src添加到Source虚拟目录树;
    图例
    图例

  • boost根目录添加到(右键点击项目节点->属性->配置属性->C\C++标签下)附加包含目录

  • lua-5.3.6/src添加到附加包含目录中;

  • luabind-0.9/根目录添加到附加包含目录中;

大致如下图,具体目录由你的具体环境而定;
图例

  1. 添加兼容代码文件luabind-0.9/luabind文件夹(头文件夹),我们这里命名为luabind_compatibility.hpp,然后添加到工程Header目录
    图例

具体代码如下:

#pragma once

// lua_strlen() and lua_equal() are used in Luabind, but these have been removed in Lua 5.4.
// Still we can enable the compatible macros by defining LUA_COMPAT_5_3 before including "luaconf.h".

#include "lua.hpp"

#if (LUA_VERSION_NUM >= 502)
// Lua 5.1 compatible functions.
inline void lua_setfenv(lua_State* L, int idx) { lua_setuservalue(L, idx); }
inline void lua_getfenv(lua_State* L, int idx) { lua_getuservalue(L, idx); }
inline lua_State* lua_open() { return luaL_newstate(); }

#if (LUA_VERSION_NUM >= 504)
inline int lua_resume(lua_State* L, int nargs)
{
	int nresults = 0;
	return lua_resume(L, nullptr, nargs, &nresults);
}
#else
inline int lua_resume(lua_State* L, int nargs) { return lua_resume(L, nullptr, nargs); }
#endif

struct DummyClassForLegacyLuaGlobalsIndex {};
const DummyClassForLegacyLuaGlobalsIndex LUA_GLOBALSINDEX;
inline void lua_pushvalue(lua_State* L, const DummyClassForLegacyLuaGlobalsIndex&) { lua_pushglobaltable(L); }
inline void lua_settable(lua_State* L, const DummyClassForLegacyLuaGlobalsIndex&) { lua_settable(L, LUA_REGISTRYINDEX); }
inline void lua_gettable(lua_State* L, const DummyClassForLegacyLuaGlobalsIndex&) { lua_gettable(L, LUA_REGISTRYINDEX); }
#else
// Lua 5.2 compatible functions.
inline void lua_pushglobaltable(lua_State* L) { lua_pushvalue(L, LUA_GLOBALSINDEX); }
#endif

//In the C++17 standard, official support for std::auto_ptr was removed, so we had to implement them manually.
//Also, Boost turns off support for std::auto_ptr under C++17, and we need to patch them in manually as well.
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
// Support for C++17
namespace std
{
    template <class _Ty>
    class auto_ptr;

    template <class _Ty>
    struct auto_ptr_ref { // proxy reference for auto_ptr copying
        explicit auto_ptr_ref(_Ty* _Right) : _Ref(_Right) {}

        _Ty* _Ref; // generic pointer to auto_ptr ptr
    };

    template <class _Ty>
    class auto_ptr { // wrap an object pointer to ensure destruction
    public:
        using element_type = _Ty;

        explicit auto_ptr(_Ty* _Ptr = nullptr) noexcept : _Myptr(_Ptr) {}

        auto_ptr(auto_ptr& _Right) noexcept : _Myptr(_Right.release()) {}

        auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept {
            _Ty* _Ptr = _Right._Ref;
            _Right._Ref = nullptr; // release old
            _Myptr = _Ptr; // reset this
        }

        template <class _Other>
        operator auto_ptr<_Other>() noexcept { // convert to compatible auto_ptr
            return auto_ptr<_Other>(*this);
        }

        template <class _Other>
        operator auto_ptr_ref<_Other>() noexcept { // convert to compatible auto_ptr_ref
            _Other* _Cvtptr = _Myptr; // test implicit conversion
            auto_ptr_ref<_Other> _Ans(_Cvtptr);
            _Myptr = nullptr; // pass ownership to auto_ptr_ref
            return _Ans;
        }

        template <class _Other>
        auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept {
            reset(_Right.release());
            return *this;
        }

        template <class _Other>
        auto_ptr(auto_ptr<_Other>& _Right) noexcept : _Myptr(_Right.release()) {}

        auto_ptr& operator=(auto_ptr& _Right) noexcept {
            reset(_Right.release());
            return *this;
        }

        auto_ptr& operator=(auto_ptr_ref<_Ty> _Right) noexcept {
            _Ty* _Ptr = _Right._Ref;
            _Right._Ref = 0; // release old
            reset(_Ptr); // set new
            return *this;
        }

        ~auto_ptr() noexcept {
            delete _Myptr;
        }

        _NODISCARD _Ty& operator*() const noexcept {
            return *get();
        }

        _NODISCARD _Ty* operator->() const noexcept {
            return get();
        }

        _NODISCARD _Ty* get() const noexcept {
            return _Myptr;
        }

        _Ty* release() noexcept {
            _Ty* _Tmp = _Myptr;
            _Myptr = nullptr;
            return _Tmp;
        }

        void reset(_Ty* _Ptr = nullptr) noexcept { // destroy designated object and store new pointer
            if (_Ptr != _Myptr) {
                delete _Myptr;
            }

            _Myptr = _Ptr;
        }

    private:
        _Ty* _Myptr; // the wrapped object pointer
    };

    template <>
    class auto_ptr<void> {
    public:
        using element_type = void;
    };
}
namespace boost
{
    template<class T> T* get_pointer(std::auto_ptr<T> const& p)
    {
        return p.get();
    }
}
#endif

// Suppress automatic inclusion of <boost/bind/placeholders.hpp> in <boost/bind/bind.hpp> in order to avoid conflict between Boost and C++11 placeholders.
#define BOOST_BIND_NO_PLACEHOLDERS

// Luabind 0.9.1 uses "boost::operator" but it has been moved to "boost::iterators::operator" in Boost 1.57.0 or later.
// As a result, many compilation errors will occur at the macro "LUABIND_OPERATOR_ADL_WKND" in "luabind/object.hpp".
// One of the best and wisest solutions is to modify the source code of Luabind directly.
// As an alternative way, the following workaround can avoid modifying it but is unbeautiful and pollutes the namespace "boost".
#include <boost/version.hpp>
#if (defined(BOOST_VERSION) && BOOST_VERSION >= 105700)
#include <boost/iterator/iterator_facade.hpp>
namespace luabind
{
    namespace detail
    {
        // Forward declaration
        template<typename T> class basic_iterator;
    }
}
namespace boost
{
    template<typename T> bool operator ==(
        const luabind::detail::basic_iterator<T>& x,
        const luabind::detail::basic_iterator<T>& y)
    {
        return boost::iterators::operator ==(x, y);
    }

    template<typename T> bool operator !=(
        const luabind::detail::basic_iterator<T>& x,
        const luabind::detail::basic_iterator<T>& y)
    {
        return boost::iterators::operator !=(x, y);
    }
}
#endif
  1. #include "luabind_compatibility.hpp" 添加到luabind源码下config.hpp 文件和 lua_include.hpp 文件 头部适当的地方;
    lua_include.hpp
    图例
    config.hpp
    图例

  2. luabind源码policy.hpp 文件的适当位置添加如下代码

LUABIND_NUMBER_CONVERTER(__int64, number)
LUABIND_NUMBER_CONVERTER(unsigned __int64, number)

policy.hpp
图例

  1. 开始编译

加入实际项目

  • boost源码根目录添加到工程的包含目录

  • luabind-0.9源码根目录下的luabind文件夹添加到工程的包含目录

  • lua源码根目录下的src文件夹添加到工程的包含目录
    图例

  • 将你lualuabind编译出来的lib文件夹添加到工程的附加库目录
    图例

  • 示例代码

#include <windows.h>

#include <array>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <vector>

#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "Lua53_64d.lib")
#pragma comment(lib, "libLuaBind64d.lib")
#else
#pragma comment(lib, "Lua53_32d.lib")
#pragma comment(lib, "libLuaBind32d.lib")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "Lua53_64.lib")
#pragma comment(lib, "libLuaBind64.lib")
#else
#pragma comment(lib, "Lua53_32.lib")
#pragma comment(lib, "libLuaBind32.lib")
#endif
#endif

extern "C" {
#include "lauxlib.h"
#include "lua.h"
#include "luaconf.h"
#include "lualib.h"
}

#include "luabind/luabind.hpp"

void print_hello(int number) {
    std::cout << "hello world is " << number << std::endl;
}

int main(void) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    luabind::open(L);
    luabind::module(L)[luabind::def("print_hello", print_hello)];

    luaL_dostring(L, "print_hello(123)");

    lua_close(L);
    return 0;
}

输出如下图:
图例

posted @ 2024-04-16 11:44  倚剑问天  阅读(119)  评论(0编辑  收藏  举报