1

I created a dynamic lib using Rust (crate type = "cdylib"). Rust/Cargo produced two files: text_loading_lib.dll and text_loading_lib.dll.lib. I want to build a really simple project (hello_world.c) on Windows that uses a function from this lib using only MSVC (the Microsoft Visual C++ toolset) and JetBrains CLion/CMake.

main.c

#include <stdio.h>

typedef unsigned long long usize_t; // 64 bit / usize on 64 bit machine
extern void show_loading_animation_ffi(usize_t, usize_t, int, usize_t (*prog_fn)());

// function that tells the lib how many percent progress we made so far
usize_t progress_reporter() { return (usize_t) 20 }

int main(void) {
    show_loading_animation_ffi(0, 100, TARGET_STDERR, progress_reporter);
    return 0;
}

I'm familiar with this process on UNIX, but I have no clue how it is done on Windows. On UNIX, I'd link the shared object against main.c during compilation and provide its location using LD_LIBRARY_PATH at runtime. Is is similar on Windows?

I also tried it with a CMAKE project using JetBrains CLion, but still no success. When I try to run main() in main.c from CLion, there are always errors that the target can't be created. The library files created with Rust (text_loading_lib.dll and text_loading_lib.dll.lib) are in the same directory as CMakeLists.txt and main.c.

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(main C)

set(CMAKE_C_STANDARD 11)

add_executable(main main.c)

# the path is correct
target_link_libraries(main text_loading_animation)
#also tried: target_link_libraries(main text_loading_animation.dll)
#also tried:  target_link_libraries(main text_loading_animation.dll.lib)

CLion-Output is:

