awelkie
awelkie

Reputation: 2652

How can I get the value of a const at compile time?

My goal is to create a C API where the user is required to provide a block of memory with a certain size. This size happens to be the size of a struct in my rust library, and so I'd like to extract the size of the rust struct and place it in a header file as a C macro.

The problem is that I'm cross-compiling my library, so I can't run a program on my computer that prints core::mem::size_of::<MyStruct>(). But I can store that value in a const variable in my library.

Is there any way to extract the value of this const variable representing the size of my struct at compile time such that I can then paste it into a C header file?

Upvotes: 1

Views: 1333

Answers (2)

eggyal
eggyal

Reputation: 125965

I think it would be wiser to approach this from the opposite direction: define a C struct in a .h file that you will distribute with your library for consumers to use, and then declare the struct #[repr(C)] in Rust (you could even have bindgen generate the declaration for you automatically from the .h as part of your build).

Upvotes: 0

Peter Hall
Peter Hall

Reputation: 58805

Definitely do not do this:

  1. In a new crate, import the type in question, and create a function that returns its size:

    #[no_mangle]
    pub fn size_of_mystruct() -> usize {
        std::mem::size_of::<MyStruct>()
    }
    
  2. Get the LLVM-IR output:

    CARGO_INCREMENTAL=0 cargo rustc -- --emit=llvm-ir -o ir
    

    Make sure to add the --target option too. This will create a few files, one which should have extension .ll. The CARGO_INCREMENTAL=0 is important - without it, it will create lots of .ll files, and who knows which is the right one! Open the file and search for size_of_mystruct. You'll find something like this:

    ; Function Attrs: uwtable
    define i64 @size_of_mystruct() unnamed_addr #0 !dbg !142 {
    start:
    ; call core::mem::size_of
      %0 = call i64 @_ZN4core3mem7size_of17hc5e3caf4d8826b98E(), !dbg !144
      br label %bb1, !dbg !144
    
  3. Search for the internal function being called here. (In this case _ZN4core3mem7size_of17hc5e3caf4d8826b98E). It will look like this:

    ; core::mem::size_of
    ; Function Attrs: inlinehint uwtable
    define internal i64 @_ZN4core3mem7size_of17hc5e3caf4d8826b98E() unnamed_addr #1 !dbg !67 {
    start:
      %tmp_ret = alloca i64, align 8
      store i64 40, i64* %tmp_ret, align 8, !dbg !87
      %0 = load i64, i64* %tmp_ret, align 8, !dbg !87
      br label %bb1, !dbg !87
    
  4. This is the important bit: store i64 40. The struct is 40 bytes!

  5. Automate the process!

  6. Wait until the whole process mysteriously breaks.

Upvotes: 2

Related Questions