用emcc编译JModelica导出的FMU C代码遇问题及RT/NRT咨询
我来梳理下你遇到的问题和对应的解决方案,顺便把RT、NRT的含义和注意事项讲清楚:
先回顾下你的环境和问题链
你的环境:
- Ubuntu 18.10(64位)
- JModelica r12614
- Emscripten(emcc 1.3820 / clang 6.0.1)
你在编译JModelica导出的BouncingBall FMU代码时,先是碰到了gnu/stubs-32.h找不到的错误,后来去掉系统头文件又遇到linux/limits.h缺失,最终加了-DRT参数编译成功,但想知道这两个宏的意义和潜在问题。
第一个错误:gnu/stubs-32.h找不到的根源和规避
错误触发场景
你一开始的编译命令带了一堆系统头文件路径:
emcc -I /usr/include/ -I /usr/include/x86_64-linux-gnu/ -I /usr/include/x86_64-linux-gnu/bits/ -I /home/osboxes/Programme/JModelica/include/RuntimeLibrary/ -I /home/osboxes/Programme/JModelica/ThirdParty/FMI/2.0/ BouncingBall.c
结果报错:
/usr/include/x86_64-linux-gnu/gnu/stubs.h:7:11 fatal error: 'gnu/stubs-32.h' file not found
为什么会这样?
看gnu/stubs.h里的分支逻辑:
#if !defined __x86_64__ # include <gnu/stubs-32.h> #endif #if defined __x86_64__ && defined __LP64__ # include <gnu/stubs-64.h> #endif #if defined __x86_64__ && defined __ILP32__ # include <gnu/stubs-x32.h> #endif
Emscripten虽然是64位目标编译,但默认没定义__LP64__宏,导致编译器跳过了64位头文件的引入,反而去加载32位的stubs-32.h——但Emscripten根本不支持32位编译,装libc6-dev:i386也没用。
最直接的解决思路
别加系统头文件路径!因为你要编译的是WebAssembly目标,Emscripten有自己的标准库实现,原生Linux的系统头文件反而会搞出兼容性问题。JModelica导出的FMU代码依赖的RuntimeLibrary和FMI头文件已经足够,完全不需要系统头文件。
第二个错误:linux/limits.h找不到的解决
错误触发场景
去掉系统头文件后执行:
emcc -I /home/osboxes/Programme/JModelica/include/RuntimeLibrary/ -I /home/osboxes/Programme/JModelica/ThirdParty/FMI/2.0/ BouncingBall.c
又报错linux/limits.h找不到,这是因为JModelica的jmi_utils.h里的逻辑:
... #if !defined(NO_FILE_SYSTEM) && (defined(RT) || defined(NRT)) #define NO_FILE_SYSTEM #endif #ifndef NO_FILE_SYSTEM #ifdef _WIN32 #include <windows.h> #define JMI_PATH_MAX MAX_PATH #else #define _GNU_SOURCE #include <dlfcn.h> #ifdef __APPLE__ #include <limits.h> #define JMI_PATH_MAX PATH_MAX #else #include <linux/limits.h> #define JMI_PATH_MAX PATH_MAX #endif #endif #include <sys/types.h> #include <sys/stat.h> #endif ...
这段代码的意思是:如果没定义NO_FILE_SYSTEM,就会引入系统文件相关的头文件;但如果定义了RT或者NRT,就会自动定义NO_FILE_SYSTEM,跳过这些系统头文件的加载。
解决方法
加-DRT参数编译就行,也就是你最后用的命令:
emcc -I /home/osboxes/Programme/JModelica/include/RuntimeLibrary/ -I /home/osboxes/Programme/JModelica/ThirdParty/FMI/2.0/ BouncingBall.c -DRT
这样就跳过了系统文件头文件的引入,编译自然成功。
重点:RT和NRT到底是什么?用的时候要注意什么?
含义解析
这两个是JModelica RuntimeLibrary的编译控制宏,用来切换功能模式:
RT:是Real-Time的缩写,对应实时仿真模式。实时场景下绝对不能有阻塞式的文件IO操作(会破坏实时性),所以定义RT后,RuntimeLibrary会自动禁用所有文件系统相关功能,只保留核心的仿真计算逻辑。NRT:是轻量非实时模式——同样会禁用文件系统功能,但更侧重无依赖的轻量运行,适合像WebAssembly这种没有原生文件系统的环境,或者不需要实时性但要最小化体积的场景。
简单说,这两个宏的核心作用都是告诉RuntimeLibrary:别碰文件系统,我不需要这个功能。
必须注意的问题
- 功能限制:一旦定义了
RT/NRT,你的FMU模型就完全不能进行任何文件操作了——比如读取外部参数文件、输出结果到本地文件这些逻辑都会失效。如果你的模型原本有这类依赖,得先修改模型,改用内存中的数据传递(比如通过FMU的输入输出接口传递数据)。 - 环境适配:WebAssembly本身就没有原生文件系统(除非用Emscripten的虚拟文件系统模拟),所以你用
-DRT完全适配这个场景,不会有额外问题。但如果之后要把这个代码编译回原生Linux程序,可能需要去掉这个参数,或者重新适配文件系统逻辑。 - 兼容性:这两个宏是JModelica专属的,其他工具(比如OpenModelica)导出的FMU代码可能不支持,别乱用。
内容的提问来源于stack exchange,提问作者19leunam93




