set_target_properties neither finds .lib file nor header files and doesn't link library correctly

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:

  1. Using ${AZUL_LINK_PATH} (an environment variable set outside of cmake) works fine for IMPORTED_LOCATION, but not IMPORTED_IMPLIB (?). I only get a “cannot file /azul.dll.lib” error, but it does work when I manually expand the AZUL_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"
)
  1. 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 adding include_directories(thirdpary/azul) to the CMakeLists.txt does not fix it.

  2. 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

The .dll.lib extension seems odd, but I guess it’s fine. If you configure with the --trace-expand flag additionally, are the paths passed to the IMPORTED_IMPLIB and INTERFACE_INCLUDE_DIRECTORIES properties correct? What do the generated command lines look like?