In C and C++, I can include a header file from a library and call its functions directly without glue code. Are there any other languages that offer this feature? Perhaps a language which compiles to C could leave the include statement and all function calls intact, so that they would be correctly compiled and linked by the C compiler.
Other than C-based languages like C++ and Objective-C I know of no languages where you can straight up use C include headers and then call C functions directly. Many languages make interfacing with C pretty easy however:
Of the best I know are:
D: extern (C) double sin(double arg); then sin(0.5)
Cython: from libc.math cimport sin then sin(0.5)
Julia: t = ccall( (:clock, "libc"), Int32, ())
2021 update:
Rust: extern "C" { fn sin(input: f64) -> f64; } then sin(0.5) in an unsafe context.
Go with cgo actually allows exactly what was asked, importing .h-header files and calling code from them directly. See link for details. Was probably the correct answer even back in 2014.
Zig: const c = #cImport({ #cInclude("math.h"); }); then c.sin(0.5)
Related
I'm new to learning rust and I saw that rust uses generic lifetimes to validate references at compile time which is very nice. I didn't dig much around building a dll or shared library in rust but from what I saw a function can be exported from dll (like in c++). But if I want to export a function that takes a reference as a parameter or returns a reference other than static references, how will this work ? the dll and the app are not in the same project so the compiler can't check lifetimes in this case so this is simply not possible like exporting templated functions in c++ is not possible without instantiation but I don't know how instantiate a generic lifetime function in rust.
Why ask this question ? rust is aimed to be a system programming language and shared libraries are mandatory in any system so how a system built in rust will provide its api in pure rust without going through c ?
In c++ this is possible like in c :
struct some_type_c
{
int i;
float f;
void* p;
};
// vary between windows and unix likes
#define EXPORT some_platform_export
EXPORT void use_some_type_c(some_type_c* s) { ++s->i; }
struct some_type_cpp
{
int i;
float f;
void* p;
// may be implemented in a cpp file
EXPORT void use() { ++i; }
};
Since rust has no stable ABI, exported functions need to go through the C ABI and deal with raw pointers along the way.
When going through C, it's common practice to create more ergonomic functions that wrap the underlying unsafe FFI (foreign function interface) calls and have the right lifetime annotations in order to represent the relationship between different references.
Crates that dynamically load system libraries are often composed of two crates, one with a -sys suffix, containing the FFI bindings, and the more ergonomic version (e.g. openssl depends on openssl-sys, containing generated C-compatible types, using bindgen).
When exporting functions, the references lifetimes are lost when converting them to raw pointers.
However it's worth noting that all rust crates are statically linked at compile time, and lifetime checks are enforced across crate boundaries.
How do I declare an external MFC function that has LPCTSTR tokens?
I have the following C function in a library I wish to use:
DLL_PUBLIC void output( LPCTSTR format, ... )
Where DLL_PUBLIC is resolved to
__declspec(dllimport) void output( LPCTSTR format, ...)
In Rust, I was able to get things to build with:
use winapi::um::winnt::CHAR;
type LPCTSTR = *const CHAR;
#[link(name="mylib", kind="static")]
extern {
#[link_name = "output"]
fn output( format:LPCTSTR, ...);
}
I'm not sure this is the best approach, but it seems to get me part way down. Although the module is declared in a DLL module, the symbol decorations in the native DLL are such that it does not have _imp prepended to it in the binary. So I find that "static" seems to look for the correct module, although I still have not been able to get it to link.
The dumpbin output for the module (this target function) in "mylib.dll" is:
31 ?output##YAXPEBDZZ (void __cdecl output(char const *,...))
This is assuming that what you are trying to accomplish here is to link Rust code against a custom DLL implementation. If that is the case, then things are looking good.
First things first, though, you'll need to do some sanity cleanup. LPCTSTR is not a type. It is a preprocessor symbol that either expands to LPCSTR (aka char const*) or LPCWSTR (aka wchar_t const*).
When the library gets built the compiler commits to either one of those, and that decision is made for all eternity. Clients, on the other hand, that #inlcude the header are still free to choose, and you have no control over this. Lucky you, if you're using C++ linkage, and have the linker save you. But we aren't using C++ linkage.
The first order of action is to change the C function signature using an explicit type, so that clients and implementation always agree. I will be using char const* here.
C++ library
Building the library is fairly straight forward. The following is a bare-bones C++ library implementation that simply outputs a formatted string to STDOUT.
dll.cpp:
#include <stdio.h>
#include <stdarg.h>
extern "C" __declspec(dllexport) void output(char const* format, ...)
{
va_list argptr{};
va_start(argptr, format);
vprintf(format, argptr);
va_end(argptr);
}
The following changes to the original code are required:
extern "C": This is requesting C linkage, controlling how symbols are decorated as seen by the linker. It's the only reasonable choice when planning to cross language boundaries.
__declspec(dllexport): This is telling the compiler to inform the linker to export the symbol. C and C++ clients will use a declaration with a corresponding __declspec(dllimport) directive.
char const*: See above.
This is all that's required to build the library. With MSVC the target architecture is implied by the toolchain used. Open up a Visual Studio command prompt that matches the architecture eventually used by Rust's toolchain, and run the following command:
cl.exe /LD dll.cpp
This produces, among other artifacts, dll.dll and dll.lib. The latter being the import library that needs to be discoverable by Rust. Copying it to the Rust client's crate's root directory is sufficient.
Consuming the library from Rust
Let's start from scratch here and make a new binary crate:
cargo new --bin client
Since we don't need any other dependencies, the default Cargo.toml can remain unchanged. As a sanity check you can cargo run to verify that everything is properly set up.
If that all went down well it's time to import the only public symbol exported by dll.dll. Add the following to src/main.rs:
#[link(name = "dll", kind = "dylib")]
extern "C" {
pub fn output(format: *const u8, ...);
}
And that's all there is to it. Again, a few details are important here, namely:
name = "dll": Specifies the import library. The .lib extension is implied, and must not be appended.
kind = "dylib": We're importing from a dynamic link library. This is the default and can be omitted, though I'm keeping it for posterity.
extern "C": As in the C++ code this controls name decoration and the calling convention. For variadic functions the C calling convention (__cdecl) is required.
*const u8: This is Rust's native type that corresponds to char const* in C and C++. Using type aliases (whether those provided by the winapi crate or otherwise) is not required. It wouldn't hurt either, but let's just keep this simple.
With that everything is set up and we can take this out for a spin. Replace the default generated fn main() with the following code in src/main.rs:
fn main() {
unsafe { output("Hello, world!\0".as_ptr()) };
}
and there you have it. cargo running this produces the famous output:
Hello, world!
So, all is fine, right? Well, no, not really. Actually, nothing is fine. You could have just as well written, compiled, and executed the following:
fn main() {
unsafe { output(b"Make sure this has reasons to crash: %f".as_ptr(), "💩") };
}
which produces the following output for me:
Make sure this has reasons to crash: 0.000000💩
though any other observable behavior is possible, too. After all, the behavior is undefined. There are two bugs: 1 The format specifier doesn't match the argument, and 2 the format string isn't NUL terminated.
Either one can be fixed, trivially even, though you have opted out of Rust's safety guarantees. Rust can't help you detect either issue, and when control reaches the library implementation, it cannot detect this either. It will just do what it was asked to do, subverting each and every one of Rust's safety guarantees.
Remarks
A few words of caution: Getting developers interested in Rust is great, and I will do my best to try whenever I get a chance to. Getting Rust-curious developers excited about Rust is often just a natural progression.
Though I will say that trying to get developers excited about Rust by starting out with unsafe Rust isn't going to be successful. It's eventually going to provoke a response like: "Look, ma, a steep learning curve with absolutely no benefit whatsoever, who could possibly resist?!" (I'm exaggerating, I know).
If your ultimate goal is to establish Rust as a superior alternative to C (and in part C++), don't start by evaluating how not to benefit from Rust. Specifically, trying to import a variadic function (the unsafest language construct in all of C++) and exposing it as an unsafe function to Rust is almost guaranteed to be the beginning of a lost battle.
Now, this may read bad as it is already, but this isn't over yet. In an attempt to make your C++ code accessible from Rust, things have gotten worse! With a C++ compiler and static code analysis tools (assuming the format string is known at compile time, and the tools understand the semantics), the tooling can and frequently will warn about mismatches. That option is now gone, forever, and there's not even a base level of protection.
If you absolutely want to make some sort of logging available to Rust, export a function from the library that takes a single char const*, use Rust's format! macro, and provide a variadic wrapper to C and C++ clients.
I'm currently in the progress of learning Rust. I'm mainly using The Rust Programming Language book and this nice reference which relates Rust features/syntax to C++ equivalents.
I'm having a hard time understanding where the core language stops and the standard library starts. I've encountered a lot of operators and/or traits which seems to have a special relationship with the compiler. For example, Rust has a trait (which from what I understand is like an interface) called Deref which let's a type implementing it be de-referenced using the * operator:
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Another example is the ? operator, which seems to depend on the Result and Option types.
Can code that uses those operators can be compiled without the standard library? And if not, what parts of the Rust language are depending on the standard library? Is it even possible to compile any Rust code without it?
The Rust standard library is in fact separated into three distinct crates:
core, which is the glue between the language and the standard library. All types, traits and functions required by the language are found in this crate. This includes operator traits (found in core::ops), the Future trait (used by async fn), and compiler intrinsics. The core crate does not have any dependencies, so you can always use it.
alloc, which contains types and traits related to or requiring dynamic memory allocation. This includes dynamically allocated types such as Box<T>, Vec<T> and String.
std, which contains the whole standard library, including things from core and alloc but also things with further requirements, such as file system access, networking, etc.
If your environment does not provide the functionality required by the std crate, you can choose to compile without it. If your environment also does not provide dynamic memory allocation, you can choose to compile without the alloc crate as well. This option is useful for targets such as embedded systems or writing operating systems, where you usually won't have all of the things that the standard library usually requires.
You can use the #![no_std] attribute in the root of your crate to tell the compiler to compile without the standard library (only core). Many libraries also usually support "no-std" compilation (e.g. base64 and futures), where functionality may be restricted but it will work when compiling without the std crate.
DISCLAIMER: This is likely not the answer you're looking for. Consider reading the other answers about no_std, if you're trying to solve a problem. I suggest you only read on, if you're interested in trivia about the inner workings of Rust.
If you really want full control over the environment you use, it is possible to use Rust without the core library using the no_core attribute.
If you decide to do so, you will run into some problems, because the compiler is integrated with some items defined in core.
This integration works by applying the #[lang = "..."] attribute to those items, making them so called "lang items".
If you use no_core, you'll have to define your own lang items for the parts of the language you'll actually use.
For more information I suggest the following blog posts, which go into more detail on the topic of lang items and no_core:
Rust Tidbits: What Is a Lang Item?
Oxidizing the technical interview
So yes, in theory it is possible to run Rust code without any sort of standard library and supplied types, but only if you then supply the required types yourself.
Also this is not stable and will likely never be stabilized and it is generally not a recommended way of using Rust.
When you're not using std, you rely on core, which is a subset of the std library which is always (?) available. This is what's called a no_std environment, which is commonly used for some types of "embedded" programming. You can find more about no_std in the Rust Embedded book, including some guidance on how to get started with no_std programming.
I just started to learn Rust and would like to know whether it is possible to call WinAPI functions without unsafe?
extern crate libc;
fn main() {
unsafe {
libc::funcs::extra::kernel32::GetCurrentProcessId();
}
}
No, it is impossible, because they are direct bindings to functions in external C libraries, just like almost everything else in libc crate. It may be not obvious with functions like GetCurrentProcessId(), but these functions are unsafe because there is a lot of them which take and return raw pointers and null-terminated strings.
In order to call them without unsafe there should be an appropriate safe wrapper, just like for any other C library. There is no such wrapper yet, as far as I know. But you can write one just for the subset of WinAPI functions you need, it shouldn't be too hard. You can find more details on how to write safe wrappers for external libraries here and here.
I'm writing a light Unicode library, but I'm stuck as to whether to write it for C, or C++? C++ has the benefit of operator overloads and better class handling, but many programs are written in plain C and it would seem nice to be compatible with C. How should I decide what language to write this for?
By the way, I know that there are many of these libraries around; I'm writing the library merely as an exercise, though I'll probably use it in my programs.
Easy - write it in C and have C++ wrappers. This makes both the C and C++ consumers happy, and if written correctly there's little overhead in wrapping C with C++. Be sure to follow sane models for re-entrant code - for example, having init and destroy functions handling struct pointers in C would correspond to constructors and destructors of a class in C++, where the struct pointer corresponds to the this pointer.