![92efe711b9af5ef7b6e3fdc0f643f8f7.png](https://i-blog.csdnimg.cn/blog_migrate/b716af9833628ba0ca9ce097e3d7a191.jpeg)
为了加速Mathematica程序,可以使用Compile[]为变量指定机器类型,得到一个高效运行的函数。Compile有一个选项CompilationTarget,默认值"WVM",可选"C"。"WVM"生成Wolfram虚拟机代码,"C"使用一个外部C编译器,生成native机器代码。
在我使用CompilationTarget->"C"时,定位了两处中文编码问题,网络上还未见讨论过,这篇文章是为了给以后遇到同样问题的人提供一个参考。如果你不希望了解我定位这些问题的过程,请直接跳到第11节查看解决方案。
1、在Windows平台上,CCompilerDriver包会自动寻找你的:
- Cygwin gcc
- MinGW
- MSVC
- Intel C Compiler
四种C编译器。实现代码在
...Wolfram ResearchMathematica11.3SystemFilesComponentsCCompilerDriver
里面。
![d5e57db45b501e2817dac2ae8abfaeda.png](https://i-blog.csdnimg.cn/blog_migrate/43a9a756f4265a81ba55215c733ece8f.png)
2、CCompilerDriver在我的机器上没有找到上述任何一个C编译器,这是因为:
我刚好删除了Cygwin(因为有了WSL),也没有安装Intel C Compiler.
文档中说MinGW 5.1.8通过了测试,而我安装的6.3.0.
文档中说VS2010 VS2012通过了测试,而我安装的VS2017.
3、我发现在我的二奶机上,CCompilerDriver找到了VS2017里面的MSVC,然后我发现:
VisualStudioCompiler.m的11.3版本会查找VS2017,而11.0不支持。
4、我将主力机上的Mathematica更新到11.3版本,它仍然不能找到MSVC,我运行了VisualStudioCompiler.m,它给出这些错误信息:
![a9bcdf7a337ff0640b427668d9866bb7.png](https://i-blog.csdnimg.cn/blog_migrate/ad2e77185b57b1752a03937655a93310.png)
5、我阅读了VisualStudioCompiler.m,它使用MS提供的vswhere.exe查找所有安装的VS,大概是这样:
$vswherePath = FileNameJoin[{$InstallationDirectory, "SystemFiles",
"Components", "CCompilerDriver", "Resources", "Windows", "vswhere.exe"}]
$vswhereOutput = Import["!"<>QuoteFile[$vswherePath]<>" -products * -legacy -format json", "Text"]
$vsInfo := $vsInfo = If[$vswhereWorks, ImportString[$vswhereOutput, "RawJSON"], False]
vswhere的输出中,"description"的值是一串中文,所以ImportString的JSON Parser挂了。
6、解决这个问题:
尝试在调用Compile[]之前,对$CCompiler赋值以显式指定MSVC的安装位置,参考CCompilerDriver User Guide的Specific Compilers章节。这似乎行不通因为CreateLibrary只接受CCompilers[Full]里面列出的经过注册编译器,所以如果CCompilerDriver没有自动检测到编译器,指定它也没有用。
1)或安装英文版VS2017。如果已经安装了中文版VS2017,使用VS Installer将VS的语言包换成英文不能改变vswhere的输出,使用英文版VS Installer重装VS才可以。
2)或重写VisualStudioCompiler.m。它只使用了vswhere给出的installationPath和installationVersion键的值,所以调用vswhere时使用 -property "xxx" 参数,两次分别获取这两个值( -property 一次只能指定一个键),而不让它输出description就可以避免吃到中文字符。
3)或自己写一个假的vswhere替换掉CCompilerDriverResourcesWindowsvswhere.exe,直接给出你的VS安装路径,避免中文编码。
7、使用6、(1)继续,Compile[]报告这个错误:
![b8442e3ff64f4479d9ad2e7d07e873b9.png](https://i-blog.csdnimg.cn/blog_migrate/118dbff453593c5cba11a5cffa0b50a5.png)
嗯,显然又是一个中文编码问题。
8、找一下CreateLibrary[]在哪里,没有收获。查找"BuildFolder"串,在CCompilerDriver.m中找到:
$CCompilerInternalDirectory =
FileNameJoin[{Quiet[ApplicationDataUserDirectory["CCompilerDriver"]],
"BuildFolder", $MachineName<>"-"<>ToString[$ProcessID]}]
$MachineName显然是罪魁祸首,因为我的计算机名字是一串中文。
9、将计算机名改成英文,Compile[ , ,CompilationTarget -> "C"]现在可以工作了。
![b6b70a29709cb7aeb8ffbdc65d25c078.png](https://i-blog.csdnimg.cn/blog_migrate/7aa4dc7402b9d224a7b10e58ebf3d9be.png)
10、新的发现
今天我出门带了二奶机,我发现即使vswhere给出中文输出,CCompiler仍能识别到MSVC。
有这几个观察:
- 二奶机一开始就使用英文站点下载的VS Installer安装了VS2017,仅有简中语言包
- 二奶机上vswhere根据系统显示语言正确地给出中文或英文输出,且CCompilerDriver总是可以找到MSVC
- 使用中文站点下载的VS Installer安装VS后,主力机上的vswhere总是给出中文输出(而与系统显示语言无关),且CCompilerDriver总是找不到MSVC
我认为,中文站点的中文版VS Installer在机器上注册的信息存在兼容性问题,而英文版VS Installer正确提供了多语言注册信息,且CCompilerDriver遇到的编码问题就是中文版VS Installer造成的。这与VS的语言包和系统语言无关。
11、总结
如果你的Mathematica 11.3以上版本无法识别已安装的VS 2017中的MSVC,检查你是否使用了从中文站点下载的中文版VS Installer。如果是,尝试将VS Installer换成英文版,或者删除VS和VS Installer后用英文版VS Installer重装VS。VS的语言包和系统显示语言都可以是中文。
如果你使用Compile[]时报告编译错误,编译器无法打开工作目录,且工作目录中出现了乱码,检查你的计算机名字是否是中文,将中文换为仅英文。Compile[]使用你的计算机名字和计算机名字+进程ID来为每个机器的每个进程生成唯一确定的工作目录,而中文计算机名会在这一步导致编码问题。