Plegeus
Plegeus

Reputation: 260

Calling C from Rust with external headers in C file

I am trying to call C code from Rust, I succeeded! The only issue I get is when I try to take other libraries with me... the documentation says that you should include all headers in the one file you try to load in Rust, so I do this in the .c file...

#include <stdio.h>
#include <stdbool.h>

#include "dependencies/glfw-3.3.4/include/GLFW/glfw3.h"

int someFunc() {
    int i = glfwInit();
    glfwTerminate();
    return i;
}

But when I run the Rust program, it says glfwInit and glfwTerminate are unresolved symbols... If I do this instead:

...

#include <GLFW/glfw3.h>

...

I get the error in my Rust program that there is no such directory, though the library was linked correctly using CMake... I read something about a cmake crate, so I am guessing it has something to do with that, but at the moment I am completely clueless. I must say that I am new to both Rust and C/C++ (student in Computer Science...) :slight_smile:

Note that when I remove any glfw related stuff, everything works correctly! I am thinking if I can somehow invoke CMake from the build.rs file, that I can link everything in the C project correctly, right? I just do not understand very much CMake since I have been doing everything with an IDE (CLion by jet brains) and very limited commands in CMakeLists.txt.

This is how the project is organised...

project structure:

// generated with cargo new rust_project ...
    .../rust_project/      
       c_project/          // This was generated with the IDE for C (CLion)...
          dependecies/
             glfw-3.3.4/
                include/
                ...
          CMakeLists.txt   
          MyCFile.c         
          ...              
       src
          main.rs
       build.rs
       cargo.toml
       ...

CMakeLists.txt:

cmake_minimum_required(VERSION 3.17)
project(c_project)

set(CMAKE_C_STANDARD 11)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/glfw-3.3.4)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/dependencies/glfw-3.3.4/include)
##some more libraries... not currently included in MyCFile.c !##

add_library(c_project MyCFile.c)

target_link_libraries(c_project PRIVATE <other_libraries> glfw ${GLFW_LIBRARIES} <other_libraries>)

MyCFile.c:

#include <GLFW/glfw3.h>

int someFunc() {
    int i = glfwInit();
    glfwTerminate();
    return i;
}

main.rs:

extern "C" {
    fn someFunc() -> i32;
}

fn main() {
    unsafe {
        println!("{}", someFunc());
    }
}

build.rs

extern crate cc;

fn main() {
    cc::Build::new()
        .file("c_project/MyCFile.c")
        .compile("library");
    /*
     * I am guessing here goes something along the lines:
     * "CMakeLists.txt".execute (as pseudo code...)
     */
}

cargo.toml:

[package]
name = "rust_project"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[build-dependencies]
cc = "1.0.70"

the error message upon "cargo check":

error: failed to run custom build command for `version_zero v0.1.0 (D:\...\rust_project)`

Caused by:
  process didn't exit successfully: `D:\...\rust_project\target\debug\build\rust_project-bf398c13c8af8b0c\build-script-build` (exit code: 1)
  --- stdout
  TARGET = Some("x86_64-pc-windows-msvc")
  OPT_LEVEL = Some("0")
  HOST = Some("x86_64-pc-windows-msvc")
  CC_x86_64-pc-windows-msvc = None
  CC_x86_64_pc_windows_msvc = None
  HOST_CC = None
  CC = None
  CFLAGS_x86_64-pc-windows-msvc = None
  CFLAGS_x86_64_pc_windows_msvc = None
  HOST_CFLAGS = None
  CFLAGS = None
  CRATE_CC_NO_DEFAULTS = None
  CARGO_CFG_TARGET_FEATURE = Some("fxsr,sse,sse2")
  DEBUG = Some("true")
  running: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30037\\bin\\HostX64\\x64\\cl.exe" "-nologo" "-MD" "-Z7" "-Brepro" "-W4" "-FoD:\\...\\rust_project\\target\\debug\\build\\version_zero-54603a96dee57aac\\out\\c_project/MyCFile.o" "-c" "c_project/MyCFile.c"
  MyCFile.c
  c_project/MyCFile.c(5): fatal error C1083: Cannot open include file: 'GLFW/glfw3.h': No such file or directory
  exit code: 2

  --- stderr


  error occurred: Command "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.29.30037\\bin\\HostX64\\x64\\cl.exe" "-nologo" "-MD" "-Z7" "-Brepro" "-W4" "-FoD:\\...\\rust_project\\target\\debug\\build\\version_zero-54603a96dee57aac\\out\\c_project/MyCFile.o" "-c" "c_project/MyCFile.c" with args "cl.exe" did not execute successfully (status code exit code: 2).

I used: https://crates.io/crates/cc, https://liufuyang.github.io/2020/02/02/call-c-in-rust.html, https://docs.rust-embedded.org/book/interoperability/c-with-rust.html


CMake was installed through: https://cmake.org/download/.

Downloaded the option: "Windows x64 Installer: Installer tool has changed. Uninstall CMake 3.4 or lower first! cmake-3.21.2-windows-x86_64.msi" Honoustly don't know how you would do it with the zip files...

tried to uninstall the current CMake, and downloaded version 3.4 (and installed it).

Also changed the build.rs file to:

use cmake;

fn main() {
    let dst = cmake::build("c_project");
    println!("cargo:rustc-link-search=native={}", dst.display());
    println!("cargo:rustc-link-lib=static=MyCFile");
}

cargo check compiles just fine, cargo run, will produce an error:

<lots of file paths...>
  = note: LINK : fatal error LNK1181: cannot open input file 'MyCFile.lib'

Note that I do not get any indications anymore of cmake not being installed...

Upvotes: 1

Views: 4147

Answers (1)

vVicente
vVicente

Reputation: 58

Cannot open include file: 'GLFW/glfw3.h': No such file or directory - the error states that the c compiler cannot find the header file glfw3.h from your build point. The cc crate provides the .include for it's builder. Find out where you have the glfw3.h file and pass its path into the include builder method:

fn main() {
    cc::Build::new()
        .file("c_project/MyCFile.c")
        .include("path/to/glfw3.h")
        .compile("library");
    /*
     * I am guessing here goes something along the lines:
     * "CMakeLists.txt".execute (as pseudo code...)
     */
}

Upvotes: 0

Related Questions