Posts

安装Macvim

25 Jun 2016

前言

本文记录了一次安装Macvim遇到的问题和解决办法,并提到了如何从终端启动Macvim。

brew install macvim 成功,但启动报错

今天重装了Mac系统(10.11.5 El Capitan,你问Mac居然也重装系统?我只是想要一块干净的硬盘。). 折腾完系统,在装回Macvim的时候遇到了问题。 我是使用Hombrew来安装的,在安装过程中brew下载了一些依赖的包。最后安装完成,在执行完brew linkapps macvim生成一个链接到Applications目录之后,我立马敲了mvim来启动Macvim, 让我吃惊的是,居然报错了!
Fatal Python error: PyThreadState_Get: no current thread
这是我在iterm2窗口中看到的错误信息,虽然Macvim跑起来了,但是很明显python报错了,这意味着vim中使用Python的插件可能都会不能工作, 确实如此YouCompleteMe首当其冲,事实证明,后来我在逐个注释掉.vimrc中用到了Python的插件以排查问题的时候,把YCM注释掉了Python就不报错了。 于是google了一下报错信息,果然在YCM的issue里有关于这个问题的讨论,YCM作者一直在甩锅:
Just tried using the latest MacVim on my OS X Mountain Lion and everything works. So this is somehow caused by your machine configuration in some way, sorry.
大意就是:”别特么来烦我,这明显是你Mac系统配置问题,去换一个官方最新的Macvim版本吧。” 看了好几个关于这个问题的issue最后看到了YCM作者最关键的一个回答:
The version of Python that YCM is linked to when being built and the version of Python linked into your Vim binary have to match, yes. If they don’t, a problem like the one you’re experiencing might ensue.
意思是:”构建YCM使用的Python版本必须和构建Vim使用的Python版本必须匹配,否则就可能出来这个问题。” ...

阅读全文 ...


【Programming In Lua (2E) 笔记】5:使用C++为Lua编写扩展库(macOS上两种动态库格式的坑)

31 May 2016

ps: 2016年6月的WWDC上,Mac操作系统正式更名为macOS, 与iOS, watchOS, tvOS的命名风格终于统一了。

前言

本文记录了在macOS上使用c++为lua编写动态库的过程,分享一个容易翻车的坑。 Lua Version: 5.1

问题描述

在PIL第26章:《从Lua调用C》,介绍了从lua调用C程序的方法,即扩展lua, 用c++来为lua编写扩展库。 文中提到了扩展lua的两种方式:
  • 把c++代码编译为为动态库,使用lua的动态链接功能来加载c++的模块(即,require “cpplib”的方式, 这里cpplib为一个例子,比如我编译为libcpplib.so, 就需要像这样来加载这个动态库。)
  • 把编写好的c++模块加入到lua源码,重新编译lua可执行程序,这样c++模块就成为了lua的一部分(类似lua标准库string,math等等)
第二种方式–重新编译lua很简单,按照书中所说,把写好的c++模块注册函数luaopen_mylib添加到luaL_openlibs会打开的标准库列表里。(在linit.c中) 经过我在mac上的实践,第二种方式顺利搞定。毕竟lua源码中的README和INSTALL文档已经把编译lua讲的很明白了。 至于这第一种方式,别看书里一笔带过,这实践起来还真是。。。。。。 一言不合就翻车了。 ...

阅读全文 ...


【Programming In Lua (2E) 笔记】4:用lua扩展C++——C++调用lua函数

31 May 2016

自从13年开始做手游接触lua,始终是边写边学,缺乏对lua更加全面系统的学习,这几篇文章开始“重识lua”, 把欠下的帐还回来。这个系列侧重于总结lua作为扩展程序的用法,不会着重介绍lua的语法。

前言

本文介绍如何在C++中调用lua的function,lua很多情况下是被用做一种扩展语言,它的function更是增加了这门扩展语言的灵活性,赋予了lua生命力,使它变化莫测。在lua的function中还可以回调宿主语言的函数。这篇文章展示如何从C++端调用lua函数,相反的过程在后面的文章再做介绍。 本文使用的Lua版本还是5.1。

简单的调用示例

还是使用上一篇文章中使用的环境,调用config.lua里面的f函数: res/config.lua:
function f(var)
    return var * var + 2 * var + 100
end
...

阅读全文 ...


【重识Lua】3:给C++程序插上翅膀——C++调用lua

