Rexdf

The devil is in the Details.

Visual Studio编译gvim支持Racket(mzscheme)

| Comments

在VS编译的64位gvim支持了Python2/3,ruby,perl,tcl,lua之后(参考在Visual Studio编译gvim和ycmd),发现配置里面还有一个叫做MzScheme,而且是在Make_mvc.mak里面,就是说原生是支持VS编译的。那么开启吧。

先来看效果吧!

x64-gvim-mzscheme

这个相对上面几种语言来说,应该是最难编译了。因为mzscheme已经变成Racket了,然而4xx版本以前的只能在原网站下载,新版本的5xx与6xx似乎就完全改成新名字Racket了,已经见不到mzscheme的字样。

按照我的惯性,首先当然就是下载64位的安装程序racket-6.1.1-x86_64-win32.exe(写本文的时候已经升级到了6.2.2了),但是几处硬编码patch后,是链接失败。于是我怀疑库的问题,于是我便源码手动编译,然而问题依旧。实际问题是vim最新的源码似乎并没有完全迁移到支持Racket 6xx,反正这里有好几个tricks,我是直接读源码才搞明白怎么回事的。

版本号

首先第一个问题是Racket/MzScheme版本是多少6.1.1?611?都是错的。我们来看看PYTHON_VER=27 PYTHON3_VER=34 PERL_VER=520 TCL_VER=86 TCL_VER_LONG=8.6 RUBY_VER=22 RUBY_VER_LONG=2.2.2 LUA_VER=53,似乎直接就会写MZSCHEME_VER=611而通过读vim/src/Make_mvs.mak,很快弄明白了,它就是用来链接库的后缀的,比如Python27.lib,而这个27就被写成了PYTHON_VER=27,以达到代码的通用性。然而我们去看看Racket\lib\msvc,简直“不堪入目”。 6.1.1的版本是如下四个文件

libracket3m_9xtjc8.exp

libracket3m_9xtjc8.lib

mzdyn3m.exp

mzdyn3m.obj

当然我立即意识到了,MZSCHEME_VER=3m_9xtjc8,然而问题远没有这么简单。

mzscheme_base.c

它有一个依赖

makefileMyBlog
mzscheme_base.c:
$(MZSCHEME)\mzc --c-mods mzscheme_base.c ++lib scheme/base

这句真的是mzscheme的,然而一番搜索,发现现在的应该是raco ctool --c-mods mzscheme_base.c ++lib scheme/base,而实际上在6.1.1上面则应该是raco ctool --c-mods mzscheme_base.c ++lib racket/base

scheme_register_tls_space

src/if_mzsch.c这个地方总是报链接错误。 于是我来探寻一番,启动VS2013 x64 Native Tools Command Prompt,我们来到Racket\lib\msvc里面。执行dumpbin.exe -headers libracket3m_9xtjc8.lib | findstr /c:" Symbol name :">libs.txt,然后打开搜索scheme_register_tls_space,确实找不到!

然后我们来到了Racket/doc/inside/im_memoryalloc.html?q=scheme_register_tls_space#%28cpp._scheme_register_tls_space%29这里,Only available on 32-bit Windows,也就是说64位不能用。然而不让用有啥替代呢?上下翻了下,没有说明。于是不管怎么样先pass过编译再说吧,于是注释掉了

