Nathon Mei
Nathon Mei

Reputation: 73

Compile app with linked dll with CMake. Need to see a working sample

Answer is found. To save your time from reading alot:

Useful Document Here:
https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets

The working CMakeLists.txt is like this:

cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
add_library(Lib SHARED IMPORTED)
set_property(TARGET Lib PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/lib.dll")
set_property(TARGET Lib PROPERTY IMPORTED_IMPLIB "${PROJECT_SOURCE_DIR}/lib.dll.a") //Notice: lib.lib here if you are using VS building system.
add_executable(App app.cxx)
target_link_libraries(App Lib)

Most tutorial online will assume you are using MS VS build system. Thus they will keep talking about importing a "*.lib" file.
If you use GCC(MinGW) like me, the actually file you are looking for is "*.dll.a"


Edit in Sep.17
No it's not right. We are using a DLL. And a DLL should not affect the compiling.
DLL should be whenever you want to place them into the folder which the .exe required instead of compiling check for header.
But we are trying to unpack a header from a dll.
There must be something wrong with this workflow.

CMake and GCC
I cannot use any IDE nor VS Build Tool due to the lack of license in my company.
Thus I'll have to learn about CMake + GCC for an open-sourced compile environment.
I could compile app and static library correctly now. But stuck in dll linkage.
This should be a simple one but since I can't find any sample on Google thus I need your help to correction the CMake workflow in this DLL linking job. Thanks.

Or maybe any hyperlink where could find a right direction.
As I know, I could simply add the dll library in IDE like VisualStudio and it will do all the magic to exchange it into something containing a header file. I must missed this part in CMake.

My Step:

  1. Compile a dll
  2. Compile an legacy app without dll
  3. Recreate the app with function linked from dll (BOOM!)

Detailed codes below:


Step 1: Compile a dll

Code in Test.h:

#pragma once
#ifdef TEST_EXPORTS
    #define TEST_API __declspec(dllexport)
#else
    #define TEST_API __declspec(dllimport)
#endif
extern "C" TEST_API int helloworld();

Code in Test.cxx:

#include <iostream>
#include "Test.h"
int helloworld() {
    std::cout << "I hate HelloWorld\n";
    return 0;
}

Code in CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(Test)
include(GenerateExportHeader)
add_library(Test SHARED Test.cxx)
generate_export_header(Test)

Compile it. Get a "libTest.dll". Good.

Step 2: Compile a legacy app without a dll

Let's skip it. Just a hello world console app. Nothing special.
Compile finished. Good to go.

Step 3: Recreate the app with linked dll

I've tried so many sample from google but no luck till now.
I've tried the library's name both "Test" and "libTest".
I've tried to put the dll directly in both ${PROJECT_BINARY_DIR}, ${PROJECT_SOURCE_DIR}, and make an add_subdirectory(libStore).
I've tried to use find_package(Test/libTest).
Thus I think there should be something incorrect in my cmake and source code.

Code in App.cxx:

#include <iostream>
#include "Test.h" //Also tried "libTest.h"
int main() {
    std::cout << helloworld();
    getchar();
    return 0;
}

Attempt 1:

Put libTest.dll under sub directory "/Lib"
Code in root CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}/Lib")
add_subdirecotry(Lib)
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest

Code in /Lib CMakeLists.txt:

add_library(libTest libTest.dll)
set_target_properties(libTest PROPERTIES LINKER_LANGUAGE C)

Build result:

Fatal Error: Test.h(libTest.h): No such file or directory.

Attempt 2:

Put libTest.dll directly in source directory (${PROJECT_SOURCE_DIR})
Code in CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}")
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest

Build Result:

Fatal Error: Test.h(libTest.h): No such file or directory.

Attempt 3:

Same with Attempt 2 but add a find_package(libTest) function.

cmake_minimum_required(VERSION 3.10)
project(App VERSION 1.0)
include_directories("${PROJECT_SOURCE_DIR}")
find_package(libTest)
add_executable(App App.cxx)
target_link_libraries(App libTest) //Tried both Test and libTest

CMake Warning:

Could not find a package configuration file provided by "libTest" with any of the following names:
libTestConfig.cmake
libTest-config.cmake

Created an empty file names libTestConfig.cmake in source directory. Build Result:

Fatal Error: Test.h(libTest.h): No such file or directory.

BOOM!

Upvotes: 3

Views: 5608

Answers (2)

Nathon Mei
Nathon Mei

Reputation: 73

At last, I found the answer here:

https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/Exporting-and-Importing-Targets

First:

All of the code in my old attempts are assuming you have your source code in your project folder.
If you want to import a DLL you get from outside, the actually CMakeLists.txt should look like this:

cmake_minimum_required(VERSION 3.10)
project(Test VERSION 1.0)
add_library(Lib SHARED IMPORTED)
set_property(TARGET Lib PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/lib.dll")
set_property(TARGET Lib PROPERTY IMPORTED_IMPLIB "${PROJECT_SOURCE_DIR}/lib.dll.a") //Notice: lib.lib here if you are using VS building system.
add_executable(App app.cxx)
target_link_libraries(App Lib)

Second:

Almost all the tutorial online will assume you are using MS VS build system. Thus they will keep talking about importing a "*.lib" file.
Which will be a big mislead and makes you meaninglessly tracing the non-exist lib file and confuse it with the dll file itself.
If you use GCC(MinGW) like me, the actually file you are looking for is "lib.dll.a"

Upvotes: 3

sfb103
sfb103

Reputation: 384

I think the problem may be here:

include_directories("${PROJECT_SOURCE_DIR}")

Rather than having an issue finding the DLL itself, it seems like cmake is simply having an issue finding the Test.h (or libTest.h) header file. Try putting the DLL's header file in a path that's specified via cmake's "include_directories".

Upvotes: 0

Related Questions