创建组件“ovalshape”失败_Unity3D调用llvm-nm失败的原因分析

近来鲜有闲暇,长一点的文章,写着写着便搁置了。那就写点轻松的话题,聊聊这两天遇到的坑吧


问题起因

最近在开发一个编辑器组件的时候,需要调用nm,从静态库中查找符号所在的.o

代码很公式话,这里就不贴了

C# 创建Process,设置 Process.StartInfo:

UseShellExecute = false

FileName = <Path to llvm-nm>

因为要读取输出,还设置了 RedirectStandardOutput = true

从 StandardOutput 上读到了 null,什么输出也没有,子进程便退出了。

检查了 ExitCode 不为0,代表有错误。

Step 1. 缩小问题范围

把同样的代码,贴到VS工程运行没有问题 √

同一份代码,控制台用mono执行也没有问题 √

通过 Process 启动 llvm-nm 失败的情况只出现 Unity3D 下,它到底哪里不一样导致了调用失败?

Step 2. 检查 stderr

既然遇到了错误退出,作为一个严谨的控制台程序 StandardError 总会有些输出吧。重定向了StandardError 得到的信息 Bad file descriptor,错误的文件描述符。

立即闪现的念头是llvm-nm是否依赖于调用其他文件所以导致失败? 经过测试排除了这种可能,所以决定还是编译调试版的nm跟一下流程吧。

Step 3. 调试LLVM-NM

ea81033bfaf67a65c63ccd82d0a22f68.png

进程一启动遍退出了,sys::ChangeStdinToBinary() 失败了, 那就看下它的代码实现。

Windows的实现是这样的:

343400439dbff94cfc7f945b00cd5b38.png

_setmode 失败了,失败的原始是当前的stdin是无效的。于是问题便成为了stdin为什么是无效的?

Step 4. 查阅Mono代码

启动进程的代码定位到 mcs/class/System/System.Diagnostics/Process.cs

函数 bool StartWithCreateProcess (ProcessStartInfostartInfo) 其中关于stdin的设置是这样的:

18a1dc33d6bb7b2214d09197cd72efed.png

如果启用stdin重定向,就创建管道,设置给子进程。

如果没有启动,则使用当前的 MonoIO.ConsoleInput。

那么 MonoIO.ConsoleInput 的值是怎么来的呢?

MonoIO.ConsoleInput 只有get方法,并且是internal call,

mono/metadata/icall-def.h 中定义了:

ICALL(MONOIO_28, "get_ConsoleInput", ves_icall_System_IO_MonoIO_get_ConsoleInput)

39f8fd83b1530e3568de22563c84761b.png

76844be427120f08f37e81f4a414a365.png

最终调用了 Windows的API GetStdHandle ,于是进一步确认:在 Unity 中通过P/Invoke调用 GetStdHandle 得到了返回 0,即 NULL。文档中如下写道:

If an application does not have associated standard handles, such as a service running on an interactive desktop, and has not redirected them, the return value is NULL.

到这里,问题的起因就查清了。

总结

Unity 没有关联 stdin, stdout, stderr,它创建的子进程也受此影响,导致llvm-nm设置stdin的转化模式失败,进而引发错误退出。

解决方案

知道了原因,问题就很好解决了,在Unity中启动 llvm-nm 时启用 stdin 重定向,规避stdin setmode失败。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值