嵌入式 Lua 单例模式 Linux vs Mingw

我正在开发一个嵌入式 Lua 项目,注意到如果使用本机 Linux 编译器与 MinGw-w64 交叉编译器行为不同。我使用 Swig 生成包装器文件,并使用 CMake 构建项目(并在 Wine 中进行测试)。

node.h

#ifndef NODE_H
#define NODE_H

class Node {
public:
  static Node* GetRoot();
  int GetCount();
  void SetCount(int count);
private:
  static Node *root;
  int count;
};

#endif /* NODE_H */

node.cpp

#include "node.h"

Node* Node::GetRoot() {
  return root;
}

int Node::GetCount() {
  return count;
}

void Node::SetCount(int count) {
  this->count = count;
}

Node* Node::root = {new Node()};

node.i

%module node

%{
  #include "node.h"
%}

%include "node.h"

main.cpp

#include <iostream>

#include "node.h"

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
extern "C" int luaopen_node(lua_State* L);

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

  luaL_loadfile(L, "main.lua");
  lua_call(L, 0, 0);
  lua_getglobal(L, "init");
  lua_call(L, 0, 0);

  std::cout << Node::GetRoot()->GetCount() << std::endl;
}

CMakeLists.txt


cmake_minimum_required(VERSION 3.13)
project(Singleton)

find_package(Lua REQUIRED)

add_executable(singleton main.cpp)
target_link_libraries(singleton nodelib)
target_link_libraries(singleton nodelua)
target_link_libraries(singleton ${LUA_LIBRARIES})

add_library(nodelib SHARED)
target_sources(nodelib PUBLIC
  node.h
  node.cpp)

find_package(SWIG REQUIRED)
include(UseSWIG)
set_property(SOURCE node.i PROPERTY CPLUSPLUS ON)

swig_add_library(nodelua
  TYPE SHARED
  LANGUAGE lua
  SOURCES node.i)
target_include_directories(nodelua PRIVATE "${PROJECT_SOURCE_DIR}")
swig_link_libraries(nodelua
  PRIVATE
  nodelib
  ${LUA_LIBRARIES})

main.lua

function init()
   local root = node.Node.GetRoot()
   root:SetCount(1)
end

请问为什么在本机编译时输出是 1,在 MinGw 交叉编译时输出是 0?如何在从嵌入式 Lua 调用返回时正确更新单例模式?

点赞
用户3187949
用户3187949

为了记录,这个问题是由于 DLL 对待静态成员的方式不好。由于 singleton 可执行文件和 nodelua 库都依赖于 nodelib,它们都会得到声明在其头文件中的静态成员的副本。通过将 root 变成 node.cpp 文件中的静态全局变量来解决这个问题。 (同时将 nodelua 变成静态库)。

为了记录,这个问题是由于 DLL 对待静态成员的方式不好。由于 `singleton` 可执行文件和 `nodelua` 库都依赖于 `nodelib`,它们都会得到声明在其头文件中的静态成员的副本。通过将 `root` 变成 `node.cpp` 文件中的静态全局变量来解决这个问题。
(同时将 `nodelua` 变成静态库)
2021-03-04 15:11:35