Problem compiling code on i32 (with i64)


#1

Hello,

my latest PR for nix-rust fails on i686 machines:

https://travis-ci.org/carllerche/nix-rust/jobs/78082470

Is there a way to conditionally compile this for the different sizes of the long in C (the mq_attr struct has c_long and they are 32 bits on i686 and 64 bits on 64bit machines.).

I thought about adding a constant to the top like this:

#[cfg(target_pointer_width = "64")]
const O_NONBLOCK_BITS: i64 = 2048;

#[cfg(target_pointer_width = "32")]
const O_NONBLOCK_BITS: i64 = 2048;

But this is not really a good idea as it does not use the O_NONBLOCK from mq.rs (which I want to use).

Is there a way to conditionally compile the one line that does not compile?

Markus


#2

If you want an integer of the size of a pointer on the compiling platform, use usize and/or isize.

Otherwise please try to explain it more clearly as your code example shows the same two lines for both condinions.


#3

Sorry, my explanation was confusing. The real problem is not the code shown but a struct which contains a variable witch is a long in C (either 32 or 64 bits).

The long is defined like this:

pub mq_flags: c_long,

in my test I try to do this:

let new_attr_non_blocking =  MqAttr::new(O_NONBLOCK.bits() as i64, 10, MSG_SIZE, 0);

The problem is the “O_NONBLOCK.bits() as i64” part. This breaks on 32 bit systems.
The O_NONBLOCK will be used for the mq_flags variable shown above. That must be a c_long to be compliant with the Linux headers.

The bitflag containing O_NONBLOCK is defined like this:

bitflags!(
        flags MQ_OFlag: c_int {
            const O_RDONLY    = 0o00000000,
            const O_WRONLY    = 0o00000001,
            const O_RDWR      = 0o00000002,
            const O_CREAT     = 0o00000100,
            const O_EXCL      = 0o00000200,
            const O_NONBLOCK  = 0o00004000,
            const O_CLOEXEC   = 0o02000000,
        }
    );

That is O_NONBLOCK is 2048.

My question was if it is possible to compile the “O_NONBLOCK.bits() as i64” with a 32 bit long on a 32 bit Linux system but as a 64 bit on any modern Linux system.

I hope this is less confusing.

Would it be ok to cast the O_NONBLOCK.bits() to a c_long? That should work on all platforms. It works but I am not sure if it is a good idea.

Markus


#4

I am not sure if it really works, but if casting to an i64 works, then try using isize instead.

The size of isize is the size of a pointer on the targeted system, so if you compile on x32 it will be 32-bit, when on x64 it will be 64-bit.

Also, why are you not just casting to a c_long?

Edit: Sorry, I didn’t read your last line.
If your struct contains a c_long then I would always prefer to cast to that, although it might be possible to use an isize in the struct itself.

Does your struct contain other variables?
If yes, are they Rust-types or C-types?


#5

Thanks for the answer. Very helpful. I think casting to c_long is the best option. I will provide wrapper functions that hide this from the user of the library.

The whole struct is defined like this:

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MqAttr {
    pub mq_flags: c_long,
    pub mq_maxmsg: c_long,
    pub mq_msgsize: c_long,
    pub mq_curmsgs: c_long,
    pad: [c_long; 4]
}

It is a Rust wrapper around the C struct used by the Posix Message Queues (The pad at the end is necessary to be compliant with the Linux header files and to avoid a broken Stack).


#6

In that case I would use c_long.

The declaration of c_long shows how it is defined:

#[cfg(any(target_pointer_width = "32", windows))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
#[cfg(all(target_pointer_width = "64", not(windows)))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;

Which is exactly what you suggested in your first post.
There is would be no difference if you did that yourself.

And it is about the same as isize's definition:

#[cfg(target_pointer_width = "32")]
int_module! { isize, 32 }
#[cfg(target_pointer_width = "64")]
int_module! { isize, 64 }

If, at some point, you notice that using the rust-type isize would improve readability, then you might just use that as well.

It is up to you to choose what you are going to use.


#7

Thanks, that has all helped me a lot!