I’m currently trying to use a DLL library written in Rust from C++ with cmake. The output from Rust is a .dll and a .dll.lib file (for linking). I’ve generated a C header file and created a new project with cmake-init.
My main code looks like this - GitHub - fschutt/cpptest: cpptest with cmake-init
// thirdparty/azul/azul-mini.h
#pragma once
extern "C" {
typedef struct {
double x;
double y;
} AzSvgVector;
// Returns the normalized vector
AzSvgVector AzSvgVector_normalize(const AzSvgVector* svgvector);
}
// source/main.cpp
#include <iostream>
#include <string>
#include "azul-mini.h"
auto main() -> int {
auto vector = AzSvgVector { 5.0, 10.0 };
auto normalized = AzSvgVector_normalize(&vector);
std::cout << normalized.x << normalized.y << std::endl;
return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
include(cmake/prelude.cmake)
project(
cpptest
VERSION 0.1.0
DESCRIPTION "This is a short description"
HOMEPAGE_URL "https://azul.rs"
LANGUAGES CXX
)
docs_early_return()
include(cmake/project-is-top-level.cmake)
include(cmake/variables.cmake)
# ---- Declare library ----
add_library(
cpptest_lib OBJECT
source/lib.cpp
)
# add azul library
add_library(azul SHARED IMPORTED)
set_target_properties(
azul PROPERTIES
IMPORTED_LOCATION "${AZUL_LINK_PATH}/azul.dll"
IMPORTED_IMPLIB "${AZUL_LINK_PATH}/azul.dll.lib"
INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/thirdparty/azul"
)
target_include_directories(
cpptest_lib ${warning_guard}
PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/source>"
)
target_compile_features(cpptest_lib PUBLIC cxx_std_17)
# ---- Declare executable ----
add_executable(cpptest_exe source/main.cpp)
add_executable(cpptest::exe ALIAS cpptest_exe)
set_target_properties(
cpptest_exe PROPERTIES
OUTPUT_NAME cpptest
EXPORT_NAME exe
)
target_compile_features(cpptest_exe PRIVATE cxx_std_17)
# link azul library
target_link_libraries(cpptest_exe PRIVATE azul)
# ---- Install rules ----
if(NOT CMAKE_SKIP_INSTALL_RULES)
include(cmake/install-rules.cmake)
endif()
# ---- Developer mode ----
if(NOT cpptest_DEVELOPER_MODE)
return()
elseif(NOT PROJECT_IS_TOP_LEVEL)
message(
AUTHOR_WARNING
"Developer mode is intended for developers of cpptest"
)
endif()
include(cmake/dev-mode.cmake)
I have two problems:
- Using
${AZUL_LINK_PATH}
(an environment variable set outside of cmake) works fine forIMPORTED_LOCATION
, but notIMPORTED_IMPLIB
(?). I only get a “cannot file /azul.dll.lib” error, but it does work when I manually expand theAZUL_LINK_PATH
variable, i.e.
# doesnt' work:
set_target_properties(
azul PROPERTIES
IMPORTED_LOCATION "${AZUL_LINK_PATH}/azul.dll"
IMPORTED_IMPLIB "${AZUL_LINK_PATH}/azul.dll.lib" # doesnt' work with azul.lib either
INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/thirdparty/azul"
)
# works:
set_target_properties(
azul PROPERTIES
IMPORTED_LOCATION "${AZUL_LINK_PATH}/azul.dll"
IMPORTED_IMPLIB "C://User/fschutt/Development/azul/target/release/azul.dll.lib"
INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/thirdparty/azul"
)
-
The next error is that “azul-mini.h” cannot be found, even though I declared it under
INTERFACE_INCLUDE_DIRECTORIES
. Why? Obviously it’s the interface file, why doesn’t it automatically get added to my include directories? I can only fix that error by using a relative path.i.e.#include "../thirdparty/azul/azul-mini.h"
. Even addinginclude_directories(thirdpary/azul)
to the CMakeLists.txt does not fix it. -
The third error (once I fix the second one with my workaround) is an “unresolved symbol” error. I have specified everything I need to link azul:
# declare library and set paths
add_library(azul SHARED IMPORTED)
set_target_properties(
azul PROPERTIES
IMPORTED_LOCATION "${AZUL_LINK_PATH}/azul.dll"
IMPORTED_IMPLIB "${AZUL_LINK_PATH}/azul.dll.lib"
INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/thirdparty/azul"
)
# ...
target_link_libraries(cpptest_exe PRIVATE azul)
I’ve found out that for MSVC you have to add #pragma(lib, "azul")
, but if I do that I just get more “undefined reference” errors, because azul.dll depends on system libraries (kernel32.dll, opengl32.dll) - do I have to manually add all default system libraries (and if I do that, I get errors that they conflict with msvcrt.dll)?
So at this point I’ve stopped. I have now spent an entire afternoon trying to configure cmake to link a single DLL with a single header. This is exactly why I use Rust instead of C++, dependency management in C++ is just an extremely frustrating experience. I just want to link cpptest.exe to my azul.dll library, it can’t be that hard. In Rust I just do println!("cargo:rustc-link-search={}", env!("AZUL_LINK_PATH"));
and it links the azul.dll
and azul.dll.lib
file correctly. Now I want to do the same with cmake and nothing works.
Any help is appreciated.
CMake version: 3.22.1
OS: Windows 8.1
Compiler: MSVC / cl.exe Version 19.28.29336