diffMyBlog
--- a/src/if_mzsch.c Thu Jun 25 18:36:26 2015 +0200
+++ b/src/if_mzsch.c Fri Jun 26 01:26:10 2015 +0800
@@ -871,7 +871,7 @@
mzscheme_main(int argc, char** argv)
{
#if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) && defined(USE_THREAD_LOCAL)
- scheme_register_tls_space(&tls_space, 0);
+ //scheme_register_tls_space(&tls_space, 0);
#endif
#ifdef TRAMPOLINED_MZVIM_STARTUP
return scheme_main_setup(TRUE, mzscheme_env_main, argc, argv);

很顺利编译通过了。然而启动gvim执行:mz (+ 1 1)却是程序无响应退出。启动Windbg_x64,先Attach上去,按F5跑起来,然后再次执行:mz (+ 1 1),于是我发现Windbg_x64也是支持源码级别的调试的了!真是强大。

自己编译Racket

因为3m版本的对C语言支持没有CGC版本的友好,于是手动编译Racket。直接官网下载min版本的源码。然后二话不说执行racket-6.2\src\worksp\build.bat,直接就编译好了最新版本的Racket,对我来说比安装exe真的要容易啊,因为它是pdb调试文件的啊!然后执行raco install安装完整的racket库。

我的修改

实际上我成功的链接是用CGC版本的,也就是MZSCHEME_VER=xxxxxxx DYNAMIC_MZSCHEME=no为编译参数,同时对源码打如下补丁。其中libintl.dll改成intl.dll是因为我自己用Visual Studio编译64位的gettext的时候发现现在已经官网名字确实已经是intl.dll,而且这个在vim官网的下载页面有明说,它给出方案是把intl.dll改成libintl.dll,而我则是改vim的源码。因为我不需要像vim官网一样顾忌老系统的支持。

diffMyBlog
diff -r a5e1a8813a3f src/GvimExt/gvimext.cpp
--- a/src/GvimExt/gvimext.cpp Thu Jun 25 18:36:26 2015 +0200
+++ b/src/GvimExt/gvimext.cpp Fri Jun 26 01:26:10 2015 +0800
@@ -157,7 +157,7 @@
# define _(x) (*dyn_libintl_gettext)(x)
# define VIMPACKAGE "vim"
# ifndef GETTEXT_DLL
-# define GETTEXT_DLL "libintl.dll"
+# define GETTEXT_DLL "intl.dll"
# endif
// Dummy functions
diff -r a5e1a8813a3f src/Make_mvc.mak
--- a/src/Make_mvc.mak Thu Jun 25 18:36:26 2015 +0200
+++ b/src/Make_mvc.mak Fri Jun 26 01:26:10 2015 +0800
@@ -797,7 +797,7 @@
!endif
CFLAGS = $(CFLAGS) -DFEAT_MZSCHEME -I $(MZSCHEME)\include
!if EXIST("$(MZSCHEME)\collects\scheme\base.ss") \
- || EXIST("$(MZSCHEME)\collects\scheme\base.rkt")
+ || EXIST("$(MZSCHEME)\collects\racket\base.rkt")
# for MzScheme >= 4 we need to include byte code for basic Scheme stuff
MZSCHEME_EXTRA_DEP = mzscheme_base.c
CFLAGS = $(CFLAGS) -DINCLUDE_MZSCHEME_BASE
@@ -1170,7 +1170,7 @@
$(CC) $(CFLAGS) if_mzsch.c \
-DMZSCHEME_COLLECTS=\"$(MZSCHEME:\=\\)\\collects\"
mzscheme_base.c:
- $(MZSCHEME)\mzc --c-mods mzscheme_base.c ++lib scheme/base
+ $(MZSCHEME)\raco ctool --c-mods mzscheme_base.c ++lib scheme/base
$(OUTDIR)/if_python.obj: $(OUTDIR) if_python.c if_py_both.h $(INCL)
$(CC) $(CFLAGS) $(PYTHON_INC) if_python.c
diff -r a5e1a8813a3f src/if_mzsch.c
--- a/src/if_mzsch.c Thu Jun 25 18:36:26 2015 +0200
+++ b/src/if_mzsch.c Fri Jun 26 01:26:10 2015 +0800
@@ -871,7 +871,7 @@
mzscheme_main(int argc, char** argv)
{
#if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) && defined(USE_THREAD_LOCAL)
- scheme_register_tls_space(&tls_space, 0);
+ //scheme_register_tls_space(&tls_space, 0);
#endif
#ifdef TRAMPOLINED_MZVIM_STARTUP
return scheme_main_setup(TRUE, mzscheme_env_main, argc, argv);
diff -r a5e1a8813a3f src/os_win32.c
--- a/src/os_win32.c Thu Jun 25 18:36:26 2015 +0200
+++ b/src/os_win32.c Fri Jun 26 01:26:10 2015 +0800
@@ -435,7 +435,7 @@
#if defined(DYNAMIC_GETTEXT) || defined(PROTO)
# ifndef GETTEXT_DLL
-# define GETTEXT_DLL "libintl.dll"
+# define GETTEXT_DLL "intl.dll"
# endif
/* Dummy functions */
static char *null_libintl_gettext(const char *);
diff -r a5e1a8813a3f src/po/Make_mvc.mak
--- a/src/po/Make_mvc.mak Thu Jun 25 18:36:26 2015 +0200
+++ b/src/po/Make_mvc.mak Fri Jun 26 01:26:10 2015 +0800
@@ -63,7 +63,7 @@
PACKAGE = vim
# Correct the following line for the directory where gettext et al is installed
-GETTEXT_PATH = H:\gettext.0.14.4\bin
+GETTEXT_PATH = gettext-0.14.4\bin
MSGFMT = $(GETTEXT_PATH)\msgfmt
XGETTEXT = $(GETTEXT_PATH)\xgettext
diff -r 99fc18dc1ede src/main.c
--- a/src/main.c Sun Jun 28 19:24:40 2015 +0200
+++ b/src/main.c Wed Jul 01 15:46:58 2015 +0800
@@ -4014,9 +4014,9 @@
* endif
*/
ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
- ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# \"");
+ ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# \'");
ga_concat(&ga, cdp);
- ga_concat(&ga, (char_u *)"\"|cd -|endif|endif<CR>");
+ ga_concat(&ga, (char_u *)"\'|cd -|endif|endif<CR>");
vim_free(cdp);
if (sendReply)

后记

本文内容已经于7月10日被Bram Moolenaar在7.4.772合并到了主分支了。

Comments