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 (其他版本也可以,但是兼容性代码可能会略有不同,有概率踩坑)
编译开始
-
下载lua5.3,luabind-0.9,boost_1_70_0,分别解压到文件夹;
-
打开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/根目录添加到附加包含目录中;
大致如下图,具体目录由你的具体环境而定;
- 添加兼容代码文件到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
-
将 #include "luabind_compatibility.hpp" 添加到luabind源码下的 config.hpp 文件和 lua_include.hpp 文件 头部适当的地方;
lua_include.hpp
config.hpp
-
在luabind源码下 policy.hpp 文件的适当位置添加如下代码
LUABIND_NUMBER_CONVERTER(__int64, number)
LUABIND_NUMBER_CONVERTER(unsigned __int64, number)
policy.hpp
- 开始编译
加入实际项目
-
将boost源码根目录添加到工程的包含目录
-
将luabind-0.9源码根目录下的luabind文件夹添加到工程的包含目录
-
将lua源码根目录下的src文件夹添加到工程的包含目录
-
将你lua和luabind编译出来的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;
}
输出如下图:
本文为博主总结文章,欢迎转载,请注明出处。