Reputation: 27636
I have a Rust crate that is targeting AVR. If I do a cargo build
, it fails at linking, which is expected because I will need to add an extra object (compiled from C) to it. However, the error message shows that Cargo has correctly picked up from the target definition that it should use avr-gcc
for linking:
"avr-gcc" "-mmcu=atmega328p" ....
= note: chirp8-avr/target/avr-unknown-gnu-atmega328/release/deps/chirp8_avr-e38dd93db57fe6d7.chirp8_avr.dlqaoark-cgu.0.rcgu.o: In function `main':
chirp8_avr.dlqaoark-cgu.0:(.text.main+0x18a): undefined reference to `font_rom_size'
chirp8_avr.dlqaoark-cgu.0:(.text.main+0x19e): undefined reference to `read_font_rom'
chirp8_avr.dlqaoark-cgu.0:(.text.main+0x1b4): undefined reference to `prog_rom_size'
chirp8_avr.dlqaoark-cgu.0:(.text.main+0x1c6): undefined reference to `read_prog_rom'
collect2: error: ld returned 1 exit status
So the next logical step is to add my external C source to the crate. From what I understand, cc
is exactly the crate for that. So let's try that: I add cc
to my [build-dependencies]
, and write the following build.rs
:
fn main() {
cc::Build::new()
// .flag("-mmcu=atmega328p").pic(false)
.file("src/rom.c")
.compile("rom");
}
If I now try building again, this fails because Cargo suddenly seems to have forgotten to use avr-gcc
, and is instead trying to use the system's default C compiler:
running: "cc" "-O3" "-ffunction-sections" "-fdata-sections" "-fPIC" "-Wall" "-Wextra" "-o" "chirp8-avr/target/avr-unknown-gnu-atmega328/release/build/chirp8-avr-fd0f12cc4390c66b/out/src/rom.o" "-c" "src/rom.c"
cargo:warning=src/rom.c:1:10: fatal error: avr/pgmspace.h: No such file or directory
cargo:warning= 1 | #include <avr/pgmspace.h>
cargo:warning= | ^~~~~~~~~~~~~~~~
cargo:warning=compilation terminated.
exit code: 1
What am I doing wrong? Why is the target platform not picked up correctly by Cargo?
Upvotes: 0
Views: 261
Reputation: 126025
As documented in the cc crate's Readme:
This crate calls out to the most relevant compiler for a platform, for example using
cl
on MSVC.
Inspecting the source reveals that the cc crate does this with some hard-coded logic for certain statically known host/target combinations. Unfortunately, avr is not a target for which it knows to use avr-gcc
.
The Readme also states:
External configuration via environment variables
To control the programs and flags used for building, the builder can set a number of different environment variables.
[ deletia ]
CC
- the actual C compiler used. Note that this is used as an exact executable name, so (for example) no extra flags can be passed inside this variable, and the builder must ensure that there aren't any trailing spaces. This compiler must understand the-c
flag. For certainTARGETs
, it also is assumed to know about other flags (most common is-fPIC
).
[ deletia ]
Each of these variables can also be supplied with certain prefixes and suffixes, in the following prioritized order:
<var>_<target>
- for example,CC_x86_64-unknown-linux-gnu
<var>_<target_with_underscores>
- for example,CC_x86_64_unknown_linux_gnu
<build-kind>_<var>
- for example,HOST_CC
orTARGET_CFLAGS
<var>
- a plainCC
,AR
as above.If none of these variables exist,
cc-rs
uses built-in defaults
Therefore, I suggest adding to your build.rs
:
std::env::set_var("CC_avr-unknown-gnu-atmega328", "avr-gcc");
Upvotes: 1