7个版本 (1个稳定版)
1.0.6 | 2020年6月27日 |
---|---|
1.0.6-alpha5 | 2020年9月21日 |
1.0.6-alpha3 | 2020年9月20日 |
1.0.6-alpha2 | 2020年7月1日 |
#96 in 模拟
5.5MB
42K SLoC
lc3tools-sys
LC3Tools的Rust绑定。
用法
将此添加到您的 Cargo.toml
[dependencies]
lc3tools-sys = "1.0.6"
由于这个crate公开的绑定与LC3Tools
API完全一一对应,因此LC3Tools
的源代码和文档是了解如何使用此crate的最佳位置,特别是API文档。
头文件
头文件在DEP_LC3CORE_LINKS
环境变量指定的路径下公开。
注意事项
然而,请注意,LC3Tools
公开了一个C++ API。虽然这个crate提供了绑定,但它与您的操作系统/平台/编译器/编译器标志一起工作的可能性非常小。不同的平台似乎有不同的名称混淆约定,并且布局(据我所知)在不同配置之间不稳定(例如,从-O3
切换到-O0
会破坏我的配置中的C++接口示例)。
所有这些(名称混淆符号、布局信息)都编码在生成的绑定中。请注意,因为链接器通常是懒惰的,即使生成的绑定中的符号与您平台实际产生的符号不匹配,除非您实际在最终二进制文件中使用(间接)这些符号,否则您可能不会收到编译错误。这就是为什么C++接口示例被功能屏蔽的原因。
我们提供了一个generate-fresh
功能,这样您可以在构建时在本地生成此文件,但C++接口仍然不太可能工作/有用。诸如vtable之类的对象通过不透明类型表示,即使您设法获取一个C++生成的vtable以传递,有时事情仍然不起作用。
例如,由于原因尚不明确,在运行C++接口示例时,传递给模拟器的printer
神秘地变成了NULL
,但仅在传递给state
实例的日志器副本中;在logger
中的副本保持不变。我只能在修改了以下LC3Tools
之后才能让示例工作
点击显示差异。
diff --git a/backend/logger.h b/backend/logger.h
index b7146ac..c172acb 100644
--- a/backend/logger.h
+++ b/backend/logger.h
@@ -28,10 +28,17 @@ namespace utils
template<typename ... Args>
void printf(PrintType level, bool bold, std::string const & format, Args ... args) const;
void newline(PrintType level = PrintType::P_ERROR) const {
- if(static_cast<uint32_t>(level) <= print_level) { printer.newline(); }
}
void print(std::string const & str) {
- if(print_level > static_cast<uint32_t>(PrintType::P_NONE)) { printer.print(str); }
}
uint32_t getPrintLevel(void) const { return print_level; }
void setPrintLevel(uint32_t print_level) { this->print_level = print_level; }
diff --git a/backend/simulator.cpp b/backend/simulator.cpp
index c8004e8..bd7f1db 100644
--- a/backend/simulator.cpp
+++ b/backend/simulator.cpp
@@ -112,7 +112,7 @@ void Simulator::simulate(void)
collecting_input = true;
- inputter.beginInput();
if(threaded_input) {
input_thread = std::thread(&core::Simulator::inputThread, this);
}
@@ -125,7 +125,7 @@ void Simulator::simulate(void)
executeEventChain(events);
updateDevices();
if(! threaded_input) {
- collectInput();
}
checkAndSetupInterrupts();
}
@@ -139,7 +139,7 @@ void Simulator::simulate(void)
if(threaded_input && input_thread.joinable()) {
input_thread.join();
}
- inputter.endInput();
解决方案
为了让这个crate至少在一定程度上可用,我们提供了一组有限的C绑定,它仅适用于运行整个程序。
这非常麻烦,但对我们来说足够好™。如果您需要真正的Rust绑定cxx
,那么这可能值得一看。由于这个crate导出了LC3Tools
头文件,您可以依赖这个crate并使用它的cc
设置(忽略它具有的绑定)。
或者,如果您需要特定于C绑定的添加,欢迎提交PR!
特性
LC3Tools
功能特性
LC3Tools
的后端部分始终包含在内。frontend
特性包括frontend
中的文件,而grader
特性(需要frontend
特性)包括frontend/grader
中的文件,但移除了main
函数在framework.cpp
中的实现。
这些特性默认都是启用的。
其他特性
generate-fresh
默认情况下,构建此crate时不会重新生成LC3Tools
的Rust绑定。生成。相反,我们捆绑了预生成的绑定并默认使用它们。我们这样做是因为生成绑定需要一些时间(大约一分钟——除非您非常关心清洁构建所需的时间,否则这不是一个问题),但更重要的是因为生成绑定是系统特定的。bindgen
在执行过程中会遍历系统libc和C++标准库头文件,并且我们维护了一个要跳过的类型和内容的列表,它非常特定于libc/system/OS。
你可能永远不需要这样做,但如果你自己想要生成这些绑定(例如,因为你修改了LC3Tools
中的某些头文件),则可以使用generate-fresh
功能来构建(build.rs
会传递正确的指令给cargo
,这样你就可以启用该功能——只有当构建图中的某个头文件/文件发生变化时,它才会实际执行工作)。
lto
不幸的是,我们无法默认启用LTO,因为它需要一些设置,并且需要使用一些特定的工具(参见此提交和此提交以获取一些背景信息,以及此页面以获取所需设置的详细信息)。
因此,我们提供了一个lto
功能,它将编译器调用的cc
传递必要的标志。当使用此功能时,你还需要确保传递给rustc
的LTO链接器插件标志,并指示它使用合适的链接器,如此处所述。对于此特定crate,必要的标志已存在于此处,但已注释。
当使用lto
功能时,你需要确保cc
最终使用的编译器能够与LTO链接器插件一起工作。此表此处提供了一些关于应使用哪个版本的信息,但它有些过时;如果使用相同版本的clang
来构建LC3Tools
,并且使用相同版本的rustc
来进行链接,则应该可以正常工作(假设它是相对较新的clang版本——本repo的CI使用版本9,成功运行)。
确定并更改cc
使用的编译器实际上更复杂;在基于Linux的系统上,确保c
别名指向所需的版本似乎就可以了(update-alternatives
可能有助于你完成此操作)。
示例
目前我们有一个示例,该示例运行一个LC-3程序,用于计算两个无符号数的乘积。如前所述,它有一个C++接口部分和一个C接口部分。默认情况下,C++部分被禁用,因为它不太可能在你的机器上工作。
cargo run --example mul
应该运行C接口部分。
最低支持的Rust版本(MSRV)
此crate目前保证可以在稳定的Rust 1.43及更高版本上编译。我们无法保证这一点在未来版本中依然成立,但承诺将始终支持(至少)最新的稳定Rust版本,并在变更日志中记录MSRV的更改。
贡献
PR(Pull Requests,拉取请求)(非常)欢迎!有关详细信息,请参阅CONTRIBUTING.md。