30 May 2016

自从13年开始做手游接触lua,始终是边写边学,缺乏对lua更加全面系统的学习,这几篇文章开始“重识lua”, 把欠下的帐还回来。这个系列侧重于总结lua作为扩展程序的用法,不会着重介绍lua的语法。

前言

前一篇文章总结了lua中C API的基本用法和常见的虚拟栈操作函数,并没有涉及到具体的lua代码,只有当这些API用来连接lua代码和C++代码的时候,才能发挥出它的最大威力。本文的主题在于使用C++来加载、调用lua代码。 本文使用的Lua版本还是5.1。

C++中加载lua脚本

就像打开其它类型的文件一样,比如打开一个txt文件读取成一个字符串,打开一个json文件用json解析库来解析出感兴趣的字段;对于lua脚本则有lua解析器去解释它,它不仅可以被当做普通的静态配置文件来使用,更牛的地方就在于,它,是可编程的!对,因为它是一门编程语言。尤其是当你为lua打开了它的翅膀(lua标准库)。 下面就给出一个简单的例子,演示一下,如何把lua脚本当做一种资源,载入到C++代码中。 下面这个lua文件里定义了两个全局变量一个是字符串类型的怪物类型,一个是怪物血量,我把它当做一个配置文件来用,在C++中读取它们的值 res/config.lua:
monster_type = "Ghost"
blood        = 99.9
main.cpp:
#include "lua_51/lua.hpp"
#include "include/inc.h"
#include <string>

using namespace elloop;
using namespace std;

int main() {

    string scriptName("res/config.lua");

    lua_State* lua = luaL_newstate();

    int luaError = luaL_loadfile(lua, scriptName.c_str());  // 加载lua文件
    if (luaError) {
        error(lua, "fail to load script: %s, %s", scriptName.c_str(), lua_tostring(lua, -1));
    }

    luaError = lua_pcall(lua, 0, 0, 0);     // 执行这个lua文件, 三个0依次表示:输入0个参数,返回0个结果,需要0个错误处理函数
    if (luaError) {
        error(lua, "fail to run script: %s", lua_tostring(lua, -1));
    }

    lua_getglobal(lua, "blood");                            // 获取全局变量blood
    lua_getglobal(lua, "monster_type");                     // 获取全局变量monster_type

    double blood     = lua_tonumber(lua, 1);                // 读取两个全局变量
    const char* type = lua_tostring(lua, 2);

    psln(blood);                                            // 打印 blood = 99.9
    psln(type);                                             // type = Ghost

    lua_close(lua);

    return 0;
}
...

阅读全文 ...


【重识Lua】2:操作lua栈

29 May 2016

自从13年开始做手游接触lua,始终是边写边学,缺乏对lua更加全面系统的学习,这几篇文章开始“重识lua”, 把欠下的帐还回来。这个系列侧重于总结lua作为扩展程序的用法,不会着重介绍lua的语法。

前言

本文总结了Lua中操作虚拟栈的API,通过这些API可以做到在Lua和C/C++之间传递数据,相互调用对方。在Programming In Lua那本书中(后文简称PIL),作者把这些API称作“C API”,一方面是因为他们是用C语言实现,另一方面它们的作用是用来实现C/C++语言和Lua之间的相互调用。正如PIL中说的那样,几乎所有的这些API都会操作虚拟栈,这个虚拟栈在C/C++与Lua通信过程中,解决了两者之间存在的两个差异,第一是内存管理方式的差异:Lua的垃圾回收和C语言的手动管理;第二是数据类型方面的差异:Lua是动态类型和C语言的静态类型。 本文使用的Lua版本还是5.1。

Lua C API 版Hello World

下面这段代码演示了C API的基本用法,向lua虚拟栈中push了一个字符串,然后从栈中读取这个字符串,将其打印出来:
extern "C" {
   #include "lua_51/lua.h"                            // C API函数声明所在的文件
   #include "lua_51/lauxlib.h"                        // luaL_ 开头的函数所在的头文件, 比如luaL_newstate
}

#include <iostream>

int main()
{
    lua_State* lua = luaL_newstate();                  // 创建一个lua state

    lua_pushstring(lua, "hello world");                // 入栈一个字符串
    std::cout << lua_tostring(lua, 1) << std::endl;    // 从栈中读取字符串

    lua_close(lua);                                    // 关闭lua state

    return 0;
}
...

阅读全文 ...