[ 50%] Linking C executable main.exe
LINK Pass 1: command "C:\PROGRA~2\MICROS~2\2019\COMMUN~1\VC\Tools\MSVC\1426~1.288\bin\Hostx64\x64\link.exe /nologo @CMakeFiles\main.dir\objects1.rsp /out:main.exe /implib:main.lib /pdb:C:\dev\lib-text-loading-animation-rust\calling-from-c-examples\windows\cmake-build-debug\main.pdb /version:0.0 /machine:x64 /debug /INCREMENTAL /subsystem:console text_loading_animation.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\main.dir/intermediate.manifest CMakeFiles\main.dir/manifest.res" failed (exit code 1104) with the following output:
LINK : fatal error LNK1104: File "text_loading_animation.lib" can't be opened.
NMAKE : fatal error U1077: ""C:\Program Files\JetBrains\CLion 2020.1.1\bin\cmake\win\bin\cmake.exe"": Return-Code "0xffffffff"
Stop.
NMAKE : fatal error U1077: ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\bin\HostX64\x64\nmake.exe"": Rückgabe-Code "0x2"
Stop.
NMAKE : fatal error U1077: ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\bin\HostX64\x64\nmake.exe"": Rückgabe-Code "0x2"
Stop.
NMAKE : fatal error U1077: ""C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.26.28801\bin\HostX64\x64\nmake.exe"": Rückgabe-Code "0x2"
Stop.
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
phip1611
  • 5,460
  • 4
  • 30
  • 57
  • "*But still no success*"... what exactly does this mean? Did you receive an error of some kind? If so, what was the specific error? BTW, the approaches for linking against an external library in CMake are well-documented [here](https://stackoverflow.com/questions/8774593/cmake-link-to-external-library). Perhaps, you could try one of those other methods. – Kevin Jun 22 '20 at 15:22
  • When I run the main() in main.c in CLION the program never starts. It always says "the target could not be created". NMAKE : fatal error U1073: I don't understand this because the library created by rust is definetly in the path that stands in CMakeLists.txt – phip1611 Jun 22 '20 at 15:24
  • 2
    What are the errors you get? They will help. For example I can see that you have written the library name as `text_loading_animation.DDL.lib` instead of `text_loading_animation.DLL.lib`. Also keep in mind that on Windows there is no `LD_LIBRARY_PATH` or `rpath` equivalent. Your dll has to be either in the same directory as the executable or it has to be on your system path. – stardust Jun 22 '20 at 15:24
  • 1
    Putting the *complete* compilation output and error message in your question post would go a long way toward understanding what **specifically** is going wrong. And as mentioned, it looks like you have a typo in the library name. – Kevin Jun 22 '20 at 15:32
  • I copied the two files (`text_loading_animation.dll` and `text_loading_animation.dll.lib`) into the same directory as `CMakeLists.txt` and `main.c`. I changed the CMakeLists.txt to `target_link_libraries(main text_loading_animation)` It says `[ 50%] Linking C executable main.exe LINK Pass 1: command "...link.exe /nologo @CM... LINK : fatal error LNK1104: File "text_loading_animation.lib" can't be opened. NMAKE : fatal error U1077: ""C:\Program Files\JetBrains\CLion 2020.1.1\bin\cmake\win\bin\cmake.exe"": Return-Code "0xffffffff"` But it's definitly in this directory with this name. – phip1611 Jun 22 '20 at 15:34
  • I added the compiler output to the question. And thanks so far to @stardust - did not know the library files must be in the same directory on Windows. – phip1611 Jun 22 '20 at 15:43
  • Hmm it seems cmake is looking for `text_loading_animation.lib` but your file is named `text_loading_animation.dll.lib` can you try renaming the file to `text_loading_animation.lib` just to see what happens. – stardust Jun 22 '20 at 15:45
  • Nothing changed. It seems like CMake/CLion is completly ignoring the files. – phip1611 Jun 22 '20 at 15:48
  • I suggest you follow one of the approaches outlined in the responses in my earlier linked SO question. You need to somehow provide the linker the **full** path to the library you want to link to. Simply putting the library in the same directory as the CMake file doesn't help. – Kevin Jun 22 '20 at 15:53
  • You can try giving the full path to the library. For example if the library is in the same directory as the CMakeLists.txt you are using you can do `target_link_libraries(main ${CMAKE_CURRENT_SOURCE_DIR}/text_loading_animation.dll.lib)` – stardust Jun 22 '20 at 15:56
  • I copied the `{*.dll, *.dll.lib}`-files manually into the cmake-target-path (used by clion) and linking worked with `target_link_libraries(main text_loading_animation.dll.lib)`! I can execute main.exe properly. But it's still not a handy way. – phip1611 Jun 22 '20 at 15:56
  • Ah! Compilation works know. The problem was that CLION doesn't include the DLL (runtime file) automatically. – phip1611 Jun 22 '20 at 16:02

1 Answers1

2

I got it working with CMake as well as the Command Line.

Cmake: CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(main C)

set(CMAKE_C_STANDARD 11)

add_executable(main main.c)
# "*.dll.lib" - important! not just *.dll
target_link_libraries(main ${CMAKE_CURRENT_SOURCE_DIR}/../../target/release/text_loading_animation.dll.lib)

# copy DLL file into target dir
add_custom_command(TARGET main POST_BUILD              # Adds a post-build event to "main"
    COMMAND ${CMAKE_COMMAND} -E copy_if_different      # which executes "cmake - E copy_if_different..."
    "${PROJECT_SOURCE_DIR}/text_loading_animation.dll" # <--this is in-file
    $<TARGET_FILE_DIR:main>)                           # <--this is out-file path

Now you can "run main" in Jetbrains CLion for example.


Command Line (windows batch script)

Important part is:

  1. cl main.c /link text_loading_animation.dll.lib
  2. main.exe

Full Batch script:

@echo off

rem: clean old data
del main.exe main.obj *.dll *.dll.lib

rem: copy rust lib into current dir
xcopy /y ..\..\target\release\text_loading_animation.dll .
xcopy /y ..\..\target\release\text_loading_animation.dll.lib .


rem: sets up Visual Studio Compilertoolsuite environment
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"

rem: *.dll.lib contains header information during compile; *.dll is the runtime file that must be in the same directory/path

rem: "cl" is windows compiler: produces main.obj and main.exe; main.obj is not needed in the end;
rem:   it is only for the stage between compiling and linking
rem: /W4 is highest warnings flag
cl /W4 main.c /link text_loading_animation.dll.lib
del main.obj

rem: now execute
main.exe
phip1611
  • 5,460
  • 4
  • 30
  • 57
  • 1
    In addition to the other approaches for adding an external library to your CMake project I linked earlier, you can also **copy** the DLL to the executable folder using CMake itself, as seen [here](https://stackoverflow.com/questions/10671916/how-to-copy-dll-files-into-the-same-folder-as-the-executable-using-cmake/10672739#10672739). No need for manual steps... – Kevin Jun 22 '20 at 20:54
  • works, thanks! I edit my answer to include this. – phip1611 Jun 22 '20 at 21:25