C-originated Rust Advancing Transformer
There is no specific requirement to build and run Crat. Just make sure that you have Cargo installed.
You should first build the deps_crate crate, which provides dependencies to
compile the Rust program to be transformed. You only need to do this once.
cargo build --manifest-path deps_crate/Cargo.tomlHere, we explain an example workflow to translate a C project to Rust using
C2Rust and Crat. The example project is a simple program that reads five
integers from the standard input and prints their sum. The C source code is
under examples/sum. In the following steps, we assume that the ~/rs and
~/rs-transformed directories exist. You may use other paths as you like.
First, run the following commands to create compile_commands.json using
intercept-build:
cd examples/sum
intercept-build make
cd ../..Then, run C2Rust to obtain the initial Rust code. c2rust-transpile should be
on your PATH. We recommend using our custom
version based on
C2Rust 0.21.0. Make sure you check out the tractor-0.21.0 branch after cloning
the repository.
c2rust-transpile -e -o ~/rs/sum examples/sum/compile_commands.jsonThis will create ~/rs/sum containing the generated Rust code.
Finally, run Crat to transform the Rust code:
cargo run --bin crat -- \
-o ~/rs-transformed \
--unsafe-remove-unused \
--unsafe-remove-no-mangle \
--unsafe-remove-extern-c \
--unexpand-use-print \
--bin-name sum \
--pass expand,extern,preprocess,pointer,io,libc,static,simpl,unsafe,unexpand,split,bin \
~/rs/sumThis will create ~/rs-transformed/sum containing the transformed Rust code.
Run the following commands to run the program:
echo 1 2 3 4 5 | cargo run --manifest-path ~/rs-transformed/sum/Cargo.tomlThe expected output is as follows:
Sum: 15
To compile and run benchmark programs, the following packages and tools are required:
apt-get install curl freeglut3-dev gcc git less libao-dev libasound2-dev \
libavcodec-dev libavfilter-dev libavformat-dev libavutil-dev libc6-dev \
libcrypt-dev libcurl4-gnutls-dev libev-dev libevent-dev libfftw3-dev \
libfuse-dev libfuse3-dev libgcrypt20-dev libgl-dev libglu1-mesa-dev \
libgmp-dev libidn2-dev libiniparser-dev libjson-c-dev liblzma-dev \
libncurses-dev libpcap0.8-dev libpcre3-dev libpq-dev libpulse-dev \
librdkafka-dev libreadline-dev librtlsdr-dev libselinux1-dev libssl-dev \
libunistring-dev libusb-1.0-0-dev libwww-perl libx11-dev libxau-dev \
libxcomposite-dev libxdamage-dev libxext-dev libxfixes-dev libxrandr-dev \
libxrender-dev locales make nettle-dev php7.4-cli postgresql-server-dev-12 \
pulseaudio redis-server squeezelite sudo time uuid-dev zlib1g-devpip install pytest cramIn addition, the username should be ubuntu, and using Ubuntu 20.04 is
recommended.
You may use the kaistplrg/crat-test-user:1.1.2 Docker image, which meets the
above requirements.
Benchmark programs are under benchmarks/rs. Each directory corresponds to each
benchmark and contains Rust code generated by C2Rust. You can run Crat to
transform the benchmark programs.
tool.py is a Python script that allows you to easily transform the benchmarks,
build the transformed code, and run their test suites. It can be executed with a
command of the following form:
./tool.py <command> <stage> <benchmark>The command can be one of the following:
transform: Transform the benchmark program(s).build: Build the transformed benchmark program(s).test: Run the test suite of the transformed benchmark program(s).clean: Remove the transformed benchmark program(s).
The stage specifies the directories being the source and the destination of the transformation and also the passes to be applied. The following stages are available:
expand: Fromrstors-expandby applyingexpand.extern: Fromrs-expandtors-externby applyingpreprocess,extern.extern-post: Fromrs-externtors-extern-postby applyingunsafe,unexpand,split,bin.
The benchmark is the name of the benchmark program to be processed, which is the
name of the directory under benchmarks/rs. For example, the following command
processes the avl benchmark:
./tool.py transform expand avlIf the given name does not match any of them, any benchmark whose name starts
with the given name will be processed. For example, the following command
processes the proxychains and proxychains-ng benchmarks:
./tool.py transform expand proxyThe benchmark name is an optional argument. If no benchmark is specified, all benchmarks will be processed. For example, the following command processes all benchmarks:
./tool.py transform expandYou can use the --exclude option to exclude benchmarks whose names start with
a certain prefix. This is especially useful when you want to process all
benchmarks except for a few of them. For example, the following command
processes all benchmarks except for proxychains and proxychains-ng:
./tool.py transform expand --exclude proxyYou can exclude multiple benchmarks by specifying the --exclude option
multiple times or by separating the names with commas. For example, the
following commands process all benchmarks except for avl, proxychains, and
proxychains-ng:
./tool.py transform expand --exclude avl --exclude proxy./tool.py transform expand --exclude avl,proxyWhen processing multiple benchmarks, tool.py immediately aborts if any of them
fails to be processed. To continue processing the remaining benchmarks even upon
failure, use the --keep-going option:
./tool.py transform expand --keep-goingIf there are failed benchmarks, tool.py will show the list of them at the end
of the output.
The following command transforms avl to the expand stage:
./tool.py transform expand avlThis will not transform the code if benchmarks/rs-expand/avl already exists.
To overwrite the existing code, use the --overwrite option:
./tool.py transform expand avl --overwritetool.py runs Crat in the release mode by default. If you want to run it in the
debug mode, you need to set the DEBUG environment variable:
DEBUG=1 ./tool.py transform expand avlThis would be useful when inspecting the stack traces or frequently re-compiling Crat during development.
If the stage depends on another stage, the tool.py will automatically
transform the required stage first if it has not been transformed yet. For
example, the following command transforms avl to the expand stage if
necessary, and then transforms it to the extern stage:
./tool.py transform extern avlNote that the --overwrite option only applies to the last stage by default.
Therefore, the following command never overwrites the expand stage:
./tool.py transform extern avl --overwriteTo overwrite other stages, you can increase the depth by using the
--overwrite-depth option:
./tool.py transform extern avl --overwrite --overwrite-depth 2The default depth is 1, and any positive integer is allowed. When max is
given, all stages will be overwritten:
./tool.py transform extern avl --overwrite --overwrite-depth maxThe following command builds the transformed avl in the expand stage:
./tool.py build expand avlThis will automatically transform avl to the expand stage if it has not
been transformed yet. To overwrite the existing code, use the --overwrite
option:
./tool.py build expand avl --overwritetool.py builds the transformed code in the release mode by default. If you
want to build it in the debug mode, use the --debug option:
./tool.py build expand avl --debugThe following command runs the test suite of the transformed avl in the
extern-post stage:
./tool.py test extern-post avlAs in build, --overwrite and --debug options can be used.
The following command remove the transformed avl in the expand stage:
./tool.py clean expand avlWhen multiple benchmarks are to be cleaned at once, a confirmation prompt will
be displayed before removing them. To skip the confirmation, use the --yes or
-y option:
./tool.py clean expand --yes